pdf2swf: added workaround for broken dashes
[swftools.git] / lib / bitio.c
1 /*  bitio.c 
2     part of swftools
3     implementation of bitio.h.
4
5     Copyright (C) 2003 Matthias Kramm <kramm@quiss.org>
6
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #ifdef HAVE_UNISTD_H
24 #include <unistd.h>
25 #endif
26 #ifdef HAVE_IO_H
27 #include <io.h>
28 #endif
29 #include <string.h>
30 #include <memory.h>
31 #include <fcntl.h>
32
33 #include "../config.h"
34
35 #ifdef HAVE_ZLIB
36 #include <zlib.h>
37 #define ZLIB_BUFFER_SIZE 16384
38 #endif
39 #include "./bitio.h"
40
41 /* ---------------------------- null reader ------------------------------- */
42
43 static int reader_nullread(reader_t*r, void* data, int len) 
44 {
45     memset(data, 0, len);
46     return len;
47 }
48 static void reader_nullread_dealloc(reader_t*r)
49 {
50     memset(r, 0, sizeof(reader_t));
51 }
52 void reader_init_nullreader(reader_t*r)
53 {
54     r->read = reader_nullread;
55     r->dealloc = reader_nullread_dealloc;
56     r->internal = 0;
57     r->type = READER_TYPE_NULL;
58     r->mybyte = 0;
59     r->bitpos = 8;
60     r->pos = 0;
61 }
62 /* ---------------------------- file reader ------------------------------- */
63
64 static int reader_fileread(reader_t*reader, void* data, int len) 
65 {
66     int ret = read((int)reader->internal, data, len);
67     if(ret>=0)
68         reader->pos += ret;
69     return ret;
70 }
71 void reader_init_filereader(reader_t*r, int handle)
72 {
73     r->read = reader_fileread;
74     r->internal = (void*)handle;
75     r->type = READER_TYPE_FILE;
76     r->mybyte = 0;
77     r->bitpos = 8;
78     r->pos = 0;
79 }
80
81 /* ---------------------------- mem reader ------------------------------- */
82
83 typedef struct _memread
84 {
85     unsigned char*data;
86     int length;
87 } memread_t;
88
89 static int reader_memread(reader_t*reader, void* data, int len) 
90 {
91     memread_t*mr = (memread_t*)reader->internal;
92
93     if(mr->length - reader->pos < len) {
94         len = mr->length - reader->pos;
95     }
96     memcpy(data, &mr->data[reader->pos], len);
97     reader->pos += len;
98     return len;
99 }
100 static void reader_memread_dealloc(reader_t*reader)
101 {
102     if(reader->internal)
103         free(reader->internal);
104     memset(reader, 0, sizeof(reader_t));
105 }
106 void reader_init_memreader(reader_t*r, void*newdata, int newlength)
107 {
108     memread_t*mr = (memread_t*)malloc(sizeof(memread_t));
109     mr->data = (unsigned char*)newdata;
110     mr->length = newlength;
111     r->read = reader_memread;
112     r->dealloc = reader_memread_dealloc;
113     r->internal = (void*)mr;
114     r->type = READER_TYPE_MEM;
115     r->mybyte = 0;
116     r->bitpos = 8;
117     r->pos = 0;
118
119
120 /* ---------------------------- mem writer ------------------------------- */
121
122 typedef struct _memwrite
123 {
124     unsigned char*data;
125     int length;
126 } memwrite_t;
127
128 static int writer_memwrite_write(writer_t*w, void* data, int len) 
129 {
130     memwrite_t*mw = (memwrite_t*)w->internal;
131     if(mw->length - w->pos > len) {
132         memcpy(&mw->data[w->pos], data, len);
133         w->pos += len;
134         return len;
135     } else {
136         memcpy(&mw->data[w->pos], data, mw->length - w->pos);
137         w->pos = mw->length;
138         return mw->length - w->pos;
139     }
140 }
141 static void writer_memwrite_finish(writer_t*w)
142 {
143     if(w->internal) 
144         free(w->internal);
145     w->internal = 0;
146 }
147 static void dummy_flush(writer_t*w)
148 {
149 }
150 void writer_init_memwriter(writer_t*w, void*data, int len)
151 {
152     memwrite_t *mr;
153     mr = (memwrite_t*)malloc(sizeof(memwrite_t));
154     mr->data = (unsigned char *)data;
155     mr->length = len;
156     memset(w, 0, sizeof(writer_t));
157     w->write = writer_memwrite_write;
158     w->flush = dummy_flush;
159     w->finish = writer_memwrite_finish;
160     w->internal = (void*)mr;
161     w->type = WRITER_TYPE_MEM;
162     w->bitpos = 0;
163     w->mybyte = 0;
164     w->pos = 0;
165 }
166
167 /* ------------------------- growing mem writer ------------------------------- */
168
169 typedef struct _growmemwrite
170 {
171     unsigned char*data;
172     int length;
173     U32 grow;
174 } growmemwrite_t;
175 static int writer_growmemwrite_write(writer_t*w, void* data, int len) 
176 {
177     growmemwrite_t*mw = (growmemwrite_t*)w->internal;
178     if(!mw->data) {
179         fprintf(stderr, "Illegal write operation: data already given away");
180         exit(1);
181     }
182     if(mw->length - w->pos < len) {
183         int newlength = mw->length;
184         while(newlength - w->pos < len) {
185             newlength += mw->grow;
186         }
187 #ifdef NO_REALLOC
188         unsigned char*newmem = (unsigned char*)malloc(newlength);
189         memcpy(newmem, mw->data, mw->length);
190         free(mw->data);
191         mw->data = newmem;
192 #else
193         mw->data = (unsigned char*)realloc(mw->data, newlength);
194 #endif
195         mw->length = newlength;
196     }
197     memcpy(&mw->data[w->pos], data, len);
198     w->pos += len;
199     return len;
200 }
201 static void writer_growmemwrite_finish(writer_t*w)
202 {
203     growmemwrite_t*mw = (growmemwrite_t*)w->internal;
204     if(mw->data) {
205         free(mw->data);mw->data = 0;
206     }
207     mw->length = 0;
208     free(w->internal);mw=0;
209     memset(w, 0, sizeof(writer_t));
210 }
211 void* writer_growmemwrite_memptr(writer_t*w, int*len)
212 {
213     growmemwrite_t*mw = (growmemwrite_t*)w->internal;
214     if(len) {
215         *len = w->pos;
216     }
217     return mw->data;
218 }
219 void* writer_growmemwrite_getmem(writer_t*w)
220 {
221     growmemwrite_t*mw = (growmemwrite_t*)w->internal;
222     void*ret = mw->data;
223     /* remove own reference so that neither write() nor finish() can free it.
224        It's property of the caller now.
225     */
226     mw->data = 0;
227     return ret;
228 }
229 void writer_growmemwrite_reset(writer_t*w)
230 {
231     growmemwrite_t*mw = (growmemwrite_t*)w->internal;
232     w->pos = 0;
233     w->bitpos = 0;
234     w->mybyte = 0;
235 }
236 void writer_init_growingmemwriter(writer_t*w, U32 grow)
237 {
238     growmemwrite_t *mw = (growmemwrite_t *)malloc(sizeof(growmemwrite_t));
239     mw->length = 4096;
240     mw->data = (unsigned char *)malloc(mw->length);
241     mw->grow = grow;
242     memset(w, 0, sizeof(writer_t));
243     w->write = writer_growmemwrite_write;
244     w->flush = dummy_flush;
245     w->finish = writer_growmemwrite_finish;
246     w->internal = (void*)mw;
247     w->type = WRITER_TYPE_GROWING_MEM;
248     w->bitpos = 0;
249     w->mybyte = 0;
250     w->pos = 0;
251 }
252
253 /* ---------------------------- file writer ------------------------------- */
254
255 typedef struct _filewrite
256 {
257     int handle;
258     char free_handle;
259 } filewrite_t;
260
261 static int writer_filewrite_write(writer_t*w, void* data, int len) 
262 {
263     filewrite_t * fw= (filewrite_t*)w->internal;
264     w->pos += len;
265     return write(fw->handle, data, len);
266 }
267 static void writer_filewrite_finish(writer_t*w)
268 {
269     filewrite_t *mr = (filewrite_t*)w->internal;
270     if(mr->free_handle)
271         close(mr->handle);
272     free(w->internal);
273     memset(w, 0, sizeof(writer_t));
274 }
275 void writer_init_filewriter(writer_t*w, int handle)
276 {
277     filewrite_t *mr = (filewrite_t *)malloc(sizeof(filewrite_t));
278     mr->handle = handle;
279     mr->free_handle = 0;
280     memset(w, 0, sizeof(writer_t));
281     w->write = writer_filewrite_write;
282     w->finish = writer_filewrite_finish;
283     w->internal = mr;
284     w->type = WRITER_TYPE_FILE;
285     w->bitpos = 0;
286     w->mybyte = 0;
287     w->pos = 0;
288 }
289 void writer_init_filewriter2(writer_t*w, char*filename)
290 {
291     int fi = open("movie.swf",
292 #ifdef O_BINARY
293             O_BINARY|
294 #endif
295             O_WRONLY|O_CREAT|O_TRUNC, 0644);
296     writer_init_filewriter(w, fi);
297     ((filewrite_t*)w->internal)->free_handle = 1;
298 }
299
300 /* ---------------------------- null writer ------------------------------- */
301
302 static int writer_nullwrite_write(writer_t*w, void* data, int len) 
303 {
304     w->pos += len;
305     return len;
306 }
307 static void writer_nullwrite_finish(writer_t*w)
308 {
309     memset(w, 0, sizeof(writer_t));
310 }
311 void writer_init_nullwriter(writer_t*w)
312 {
313     memset(w, 0, sizeof(writer_t));
314     w->write = writer_nullwrite_write;
315     w->flush = dummy_flush;
316     w->finish = writer_nullwrite_finish;
317     w->internal = 0;
318     w->type = WRITER_TYPE_NULL;
319     w->bitpos = 0;
320     w->mybyte = 0;
321     w->pos = 0;
322 }
323 /* ---------------------------- zlibinflate reader -------------------------- */
324
325 typedef struct _zlibinflate
326 {
327 #ifdef HAVE_ZLIB
328     z_stream zs;
329     reader_t*input;
330     unsigned char readbuffer[ZLIB_BUFFER_SIZE];
331 #endif
332 } zlibinflate_t;
333
334 #ifdef HAVE_ZLIB
335 static void zlib_error(int ret, char* msg, z_stream*zs)
336 {
337     fprintf(stderr, "%s: zlib error (%d): last zlib error: %s\n",
338           msg,
339           ret,
340           zs->msg?zs->msg:"unknown");
341     perror("errno:");
342     exit(1);
343 }
344 #endif
345
346 static int reader_zlibinflate(reader_t*reader, void* data, int len) 
347 {
348 #ifdef HAVE_ZLIB
349     zlibinflate_t*z = (zlibinflate_t*)reader->internal;
350     int ret;
351     if(!z) {
352         return 0;
353     }
354     if(!len)
355         return 0;
356     
357     z->zs.next_out = (Bytef *)data;
358     z->zs.avail_out = len;
359
360     while(1) {
361         if(!z->zs.avail_in) {
362             z->zs.avail_in = z->input->read(z->input, z->readbuffer, ZLIB_BUFFER_SIZE);
363             z->zs.next_in = z->readbuffer;
364         }
365         if(z->zs.avail_in)
366             ret = inflate(&z->zs, Z_NO_FLUSH);
367         else
368             ret = inflate(&z->zs, Z_FINISH);
369     
370         if (ret != Z_OK &&
371             ret != Z_STREAM_END) zlib_error(ret, "bitio:inflate_inflate", &z->zs);
372
373         if (ret == Z_STREAM_END) {
374                 int pos = z->zs.next_out - (Bytef*)data;
375                 ret = inflateEnd(&z->zs);
376                 if (ret != Z_OK) zlib_error(ret, "bitio:inflate_end", &z->zs);
377                 free(reader->internal);
378                 reader->internal = 0;
379                 reader->pos += pos;
380                 return pos;
381         }
382         if(!z->zs.avail_out) {
383             break;
384         }
385     }
386     reader->pos += len;
387     return len;
388 #else
389     fprintf(stderr, "Error: swftools was compiled without zlib support");
390     exit(1);
391 #endif
392 }
393 static void reader_zlibinflate_dealloc(reader_t*reader)
394 {
395 #ifdef HAVE_ZLIB
396     zlibinflate_t*z = (zlibinflate_t*)reader->internal;
397     /* test whether read() already did basic deallocation */
398     if(reader->internal) {
399         inflateEnd(&z->zs);
400         free(reader->internal);
401     }
402     memset(reader, 0, sizeof(reader_t));
403 #endif
404 }
405 void reader_init_zlibinflate(reader_t*r, reader_t*input)
406 {
407 #ifdef HAVE_ZLIB
408     zlibinflate_t*z = (zlibinflate_t*)malloc(sizeof(zlibinflate_t));
409     memset(z, 0, sizeof(zlibinflate_t));
410     int ret;
411     memset(r, 0, sizeof(reader_t));
412     r->internal = z;
413     r->read = reader_zlibinflate;
414     r->dealloc = reader_zlibinflate_dealloc;
415     r->type = READER_TYPE_ZLIB;
416     r->pos = 0;
417     z->input = input;
418     memset(&z->zs,0,sizeof(z_stream));
419     z->zs.zalloc = Z_NULL;
420     z->zs.zfree  = Z_NULL;
421     z->zs.opaque = Z_NULL;
422     ret = inflateInit(&z->zs);
423     if (ret != Z_OK) zlib_error(ret, "bitio:inflate_init", &z->zs);
424     reader_resetbits(r);
425 #else
426     fprintf(stderr, "Error: swftools was compiled without zlib support");
427     exit(1);
428 #endif
429 }
430
431 /* ---------------------------- zlibdeflate writer -------------------------- */
432
433 typedef struct _zlibdeflate
434 {
435 #ifdef HAVE_ZLIB
436     z_stream zs;
437     writer_t*output;
438     unsigned char writebuffer[ZLIB_BUFFER_SIZE];
439 #endif
440 } zlibdeflate_t;
441
442 static int writer_zlibdeflate_write(writer_t*writer, void* data, int len) 
443 {
444 #ifdef HAVE_ZLIB
445     zlibdeflate_t*z = (zlibdeflate_t*)writer->internal;
446     int ret;
447     if(writer->type != WRITER_TYPE_ZLIB) {
448         fprintf(stderr, "Wrong writer ID (writer not initialized?)\n");
449         return 0;
450     }
451     if(!z) {
452         fprintf(stderr, "zlib not initialized!\n");
453         return 0;
454     }
455     if(!len)
456         return 0;
457     
458     z->zs.next_in = (Bytef *)data;
459     z->zs.avail_in = len;
460
461     while(1) {
462         ret = deflate(&z->zs, Z_NO_FLUSH);
463         
464         if (ret != Z_OK) zlib_error(ret, "bitio:deflate_deflate", &z->zs);
465
466         if(z->zs.next_out != z->writebuffer) {
467             writer->pos += z->zs.next_out - (Bytef*)z->writebuffer;
468             z->output->write(z->output, z->writebuffer, z->zs.next_out - (Bytef*)z->writebuffer);
469             z->zs.next_out = z->writebuffer;
470             z->zs.avail_out = ZLIB_BUFFER_SIZE;
471         }
472
473         if(!z->zs.avail_in) {
474             break;
475         }
476     }
477     return len;
478 #else
479     fprintf(stderr, "Error: swftools was compiled without zlib support");
480     exit(1);
481 #endif
482 }
483
484 void writer_zlibdeflate_flush(writer_t*writer)
485 {
486 #ifdef HAVE_ZLIB
487     zlibdeflate_t*z = (zlibdeflate_t*)writer->internal;
488     int ret;
489     if(writer->type != WRITER_TYPE_ZLIB) {
490         fprintf(stderr, "Wrong writer ID (writer not initialized?)\n");
491         return;
492     }
493     if(!z) {
494         fprintf(stderr, "zlib not initialized!\n");
495         return;
496     }
497
498     z->zs.next_in = 0;
499     z->zs.avail_in = 0;
500     while(1) {
501         ret = deflate(&z->zs, Z_SYNC_FLUSH);
502         if (ret != Z_OK) zlib_error(ret, "bitio:deflate_flush", &z->zs);
503         if(z->zs.next_out != z->writebuffer) {
504             writer->pos += z->zs.next_out - (Bytef*)z->writebuffer;
505             z->output->write(z->output, z->writebuffer, z->zs.next_out - (Bytef*)z->writebuffer);
506             z->zs.next_out = z->writebuffer;
507             z->zs.avail_out = ZLIB_BUFFER_SIZE;
508         } 
509         /* TODO: how will zlib let us know it needs more buffer space? */
510         break;
511     }
512     return;
513 #else
514     fprintf(stderr, "Error: swftools was compiled without zlib support");
515     exit(1);
516 #endif
517 }
518
519 static void writer_zlibdeflate_finish(writer_t*writer)
520 {
521 #ifdef HAVE_ZLIB
522     zlibdeflate_t*z = (zlibdeflate_t*)writer->internal;
523     writer_t*output;
524     int ret;
525     if(writer->type != WRITER_TYPE_ZLIB) {
526         fprintf(stderr, "Wrong writer ID (writer not initialized?)\n");
527         return;
528     }
529     if(!z)
530         return;
531     output= z->output;
532     while(1) {
533         ret = deflate(&z->zs, Z_FINISH);
534         if (ret != Z_OK &&
535             ret != Z_STREAM_END) zlib_error(ret, "bitio:deflate_finish", &z->zs);
536
537         if(z->zs.next_out != z->writebuffer) {
538             writer->pos += z->zs.next_out - (Bytef*)z->writebuffer;
539             z->output->write(z->output, z->writebuffer, z->zs.next_out - (Bytef*)z->writebuffer);
540             z->zs.next_out = z->writebuffer;
541             z->zs.avail_out = ZLIB_BUFFER_SIZE;
542         }
543
544         if (ret == Z_STREAM_END) {
545             break;
546
547         }
548     }
549     ret = deflateEnd(&z->zs);
550     if (ret != Z_OK) zlib_error(ret, "bitio:deflate_end", &z->zs);
551     free(writer->internal);
552     memset(writer, 0, sizeof(writer_t));
553     //output->finish(output); 
554 #else
555     fprintf(stderr, "Error: swftools was compiled without zlib support");
556     exit(1);
557 #endif
558 }
559 void writer_init_zlibdeflate(writer_t*w, writer_t*output)
560 {
561 #ifdef HAVE_ZLIB
562     zlibdeflate_t*z;
563     int ret;
564     memset(w, 0, sizeof(writer_t));
565     z = (zlibdeflate_t*)malloc(sizeof(zlibdeflate_t));
566     memset(z, 0, sizeof(zlibdeflate_t));
567     w->internal = z;
568     w->write = writer_zlibdeflate_write;
569     w->flush = writer_zlibdeflate_flush;
570     w->finish = writer_zlibdeflate_finish;
571     w->type = WRITER_TYPE_ZLIB;
572     w->pos = 0;
573     z->output = output;
574     memset(&z->zs,0,sizeof(z_stream));
575     z->zs.zalloc = Z_NULL;
576     z->zs.zfree  = Z_NULL;
577     z->zs.opaque = Z_NULL;
578     ret = deflateInit(&z->zs, 9);
579     if (ret != Z_OK) zlib_error(ret, "bitio:deflate_init", &z->zs);
580     w->bitpos = 0;
581     w->mybyte = 0;
582     z->zs.next_out = z->writebuffer;
583     z->zs.avail_out = ZLIB_BUFFER_SIZE;
584 #else
585     fprintf(stderr, "Error: swftools was compiled without zlib support");
586     exit(1);
587 #endif
588 }
589
590 /* ----------------------- bit handling routines -------------------------- */
591
592 void writer_writebit(writer_t*w, int bit)
593 {    
594     if(w->bitpos==8) 
595     {
596         w->write(w, &w->mybyte, 1);
597         w->bitpos = 0;
598         w->mybyte = 0;
599     }
600     if(bit&1)
601         w->mybyte |= 1 << (7 - w->bitpos);
602     w->bitpos ++;
603 }
604 void writer_writebits(writer_t*w, unsigned int data, int bits)
605 {
606     int t;
607     for(t=0;t<bits;t++)
608     {
609         writer_writebit(w, (data >> (bits-t-1))&1);
610     }
611 }
612 void writer_resetbits(writer_t*w)
613 {
614     if(w->bitpos)
615         w->write(w, &w->mybyte, 1);
616     w->bitpos = 0;
617     w->mybyte = 0;
618 }
619  
620 unsigned int reader_readbit(reader_t*r)
621 {
622     if(r->bitpos==8) 
623     {
624         r->bitpos=0;
625         r->read(r, &r->mybyte, 1);
626     }
627     return (r->mybyte>>(7-r->bitpos++))&1;
628 }
629 unsigned int reader_readbits(reader_t*r, int num)
630 {
631     int t;
632     int val = 0;
633     for(t=0;t<num;t++)
634     {
635         val<<=1;
636         val|=reader_readbit(r);
637     }
638     return val;
639 }
640 void reader_resetbits(reader_t*r)
641 {
642     r->mybyte = 0;
643     r->bitpos = 8;
644
645 }
646
647 U8 reader_readU8(reader_t*r)
648 {
649     U8 b = 0;
650     if(r->read(r, &b, 1)<1) {
651         fprintf(stderr, "bitio.c:reader_readU8: Read over end of memory region\n");
652     }
653     return b;
654 }
655 U16 reader_readU16(reader_t*r)
656 {
657     U8 b1=0,b2=0;
658     if(r->read(r, &b1, 1)<1) {
659         fprintf(stderr, "bitio.c:reader_readU16: Read over end of memory region\n");
660     }
661     if(r->read(r, &b2, 1)<1) {
662         fprintf(stderr, "bitio.c:reader_readU16: Read over end of memory region\n");
663     }
664     return b1|b2<<8;
665 }
666 U32 reader_readU32(reader_t*r)
667 {
668     U8 b1=0,b2=0,b3=0,b4=0;
669     if(r->read(r, &b1, 1)<1)
670         fprintf(stderr, "bitio.c:reader_readU32: Read over end of memory region\n");
671     if(r->read(r, &b2, 1)<1)
672         fprintf(stderr, "bitio.c:reader_readU32: Read over end of memory region\n");
673     if(r->read(r, &b3, 1)<1)
674         fprintf(stderr, "bitio.c:reader_readU32: Read over end of memory region\n");
675     if(r->read(r, &b4, 1)<1)
676         fprintf(stderr, "bitio.c:reader_readU32: Read over end of memory region\n");
677     return b1|b2<<8|b3<<16|b4<<24;
678 }
679 float reader_readFloat(reader_t*r)
680 {
681     float f;
682     r->read(r, &f, 4);
683     return f;
684
685     U8 b1=0,b2=0,b3=0,b4=0;
686     r->read(r, &b1, 1);
687     r->read(r, &b2, 1);
688     r->read(r, &b3, 1);
689     r->read(r, &b4, 1);
690     U32 w = (b1|b2<<8|b3<<16|b4<<24);
691     return *(float*)&w;
692 }
693 double reader_readDouble(reader_t*r)
694 {
695     double f;
696     r->read(r, &f, 8);
697     return f;
698
699     U8 b[8];
700     r->read(r, b, 8);
701     U64 w = ((U64)b[0]|(U64)b[1]<<8|(U64)b[2]<<16|(U64)b[3]<<24|(U64)b[4]<<32|(U64)b[5]<<40|(U64)b[6]<<48|(U64)b[7]<<56);
702     return *(double*)&w;
703 }
704 char*reader_readString(reader_t*r)
705 {
706     writer_t g;
707     writer_init_growingmemwriter(&g, 16);
708     while(1) {
709         U8 b = reader_readU8(r);
710         writer_writeU8(&g, b);
711         if(!b)
712             break;
713     }
714     char*string = (char*)writer_growmemwrite_getmem(&g);
715     g.finish(&g);
716     return string;
717 }
718
719 void writer_writeString(writer_t*w, const char*s)
720 {
721     int l = strlen(s);
722     char zero = 0;
723     w->write(w, (void*)s, l);
724     w->write(w, &zero, 1);
725 }
726 void writer_writeU8(writer_t*w, unsigned char b)
727 {
728     w->write(w, &b, 1);
729 }
730 void writer_writeU16(writer_t*w, unsigned short v)
731 {
732     unsigned char b1 = v;
733     unsigned char b2 = v>>8;
734     w->write(w, &b1, 1);
735     w->write(w, &b2, 1);
736 }
737 void writer_writeU32(writer_t*w, unsigned long v)
738 {
739     unsigned char b1 = v;
740     unsigned char b2 = v>>8;
741     unsigned char b3 = v>>16;
742     unsigned char b4 = v>>24;
743     w->write(w, &b1, 1);
744     w->write(w, &b2, 1);
745     w->write(w, &b3, 1);
746     w->write(w, &b4, 1);
747 }
748 void writer_writeFloat(writer_t*w, float f)
749 {
750     w->write(w, &f, 4);
751     return;
752
753     unsigned v = *(unsigned*)&f;
754     unsigned char b1 = v;
755     unsigned char b2 = v>>8;
756     unsigned char b3 = v>>16;
757     unsigned char b4 = v>>24;
758     w->write(w, &b1, 1);
759     w->write(w, &b2, 1);
760     w->write(w, &b3, 1);
761     w->write(w, &b4, 1);
762 }
763 void writer_writeDouble(writer_t*w, double f)
764 {
765     w->write(w, &f, 8);
766     return;
767
768     unsigned long long v = *(unsigned long long*)&f;
769     unsigned char b1 = v;
770     unsigned char b2 = v>>8;
771     unsigned char b3 = v>>16;
772     unsigned char b4 = v>>24;
773     unsigned char b5 = v>>32;
774     unsigned char b6 = v>>40;
775     unsigned char b7 = v>>48;
776     unsigned char b8 = v>>56;
777     w->write(w, &b1, 1);
778     w->write(w, &b2, 1);
779     w->write(w, &b3, 1);
780     w->write(w, &b4, 1);
781     w->write(w, &b5, 1);
782     w->write(w, &b6, 1);
783     w->write(w, &b7, 1);
784     w->write(w, &b8, 1);
785 }