chiark / gitweb /
JPEG support and other fixes from Nick Clark
[ssr] / StraySrc / Libraries / Sapphire / s / chunk
1 ;
2 ; chunk.s
3 ;
4 ; Loading and management of options chunks (MDW)
5 ;
6 ; © 1995-1998 Straylight
7 ;
8
9 ;----- Licensing note -------------------------------------------------------
10 ;
11 ; This file is part of Straylight's Sapphire library.
12 ;
13 ; Sapphire is free software; you can redistribute it and/or modify
14 ; it under the terms of the GNU General Public License as published by
15 ; the Free Software Foundation; either version 2, or (at your option)
16 ; any later version.
17 ;
18 ; Sapphire is distributed in the hope that it will be useful,
19 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 ; GNU General Public License for more details.
22 ;
23 ; You should have received a copy of the GNU General Public License
24 ; along with Sapphire.  If not, write to the Free Software Foundation,
25 ; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26
27 ;----- Standard header ------------------------------------------------------
28
29                 GET     libs:header
30                 GET     libs:swis
31
32                 GET     libs:stream
33
34 ;----- External dependencies ------------------------------------------------
35
36                 GET     sapphire:alloc
37                 GET     sapphire:fastMove
38                 GET     sapphire:flex
39                 GET     sapphire:string
40
41                 GET     sapphire:xfer.xsave
42
43 ;----- Main code ------------------------------------------------------------
44
45                 AREA    |Sapphire$$Code|,CODE,READONLY
46
47 ; --- chunk_create ---
48 ;
49 ; On entry:     --
50 ;
51 ; On exit:      R0 == chunk file handle
52 ;               May return an error
53 ;
54 ; Use:          Creates a new chunk file structure and returns a handle to
55 ;               it.
56
57                 EXPORT  chunk_create
58 chunk_create    ROUT
59
60                 STMFD   R13!,{R14}              ;Save a register
61                 MOV     R0,#cBase__size         ;Get the size of the block
62                 BL      alloc                   ;Try to allocate the block
63                 BLCS    alloc_error             ;If it failed, get error
64                 MOVCC   R14,#0                  ;Otherwise make list empty
65                 STRCC   R14,[R0,#cBase__list]   ;By clearing the link
66                 LDMFD   R13!,{R14}              ;Restore link register
67                 BICCCS  PC,R14,#V_flag          ;If OK, return without error
68                 ORRCSS  PC,R14,#V_flag          ;Else return the error
69
70                 LTORG
71
72 ; --- chunk_destroy ---
73 ;
74 ; On entry:     R0 == chunk file handle
75 ;
76 ; On exit:      --
77 ;
78 ; Use:          Removes a chunk file structure from memory.  Chunk data in
79 ;               flex blocks is freed; chunk claimers who free flex blocks
80 ;               should clear the anchors to 0.
81
82                 EXPORT  chunk_destroy
83 chunk_destroy   ROUT
84
85                 STMFD   R13!,{R0-R2,R14}        ;Save some registers
86                 MOV     R2,R0                   ;Look after the chunk base
87                 LDR     R1,[R2,#0]              ;Load the first chunk block
88
89 00chunk_destroy MOVS    R0,R1                   ;Is this the end of the list?
90                 BEQ     %f00chunk_destroy       ;Yes -- stop the loop
91                 LDR     R14,[R0,#0]             ;Load the flex anchor
92                 CMP     R14,#0                  ;Is there a block here?
93                 BLNE    flex_free               ;Yes -- free it then
94                 LDR     R1,[R0,#cLink__next]    ;Load the next block
95                 BL      free                    ;Free this block
96                 B       %b00chunk_destroy       ;And loop back
97
98 00chunk_destroy MOV     R0,R2                   ;Point to the chunk base
99                 BL      free                    ;Don't need that any more
100                 LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
101
102                 LTORG
103
104 ; --- chunk_claim ---
105 ;
106 ; On entry:     R0 == chunk file handle
107 ;               R1 == pointer to chunk name
108 ;               R2 == pointer to saver routine, or 0 for none, or -1 for no
109 ;                       change
110 ;               R3 == R10 value to pass to saver
111 ;               R4 == R12 value to pass to saver
112 ;
113 ; On exit:      R1 == chunk handle/anchor
114 ;               CS if the chunk already existed
115 ;               May return an error
116 ;
117 ; Use:          Claims a chunk, installing a save handler for it.  The chunk
118 ;               handle returned is actually the address of a flex anchor for
119 ;               the chunk's data (use flex_size to find the block's size).
120 ;               If the save handle is 0, the data in the flex block (which
121 ;               may be modified) is saved directly from the block.  Otherwise
122 ;               the save routine is expected to save its data, using xsave.
123 ;
124 ;               The anchor is followed by 3 unused words -- you can use them
125 ;               for whatever you want.
126 ;
127 ;               Warning: this routine may move flex blocks.
128
129                 EXPORT  chunk_claim
130 chunk_claim     ROUT
131
132                 BIC     R14,R14,#V_flag         ;Clear V and hope...
133                 STMFD   R13!,{R0,R5,R6,R14}     ;Save some registers
134                 SUB     R5,R0,#cLink__next      ;Look after the handle
135
136 00chunk_claim   LDR     R6,[R5,#cLink__next]    ;Load the next pointer
137                 CMP     R6,#0                   ;Is this the very end?
138                 BEQ     %f00chunk_claim         ;Yes -- create a new chunk
139                 ADD     R0,R6,#cLink__name      ;Point to the chunk's name
140                 BL      str_icmp                ;Compare the names
141                 MOVNE   R5,R6                   ;No match -- move on
142                 BNE     %b00chunk_claim         ;Loop back to start
143
144                 ; --- Found a matching chunk ---
145
146                 CMP     R2,#-1                  ;Do we change the saver?
147                 ADDNE   R14,R6,#cLink__saver    ;No -- point to saver info
148                 STMNEIA R14,{R2-R4}             ;And stuff the values in
149                 MOV     R1,R6                   ;Point to the anchor
150                 LDMFD   R13!,{R0,R5,R6,R14}     ;Restore registers
151                 ORRS    PC,R14,#C_flag          ;And return to caller
152
153                 ; --- No match -- create a new chunk ---
154
155 00chunk_claim   MOV     R0,#cLink__size         ;Get the block size I need
156                 BL      alloc                   ;Try to allocate the memory
157                 BLCS    alloc_error             ;If it failed, get error
158                 BCS     %99chunk_claim          ;And return the failure
159                 MOV     R6,R0                   ;Get the chunk handle
160                 ADD     R0,R6,#cLink__name      ;Point to the name field
161                 BL      str_cpy                 ;Fill in the new name
162
163                 ; --- Allocate an empty flex block for it ---
164
165                 MOV     R1,#0                   ;Allocate no memory
166                 MOV     R0,R6                   ;Point to the anchor
167                 BL      flex_alloc              ;Allocate the block
168                 BLCS    alloc_error             ;If it failed, get error
169                 BCS     %98chunk_claim          ;And tidy up on the way out
170
171                 ; --- Fill in the rest of the chunk ---
172
173                 MOV     R14,#0                  ;Fill in the next field
174                 STR     R14,[R6,#cLink__next]   ;Clear the next pointer
175                 STR     R6,[R5,#cLink__next]    ;And link in the new chunk
176                 STR     R14,[R6,#cLink__flags]  ;Clear flags initially
177                 CMP     R2,#-1                  ;Do we change the saver?
178                 MOVEQ   R2,#0                   ;No -- then leave none there
179                 ADD     R14,R6,#cLink__saver    ;Point to saver info
180                 STMIA   R14,{R2-R4}             ;And stuff the values in
181
182                 MOV     R1,R6                   ;Point to the anchor
183                 LDMFD   R13!,{R0,R5,R6,R14}     ;Restore registers
184                 BICS    PC,R14,#C_flag          ;And return to caller
185
186                 ; --- Tidy up on the way out ---
187
188 98chunk_claim   MOV     R5,R0                   ;Look after the error
189                 MOV     R0,R6                   ;Point to new chunk block
190                 BL      free                    ;Free the block
191                 MOV     R0,R5                   ;Get the error pointer back
192
193 99chunk_claim   ADD     R13,R13,#4              ;Don't restore R0 on exit
194                 LDMFD   R13!,{R5,R6,R14}        ;Restore registers
195                 ORRS    PC,R14,#V_flag          ;And return the error
196
197                 LTORG
198
199 ; --- chunk_makeBinary ---
200 ;
201 ; On entry:     R0 == chunk file handle
202 ;               R1 == chunk handle
203 ;
204 ; On exit:      --
205 ;
206 ; Use:          Marks a given chunk as containing binary data.
207
208                 EXPORT  chunk_makeBinary
209 chunk_makeBinary ROUT
210
211                 STMFD   R13!,{R14}              ;Save a register
212                 LDR     R14,[R1,#cLink__flags]  ;Load the flags word
213                 ORR     R14,R14,#clFlag__binary ;Set the binary flag
214                 STR     R14,[R1,#cLink__flags]  ;Save the flags back again
215                 LDMFD   R13!,{PC}^              ;And return to caller
216
217                 LTORG
218
219 ; --- chunk_read ---
220 ;
221 ; On entry:     R0 == chunk file handle
222 ;               R1 == address of a flex anchor
223 ;
224 ; On exit:      May return an error
225 ;
226 ; Use:          Merges the data contained in the flex block with that already
227 ;               in the chunk file.  If the chunk file is empty, this is
228 ;               equivalent to a load.  Data from the flex block is appended
229 ;               to chunks already loaded where appropriate.
230 ;
231 ;               Warning: this routine may move flex blocks.
232
233                 EXPORT  chunk_read
234 chunk_read      ROUT
235
236                 STMFD   R13!,{R0-R9,R14}        ;Save some registers
237                 LDR     R8,[R1,#0]              ;Load the block address
238                 MOV     R7,R0                   ;Look after the chunk handle
239                 MOV     R0,R1                   ;Point to the anchor
240                 BL      flex_size               ;Read the block's size
241                 ADD     R9,R8,R0                ;And find the limit pointer
242
243                 ; --- Find the first chunk ---
244                 ;
245                 ; There'll probably be some comments at the top -- we don't
246                 ; care about them.
247
248 10chunk_read    MOV     R2,#&0A                 ;Say this is a new line
249 00chunk_read    CMP     R8,R9                   ;Have we reached the end?
250                 BCS     %90chunk_read           ;Yes -- nothing to read
251                 LDRB    R1,[R8],#1              ;Load the next byte
252                 CMP     R2,#&0A                 ;Is this a new line?
253                 CMPEQ   R1,#'['                 ;And is this a chunk start?
254                 MOVNE   R2,R1                   ;No -- stash previous char
255                 BNE     %b00chunk_read          ;And skip back for more
256
257                 ; --- Read the next chunk ---
258
259                 MOV     R2,R11                  ;Copy name to scratchpad
260 00chunk_read    CMP     R8,R9                   ;Reached the end yet?
261                 BCS     %90chunk_read           ;Yes -- ignore bogus header
262                 LDRB    R1,[R8],#1              ;Get a byte of name
263                 CMP     R1,#']'                 ;Is it the end of it?
264                 MOVEQ   R1,#0                   ;Yes -- terminate the name
265                 STRB    R1,[R2],#1              ;Store this byte away
266                 BNE     %b00chunk_read          ;Keep on going to the end
267                 STRB    R1,[R11,#19]            ;Make sure name's <12 chars
268
269                 ; --- Ignore the rest of this line ---
270
271                 MOV     R3,#0                   ;Clear size just in case
272 00chunk_read    CMP     R8,R9                   ;Reached the end yet?
273                 BCS     %f05chunk_read          ;Yes -- stop here then
274                 LDRB    R1,[R8],#1              ;Load the next byte out
275                 CMP     R1,#&0A                 ;Is this the end of the line?
276                 BNE     %b00chunk_read          ;No -- skip back then
277
278                 ; --- Work out how big the chunk is ---
279
280                 AND     R0,R8,#3                ;Get the non-word-alignedness
281                 BIC     R1,R8,#3                ;And round down nicely
282                 LDMIA   R1,{R2-R4}              ;Load next two fullwords
283                 MOVS    R0,R0,LSL #3            ;Turn bytes into bits
284                 RSB     R14,R0,#32              ;And work out other shift
285                 MOVNE   R2,R2,LSR R0            ;Shift down lowest word
286                 ORRNE   R2,R2,R3,LSL R14        ;Copy in bottom of next word
287                 MOVNE   R3,R3,LSR R0            ;Shift rest of this one down
288                 ORRNE   R3,R3,R4,LSL R14        ;Copy in bottom of top word
289
290                 LDR     R14,=chunk__binMark     ;Is this the binary marker?
291                 CMP     R2,R14                  ;Is this a binary chunk?
292                 MOVNE   R5,#0                   ;No -- don't set any flags
293                 MOVEQ   R5,#clFlag__binary      ;Yes -- set the binary flag
294                 BNE     %f00chunk_read          ;No -- search for next chunk
295
296                 ADD     R8,R8,#8                ;Skip past those two words
297                 ADD     R8,R8,R3                ;And move on to end of chunk
298                 B       %f05chunk_read          ;And skip on (size in R3)
299
300                 ; --- Now search for a new chunk ---
301
302 00chunk_read    MOV     R3,#0                   ;No bytes counted so far
303 00chunk_read    CMP     R8,R9                   ;Reached the end yet?
304                 BCS     %f05chunk_read          ;Yes -- stop here then
305                 LDRB    R0,[R8],#1              ;Load the next byte
306                 CMP     R1,#&0A                 ;Is this a new line?
307                 CMPEQ   R0,#'['                 ;And is this a new chunk?
308                 ADDNE   R3,R3,#1                ;No -- bump the counter
309                 MOVNE   R1,R0                   ;Remember the last character
310                 BNE     %b00chunk_read          ;And go back found
311
312                 SUB     R8,R8,#1                ;Go back to the newline char
313
314                 ; --- Now claim a chunk for us ---
315
316 05chunk_read    MOV     R0,R7                   ;Get the chunk handle
317                 MOV     R1,R11                  ;Point to the chunk's name
318                 MOV     R2,#-1                  ;Don't care about savers
319                 FSAVE   "R8,R9"                 ;Stash flex pointers
320                 BL      chunk_claim             ;Claim this block please
321                 BVS     %99chunk_read           ;It failed -- tidy up
322                 MOV     R6,R1                   ;Look after the link block
323
324                 LDR     R14,[R6,#cLink__flags]  ;Load the flags word
325                 ORR     R14,R14,R5              ;Set any flags we need
326                 STR     R14,[R6,#cLink__flags]  ;Save the flags back again
327
328                 ; --- Grow the flex block and copy ---
329
330                 MOV     R0,R6                   ;Point to the anchor
331                 BL      flex_size               ;Read the block's size
332                 MOV     R5,R0                   ;Look after this
333                 ADD     R1,R0,R3                ;Add on a little size
334                 MOV     R0,R6                   ;Point to the anchor again
335                 BL      flex_extend             ;Make the block bigger
336                 BLCS    alloc_error             ;If it failed, moan a lot
337                 BCS     %99chunk_read           ;And go off in a huff
338
339                 LDR     R0,[R6,#0]              ;Load the block base
340                 ADD     R0,R0,R5                ;Find the destination addr
341                 FLOAD   "R8,R9"                 ;Reload my saved pointers
342                 SUB     R1,R8,R3                ;Reclaim my data
343                 MOV     R2,R3                   ;Set the amount to copy
344                 BL      fastMove                ;And copy it all across
345
346                 ; --- That's done -- now do the rest ---
347
348                 B       %10chunk_read           ;Go back to the top again
349
350                 ; --- We made it -- huzzah! ---
351
352 90chunk_read    LDMFD   R13!,{R0-R9,R14}        ;Restore registers
353                 BICS    PC,R14,#V_flag          ;And return with no error
354
355                 ; --- Something went awry ---
356
357 99chunk_read
358                 FLOAD   "R8,R9"                 ;Restore regs from flex stack
359                 ADD     R13,R13,#4              ;Don't restore R0 on exit
360                 LDMFD   R13!,{R1-R9,R14}        ;Restore registers
361                 ORRS    PC,R14,#V_flag          ;And return the error
362
363                 LTORG
364
365 ; --- chunk_enum ---
366 ;
367 ; On entry:     R0 == chunk file handle
368 ;               R1 == 0 for first call or continuation value
369 ;
370 ; On exit:      CC if this isn't over yet, and
371 ;                 R1 == continuation value for next call
372 ;                 R2 == pointer to chunk name
373 ;               else CS and
374 ;                 R1 == 0
375 ;                 R2 preserved
376 ;
377 ; Use:          Allows you to enumerate the chunks in a chunk file structure.
378
379                 EXPORT  chunk_enum
380 chunk_enum      ROUT
381
382                 CMP     R1,#0                   ;Is this a new call?
383                 SUBEQ   R1,R0,#cLink__next      ;Yes -- set up continuation
384                 LDR     R1,[R1,#cLink__next]    ;Move onto the next block
385                 CMP     R1,#0                   ;Is this at the end?
386                 ADDNE   R2,R1,#cLink__name      ;No -- point to the name
387                 BICNES  PC,R14,#C_flag          ;And return OK
388                 ORREQS  PC,R14,#C_flag          ;Otherwise say it's over
389
390                 LTORG
391
392 ; --- chunk_save ---
393 ;
394 ; On entry:     R0 == chunk file handle
395 ;
396 ; On exit:      May return an error
397 ;
398 ; Use:          Saves a chunk file to xsave's current output.
399
400                 EXPORT  chunk_save
401 chunk_save      ROUT
402
403                 STMFD   R13!,{R0-R4,R10,R12,R14} ;Save a few registers
404                 LDR     R4,[R0,#0]              ;Load the list base
405 05chunk_save    CMP     R4,#0                   ;Is there nothing to do?
406                 BEQ     %90chunk_save           ;That's OK -- do nothing then
407
408                 ; --- Write out this chunk's name ---
409
410                 MOV     R0,#'['                 ;Output a `[' character
411                 BL      xsave_byte              ;Write that OK
412                 BVS     %99chunk_save           ;Die if that went wrong
413
414                 ADD     R1,R4,#cLink__name      ;Point to the name
415 00chunk_save    LDRB    R0,[R1],#1              ;Load the next byte
416                 CMP     R0,#0                   ;Is this the end yet?
417                 MOVEQ   R0,#']'                 ;Yes -- write terminator
418                 BL      xsave_byte              ;Write that out
419                 BVS     %99chunk_save           ;Die if that went wrong
420                 BNE     %b00chunk_save          ;And if there's more, do it
421
422                 ; --- Write any necessary preamble ---
423
424                 MOV     R0,#&0A                 ;Start a new line
425                 BL      xsave_byte              ;Write the newline byte
426                 BVS     %99chunk_save           ;Die if that went wrong
427
428                 LDR     R14,[R4,#cLink__flags]  ;Load the flags word
429                 TST     R14,#clFlag__binary     ;Is this block binary?
430                 LDRNE   R0,=chunk__binMark      ;Yes -- write a bin marker
431                 BLNE    xsave_word              ;Yes -- write a whole word
432                 BVS     %99chunk_save           ;Die if that went wrong
433
434                 ; --- Now work out how to write this block ---
435
436                 ADD     R14,R4,#cLink__saver    ;Point to saver info
437                 LDMIA   R14,{R2,R10,R12}        ;Load that lot out
438                 CMP     R2,#0                   ;Is this a real saver?
439                 BEQ     %10chunk_save           ;No -- skip on then
440                 MOV     R0,R4                   ;Point to the anchor
441                 MOV     R14,PC                  ;Set up return address
442                 MOV     PC,R2                   ;And call the saver
443                 LDRVC   R4,[R4,#cLink__next]    ;Find the next block
444                 BVC     %05chunk_save           ;And loop back to the start
445                 BVS     %99chunk_save           ;Die if that went wrong
446
447                 ; --- We must save the chunk ourselves ---
448
449 10chunk_save    LDR     R14,[R4,#cLink__flags]  ;Load the flags word
450                 TST     R14,#clFlag__binary     ;Is this block binary?
451
452                 MOV     R0,R4                   ;If OK, get flex anchor
453                 BL      flex_size               ;Find the block's size
454                 BLNE    xsave_word              ;If binary, write that out
455                 MOVVC   R1,R0                   ;Look after that
456                 LDRVC   R0,[R4,#0]              ;Load the flex base address
457                 BLVC    xsave_block             ;And write out the whole lot
458                 BVS     %99chunk_save           ;Die if anything went wrong
459                 MOVNE   R0,#&0A                 ;Write a final line end
460                 BLNE    xsave_byte              ;Just to make sure
461                 BLNE    xsave_byte              ;Leave blank line under bin
462                 LDRVC   R4,[R4,#cLink__next]    ;Find the next block
463                 BVC     %05chunk_save           ;And loop back to the start
464                 BVS     %99chunk_save           ;Die if anything went wrong
465
466                 ; --- Finished writing the file ---
467
468 90chunk_save    LDMFD   R13!,{R0-R4,R10,R12,R14} ;Restore registers
469                 BICS    PC,R14,#V_flag          ;Return error-free
470
471                 ; --- Something got messed up ---
472
473 99chunk_save    ADD     R13,R13,#4              ;Don't restore R0
474                 LDMFD   R13!,{R1-R4,R10,R12,R14} ;Restore other registers
475                 ORRS    PC,R14,#V_flag          ;And return the error
476
477                 LTORG
478
479 ;----- Data structures ------------------------------------------------------
480
481 ; --- Chunk base ---
482
483                 ^       0
484 cBase__list     #       4                       ;List of chunks
485 cBase__size     #       0
486
487 ; --- Chunk link blocks ---
488
489                 ^       0
490 cLink__anchor   #       4                       ;Anchor for flex block
491 cLink__userData #       12                      ;12 bytes of user data
492 cLink__next     #       4                       ;Link to next block
493 cLink__flags    #       4                       ;Interesting things
494 cLink__name     #       20                      ;Name of this chunk
495 cLink__saver    #       12                      ;Saver routine for chunk
496 cLink__size     #       0
497
498 ; --- Flags ---
499
500 clFlag__binary  EQU     (1<<0)                  ;Chunk contains binary data
501
502 ; --- Other magic values ---
503
504 chunk__binMark  EQU     &6E694200               ;Magic word for binary data
505
506 ;----- That's all, folks ----------------------------------------------------
507
508                 END