don't try to copy 30 bytes of string into a 16 byte buffer.
[AROS.git] / compiler / arossupport / readstruct.c
blobd9ebe1fc50389d96c6aaaddbbcc18b7298575c76
1 /*
2 Copyright © 1995-2017, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Read a big endian structure from a streamhook
6 Lang: english
7 */
9 #include <string.h>
10 #include <exec/memory.h>
11 #include <proto/dos.h>
12 #include <proto/exec.h>
13 #include <aros/debug.h>
14 #include <utility/hooks.h>
16 struct ReadLevel
18 struct MinNode node;
19 const IPTR * sd;
20 UBYTE * s;
21 int pos;
24 /******************************************************************************
26 NAME */
27 #include <stdio.h>
28 #include <aros/bigendianio.h>
29 #include <proto/alib.h>
31 BOOL ReadStruct (
33 /* SYNOPSIS */
34 struct Hook * hook,
35 APTR * dataptr,
36 void * stream,
37 const IPTR * sd)
39 /* FUNCTION
40 Reads one big endian structure from a streamhook.
42 INPUTS
43 hook - Streamhook
44 dataptr - Put the data here. If NULL, a new memory block is allocated
45 stream - Read from this stream
46 sd - Description of the structure to be read. The first element
47 is the size of the structure.
49 RESULT
50 The function returns TRUE on success. On success, the value
51 read is written into dataptr. On failure, FALSE is returned and the
52 contents of dataptr are not changed.
54 NOTES
55 This function reads big endian values from a streamhook even on
56 little endian machines.
58 EXAMPLE
59 See below.
61 BUGS
63 SEE ALSO
64 ReadByte(), ReadWord(), ReadLong(), ReadFloat(), ReadDouble(),
65 ReadString(), ReadStruct(), WriteByte(), WriteWord(), WriteLong(),
66 WriteFloat(), WriteDouble(), WriteString(), WriteStruct()
68 HISTORY
70 ******************************************************************************/
72 struct MinList _list;
73 struct ReadLevel * curr;
74 BOOL pre_alloc = (*dataptr) ? TRUE : FALSE;
76 # define list ((struct List *)&_list)
78 NEWLIST(list);
80 if (!(curr = AllocMem (sizeof (struct ReadLevel), MEMF_ANY)) )
81 return FALSE;
83 AddTail (list, (struct Node *)curr);
85 curr->sd = sd;
86 curr->pos = 0;
87 curr->s = *dataptr;
89 # define DESC curr->sd[curr->pos]
90 # define IDESC curr->sd[curr->pos ++]
92 for (;;)
94 if (!curr->pos)
96 IPTR size = IDESC;
97 if (!curr->s && !(curr->s = AllocMem (size, MEMF_CLEAR)) )
98 goto error;
101 if (DESC == SDT_END)
102 break;
104 switch (IDESC)
106 case SDT_UBYTE: /* Read one 8bit byte */
107 if (!ReadByte (hook, (UBYTE *)(curr->s + IDESC), stream))
108 goto error;
110 break;
112 case SDT_UWORD: /* Read one 16bit word */
113 if (!ReadWord (hook, (UWORD *)(curr->s + IDESC), stream))
114 goto error;
116 break;
118 case SDT_ULONG: /* Read one 32bit long */
119 if (!ReadLong (hook, (ULONG *)(curr->s + IDESC), stream))
120 goto error;
122 break;
124 case SDT_FLOAT: /* Read one 32bit IEEE */
125 if (!ReadFloat (hook, (FLOAT *)(curr->s + IDESC), stream))
126 goto error;
128 break;
130 case SDT_DOUBLE: /* Read one 64bit IEEE */
131 if (!ReadDouble (hook, (DOUBLE *)(curr->s + IDESC), stream))
132 goto error;
134 break;
136 case SDT_COPY: { /* Copy 'n' bytes */
137 int i, count, offset;
139 offset = IDESC;
140 count = IDESC;
142 for (i= 0; i < count; i++)
144 if (!ReadByte (hook, (UBYTE *)(curr->s + offset + i), stream))
145 goto error;
148 break; }
150 case SDT_STRING: { /* Read a string */
151 UBYTE valid_ptr;
152 STRPTR * sptr;
154 sptr = (STRPTR *)(curr->s + IDESC);
156 if (!ReadByte (hook, &valid_ptr, stream))
157 goto error;
159 if (valid_ptr)
161 if (!ReadString (hook, sptr, stream))
162 goto error;
164 else
166 *sptr = NULL;
169 break; }
171 case SDT_STRUCT: { /* Read a structure */
172 struct ReadLevel * next;
173 IPTR * desc;
174 APTR aptr;
176 aptr = (APTR)(curr->s + IDESC);
177 desc = (IPTR *)IDESC;
179 curr->pos -= 3; /* Go back to type */
181 if (!(next = AllocMem (sizeof (struct ReadLevel), MEMF_ANY)) )
182 goto error;
184 AddTail (list, (struct Node *)next);
185 next->sd = desc;
186 next->pos = 1;
187 next->s = aptr;
189 curr = next;
191 break; }
193 case SDT_PTR: { /* Follow a pointer */
194 struct ReadLevel * next;
196 UBYTE valid_ptr;
197 IPTR * desc;
198 APTR * aptr;
200 aptr = ((APTR *)(curr->s + IDESC));
201 desc = (IPTR *)IDESC;
203 if (!ReadByte (hook, &valid_ptr, stream))
204 goto error;
206 if (valid_ptr)
208 curr->pos -= 3;
210 if (!(next = AllocMem (sizeof (struct ReadLevel), MEMF_ANY)) )
211 goto error;
213 AddTail (list, (struct Node *)next);
214 next->sd = desc;
215 next->pos = 0;
217 curr = next;
219 else
221 *aptr = NULL;
224 break; }
226 case SDT_IGNORE: { /* Ignore x bytes */
227 struct BEIOM_Ignore ig = {BEIO_IGNORE, IDESC};
228 if (CallHookA (hook, stream, &ig) == EOF)
229 goto error;
231 break; }
233 case SDT_FILL_BYTE: { /* Fill x bytes */
234 IPTR offset;
235 UBYTE value;
236 IPTR count;
238 offset = IDESC;
239 value = IDESC;
240 count = IDESC;
242 memset (curr->s + offset, value, count);
244 break; }
246 case SDT_FILL_LONG: { /* Fill x longs */
247 ULONG * ulptr;
248 ULONG value;
249 IPTR count;
251 ulptr = (ULONG *)(curr->s + IDESC);
252 value = IDESC;
253 count = IDESC;
255 while (count --)
256 *ulptr ++ = value;
258 break; }
260 case SDT_IFILL_BYTE: { /* Fill x bytes */
261 IPTR offset;
262 UBYTE value;
263 IPTR count;
265 offset = IDESC;
266 value = IDESC;
267 count = IDESC;
269 struct BEIOM_Ignore ig = {BEIO_IGNORE, count};
271 if (CallHookA (hook, stream, &ig) == EOF)
272 goto error;
274 memset (curr->s + offset, value, count);
276 break; }
278 case SDT_IFILL_LONG: { /* Fill x longs */
279 ULONG * ulptr;
280 ULONG value;
281 IPTR count;
283 ulptr = (ULONG *)(curr->s + IDESC);
284 value = IDESC;
285 count = IDESC;
287 struct BEIOM_Ignore ig = {BEIO_IGNORE, count << 2};
289 if (CallHookA (hook, stream, &ig) == EOF)
290 goto error;
292 while (count --)
293 *ulptr ++ = value;
295 break; }
297 case SDT_SPECIAL: { /* Call user hook */
298 struct Hook * uhook;
299 struct SDData data;
301 data.sdd_Dest = ((APTR)(curr->s + IDESC));
302 data.sdd_Mode = SDV_SPECIALMODE_READ;
303 data.sdd_Stream = stream;
305 uhook = (struct Hook *)IDESC;
307 if (!CallHookA (uhook, hook, &data))
308 goto error;
310 break; }
312 default:
313 goto error;
315 } /* switch */
317 /* End of the description list ? */
318 if (DESC == SDT_END)
320 struct ReadLevel * last;
322 /* Remove the current level */
323 last = curr;
324 Remove ((struct Node *)last);
326 /* Get the last level */
327 if ((curr = (struct ReadLevel *)GetTail (list)))
329 switch (IDESC)
331 case SDT_STRUCT:
332 curr->pos += 2; /* Skip 2 parameters */
333 break;
335 case SDT_PTR: {
336 APTR * aptr;
338 aptr = ((APTR *)(curr->s + IDESC));
339 curr->pos ++; /* Skip description parameter */
342 Now put the result of the current level in the
343 struct of the previous level.
345 *aptr = last->s;
347 break; }
351 FreeMem (last, sizeof (struct ReadLevel));
353 else
355 curr = last;
358 } /* while */
360 *dataptr = curr->s;
362 FreeMem (curr, sizeof (struct ReadLevel));
364 return TRUE;
366 error:
367 curr = (struct ReadLevel *)GetHead (list);
369 if (curr && curr->s && !pre_alloc)
370 FreeStruct (curr->s, curr->sd);
372 while ((curr = (struct ReadLevel *)RemTail (list)))
373 FreeMem (curr, sizeof (struct ReadLevel));
375 return FALSE;
376 } /* ReadStruct */
378 #ifdef TEST
379 #include <stdio.h>
380 #include <dos/dos.h>
381 #include <aros/structdesc.h>
382 #include <proto/alib.h>
384 struct Level1
386 BYTE l1_Byte;
387 LONG l1_Long;
390 struct MainLevel
392 BYTE ml_Byte;
393 UBYTE ml_UByte;
394 WORD ml_Word;
395 UWORD ml_UWord;
396 LONG ml_Long;
397 ULONG ml_ULong;
398 FLOAT ml_Float;
399 DOUBLE ml_Double;
400 STRPTR ml_String;
401 struct Level1 ml_Level1;
403 BYTE * ml_BytePtr;
404 WORD * ml_WordPtr;
405 LONG * ml_LongPtr;
406 FLOAT * ml_FloatPtr;
407 DOUBLE * ml_DoublePtr;
408 STRPTR * ml_StringPtr;
409 struct Level1 * ml_Level1Ptr;
412 IPTR ByteDesc[] = { sizeof(UBYTE), SDM_UBYTE(0), SDM_END };
413 IPTR WordDesc[] = { sizeof(UWORD), SDM_UWORD(0), SDM_END };
414 IPTR LongDesc[] = { sizeof(ULONG), SDM_ULONG(0), SDM_END };
415 IPTR FloatDesc[] = { sizeof(FLOAT), SDM_FLOAT(0), SDM_END };
416 IPTR DoubleDesc[] = { sizeof(DOUBLE), SDM_DOUBLE(0), SDM_END };
417 IPTR StringDesc[] = { sizeof(STRPTR), SDM_STRING(0), SDM_END };
419 #define O(x) offsetof(struct Level1,x)
420 IPTR Level1Desc[] =
422 sizeof (struct Level1),
423 SDM_UBYTE(O(l1_Byte)),
424 SDM_ULONG(O(l1_Long)),
425 SDM_END
428 #undef O
429 #define O(x) offsetof(struct MainLevel,x)
430 IPTR MainDesc[] =
432 sizeof (struct MainLevel),
433 SDM_UBYTE(O(ml_Byte)),
434 SDM_UBYTE(O(ml_UByte)),
435 SDM_UWORD(O(ml_Word)),
436 SDM_UWORD(O(ml_UWord)),
437 SDM_ULONG(O(ml_Long)),
438 SDM_ULONG(O(ml_ULong)),
439 SDM_FLOAT(O(ml_Float)),
440 SDM_DOUBLE(O(ml_Double)),
441 SDM_STRING(O(ml_String)),
442 SDM_STRUCT(O(ml_Level1),Level1Desc),
444 SDM_PTR(O(ml_BytePtr),ByteDesc),
445 SDM_PTR(O(ml_WordPtr),WordDesc),
446 SDM_PTR(O(ml_LongPtr),LongDesc),
447 SDM_PTR(O(ml_FloatPtr),FloatDesc),
448 SDM_PTR(O(ml_DoublePtr),DoubleDesc),
449 SDM_PTR(O(ml_StringPtr),StringDesc),
450 SDM_PTR(O(ml_Level1Ptr),Level1Desc),
452 SDM_END
455 LONG dosstreamhook (struct Hook * hook, BPTR fh, ULONG * msg);
457 struct Hook dsh =
459 { NULL, NULL }, HookEntry, (void *)dosstreamhook, NULL
462 LONG dosstreamhook (struct Hook * hook, BPTR fh, ULONG * msg)
464 LONG rc;
466 switch (*msg)
468 case BEIO_READ:
469 rc = FGetC (fh);
470 break;
472 case BEIO_WRITE:
473 rc = FPutC (fh, ((struct BEIOM_Write *)msg)->Data);
474 break;
476 case BEIO_IGNORE:
477 Flush (fh);
479 rc = Seek (fh, ((struct BEIOM_Ignore *)msg)->Count, OFFSET_CURRENT);
480 break;
484 return rc;
485 } /* dosstreamhook */
487 int main (int argc, char ** argv)
489 struct MainLevel demo =
491 (BYTE)0x88, 0xFF,
492 (WORD)0x8844, 0xFF77,
493 (LONG)0x88442211, 0xFF773311,
494 1.5, 1.75,
495 "Hallo",
496 { (BYTE)0x88, (LONG)0x88442211 },
497 /* ... */
499 BYTE b = (BYTE)0x88;
500 WORD w = (WORD)0x8844;
501 LONG l = (LONG)0x88442211;
502 FLOAT f = 1.5;
503 DOUBLE d = 1.75;
504 STRPTR s = "Hallo";
505 struct Level1 l1 =
507 (BYTE)0x88, (LONG)0x88442211
509 BPTR fh;
510 struct MainLevel * readback;
512 demo.ml_BytePtr = &b;
513 demo.ml_WordPtr = &w;
514 demo.ml_LongPtr = &l;
515 demo.ml_FloatPtr = &f;
516 demo.ml_DoublePtr = &d;
517 demo.ml_StringPtr = &s;
518 demo.ml_Level1Ptr = &l1;
520 fh = Open ("writestruct.dat", MODE_NEWFILE);
522 if (!fh)
524 PrintFault (IoErr(), "Can't open file\n");
525 return 10;
529 This writes the following data stream:
531 0000 88 ml_Byte
532 0001 ff ml_Ubyte
533 0002 88 44 ml_Word
534 0004 ff 77 ml_UWord
535 0006 88 44 22 11 ml_Long
536 000a ff 77 33 11 ml_ULong
537 000e 3f c0 00 00 ml_Float
538 0012 3f fc 00 00 00 00 00 00 ml_Double
539 001a 01:48 61 6c 6c 6f 00 ml_String
540 0021 88 ml_Level1.l1_Byte
541 0022 88 44 22 11 ml_Level1.l1_Long
542 0026 01:88 ml_BytePtr
543 0028 01:88 44 ml_WordPtr
544 002b 01:88 44 22 11 ml_LongPtr
545 0030 01:3f c0 00 00 ml_FloatPtr
546 0035 01:3f fc 00 00 00 00 00 00 ml_DoublePtr
547 003e 01:01:48 61 6c 6c 6f 00 ml_StringPtr - Note two 01 !
548 0046 01:88 88 44 22 11 ml_Level1Ptr
551 if (!WriteStruct (&dsh, &demo, fh, MainDesc))
553 PrintFault (IoErr(), "Failed to write to file\n");
556 if (!Close (fh))
558 PrintFault (IoErr(), "Failed to close file\n");
561 /* Read the structure back */
562 fh = Open ("writestruct.dat", MODE_OLDFILE);
564 if (!fh)
566 PrintFault (IoErr(), "Can't open file for reading\n");
567 return 10;
570 if (!ReadStruct (&dsh, (APTR *)&readback, fh, MainDesc))
572 PrintFault (IoErr(), "Failed to read from file\n");
574 else
576 UBYTE * ptr;
577 int t;
579 ptr = (UBYTE *)readback;
580 t = 0;
582 kprintf ("readback = %p\n", readback);
584 kprintf ("%02X (88) %02X (FF)\n"
585 , (UBYTE)readback->ml_Byte
586 , readback->ml_UByte
588 kprintf ("%04X (8844) %04X (FF77)\n"
589 , (UWORD)readback->ml_Word
590 , readback->ml_UWord
592 kprintf ("%08lX (88442211) %08lX (FF773311)\n"
593 , readback->ml_Long
594 , readback->ml_ULong
596 kprintf ("%08lX (3FC00000) %08lX:%08lX (3FFC0000:00000000)\n"
597 , *(ULONG *)&readback->ml_Float
598 , ((ULONG *)&readback->ml_Double)[1]
599 , ((ULONG *)&readback->ml_Double)[0]
601 kprintf ("%s (Hallo)\n"
602 , readback->ml_String
604 kprintf ("{ %02X %08X } ({ 88 88442211 })\n"
605 , (UBYTE)readback->ml_Level1.l1_Byte
606 , readback->ml_Level1.l1_Long
608 kprintf ("%02X (88)\n"
609 , (UBYTE)*readback->ml_BytePtr
611 kprintf ("%04X (8844)\n"
612 , (UWORD)*readback->ml_WordPtr
614 kprintf ("%08lX (88442211)\n"
615 , *readback->ml_LongPtr
617 kprintf ("%08lX (3FC00000) %08lX:%08lX (3FFC0000:00000000)\n"
618 , *(ULONG *)readback->ml_FloatPtr
619 , ((ULONG *)readback->ml_DoublePtr)[1]
620 , ((ULONG *)readback->ml_DoublePtr)[0]
622 kprintf ("%s (Hallo)\n"
623 , *readback->ml_StringPtr
625 kprintf ("{ %02X %08X } ({ 88 88442211 })\n"
626 , (UBYTE)readback->ml_Level1Ptr->l1_Byte
627 , readback->ml_Level1Ptr->l1_Long
630 FreeStruct (readback, MainDesc);
633 if (!Close (fh))
635 PrintFault (IoErr(), "Failed to close file after reading\n");
638 return 0;
639 } /* main */
641 #endif /* TEST */