From bd0b3cf306759c5aa5e43a88e4f030100dbac496 Mon Sep 17 00:00:00 2001 From: Mark Huang <mlhuang@cs.princeton.edu> Date: Mon, 3 Apr 2006 19:33:23 +0000 Subject: [PATCH] syslinux-3.08-2 sources from FC4 --- syslinux/.depend | 27 + syslinux/BUGS | 4 + syslinux/COPYING | 340 ++ syslinux/Makefile | 257 + syslinux/NEWS | 744 +++ syslinux/README | 31 + syslinux/README.menu | 119 + syslinux/README.usbkey | 49 + syslinux/TODO | 30 + syslinux/bcopy32.inc | 458 ++ syslinux/bin2c.pl | 59 + syslinux/bin2hex.pl | 46 + syslinux/bios.inc | 40 + syslinux/bootsect.inc | 157 + syslinux/cache.inc | 83 + syslinux/checksumiso.pl | 36 + syslinux/cmdline.inc | 44 + syslinux/com32.inc | 359 ++ syslinux/com32/LICENCE | 31 + syslinux/com32/Makefile | 4 + syslinux/com32/include/bitsize/limits.h | 14 + syslinux/com32/include/bitsize/stddef.h | 18 + syslinux/com32/include/bitsize/stdint.h | 34 + syslinux/com32/include/bitsize/stdintconst.h | 18 + syslinux/com32/include/bitsize/stdintlimits.h | 22 + syslinux/com32/include/com32.h | 117 + syslinux/com32/include/console.h | 60 + syslinux/com32/include/ctype.h | 119 + syslinux/com32/include/dev.h | 57 + syslinux/com32/include/errno.h | 135 + syslinux/com32/include/fcntl.h | 24 + syslinux/com32/include/inttypes.h | 226 + syslinux/com32/include/klibc/compiler.h | 115 + syslinux/com32/include/klibc/diverr.h | 4 + syslinux/com32/include/klibc/extern.h | 14 + syslinux/com32/include/klibc/sysconfig.h | 34 + syslinux/com32/include/limits.h | 39 + syslinux/com32/include/minmax.h | 44 + syslinux/com32/include/netinet/in.h | 43 + syslinux/com32/include/png.h | 3419 +++++++++++ syslinux/com32/include/pngconf.h | 1437 +++++ syslinux/com32/include/stdarg.h | 14 + syslinux/com32/include/stdbool.h | 33 + syslinux/com32/include/stddef.h | 24 + syslinux/com32/include/stdint.h | 146 + syslinux/com32/include/stdio.h | 120 + syslinux/com32/include/stdlib.h | 90 + syslinux/com32/include/string.h | 43 + syslinux/com32/include/sys/cpu.h | 78 + syslinux/com32/include/sys/io.h | 42 + syslinux/com32/include/sys/pci.h | 31 + syslinux/com32/include/sys/stat.h | 43 + syslinux/com32/include/sys/times.h | 21 + syslinux/com32/include/sys/types.h | 16 + syslinux/com32/include/syslinux.h | 40 + syslinux/com32/include/time.h | 0 syslinux/com32/include/unistd.h | 29 + syslinux/com32/include/zconf.h | 323 + syslinux/com32/include/zlib.h | 1200 ++++ syslinux/com32/lib/MCONFIG | 66 + syslinux/com32/lib/Makefile | 70 + syslinux/com32/lib/abort.c | 12 + syslinux/com32/lib/asprintf.c | 30 + syslinux/com32/lib/atexit.c | 10 + syslinux/com32/lib/atexit.h | 17 + syslinux/com32/lib/atoi.c | 3 + syslinux/com32/lib/atol.c | 3 + syslinux/com32/lib/atoll.c | 3 + syslinux/com32/lib/atox.c | 14 + syslinux/com32/lib/calloc.c | 21 + syslinux/com32/lib/com32.ld | 127 + syslinux/com32/lib/creat.c | 12 + syslinux/com32/lib/ctypes.c | 284 + syslinux/com32/lib/errno.c | 7 + syslinux/com32/lib/exit.c | 42 + syslinux/com32/lib/fgetc.c | 20 + syslinux/com32/lib/fgets.c | 33 + syslinux/com32/lib/fopen.c | 43 + syslinux/com32/lib/fopendev.c | 43 + syslinux/com32/lib/fprintf.c | 19 + syslinux/com32/lib/fputc.c | 14 + syslinux/com32/lib/fputs.c | 15 + syslinux/com32/lib/fread.c | 32 + syslinux/com32/lib/fread2.c | 13 + syslinux/com32/lib/free.c | 78 + syslinux/com32/lib/fwrite.c | 32 + syslinux/com32/lib/fwrite2.c | 13 + syslinux/com32/lib/getopt.c | 74 + syslinux/com32/lib/init.h | 15 + syslinux/com32/lib/libgcc/__ashldi3.S | 29 + syslinux/com32/lib/libgcc/__ashrdi3.S | 29 + syslinux/com32/lib/libgcc/__divdi3.c | 29 + syslinux/com32/lib/libgcc/__lshrdi3.S | 29 + syslinux/com32/lib/libgcc/__moddi3.c | 29 + syslinux/com32/lib/libgcc/__muldi3.S | 34 + syslinux/com32/lib/libgcc/__negdi2.S | 21 + syslinux/com32/lib/libgcc/__udivdi3.c | 13 + syslinux/com32/lib/libgcc/__udivmoddi4.c | 32 + syslinux/com32/lib/libgcc/__umoddi3.c | 16 + syslinux/com32/lib/libpng/ANNOUNCE | 32 + syslinux/com32/lib/libpng/CHANGES | 1419 +++++ syslinux/com32/lib/libpng/KNOWNBUG | 11 + syslinux/com32/lib/libpng/LICENSE | 113 + syslinux/com32/lib/libpng/README | 262 + syslinux/com32/lib/libpng/TODO | 24 + syslinux/com32/lib/libpng/Y2KINFO | 55 + syslinux/com32/lib/libpng/example.c | 808 +++ syslinux/com32/lib/libpng/libpng.3 | 4022 ++++++++++++ syslinux/com32/lib/libpng/libpng.txt | 2959 +++++++++ syslinux/com32/lib/libpng/libpngpf.3 | 1096 ++++ syslinux/com32/lib/libpng/png.5 | 74 + syslinux/com32/lib/libpng/png.c | 828 +++ syslinux/com32/lib/libpng/pngerror.c | 295 + syslinux/com32/lib/libpng/pnggccrd.c | 5408 +++++++++++++++++ syslinux/com32/lib/libpng/pngget.c | 934 +++ syslinux/com32/lib/libpng/pngmem.c | 595 ++ syslinux/com32/lib/libpng/pngpread.c | 1573 +++++ syslinux/com32/lib/libpng/pngread.c | 1456 +++++ syslinux/com32/lib/libpng/pngrio.c | 161 + syslinux/com32/lib/libpng/pngrtran.c | 4177 +++++++++++++ syslinux/com32/lib/libpng/pngrutil.c | 3124 ++++++++++ syslinux/com32/lib/libpng/pngset.c | 1219 ++++ syslinux/com32/lib/libpng/pngtest.c | 1554 +++++ syslinux/com32/lib/libpng/pngtrans.c | 650 ++ syslinux/com32/lib/libpng/pngvcrd.c | 3903 ++++++++++++ syslinux/com32/lib/libpng/pngwio.c | 228 + syslinux/com32/lib/libpng/pngwrite.c | 1464 +++++ syslinux/com32/lib/libpng/pngwtran.c | 563 ++ syslinux/com32/lib/libpng/pngwutil.c | 2730 +++++++++ syslinux/com32/lib/lrand48.c | 42 + syslinux/com32/lib/malloc.c | 120 + syslinux/com32/lib/malloc.h | 54 + syslinux/com32/lib/memccpy.c | 23 + syslinux/com32/lib/memchr.c | 18 + syslinux/com32/lib/memcmp.c | 19 + syslinux/com32/lib/memcpy.c | 29 + syslinux/com32/lib/memmem.c | 44 + syslinux/com32/lib/memmove.c | 34 + syslinux/com32/lib/memset.c | 30 + syslinux/com32/lib/memswap.c | 23 + syslinux/com32/lib/onexit.c | 39 + syslinux/com32/lib/pci/cfgtype.c | 23 + syslinux/com32/lib/pci/pci.h | 14 + syslinux/com32/lib/pci/readb.c | 3 + syslinux/com32/lib/pci/readl.c | 3 + syslinux/com32/lib/pci/readw.c | 3 + syslinux/com32/lib/pci/readx.c | 48 + syslinux/com32/lib/pci/writeb.c | 3 + syslinux/com32/lib/pci/writel.c | 3 + syslinux/com32/lib/pci/writew.c | 3 + syslinux/com32/lib/pci/writex.c | 45 + syslinux/com32/lib/perror.c | 12 + syslinux/com32/lib/printf.c | 19 + syslinux/com32/lib/putchar.c | 16 + syslinux/com32/lib/puts.c | 13 + syslinux/com32/lib/qsort.c | 42 + syslinux/com32/lib/realloc.c | 49 + syslinux/com32/lib/seed48.c | 19 + syslinux/com32/lib/setjmp.S | 58 + syslinux/com32/lib/snprintf.c | 16 + syslinux/com32/lib/sprintf.c | 18 + syslinux/com32/lib/srand48.c | 16 + syslinux/com32/lib/sscanf.c | 17 + syslinux/com32/lib/stack.c | 4 + syslinux/com32/lib/strcasecmp.c | 24 + syslinux/com32/lib/strcat.c | 11 + syslinux/com32/lib/strchr.c | 16 + syslinux/com32/lib/strcmp.c | 21 + syslinux/com32/lib/strcpy.c | 20 + syslinux/com32/lib/strdup.c | 17 + syslinux/com32/lib/strerror.c | 24 + syslinux/com32/lib/strlcat.c | 31 + syslinux/com32/lib/strlcpy.c | 26 + syslinux/com32/lib/strlen.c | 14 + syslinux/com32/lib/strncasecmp.c | 24 + syslinux/com32/lib/strncat.c | 11 + syslinux/com32/lib/strncmp.c | 21 + syslinux/com32/lib/strncpy.c | 22 + syslinux/com32/lib/strndup.c | 17 + syslinux/com32/lib/strntoimax.c | 13 + syslinux/com32/lib/strntoumax.c | 75 + syslinux/com32/lib/strrchr.c | 18 + syslinux/com32/lib/strsep.c | 21 + syslinux/com32/lib/strspn.c | 67 + syslinux/com32/lib/strstr.c | 10 + syslinux/com32/lib/strtoimax.c | 3 + syslinux/com32/lib/strtok.c | 16 + syslinux/com32/lib/strtol.c | 3 + syslinux/com32/lib/strtoll.c | 3 + syslinux/com32/lib/strtoul.c | 3 + syslinux/com32/lib/strtoull.c | 3 + syslinux/com32/lib/strtoumax.c | 3 + syslinux/com32/lib/strtox.c | 13 + syslinux/com32/lib/sys/ansicon_write.c | 538 ++ syslinux/com32/lib/sys/ansiserial_write.c | 56 + syslinux/com32/lib/sys/argv.c | 98 + syslinux/com32/lib/sys/close.c | 62 + syslinux/com32/lib/sys/entry.S | 90 + syslinux/com32/lib/sys/err_read.c | 54 + syslinux/com32/lib/sys/err_write.c | 54 + syslinux/com32/lib/sys/exit.S | 35 + syslinux/com32/lib/sys/file.h | 99 + syslinux/com32/lib/sys/fileclose.c | 53 + syslinux/com32/lib/sys/fileinfo.c | 3 + syslinux/com32/lib/sys/fileread.c | 86 + syslinux/com32/lib/sys/ftell.c | 18 + syslinux/com32/lib/sys/idle.c | 49 + syslinux/com32/lib/sys/isatty.c | 53 + syslinux/com32/lib/sys/line_input.c | 90 + syslinux/com32/lib/sys/null_read.c | 53 + syslinux/com32/lib/sys/null_write.c | 53 + syslinux/com32/lib/sys/open.c | 90 + syslinux/com32/lib/sys/openconsole.c | 52 + syslinux/com32/lib/sys/opendev.c | 69 + syslinux/com32/lib/sys/rawcon_read.c | 80 + syslinux/com32/lib/sys/rawcon_write.c | 67 + syslinux/com32/lib/sys/read.c | 52 + syslinux/com32/lib/sys/serial_write.c | 67 + syslinux/com32/lib/sys/stdcon_read.c | 77 + syslinux/com32/lib/sys/stdcon_write.c | 71 + syslinux/com32/lib/sys/times.c | 45 + syslinux/com32/lib/sys/write.c | 52 + syslinux/com32/lib/vasprintf.c | 25 + syslinux/com32/lib/vfprintf.c | 26 + syslinux/com32/lib/vprintf.c | 11 + syslinux/com32/lib/vsnprintf.c | 433 ++ syslinux/com32/lib/vsprintf.c | 11 + syslinux/com32/lib/vsscanf.c | 365 ++ syslinux/com32/lib/zlib/FAQ | 315 + syslinux/com32/lib/zlib/README | 126 + syslinux/com32/lib/zlib/adler32.c | 74 + syslinux/com32/lib/zlib/algorithm.txt | 209 + syslinux/com32/lib/zlib/compress.c | 79 + syslinux/com32/lib/zlib/crc32.c | 312 + syslinux/com32/lib/zlib/crc32.h | 441 ++ syslinux/com32/lib/zlib/deflate.c | 1502 +++++ syslinux/com32/lib/zlib/deflate.h | 326 + syslinux/com32/lib/zlib/example.c | 567 ++ syslinux/com32/lib/zlib/gzio.c | 1018 ++++ syslinux/com32/lib/zlib/infback.c | 619 ++ syslinux/com32/lib/zlib/inffast.c | 305 + syslinux/com32/lib/zlib/inffast.h | 11 + syslinux/com32/lib/zlib/inffixed.h | 94 + syslinux/com32/lib/zlib/inflate.c | 1270 ++++ syslinux/com32/lib/zlib/inflate.h | 117 + syslinux/com32/lib/zlib/inftrees.c | 321 + syslinux/com32/lib/zlib/inftrees.h | 55 + syslinux/com32/lib/zlib/minigzip.c | 323 + syslinux/com32/lib/zlib/trees.c | 1215 ++++ syslinux/com32/lib/zlib/trees.h | 128 + syslinux/com32/lib/zlib/uncompr.c | 61 + syslinux/com32/lib/zlib/zconf.in.h | 323 + syslinux/com32/lib/zlib/zlib.3 | 159 + syslinux/com32/lib/zlib/zutil.c | 319 + syslinux/com32/lib/zlib/zutil.h | 258 + syslinux/com32/libutil/Makefile | 112 + syslinux/com32/libutil/ansiline.c | 92 + syslinux/com32/libutil/ansiraw.c | 94 + syslinux/com32/libutil/get_key.c | 172 + syslinux/com32/libutil/idle.c | 53 + syslinux/com32/libutil/include/base64.h | 42 + syslinux/com32/libutil/include/consoles.h | 42 + syslinux/com32/libutil/include/getkey.h | 76 + syslinux/com32/libutil/include/libutil.h | 40 + syslinux/com32/libutil/include/minmax.h | 44 + syslinux/com32/libutil/include/sha1.h | 18 + syslinux/com32/libutil/sha1hash.c | 308 + syslinux/com32/libutil/unbase64.c | 78 + syslinux/com32/modules/Makefile | 98 + syslinux/com32/modules/chain.c | 377 ++ syslinux/com32/modules/ethersel.c | 282 + syslinux/com32/modules/i386-elf.h | 237 + syslinux/com32/modules/mb_header.h | 90 + syslinux/com32/modules/mb_info.h | 217 + syslinux/com32/modules/mboot.c | 979 +++ syslinux/com32/modules/mboot.doc | 27 + syslinux/com32/modules/menu.c | 631 ++ syslinux/com32/modules/menu.h | 49 + syslinux/com32/modules/readconfig.c | 259 + syslinux/com32/samples/Makefile | 82 + syslinux/com32/samples/cat.c | 31 + syslinux/com32/samples/fancyhello.c | 43 + syslinux/com32/samples/hello.c | 41 + syslinux/com32/samples/keytest.c | 82 + syslinux/com32/samples/resolv.c | 67 + syslinux/comboot.doc | 585 ++ syslinux/comboot.inc | 693 +++ syslinux/config.inc | 44 + syslinux/conio.inc | 402 ++ syslinux/copybs.asm | 272 + syslinux/cpuinit.inc | 76 + syslinux/distrib.doc | 30 + syslinux/dnsresolv.inc | 378 ++ syslinux/dos/Makefile | 60 + syslinux/dos/__divdi3.c | 29 + syslinux/dos/__udivmoddi4.c | 31 + syslinux/dos/argv.c | 94 + syslinux/dos/atou.c | 10 + syslinux/dos/code16.h | 2 + syslinux/dos/com16.ld | 127 + syslinux/dos/conio.c | 43 + syslinux/dos/crt0.S | 53 + syslinux/dos/errno.h | 7 + syslinux/dos/free.c | 78 + syslinux/dos/malloc.c | 114 + syslinux/dos/malloc.h | 54 + syslinux/dos/memcpy.S | 24 + syslinux/dos/memset.S | 22 + syslinux/dos/mystuff.h | 15 + syslinux/dos/perror.c | 8 + syslinux/dos/printf.c | 298 + syslinux/dos/skipatou.c | 10 + syslinux/dos/stdio.h | 22 + syslinux/dos/stdlib.h | 12 + syslinux/dos/string.h | 23 + syslinux/dos/syslinux.c | 594 ++ syslinux/dos/syslinux.com | Bin 0 -> 16620 bytes syslinux/ext2_fs.inc | 163 + syslinux/extlinux.asm | 1500 +++++ syslinux/extlinux.bin | Bin 0 -> 9832 bytes syslinux/extlinux.bss | Bin 0 -> 512 bytes syslinux/extlinux.doc | 89 + syslinux/extlinux.sys | Bin 0 -> 9320 bytes syslinux/extlinux/Makefile | 40 + syslinux/extlinux/ext2_fs.h | 508 ++ syslinux/extlinux/extlinux.c | 756 +++ syslinux/font.inc | 131 + syslinux/genhash.pl | 26 + syslinux/getc.inc | 290 + syslinux/gethostip.c | 132 + syslinux/graphics.inc | 336 + syslinux/highmem.inc | 145 + syslinux/init.inc | 67 + syslinux/isolinux-debug.bin | Bin 0 -> 11084 bytes syslinux/isolinux.asm | 1656 +++++ syslinux/isolinux.bin | Bin 0 -> 10424 bytes syslinux/isolinux.doc | 111 + syslinux/kernel.inc | 91 + syslinux/keytab-lilo.doc | 85 + syslinux/keytab-lilo.pl | 111 + syslinux/keywords | 34 + syslinux/keywords.inc | 85 + syslinux/kwdhash.gen | 34 + syslinux/layout.inc | 55 + syslinux/ldlinux.asm | 1539 +++++ syslinux/ldlinux.bin | Bin 0 -> 9932 bytes syslinux/ldlinux.bss | Bin 0 -> 512 bytes syslinux/ldlinux.sys | Bin 0 -> 9420 bytes syslinux/libfat/cache.c | 70 + syslinux/libfat/fat.h | 112 + syslinux/libfat/fatchain.c | 136 + syslinux/libfat/libfat.h | 87 + syslinux/libfat/libfatint.h | 56 + syslinux/libfat/open.c | 118 + syslinux/libfat/searchdir.c | 64 + syslinux/libfat/ulint.h | 115 + syslinux/loadhigh.inc | 96 + syslinux/lss16toppm | 112 + syslinux/macros.inc | 111 + syslinux/mbr.asm | 229 + syslinux/mbr.bin | Bin 0 -> 304 bytes syslinux/memdisk/.depend | 27 + syslinux/memdisk/Makefile | 121 + syslinux/memdisk/conio.c | 365 ++ syslinux/memdisk/conio.h | 32 + syslinux/memdisk/e820.h | 34 + syslinux/memdisk/e820data | 13 + syslinux/memdisk/e820func.c | 105 + syslinux/memdisk/e820test.c | 89 + syslinux/memdisk/inflate.c | 1083 ++++ syslinux/memdisk/memcpy.S | 29 + syslinux/memdisk/memdisk | Bin 0 -> 19124 bytes syslinux/memdisk/memdisk.asm | 759 +++ syslinux/memdisk/memdisk.doc | 186 + syslinux/memdisk/memdisk.h | 74 + syslinux/memdisk/memdisk16.asm | 768 +++ syslinux/memdisk/memset.S | 30 + syslinux/memdisk/msetup.c | 169 + syslinux/memdisk/postprocess.pl | 58 + syslinux/memdisk/setup.c | 761 +++ syslinux/memdisk/start32.S | 9 + syslinux/memdisk/testdata1 | 13 + syslinux/memdisk/testdata2 | 10 + syslinux/memdisk/testdata3 | 14 + syslinux/memdisk/unzip.c | 388 ++ syslinux/memdisk/version.h | 26 + syslinux/menu/CHANGES | 12 + syslinux/menu/HISTORY | 20 + syslinux/menu/MANUAL | 330 + syslinux/menu/Makefile | 79 + syslinux/menu/README | 93 + syslinux/menu/TODO | 9 + syslinux/menu/complex.c | 424 ++ syslinux/menu/libmenu/com32io.c | 147 + syslinux/menu/libmenu/com32io.h | 97 + syslinux/menu/libmenu/des.c | 1102 ++++ syslinux/menu/libmenu/des.h | 9 + syslinux/menu/libmenu/help.c | 84 + syslinux/menu/libmenu/help.h | 39 + syslinux/menu/libmenu/menu.c | 1148 ++++ syslinux/menu/libmenu/menu.h | 287 + syslinux/menu/libmenu/passwords.c | 140 + syslinux/menu/libmenu/passwords.h | 27 + syslinux/menu/libmenu/scancodes.h | 75 + syslinux/menu/libmenu/syslnx.c | 44 + syslinux/menu/libmenu/syslnx.h | 47 + syslinux/menu/libmenu/tui.c | 360 ++ syslinux/menu/libmenu/tui.h | 85 + syslinux/menu/password | 19 + syslinux/menu/simple.c | 78 + syslinux/mkdiskimage.in | 263 + syslinux/mtools/Makefile | 40 + syslinux/mtools/syslinux.c | 294 + syslinux/now.pl | 22 + syslinux/parsecmd.inc | 113 + syslinux/parseconfig.inc | 374 ++ syslinux/ppmtolss16 | 398 ++ syslinux/pxe.inc | 145 + syslinux/pxelinux.0 | Bin 0 -> 12952 bytes syslinux/pxelinux.asm | 2606 ++++++++ syslinux/pxelinux.doc | 374 ++ syslinux/rawcon.inc | 72 + syslinux/regdump.inc | 111 + syslinux/rllpack.inc | 133 + syslinux/runkernel.inc | 635 ++ syslinux/sample/Makefile | 84 + syslinux/sample/README | 6 + syslinux/sample/atou.c | 14 + syslinux/sample/c32echo.c | 49 + syslinux/sample/c32entry.S | 67 + syslinux/sample/c32exit.S | 10 + syslinux/sample/comecho.asm | 35 + syslinux/sample/conio.c | 61 + syslinux/sample/fd.c | 63 + syslinux/sample/filetest.c | 98 + syslinux/sample/hello.c | 45 + syslinux/sample/hello2.c | 61 + syslinux/sample/mdiskchk.c | 147 + syslinux/sample/mdiskchk.com | Bin 0 -> 9680 bytes syslinux/sample/printf.c | 307 + syslinux/sample/sample.msg | 13 + syslinux/sample/skipatou.c | 14 + syslinux/sample/syslogo.png | Bin 0 -> 19847 bytes syslinux/sha1pass | 32 + syslinux/strcpy.inc | 14 + syslinux/sys2ansi.pl | 54 + syslinux/syslinux.doc | 683 +++ syslinux/syslinux.h | 44 + syslinux/syslinux.spec | 203 + syslinux/syslxmod.c | 284 + syslinux/tracers.inc | 41 + syslinux/ui.inc | 495 ++ syslinux/unix/Makefile | 43 + syslinux/unix/syslinux.c | 505 ++ syslinux/version | 1 + syslinux/version.gen | 3 + syslinux/version.h | 3 + syslinux/version.pl | 26 + syslinux/win32/Makefile | 86 + syslinux/win32/hello.c | 13 + syslinux/win32/hello.exe | Bin 0 -> 10752 bytes syslinux/win32/syslinux.c | 483 ++ syslinux/win32/syslinux.exe | Bin 0 -> 29696 bytes syslinux/writehex.inc | 55 + syslinux/writestr.inc | 48 + 465 files changed, 107474 insertions(+) create mode 100644 syslinux/.depend create mode 100644 syslinux/BUGS create mode 100644 syslinux/COPYING create mode 100644 syslinux/Makefile create mode 100644 syslinux/NEWS create mode 100644 syslinux/README create mode 100644 syslinux/README.menu create mode 100644 syslinux/README.usbkey create mode 100644 syslinux/TODO create mode 100644 syslinux/bcopy32.inc create mode 100644 syslinux/bin2c.pl create mode 100755 syslinux/bin2hex.pl create mode 100644 syslinux/bios.inc create mode 100644 syslinux/bootsect.inc create mode 100644 syslinux/cache.inc create mode 100755 syslinux/checksumiso.pl create mode 100644 syslinux/cmdline.inc create mode 100644 syslinux/com32.inc create mode 100644 syslinux/com32/LICENCE create mode 100644 syslinux/com32/Makefile create mode 100644 syslinux/com32/include/bitsize/limits.h create mode 100644 syslinux/com32/include/bitsize/stddef.h create mode 100644 syslinux/com32/include/bitsize/stdint.h create mode 100644 syslinux/com32/include/bitsize/stdintconst.h create mode 100644 syslinux/com32/include/bitsize/stdintlimits.h create mode 100644 syslinux/com32/include/com32.h create mode 100644 syslinux/com32/include/console.h create mode 100644 syslinux/com32/include/ctype.h create mode 100644 syslinux/com32/include/dev.h create mode 100644 syslinux/com32/include/errno.h create mode 100644 syslinux/com32/include/fcntl.h create mode 100644 syslinux/com32/include/inttypes.h create mode 100644 syslinux/com32/include/klibc/compiler.h create mode 100644 syslinux/com32/include/klibc/diverr.h create mode 100644 syslinux/com32/include/klibc/extern.h create mode 100644 syslinux/com32/include/klibc/sysconfig.h create mode 100644 syslinux/com32/include/limits.h create mode 100644 syslinux/com32/include/minmax.h create mode 100644 syslinux/com32/include/netinet/in.h create mode 100644 syslinux/com32/include/png.h create mode 100644 syslinux/com32/include/pngconf.h create mode 100644 syslinux/com32/include/stdarg.h create mode 100644 syslinux/com32/include/stdbool.h create mode 100644 syslinux/com32/include/stddef.h create mode 100644 syslinux/com32/include/stdint.h create mode 100644 syslinux/com32/include/stdio.h create mode 100644 syslinux/com32/include/stdlib.h create mode 100644 syslinux/com32/include/string.h create mode 100644 syslinux/com32/include/sys/cpu.h create mode 100644 syslinux/com32/include/sys/io.h create mode 100644 syslinux/com32/include/sys/pci.h create mode 100644 syslinux/com32/include/sys/stat.h create mode 100644 syslinux/com32/include/sys/times.h create mode 100644 syslinux/com32/include/sys/types.h create mode 100644 syslinux/com32/include/syslinux.h create mode 100644 syslinux/com32/include/time.h create mode 100644 syslinux/com32/include/unistd.h create mode 100644 syslinux/com32/include/zconf.h create mode 100644 syslinux/com32/include/zlib.h create mode 100644 syslinux/com32/lib/MCONFIG create mode 100644 syslinux/com32/lib/Makefile create mode 100644 syslinux/com32/lib/abort.c create mode 100644 syslinux/com32/lib/asprintf.c create mode 100644 syslinux/com32/lib/atexit.c create mode 100644 syslinux/com32/lib/atexit.h create mode 100644 syslinux/com32/lib/atoi.c create mode 100644 syslinux/com32/lib/atol.c create mode 100644 syslinux/com32/lib/atoll.c create mode 100644 syslinux/com32/lib/atox.c create mode 100644 syslinux/com32/lib/calloc.c create mode 100644 syslinux/com32/lib/com32.ld create mode 100644 syslinux/com32/lib/creat.c create mode 100644 syslinux/com32/lib/ctypes.c create mode 100644 syslinux/com32/lib/errno.c create mode 100644 syslinux/com32/lib/exit.c create mode 100644 syslinux/com32/lib/fgetc.c create mode 100644 syslinux/com32/lib/fgets.c create mode 100644 syslinux/com32/lib/fopen.c create mode 100644 syslinux/com32/lib/fopendev.c create mode 100644 syslinux/com32/lib/fprintf.c create mode 100644 syslinux/com32/lib/fputc.c create mode 100644 syslinux/com32/lib/fputs.c create mode 100644 syslinux/com32/lib/fread.c create mode 100644 syslinux/com32/lib/fread2.c create mode 100644 syslinux/com32/lib/free.c create mode 100644 syslinux/com32/lib/fwrite.c create mode 100644 syslinux/com32/lib/fwrite2.c create mode 100644 syslinux/com32/lib/getopt.c create mode 100644 syslinux/com32/lib/init.h create mode 100644 syslinux/com32/lib/libgcc/__ashldi3.S create mode 100644 syslinux/com32/lib/libgcc/__ashrdi3.S create mode 100644 syslinux/com32/lib/libgcc/__divdi3.c create mode 100644 syslinux/com32/lib/libgcc/__lshrdi3.S create mode 100644 syslinux/com32/lib/libgcc/__moddi3.c create mode 100644 syslinux/com32/lib/libgcc/__muldi3.S create mode 100644 syslinux/com32/lib/libgcc/__negdi2.S create mode 100644 syslinux/com32/lib/libgcc/__udivdi3.c create mode 100644 syslinux/com32/lib/libgcc/__udivmoddi4.c create mode 100644 syslinux/com32/lib/libgcc/__umoddi3.c create mode 100644 syslinux/com32/lib/libpng/ANNOUNCE create mode 100644 syslinux/com32/lib/libpng/CHANGES create mode 100644 syslinux/com32/lib/libpng/KNOWNBUG create mode 100644 syslinux/com32/lib/libpng/LICENSE create mode 100644 syslinux/com32/lib/libpng/README create mode 100644 syslinux/com32/lib/libpng/TODO create mode 100644 syslinux/com32/lib/libpng/Y2KINFO create mode 100644 syslinux/com32/lib/libpng/example.c create mode 100644 syslinux/com32/lib/libpng/libpng.3 create mode 100644 syslinux/com32/lib/libpng/libpng.txt create mode 100644 syslinux/com32/lib/libpng/libpngpf.3 create mode 100644 syslinux/com32/lib/libpng/png.5 create mode 100644 syslinux/com32/lib/libpng/png.c create mode 100644 syslinux/com32/lib/libpng/pngerror.c create mode 100644 syslinux/com32/lib/libpng/pnggccrd.c create mode 100644 syslinux/com32/lib/libpng/pngget.c create mode 100644 syslinux/com32/lib/libpng/pngmem.c create mode 100644 syslinux/com32/lib/libpng/pngpread.c create mode 100644 syslinux/com32/lib/libpng/pngread.c create mode 100644 syslinux/com32/lib/libpng/pngrio.c create mode 100644 syslinux/com32/lib/libpng/pngrtran.c create mode 100644 syslinux/com32/lib/libpng/pngrutil.c create mode 100644 syslinux/com32/lib/libpng/pngset.c create mode 100644 syslinux/com32/lib/libpng/pngtest.c create mode 100644 syslinux/com32/lib/libpng/pngtrans.c create mode 100644 syslinux/com32/lib/libpng/pngvcrd.c create mode 100644 syslinux/com32/lib/libpng/pngwio.c create mode 100644 syslinux/com32/lib/libpng/pngwrite.c create mode 100644 syslinux/com32/lib/libpng/pngwtran.c create mode 100644 syslinux/com32/lib/libpng/pngwutil.c create mode 100644 syslinux/com32/lib/lrand48.c create mode 100644 syslinux/com32/lib/malloc.c create mode 100644 syslinux/com32/lib/malloc.h create mode 100644 syslinux/com32/lib/memccpy.c create mode 100644 syslinux/com32/lib/memchr.c create mode 100644 syslinux/com32/lib/memcmp.c create mode 100644 syslinux/com32/lib/memcpy.c create mode 100644 syslinux/com32/lib/memmem.c create mode 100644 syslinux/com32/lib/memmove.c create mode 100644 syslinux/com32/lib/memset.c create mode 100644 syslinux/com32/lib/memswap.c create mode 100644 syslinux/com32/lib/onexit.c create mode 100644 syslinux/com32/lib/pci/cfgtype.c create mode 100644 syslinux/com32/lib/pci/pci.h create mode 100644 syslinux/com32/lib/pci/readb.c create mode 100644 syslinux/com32/lib/pci/readl.c create mode 100644 syslinux/com32/lib/pci/readw.c create mode 100644 syslinux/com32/lib/pci/readx.c create mode 100644 syslinux/com32/lib/pci/writeb.c create mode 100644 syslinux/com32/lib/pci/writel.c create mode 100644 syslinux/com32/lib/pci/writew.c create mode 100644 syslinux/com32/lib/pci/writex.c create mode 100644 syslinux/com32/lib/perror.c create mode 100644 syslinux/com32/lib/printf.c create mode 100644 syslinux/com32/lib/putchar.c create mode 100644 syslinux/com32/lib/puts.c create mode 100644 syslinux/com32/lib/qsort.c create mode 100644 syslinux/com32/lib/realloc.c create mode 100644 syslinux/com32/lib/seed48.c create mode 100644 syslinux/com32/lib/setjmp.S create mode 100644 syslinux/com32/lib/snprintf.c create mode 100644 syslinux/com32/lib/sprintf.c create mode 100644 syslinux/com32/lib/srand48.c create mode 100644 syslinux/com32/lib/sscanf.c create mode 100644 syslinux/com32/lib/stack.c create mode 100644 syslinux/com32/lib/strcasecmp.c create mode 100644 syslinux/com32/lib/strcat.c create mode 100644 syslinux/com32/lib/strchr.c create mode 100644 syslinux/com32/lib/strcmp.c create mode 100644 syslinux/com32/lib/strcpy.c create mode 100644 syslinux/com32/lib/strdup.c create mode 100644 syslinux/com32/lib/strerror.c create mode 100644 syslinux/com32/lib/strlcat.c create mode 100644 syslinux/com32/lib/strlcpy.c create mode 100644 syslinux/com32/lib/strlen.c create mode 100644 syslinux/com32/lib/strncasecmp.c create mode 100644 syslinux/com32/lib/strncat.c create mode 100644 syslinux/com32/lib/strncmp.c create mode 100644 syslinux/com32/lib/strncpy.c create mode 100644 syslinux/com32/lib/strndup.c create mode 100644 syslinux/com32/lib/strntoimax.c create mode 100644 syslinux/com32/lib/strntoumax.c create mode 100644 syslinux/com32/lib/strrchr.c create mode 100644 syslinux/com32/lib/strsep.c create mode 100644 syslinux/com32/lib/strspn.c create mode 100644 syslinux/com32/lib/strstr.c create mode 100644 syslinux/com32/lib/strtoimax.c create mode 100644 syslinux/com32/lib/strtok.c create mode 100644 syslinux/com32/lib/strtol.c create mode 100644 syslinux/com32/lib/strtoll.c create mode 100644 syslinux/com32/lib/strtoul.c create mode 100644 syslinux/com32/lib/strtoull.c create mode 100644 syslinux/com32/lib/strtoumax.c create mode 100644 syslinux/com32/lib/strtox.c create mode 100644 syslinux/com32/lib/sys/ansicon_write.c create mode 100644 syslinux/com32/lib/sys/ansiserial_write.c create mode 100644 syslinux/com32/lib/sys/argv.c create mode 100644 syslinux/com32/lib/sys/close.c create mode 100644 syslinux/com32/lib/sys/entry.S create mode 100644 syslinux/com32/lib/sys/err_read.c create mode 100644 syslinux/com32/lib/sys/err_write.c create mode 100644 syslinux/com32/lib/sys/exit.S create mode 100644 syslinux/com32/lib/sys/file.h create mode 100644 syslinux/com32/lib/sys/fileclose.c create mode 100644 syslinux/com32/lib/sys/fileinfo.c create mode 100644 syslinux/com32/lib/sys/fileread.c create mode 100644 syslinux/com32/lib/sys/ftell.c create mode 100644 syslinux/com32/lib/sys/idle.c create mode 100644 syslinux/com32/lib/sys/isatty.c create mode 100644 syslinux/com32/lib/sys/line_input.c create mode 100644 syslinux/com32/lib/sys/null_read.c create mode 100644 syslinux/com32/lib/sys/null_write.c create mode 100644 syslinux/com32/lib/sys/open.c create mode 100644 syslinux/com32/lib/sys/openconsole.c create mode 100644 syslinux/com32/lib/sys/opendev.c create mode 100644 syslinux/com32/lib/sys/rawcon_read.c create mode 100644 syslinux/com32/lib/sys/rawcon_write.c create mode 100644 syslinux/com32/lib/sys/read.c create mode 100644 syslinux/com32/lib/sys/serial_write.c create mode 100644 syslinux/com32/lib/sys/stdcon_read.c create mode 100644 syslinux/com32/lib/sys/stdcon_write.c create mode 100644 syslinux/com32/lib/sys/times.c create mode 100644 syslinux/com32/lib/sys/write.c create mode 100644 syslinux/com32/lib/vasprintf.c create mode 100644 syslinux/com32/lib/vfprintf.c create mode 100644 syslinux/com32/lib/vprintf.c create mode 100644 syslinux/com32/lib/vsnprintf.c create mode 100644 syslinux/com32/lib/vsprintf.c create mode 100644 syslinux/com32/lib/vsscanf.c create mode 100644 syslinux/com32/lib/zlib/FAQ create mode 100644 syslinux/com32/lib/zlib/README create mode 100644 syslinux/com32/lib/zlib/adler32.c create mode 100644 syslinux/com32/lib/zlib/algorithm.txt create mode 100644 syslinux/com32/lib/zlib/compress.c create mode 100644 syslinux/com32/lib/zlib/crc32.c create mode 100644 syslinux/com32/lib/zlib/crc32.h create mode 100644 syslinux/com32/lib/zlib/deflate.c create mode 100644 syslinux/com32/lib/zlib/deflate.h create mode 100644 syslinux/com32/lib/zlib/example.c create mode 100644 syslinux/com32/lib/zlib/gzio.c create mode 100644 syslinux/com32/lib/zlib/infback.c create mode 100644 syslinux/com32/lib/zlib/inffast.c create mode 100644 syslinux/com32/lib/zlib/inffast.h create mode 100644 syslinux/com32/lib/zlib/inffixed.h create mode 100644 syslinux/com32/lib/zlib/inflate.c create mode 100644 syslinux/com32/lib/zlib/inflate.h create mode 100644 syslinux/com32/lib/zlib/inftrees.c create mode 100644 syslinux/com32/lib/zlib/inftrees.h create mode 100644 syslinux/com32/lib/zlib/minigzip.c create mode 100644 syslinux/com32/lib/zlib/trees.c create mode 100644 syslinux/com32/lib/zlib/trees.h create mode 100644 syslinux/com32/lib/zlib/uncompr.c create mode 100644 syslinux/com32/lib/zlib/zconf.in.h create mode 100644 syslinux/com32/lib/zlib/zlib.3 create mode 100644 syslinux/com32/lib/zlib/zutil.c create mode 100644 syslinux/com32/lib/zlib/zutil.h create mode 100644 syslinux/com32/libutil/Makefile create mode 100644 syslinux/com32/libutil/ansiline.c create mode 100644 syslinux/com32/libutil/ansiraw.c create mode 100644 syslinux/com32/libutil/get_key.c create mode 100644 syslinux/com32/libutil/idle.c create mode 100644 syslinux/com32/libutil/include/base64.h create mode 100644 syslinux/com32/libutil/include/consoles.h create mode 100644 syslinux/com32/libutil/include/getkey.h create mode 100644 syslinux/com32/libutil/include/libutil.h create mode 100644 syslinux/com32/libutil/include/minmax.h create mode 100644 syslinux/com32/libutil/include/sha1.h create mode 100644 syslinux/com32/libutil/sha1hash.c create mode 100644 syslinux/com32/libutil/unbase64.c create mode 100644 syslinux/com32/modules/Makefile create mode 100644 syslinux/com32/modules/chain.c create mode 100644 syslinux/com32/modules/ethersel.c create mode 100644 syslinux/com32/modules/i386-elf.h create mode 100644 syslinux/com32/modules/mb_header.h create mode 100644 syslinux/com32/modules/mb_info.h create mode 100644 syslinux/com32/modules/mboot.c create mode 100644 syslinux/com32/modules/mboot.doc create mode 100644 syslinux/com32/modules/menu.c create mode 100644 syslinux/com32/modules/menu.h create mode 100644 syslinux/com32/modules/readconfig.c create mode 100644 syslinux/com32/samples/Makefile create mode 100644 syslinux/com32/samples/cat.c create mode 100644 syslinux/com32/samples/fancyhello.c create mode 100644 syslinux/com32/samples/hello.c create mode 100644 syslinux/com32/samples/keytest.c create mode 100644 syslinux/com32/samples/resolv.c create mode 100644 syslinux/comboot.doc create mode 100644 syslinux/comboot.inc create mode 100644 syslinux/config.inc create mode 100644 syslinux/conio.inc create mode 100644 syslinux/copybs.asm create mode 100644 syslinux/cpuinit.inc create mode 100644 syslinux/distrib.doc create mode 100644 syslinux/dnsresolv.inc create mode 100644 syslinux/dos/Makefile create mode 100644 syslinux/dos/__divdi3.c create mode 100644 syslinux/dos/__udivmoddi4.c create mode 100644 syslinux/dos/argv.c create mode 100644 syslinux/dos/atou.c create mode 100644 syslinux/dos/code16.h create mode 100644 syslinux/dos/com16.ld create mode 100644 syslinux/dos/conio.c create mode 100644 syslinux/dos/crt0.S create mode 100644 syslinux/dos/errno.h create mode 100644 syslinux/dos/free.c create mode 100644 syslinux/dos/malloc.c create mode 100644 syslinux/dos/malloc.h create mode 100644 syslinux/dos/memcpy.S create mode 100644 syslinux/dos/memset.S create mode 100644 syslinux/dos/mystuff.h create mode 100644 syslinux/dos/perror.c create mode 100644 syslinux/dos/printf.c create mode 100644 syslinux/dos/skipatou.c create mode 100644 syslinux/dos/stdio.h create mode 100644 syslinux/dos/stdlib.h create mode 100644 syslinux/dos/string.h create mode 100644 syslinux/dos/syslinux.c create mode 100755 syslinux/dos/syslinux.com create mode 100644 syslinux/ext2_fs.inc create mode 100644 syslinux/extlinux.asm create mode 100644 syslinux/extlinux.bin create mode 100644 syslinux/extlinux.bss create mode 100644 syslinux/extlinux.doc create mode 100644 syslinux/extlinux.sys create mode 100644 syslinux/extlinux/Makefile create mode 100644 syslinux/extlinux/ext2_fs.h create mode 100644 syslinux/extlinux/extlinux.c create mode 100644 syslinux/font.inc create mode 100755 syslinux/genhash.pl create mode 100644 syslinux/getc.inc create mode 100644 syslinux/gethostip.c create mode 100644 syslinux/graphics.inc create mode 100644 syslinux/highmem.inc create mode 100644 syslinux/init.inc create mode 100644 syslinux/isolinux-debug.bin create mode 100644 syslinux/isolinux.asm create mode 100644 syslinux/isolinux.bin create mode 100644 syslinux/isolinux.doc create mode 100644 syslinux/kernel.inc create mode 100644 syslinux/keytab-lilo.doc create mode 100755 syslinux/keytab-lilo.pl create mode 100644 syslinux/keywords create mode 100644 syslinux/keywords.inc create mode 100644 syslinux/kwdhash.gen create mode 100644 syslinux/layout.inc create mode 100644 syslinux/ldlinux.asm create mode 100644 syslinux/ldlinux.bin create mode 100644 syslinux/ldlinux.bss create mode 100644 syslinux/ldlinux.sys create mode 100644 syslinux/libfat/cache.c create mode 100644 syslinux/libfat/fat.h create mode 100644 syslinux/libfat/fatchain.c create mode 100644 syslinux/libfat/libfat.h create mode 100644 syslinux/libfat/libfatint.h create mode 100644 syslinux/libfat/open.c create mode 100644 syslinux/libfat/searchdir.c create mode 100644 syslinux/libfat/ulint.h create mode 100644 syslinux/loadhigh.inc create mode 100755 syslinux/lss16toppm create mode 100644 syslinux/macros.inc create mode 100644 syslinux/mbr.asm create mode 100644 syslinux/mbr.bin create mode 100644 syslinux/memdisk/.depend create mode 100644 syslinux/memdisk/Makefile create mode 100644 syslinux/memdisk/conio.c create mode 100644 syslinux/memdisk/conio.h create mode 100644 syslinux/memdisk/e820.h create mode 100644 syslinux/memdisk/e820data create mode 100644 syslinux/memdisk/e820func.c create mode 100644 syslinux/memdisk/e820test.c create mode 100644 syslinux/memdisk/inflate.c create mode 100644 syslinux/memdisk/memcpy.S create mode 100644 syslinux/memdisk/memdisk create mode 100644 syslinux/memdisk/memdisk.asm create mode 100644 syslinux/memdisk/memdisk.doc create mode 100644 syslinux/memdisk/memdisk.h create mode 100644 syslinux/memdisk/memdisk16.asm create mode 100644 syslinux/memdisk/memset.S create mode 100644 syslinux/memdisk/msetup.c create mode 100755 syslinux/memdisk/postprocess.pl create mode 100644 syslinux/memdisk/setup.c create mode 100644 syslinux/memdisk/start32.S create mode 100644 syslinux/memdisk/testdata1 create mode 100644 syslinux/memdisk/testdata2 create mode 100644 syslinux/memdisk/testdata3 create mode 100644 syslinux/memdisk/unzip.c create mode 100644 syslinux/memdisk/version.h create mode 100644 syslinux/menu/CHANGES create mode 100644 syslinux/menu/HISTORY create mode 100644 syslinux/menu/MANUAL create mode 100644 syslinux/menu/Makefile create mode 100644 syslinux/menu/README create mode 100644 syslinux/menu/TODO create mode 100644 syslinux/menu/complex.c create mode 100644 syslinux/menu/libmenu/com32io.c create mode 100644 syslinux/menu/libmenu/com32io.h create mode 100644 syslinux/menu/libmenu/des.c create mode 100644 syslinux/menu/libmenu/des.h create mode 100644 syslinux/menu/libmenu/help.c create mode 100644 syslinux/menu/libmenu/help.h create mode 100644 syslinux/menu/libmenu/menu.c create mode 100644 syslinux/menu/libmenu/menu.h create mode 100644 syslinux/menu/libmenu/passwords.c create mode 100644 syslinux/menu/libmenu/passwords.h create mode 100644 syslinux/menu/libmenu/scancodes.h create mode 100644 syslinux/menu/libmenu/syslnx.c create mode 100644 syslinux/menu/libmenu/syslnx.h create mode 100644 syslinux/menu/libmenu/tui.c create mode 100644 syslinux/menu/libmenu/tui.h create mode 100644 syslinux/menu/password create mode 100644 syslinux/menu/simple.c create mode 100755 syslinux/mkdiskimage.in create mode 100644 syslinux/mtools/Makefile create mode 100644 syslinux/mtools/syslinux.c create mode 100644 syslinux/now.pl create mode 100644 syslinux/parsecmd.inc create mode 100644 syslinux/parseconfig.inc create mode 100755 syslinux/ppmtolss16 create mode 100644 syslinux/pxe.inc create mode 100644 syslinux/pxelinux.0 create mode 100644 syslinux/pxelinux.asm create mode 100644 syslinux/pxelinux.doc create mode 100644 syslinux/rawcon.inc create mode 100644 syslinux/regdump.inc create mode 100644 syslinux/rllpack.inc create mode 100644 syslinux/runkernel.inc create mode 100644 syslinux/sample/Makefile create mode 100644 syslinux/sample/README create mode 100644 syslinux/sample/atou.c create mode 100644 syslinux/sample/c32echo.c create mode 100644 syslinux/sample/c32entry.S create mode 100644 syslinux/sample/c32exit.S create mode 100644 syslinux/sample/comecho.asm create mode 100644 syslinux/sample/conio.c create mode 100644 syslinux/sample/fd.c create mode 100644 syslinux/sample/filetest.c create mode 100644 syslinux/sample/hello.c create mode 100644 syslinux/sample/hello2.c create mode 100644 syslinux/sample/mdiskchk.c create mode 100755 syslinux/sample/mdiskchk.com create mode 100644 syslinux/sample/printf.c create mode 100644 syslinux/sample/sample.msg create mode 100644 syslinux/sample/skipatou.c create mode 100644 syslinux/sample/syslogo.png create mode 100755 syslinux/sha1pass create mode 100644 syslinux/strcpy.inc create mode 100755 syslinux/sys2ansi.pl create mode 100644 syslinux/syslinux.doc create mode 100644 syslinux/syslinux.h create mode 100644 syslinux/syslinux.spec create mode 100644 syslinux/syslxmod.c create mode 100644 syslinux/tracers.inc create mode 100644 syslinux/ui.inc create mode 100644 syslinux/unix/Makefile create mode 100644 syslinux/unix/syslinux.c create mode 100644 syslinux/version create mode 100644 syslinux/version.gen create mode 100644 syslinux/version.h create mode 100755 syslinux/version.pl create mode 100644 syslinux/win32/Makefile create mode 100644 syslinux/win32/hello.c create mode 100755 syslinux/win32/hello.exe create mode 100644 syslinux/win32/syslinux.c create mode 100755 syslinux/win32/syslinux.exe create mode 100644 syslinux/writehex.inc create mode 100644 syslinux/writestr.inc diff --git a/syslinux/.depend b/syslinux/.depend new file mode 100644 index 0000000..34adb7c --- /dev/null +++ b/syslinux/.depend @@ -0,0 +1,27 @@ +syslxmod.o: syslxmod.c syslinux.h +gethostip.o: gethostip.c +copybs.bin: copybs.asm +extlinux.bin: extlinux.asm macros.inc config.inc kernel.inc bios.inc tracers.inc \ + layout.inc ext2_fs.inc init.inc cpuinit.inc ui.inc runkernel.inc \ + comboot.inc com32.inc cmdline.inc bootsect.inc getc.inc conio.inc \ + writestr.inc parseconfig.inc rllpack.inc parsecmd.inc bcopy32.inc \ + loadhigh.inc font.inc graphics.inc highmem.inc strcpy.inc cache.inc \ + keywords.inc +isolinux.bin: isolinux.asm macros.inc config.inc kernel.inc bios.inc tracers.inc \ + layout.inc writestr.inc writehex.inc init.inc cpuinit.inc ui.inc \ + runkernel.inc comboot.inc com32.inc cmdline.inc bootsect.inc getc.inc \ + conio.inc parseconfig.inc rllpack.inc parsecmd.inc bcopy32.inc \ + loadhigh.inc font.inc graphics.inc highmem.inc strcpy.inc rawcon.inc \ + keywords.inc +ldlinux.bin: ldlinux.asm macros.inc config.inc kernel.inc bios.inc tracers.inc \ + layout.inc cpuinit.inc init.inc ui.inc runkernel.inc comboot.inc \ + com32.inc cmdline.inc bootsect.inc getc.inc conio.inc writestr.inc \ + parseconfig.inc rllpack.inc parsecmd.inc bcopy32.inc loadhigh.inc font.inc \ + graphics.inc highmem.inc strcpy.inc cache.inc keywords.inc +mbr.bin: mbr.asm bios.inc +pxelinux.bin: pxelinux.asm macros.inc config.inc kernel.inc bios.inc tracers.inc pxe.inc \ + layout.inc init.inc cpuinit.inc ui.inc runkernel.inc comboot.inc \ + com32.inc cmdline.inc bootsect.inc getc.inc conio.inc writestr.inc \ + writehex.inc parseconfig.inc rllpack.inc parsecmd.inc bcopy32.inc \ + loadhigh.inc font.inc graphics.inc highmem.inc strcpy.inc rawcon.inc \ + dnsresolv.inc keywords.inc diff --git a/syslinux/BUGS b/syslinux/BUGS new file mode 100644 index 0000000..9639da8 --- /dev/null +++ b/syslinux/BUGS @@ -0,0 +1,4 @@ +Known bugs that have not yet been fixed: + +- PXELINUX: Some PXE stacks fail with routing enabled, some with + routing disabled. Try both? diff --git a/syslinux/COPYING b/syslinux/COPYING new file mode 100644 index 0000000..60549be --- /dev/null +++ b/syslinux/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/syslinux/Makefile b/syslinux/Makefile new file mode 100644 index 0000000..be8378f --- /dev/null +++ b/syslinux/Makefile @@ -0,0 +1,257 @@ +## $Id: Makefile,v 1.120 2005/04/02 21:48:47 hpa Exp $ +## ----------------------------------------------------------------------- +## +## Copyright 1998-2005 H. Peter Anvin - All Rights Reserved +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, Inc., 53 Temple Place Ste 330, +## Boston MA 02111-1307, USA; either version 2 of the License, or +## (at your option) any later version; incorporated herein by reference. +## +## ----------------------------------------------------------------------- + +# +# Main Makefile for SYSLINUX +# + +OSTYPE = $(shell uname -msr) +CC = gcc +INCLUDE = +CFLAGS = -W -Wall -Os -fomit-frame-pointer -D_FILE_OFFSET_BITS=64 +PIC = -fPIC +LDFLAGS = -O2 -s +AR = ar +RANLIB = ranlib + +NASM = nasm -O99 +NINCLUDE = +BINDIR = /usr/bin +SBINDIR = /sbin +LIBDIR = /usr/lib +AUXDIR = $(LIBDIR)/syslinux +INCDIR = /usr/include + +PERL = perl + +VERSION = $(shell cat version) + +.c.o: + $(CC) $(INCLUDE) $(CFLAGS) -c $< + +# +# The BTARGET refers to objects that are derived from ldlinux.asm; we +# like to keep those uniform for debugging reasons; however, distributors +# want to recompile the installers (ITARGET). +# +# BOBJECTS and IOBJECTS are the same thing, except used for +# installation, so they include objects that may be in subdirectories +# with their own Makefiles. Finally, there is a list of those +# directories. +# +CSRC = syslxmod.c gethostip.c +NASMSRC = $(wildcard *.asm) +SOURCES = $(CSRC) *.h $(NASMSRC) *.inc + +# _bin.c files required by both BTARGET and ITARGET installers +BINFILES = bootsect_bin.c ldlinux_bin.c mbr_bin.c \ + extlinux_bss_bin.c extlinux_sys_bin.c + +# syslinux.exe is BTARGET so as to not require everyone to have the +# mingw suite installed +BTARGET = kwdhash.gen version.gen version.h \ + ldlinux.bss ldlinux.sys ldlinux.bin \ + pxelinux.0 mbr.bin isolinux.bin isolinux-debug.bin \ + extlinux.bin extlinux.bss extlinux.sys +BOBJECTS = $(BTARGET) dos/syslinux.com win32/syslinux.exe memdisk/memdisk +BSUBDIRS = memdisk dos win32 +ITARGET = copybs.com gethostip mkdiskimage +IOBJECTS = $(ITARGET) mtools/syslinux unix/syslinux extlinux/extlinux +ISUBDIRS = mtools unix extlinux sample com32 +DOCS = COPYING NEWS README TODO BUGS *.doc sample menu com32 +OTHER = Makefile bin2c.pl now.pl genhash.pl keywords findpatch.pl \ + keytab-lilo.pl version version.pl sys2ansi.pl \ + ppmtolss16 lss16toppm memdisk bin2hex.pl mkdiskimage.in +OBSOLETE = pxelinux.bin + +# Things to install in /usr/bin +INSTALL_BIN = mtools/syslinux gethostip ppmtolss16 lss16toppm +# Things to install in /sbin +INSTALL_SBIN = extlinux/extlinux +# Things to install in /usr/lib/syslinux +INSTALL_AUX = pxelinux.0 isolinux.bin isolinux-debug.bin \ + dos/syslinux.com copybs.com memdisk/memdisk mbr.bin +INSTALL_AUX_OPT = win32/syslinux.exe + +# The DATE is set on the make command line when building binaries for +# official release. Otherwise, substitute a hex string that is pretty much +# guaranteed to be unique to be unique from build to build. +ifndef HEXDATE +HEXDATE := $(shell $(PERL) now.pl ldlinux.asm pxelinux.asm isolinux.asm) +endif +ifndef DATE +DATE := $(HEXDATE) +endif +MAKE += DATE=$(DATE) HEXDATE=$(HEXDATE) + +# +# NOTE: If you don't have the mingw compiler suite installed, you probably +# want to remove win32 from this list; otherwise you're going to get an +# error every time you try to build. +# + +all: all-local + set -e ; for i in $(BSUBDIRS) $(ISUBDIRS) ; do $(MAKE) -C $$i $@ ; done + $(MAKE) all-local + -ls -l $(BOBJECTS) $(IOBJECTS) + +all-local: $(BTARGET) $(ITARGET) $(BINFILES) + +installer: installer-local + set -e ; for i in $(ISUBDIRS); do $(MAKE) -C $$i all ; done + -ls -l $(BOBJECTS) $(IOBJECTS) + +installer-local: $(ITARGET) $(BINFILES) + +version.gen: version version.pl + $(PERL) version.pl $< $@ '%define' + +version.h: version version.pl + $(PERL) version.pl $< $@ '#define' + +kwdhash.gen: keywords genhash.pl + $(PERL) genhash.pl < keywords > kwdhash.gen + +ldlinux.bin: ldlinux.asm kwdhash.gen version.gen + $(NASM) -f bin -DDATE_STR="'$(DATE)'" -DHEXDATE="$(HEXDATE)" \ + -DMAP=ldlinux.map -l ldlinux.lst -o ldlinux.bin ldlinux.asm + +pxelinux.bin: pxelinux.asm kwdhash.gen version.gen + $(NASM) -f bin -DDATE_STR="'$(DATE)'" -DHEXDATE="$(HEXDATE)" \ + -DMAP=pxelinux.map -l pxelinux.lst -o pxelinux.bin pxelinux.asm + +isolinux.bin: isolinux.asm kwdhash.gen version.gen checksumiso.pl + $(NASM) -f bin -DDATE_STR="'$(DATE)'" -DHEXDATE="$(HEXDATE)" \ + -DMAP=isolinux.map -l isolinux.lst -o isolinux.bin isolinux.asm + $(PERL) checksumiso.pl isolinux.bin + +# Special verbose version of isolinux.bin +isolinux-debug.bin: isolinux.asm kwdhash.gen version.gen checksumiso.pl + $(NASM) -f bin -DDATE_STR="'$(DATE)'" -DHEXDATE="$(HEXDATE)" \ + -DDEBUG_MESSAGES \ + -DMAP=isolinux-debug.map -l isolinux-debug.lst \ + -o isolinux-debug.bin isolinux.asm + $(PERL) checksumiso.pl $@ + +extlinux.bin: extlinux.asm kwdhash.gen version.gen + $(NASM) -f bin -DDATE_STR="'$(DATE)'" -DHEXDATE="$(HEXDATE)" \ + -DMAP=extlinux.map -l extlinux.lst -o extlinux.bin extlinux.asm + +pxelinux.0: pxelinux.bin + cp pxelinux.bin pxelinux.0 + +ldlinux.bss: ldlinux.bin + dd if=$< of=$@ bs=512 count=1 + +ldlinux.sys: ldlinux.bin + dd if=$< of=$@ bs=512 skip=1 + +extlinux.bss: extlinux.bin + dd if=$< of=$@ bs=512 count=1 + +extlinux.sys: extlinux.bin + dd if=$< of=$@ bs=512 skip=1 + +mbr.bin: mbr.asm + $(NASM) -f bin -l mbr.lst -o mbr.bin mbr.asm + +mbr_bin.c: mbr.bin bin2c.pl + $(PERL) bin2c.pl syslinux_mbr < $< > $@ + +copybs.com: copybs.asm + $(NASM) -f bin -l copybs.lst -o copybs.com copybs.asm + +bootsect_bin.c: ldlinux.bss bin2c.pl + $(PERL) bin2c.pl syslinux_bootsect < $< > $@ + +ldlinux_bin.c: ldlinux.sys bin2c.pl + $(PERL) bin2c.pl syslinux_ldlinux < $< > $@ + +extlinux_bss_bin.c: extlinux.bss bin2c.pl + $(PERL) bin2c.pl extlinux_bootsect < $< > $@ + +extlinux_sys_bin.c: extlinux.sys bin2c.pl + $(PERL) bin2c.pl extlinux_image < $< > $@ + +libsyslinux.a: bootsect_bin.o ldlinux_bin.o mbr_bin.o syslxmod.o + rm -f $@ + $(AR) cq $@ $^ + $(RANLIB) $@ + +$(LIB_SO): bootsect_bin.o ldlinux_bin.o syslxmod.o + $(CC) $(LDFLAGS) -shared -Wl,-soname,$(LIB_SONAME) -o $@ $^ + +gethostip.o: gethostip.c + +gethostip: gethostip.o + +mkdiskimage: mkdiskimage.in mbr.bin bin2hex.pl + $(PERL) bin2hex.pl < mbr.bin | cat mkdiskimage.in - > $@ + chmod a+x $@ + +install: installer + mkdir -m 755 -p $(INSTALLROOT)$(BINDIR) + install -m 755 -c $(INSTALL_BIN) $(INSTALLROOT)$(BINDIR) + mkdir -m 755 -p $(INSTALLROOT)$(SBINDIR) + install -m 755 -c $(INSTALL_SBIN) $(INSTALLROOT)$(SBINDIR) + mkdir -m 755 -p $(INSTALLROOT)$(AUXDIR) + install -m 644 -c $(INSTALL_AUX) $(INSTALLROOT)$(AUXDIR) + -install -m 644 -c $(INSTALL_AUX_OPT) $(INSTALLROOT)$(AUXDIR) + $(MAKE) -C com32 install + +install-lib: installer + +install-all: install install-lib + +local-tidy: + rm -f *.o *_bin.c stupid.* patch.offset + rm -f *.lst *.map + rm -f $(OBSOLETE) + +tidy: local-tidy + set -e ; for i in $(BSUBDIRS) $(ISUBDIRS) ; do $(MAKE) -C $$i $@ ; done + +local-clean: + rm -f $(ITARGET) + +clean: local-tidy local-clean + set -e ; for i in $(BSUBDIRS) $(ISUBDIRS) ; do $(MAKE) -C $$i $@ ; done + +dist: tidy + for dir in . sample memdisk ; do \ + ( cd $$dir && rm -f *~ \#* core ) ; \ + done + +local-spotless: + rm -f $(BTARGET) .depend *.so.* + +spotless: local-clean dist local-spotless + set -e ; for i in $(BSUBDIRS) $(ISUBDIRS) ; do $(MAKE) -C $$i $@ ; done + +.depend: + rm -f .depend + for csrc in $(CSRC) ; do $(CC) $(INCLUDE) -MM $$csrc >> .depend ; done + for nsrc in $(NASMSRC) ; do $(NASM) -DDEPEND $(NINCLUDE) -o `echo $$nsrc | sed -e 's/\.asm/\.bin/'` -M $$nsrc >> .depend ; done + +local-depend: + rm -f .depend + $(MAKE) .depend + +depend: local-depend + $(MAKE) -C memdisk depend + +# Hook to add private Makefile targets for the maintainer. +-include Makefile.private + +# Include dependencies file +-include .depend diff --git a/syslinux/NEWS b/syslinux/NEWS new file mode 100644 index 0000000..7b0be3e --- /dev/null +++ b/syslinux/NEWS @@ -0,0 +1,744 @@ +Starting with 1.47, changes marked with SYSLINUX/PXELINUX/ISOLINUX +apply to that specific program only; other changes apply to all of +them. + +Changes in 3.08: + * SYSLINUX: Fix performance regression (-s mode always + enabled.) + * Add API function for idle loop. + * libutil: Add do_idle() function for idle loop, make + get_key() use it. + * libutil: Add SHA-1 and base64 functions. + * Simple menu system: add password support. + * EXTLINUX: Sparse files now handled correctly. + * EXTLINUX: Large directories now handled correctly. + * ALL: At the prompt, Ctrl-X now forces text mode. + * Fix configuration file parsing error, that could cause + hangs. + * Rewritten advanced menuing system from Murali Ganapathy. + * MEMDISK: New "bigraw" mode to work around certain broken + BIOS flash programs. + * COM32 module to boot Multiboot systems, including Xen. See + com32/modules/mboot.doc. + * Max command line changed to 1024 characters. Note that the + kernel proper still can only handle 255 characters without + patching, and COM16 binaries can only handle 125 characters. + +Changes in 3.07: + * Fix chainloading (chain.c32). + * Fix zlib build problem. + * Use a private copy of <linux/ext2_fs.h>. + +Changes in 3.06: + * Fix typo that caused the ramdisk to load in the wrong place. + +Changes in 3.05: + * New API function "shuffle and boot"; allows COM32 modules to + load or construct (almost) arbitrarily complex objects, + e.g. a kernel and its initrd/initramfs in pieces, and have + the API core reorganize memory for booting. (A library API + for this function will be introduced in a later version.) + * The initrd= option now supports multiple filenames separated + by commas. This is mostly useful for initramfs, which can + be composed of multiple separate cpio or cpio.gz archives. + (Note: all files except the last one are zero-padded to a 4K + page boundary. This should not affect initramfs.) + * EXTLINUX: Fix API function 000Ah (get derivative-specific + info). + * libcom32/ethersel: Support PCI Config Mechanism #2 on + machines still infested with that hideous old hack. + * SYSLINUX: Fix directory-parsing bug. + +Changes in 3.02: + * SYSLINUX: The "unix" installer now sets the MS-DOS + attributes (hidden, system, readonly.) + * COM32 library: build the .lnx (test modules for running + under Linux) as architecture native modules, in case + i386 devel libraries aren't installed. + * EXTLINUX: Hack for systems which don't have BLKGETSIZE64 + defined in the standard header files. + * Simple menu system: minor aestetic improvements, and try to + work better over a serial console (speed, and readability on + monochrome terminal emulators.) + * New CONSOLE directive to control output on the video console + (useful for dealing with some broken serial-forwarding + BIOSes.) + * New com32 module "ethersel" for searching for an Ethernet + card and selecting the proper version of Etherboot. + * EXTLINUX: Allow the user to override the detected geometry. + Add help. + +Changes in 3.01: + * EXTLINUX, SYSLINUX: Fix compile errors on some systems. + * EXTLINUX: Default to zipdrive geometry (64 heads, 32 + sectors) if no other geometry can be detected. + +Changes in 3.00: + * SYSLINUX: Support FAT32 and EDD. As an unfortunate + consequence, LDLINUX.SYS is no longer an ordinary file; it + is block-mapped at install time, which means it can only be + written using the syslinux installers. + * SYSLINUX: Reorganize the source code for the installers; + each one of the installers (dos, win32, unix, mtools) is now + built in its own subdirectory. In particular, "mtools" is + the unprivileged installer which uses mtools; "unix" is the + privileged installer which uses system calls. + * SYSLINUX: Completely rewritten DOS installer in C. + * ALL: "label" statement information is now stored in a + compressed format, which means that a lot more labels are + permitted (500-1000 in a typical configuration, but depends + on the complexity.) + * EXTLINUX: New derivative, which boots from an ext2/ext3 + filesystem. + * SYSLINUX: The DOS and Win32 installers can now optionally + write the boot sector to a file instead of the real boot + sector. This is not supported in the Linux installers, + however. + * ALL: New NOESCAPE command, disables the "hold down the Shift + key to display the prompt" behaviour. + * New simple menu system, as an alternative to the advanced + menu system already present. See README.menu for details. + * PXELINUX: Filenames can now be prefixed with an IP address + or DNS name plus :: (e.g. 192.0.2.1::filename or + server.domain.com::filename), which downloads a file from an + alternate TFTP server, or just a :: (e.g. ::filename), which + suppresses the common pathname prefix. See pxelinux.doc. + * SYSLINUX: Add an -m option to the DOS and Win32 installers + to write an MBR and -a to mark the partition SYSLINUX is + being installed on active. + * MEMDISK: Give a way to query the boot loader type while + running MEMDISK; see memdisk/memdisk.doc and + sample/mdiskchk.c. + * mkdiskimage: substantially improved mkdiskimage which, among + other things, can now be used to initialize USB keys as + zipdrives; see README.usbkey for more information. + +Changes in 2.13: + * MEMDISK: Fix command-line parsing "brown paper bag" class + bug. + * MEMDISK: Add "raw" mode to support the DOS boot disk from + WinME/XP, which seems to deliberately crash the system + when someone uses the "INT 15h mover" highmem API. + * Make "make install" do something sane for the com32 + development environment. + * In the spec file, create a separate -devel RPM for the com32 + development environment. + +Changes in 2.12: + * Simple C library, based on klibc, for writing COM32 + programs. + * Fix the handling of file length in loading of COM32 + programs. + * MEMDISK: Work around a linker bug by rearranging the code to + not use the linker for the 16-bit code. + * SYSLINUX: If we're building on a machine without a Win32 + (mingw) compiler, just skip building syslinux.exe. + * ISOLINUX: Support non-mkisofs mastering programs, at least + as long as the image is single-session. For best results, + ISOLINUX should be the only boot loader installed. + * MEMDISK: Allow the user to specify that the simulated disk + should be write-protected. + +Changes in 2.11: + * ALL: Add an API call to get the configuration file name. + * SYSLINUX: Fix bug in 2.10 that prevented it from working + correctly for a lot of people. + * SYSLINUX: In the installer, make mtools a bit less fussy. + * Make the menu system compile with newer gcc's. + +Changes in 2.10: + * MEMDISK: Handle images compressed with zip as well as with + gzip. Some Windows-based image tools apparently generate + these kinds of images by default. Patch by Patrick + LoPresti. + * Major menu improvement from Murali Ganapathy. + * ISOLINUX: Wonderfully sick and brilliant workaround for + severe bugs in certain Award BIOSes; from Knut Petersen. + * SYSLINUX: Fix for the nomtools installed, from Frederic + Pasteleurs. + * PXELINUX: Fix handling of IP numbers in the ranges + 100-109 and 200-209. + * ALL: New option "allowoptions" (defaults to 1), which + controls if options are allowed on the command line or not. + * SYSLINUX: Support building under klibc (see the klibc + distribution for details.) + +Changes in 2.09: + * SYSLINUX: Remove residual setuid crap from + syslinux-nomtools. + * Handle video pages correctly when using the API functions. + * Handle compiling on an x86-64 platform correctly. + * Menu system from Murali Krishnan Ganapathy; see the menu + directory for information. + * COMBOOT: Allow COMBOOT programs to change screen text mode. + * COMBOOT: Correct the documentation of how to detect + SYSLINUX from COMBOOT!!!! + * COMBOOT: Fix "get key without echo" API function. + * SYSLINUX: Fix bug that affected the API open function. + * ALL: Improve the E820 memory parser, to work around some + buggy BIOSes. + +Changes in 2.08: + * Add new configuration command "ontimeout" to allow timeout + to have a different action than just pressing Enter. + * Add new configuration command "onerror" to allow a custom + command to be executed in case the kernel image is not found. + * Fix bugs in the COMBOOT/COM32 command-line parsing. APPEND + now works with COMBOOT/COM32 images. + * PXELINUX: Poll for ARP requests while sitting at the + prompt. This makes some boot servers a lot less unhappy. + * PXELINUX: Actually free sockets when we get a failure + (including file not found.) This bug would cause us to run + out of sockets and thus "go deaf" after a while. + * MEMDISK: Add an API to query for the existence of MEMDISK. + * SYSLINUX: Fix loading boot sectors (.bs/.bss) from floppy + disk. + * .c32 is now one of the extensions searched for + automatically. + * PXELINUX: RFBG.exe seems to randomly overwrite memory + location 0x5700. Thus, don't use it! + * PXELINUX: Change pathname length max from 63 to 127; change + max vkernels from 128 to 64. + * Support Ctrl-U -> kill entire command line input. + * The "samples" directory contains a (barely at all tested) + chain loading example, chain.c32, which may be used to + chainload local floppy disks and hard disks. Use with + "chain fdN" or "chain hdN [partition]"; N = 0 for the first + drive of each type. + +Changes in 2.07: + * MEMDISK: Workaround for BIOSes which go into a snit when + they get a RESET command for the floppy system when there is + no floppy in the system. + * PXELINUX: Add "ipappend 2", which passes the hardware + address of the boot interface to the kernel as a + command-line option. + * mkdiskimage: fix the generation of the end limit. + * PXELINUX: Fix multiple bugs in chainloading of other NBPs. + * MEMDISK: Fix bug that would occationally cause "ran out of + input data" when using compressed disk images. + * SYSLINUX: Updates for the win32 installer (from Lars Munch.) + * PXELINUX: PXELINUX-specific options are now recognized both + in a vendor-option-space (a.k.a. type 43 encapsulated) as + well as in a site-option-space (unencapsulated.) + * COM32: Don't crash when DS != 0. + * COMBOOT/COM32: Make file reading work correctly. Thanks to + Phung Chi Kien for submitting a test program. + +Changes in 2.06: + * ALL: Fix problem that would occationally cause a + boot failure, depending on the length of the kernel. + * ISOLINUX: Fix problem that would occationally cause a + boot failure, depending on the length of directories. + * SYSLINUX: Win32 installer now flushes buffers. + * ppmtolss16: Be fully compliant with the PNM spec; + actually process comments in the header and odd + alignments of the various parameters, as well as + "plain" (not raw) files and PBM and PGM files. + * PXELINUX: Lower the default MTU to 1472 in order to deal + with systems with slightly nonstandard MTUs, and PXE + stacks which don't defragment correctly. Unfortunately this + is very hard to test dynamically. + +Changes in 2.05: + * PXELINUX: Add a default query based on the hardware address + of the boot device. This is in lower case hexadecimal form + separated by dashes and including the hardware type, for + example, the Ethernet (type 1) address 88:99:AA:BB:CC:DD + would query the file pxelinux.cfg/01-88-99-aa-bb-cc-dd. + * PXELINUX: Fix bug involving non-IP-based config file names. + * SYSLINUX: New installer for WinNT-based systems, from Lars + Munch. + * MEMDISK: Fix handling of memory region overlap when + decompressing. Thanks to Mikhail Kupchik for identifying + the problem. + +Changes in 2.04: + * ALL: Reclaim even more low memory by observing that + comboot_seg == real_mode_seg is perfectly fine, and by the + fact that the 1000h segment managed to get unused in all + derivatives... + * PXELINUX: Attempt to negotiate full Ethernet-sized blocks + (1468 bytes) using the blksize option. + * SYSLINUX: Resurrect the old no-mtools version of the + installer, although as a root-only tool. Some distributors + have indicated that they need a small standalone installer. + * MEMDISK: Fix a memory offset computation error when + installing compressed disks which generally would cause + 1 MB of memory to be wasted. + * MEMDISK: Fix installing the E820 memory map. Calling + INT 15h AX=0E820h with MEMDISK 2.03 loaded would give a + completely corrupt memory map. + * SYSLINUX: Make libsyslinux a dynamic library, so that it can + be updated separately from client programs. The whole idea, + after all, is to enable alternate programs to become + syslinux installers. + * Include an rpm spec file in the distribution, so rpmbuild + -ta works. + +Changes in 2.03: + * Actually support comment lines in the configuration file. + * PXELINUX: Try to resolve some problems with stack switches. + * PXELINUX: Handle PXE stacks with broken routing. + With these workarounds, the remote install PXE boot floppy + (rbfg.exe) from Argon Technologies should work correctly. + * Fix problems with Perl scripts in UTF-8 locales. + * You probably need NASM 0.98.34 or later to compile this + version. 0.98.36 is recommended. + * MEMDISK: Now supports gzip compressed images. + +Changes in 2.02: + * SYSLINUX: Security flaws have been found in the SYSLINUX + installer when running setuid root. Rewrite the SYSLINUX + installer so it uses mtools instead. It therefore now + requires mtools (specifically mcopy and mattrib) to exist on + your system, but it will not require root privileges and + SHOULD NOT be setuid. + +Changes in 2.01: + * MEMDISK: Fix memory sizing bug when the ramdisk crosses the + 16 MB boundary. + * MEMDISK: Add a "pause" option to stop immediately before + booting, to read off the messages. + * MEMDISK: Support disk images with DOSEMU headers. + * Update the mkdiskimage script to handle newer mtools + versions, and be able to generate disk images with DOSEMU + headers (controlled by the -d option). + * Fix the COM32 sample program. + * PXELINUX, ISOLINUX: Fix some COMBOOT API calls. + * PXELINUX: Doc fix. + * Build SYSLINUX into a small library for encapsulation into + other programs (however, please keep in mind this is a GPL'd + library.) + * SYSLINUX: Make installer work with "owner" in /etc/fstab. + * SYSLINUX: Fix issue with working on nonpartitioned hard disk + devices. THIS CONFIGURATION IS NOT RECOMMENDED. + +Changes in 2.00: + * ALL: Add support for "COM32" (32-bit COMBOOT) images. + * ALL: Add an API for COMBOOT/COM32 images. See comboot.doc + for details. There is a C development environment for + COM32 being created; it should be ready at some point in + the future. + * Fix mbr.asm so that it actually works. + * SYSLINUX: The syslinux installer *SHOULD* now be safe to + run setuid root. + * PXELINUX: Fix bug where PXELINUX would override random + chunks of the UNDI code segment! Thanks to Kevin Tran for + finding this bug. + * ISOLINUX: Fix a bug related to slashes in pathnames. + * ISOLINUX: Fix a bug in handling initrds over 128 MB. + * ALL: Make the <Ctrl-V> key print out the version; this is + to help debugging. + * Add a small script, mkdiskimage, to create a DOS-formatted + hard disk image using mtools. This may be useful in + conjunction with MEMDISK. + * ISOLINUX: Search for a /boot/isolinux directory as well as + /isolinux. + * ALL: Fix a bug related to very long configuration files. + * PXELINUX: Work around a NASM bug which would result in no + delay before reset if an error occurs. + +Changes in 1.76: + * ISOLINUX: Remove code no longer used which caused hangs on + some Toshiba laptops. + +Changes in 1.75: + * ALL: NASM 0.98.32 or later is now required to build + SYSLINUX from sources. + * SYSLINUX: put back in the workaround for the BIOS floppy + table. This seems to be a requirement for "extended" floppy + formats to work correctly. + * SYSLINUX: No longer warn if one is trying to boot on a 286 + or older. The above BIOS workaround no longer fits if the + requirement to use only 8086-compatible code in the early + boot is maintained. It made sense in 1994, but in 2002 a + 286 or older is a museum object. + * SYSLINUX: Use a downright bizarre, stateful algorithm to try + to guess the maximum transfer size. I am *hoping* this will + cut down on the number of systems for which -s is required + to work at any acceptable speed. + * ISOLINUX: Add a few more workarounds for various broken El + Torito BIOSes. + * Make sure .depend files aren't accidentally packed... + * ALL: Fix bugs in the extension-detect code; this caused + files like COMBOOT images and CD boot sectors to be + mis-identified as Linux kernels and rejected. + * ALL: Fix the return from COMBOOT. + * ALL: Do some of the early groundwork for supporting DOS + system calls in COMBOOT. + * Get rid of unnecessary "near" directives, making the code + bigger. + * PXELINUX: Put the PXE stack back in the init state before + invoking a chain-loaded NBP. + * PXELINUX: Actually found the combination of calls that + allows some (most?) PXE 2+ stacks to be unloaded from memory + properly. + * PXELINUX: Add "keeppxe" command-line option to disable + the standard unloading of the PXE stack. + +Changes in 1.74: + * SYSLINUX: fix bug that would cause valid kernel images to be + labelled "invalid". + +Changes in 1.73: + * Work on removing gratuitous differences between modules. + * Break up the source in common and module-specific files. + * PXELINUX: Allow chaining of other PXE NBPs. + * ISOLINUX: Allow loading "CD-ROM boot sectors". + * ALL: generalize the definition of a boot sector/NBP. + +Changes in 1.72: + * PXELINUX, ISOLINUX: Fix bugs in the new core code. + +Changes in 1.71: + * Fix a "brown paper bag" class bug in the new core code. + +Changes in 1.70: + * Major code restructuring. + * Relax the conventional memory limits somewhat. + * MEMDISK: Set up the "version number string" pointer in the + header correctly. + * SYSLINUX: Fix, again, "the bug that won't die": the use of + the offset parameter with the SYSLINUX installer. + * SYSLINUX: Fix possible superblock corruption problem in the + SYSLINUX installer. + +Changes in 1.67: + * Handle bug in the location of initrd. + +Changes in 1.66: + * MEMDISK: Make compile with newer versions of gcc. + +Changes in 1.65: + * ISOLINUX: Support booting disk image files (to boot DOS or + other non-Linux operating systems), *IF* the BIOS works + correctly; unfortunately many BIOSes apparently don't. + * Support Linux boot protocol version 2.03 (explicitly + specify the initrd address limit.) + * Handle small "pseudo-kernels"; images that use the Linux + kernel boot protocols but are less than 64K in size. + * MEMDISK: New subsystem; this is a driver which allows + legacy OSes to boot using an in-memory simulated disk. + See memdisk/memdisk.doc for more info. + * PXELINUX, ISOLINUX: Correctly handle files larger than 65535 + blocks (32 MB for PXELINUX, 128 MB for ISOLINUX.) + * PXELINUX: Make a best-effort attempt at freeing all memory + claimed. From the looks of it, it will fail on most PXE + stacks. + +Changes in 1.64: + * Limited support for hardware flow control when using a + serial port console. + * Support specifying the serial port I/O address explicitly. + * Make DOS installer hopefully behave more nicely when used on + recent Windows versions. + * Fix returning to text mode when a font has been specified. + * Attempt to detect missing serial port hardware and disable + the serial port if there is nothing there. + +Changes in 1.63: + * Make the ppmtolss16 program handle color conversion more + correctly. + * Clean up "make install" target, honour INSTALLROOT if it + exists. + * SYSLINUX: Fix stack-smash bug identified by Steffen + Winterfeldt. + * Hopefully fix return-to-text-mode on some graphics cards. + * ISOLINUX: Bug workaround for Award BIOS 4.51, and perhaps + other buggy BIOSes as well. + +Changes in 1.62: + * PXELINUX: Allow the DHCP server to override the + configuration file name and pathname prefix, using + "site-specific" DHCP options. + * PXELINUX: Documentation fixes. + * PXELINUX: Fix the "ipappend" option; the last two values + were reversed vs. what the kernel expected. + * Introduce a way to return to text mode once we are already + in graphics mode. This may be useful for F-key help + screens. + * Fix several bugs in the way return to text mode was handled. + +Changes in 1.61: + * ISOLINUX: Support full pathname searches. Max length for a + pathname is 255 characters. As a result, only 64 "label" + statements are supported in ISOLINUX. + * PXELINUX: Max filename length extended to 63 characters. + +Changes in 1.60: + * Add support for graphical splash screens. + * Add mode control characters, which allows you to control + message display output depending on output mode (text, + graphics, or serial port.) + * ISOLINUX: New program, which boots Linux from a CD-ROM + without using floppy emulation mode. See isolinux.doc for + more details. + * PXELINUX: Don't search for boot sector file types, since + they don't work anyway. + * SYSLINUX: Document the LOCK command for Win9x, and the error + dialog box for WinNT/2K. + +Changes in 1.54: + * PXELINUX: Fix code for finding !PXE from PXENV+. This was + due to a spec bug; match the most recent spec since that + seems to be what implementations actually do. + * SYSLINUX: Add some smarts to the boot sector, which + hopefully should reduce the number of systems which require + stupid mode ("syslinux -s"). + * PXELINUX: Document further some of the pathologies with old + PXE stacks. + * When specifying a "default" command line, no longer + automatically appent "auto". See the "DEFAULT" command in + syslinux.doc for more information. + * PXELINUX: Clean up the allocation of local socket numbers. + +Changes in 1.53: + * PXELINUX: Rename pxelinux.bin to pxelinux.0, to match what + most PXE servers seem to expect. + * PXELINUX: Update the DHCP/boot server setup documentation. + * PXELINUX: Support new "localboot" option for "label" + sections. + * PXELINUX: More robust parsing of DHCP/boot server packets. + * PXELINUX: Include a small utility program "gethostip" to + compute hexadecimal IP addresses. + +Changes in 1.52: + * PXELINUX: Fix bugs introduced by new A20 code. (SYSLINUX + has also been changed for code consistency reasons, but I'm + pretty sure the changes are don't care on SYSLINUX.) + * Documentation updates. + * PXELINUX: Add "ipappend" option to generate an ip= option to + the kernel. + +Changes in 1.51: + * PXELINUX: Not all PXE stacks fill in the IP address for a + type 3 cached info query. Use a type 2 cached info query + for this information (only.) + * Yet another attempt at A20 coding. Now support BIOS call + 15:2401 as well, and handle machines which always have A20 + on separately. + * Support memory detection using INT 15h, AX=0E820h. BIOS + manufacturers have apparently gotten sloppy about keeping + INT 15h, AX=0E801h working properly. + * Don't issue <CR><LF> onto the serial port when we're doing + screen wraparound. + +Changes in 1.50: + * Yet another A20-code update. It seems some "legacy-free" + machines and embedded gear simply don't have a KBC to talk + to, and that waiting for one will wait forever. Sigh. + +Changes in 1.49: + * SYSLINUX: Implement a hack for BIOS drivers which hog significant + chunks of low memory during boot. (Note: PXELINUX already + had this modification. SYSLINUX does still require that the + low 512K is available; PXELINUX requires 384K. Machines + with a physical memory hole in the low 640K cannot boot + Linux no matter what.) Depending what the reason is for the + memory hole, a new kernel (2.4.0-test3-pre3 or later) may be + required. + * SYSLINUX: Default installer binary now compiled against + glibc 2.1. If this is inappropriate for your system and you + still want to use the offical version of SYSLINUX, please + follow the instructions in "distrib.doc" to rebuild the + installer. + * SYSLINUX: Linux installer program now supports -o <offset> + option which does a loopback mount with the + -o loop,offset=<> option. Useful to run SYSLINUX on an + individual partition of a whole-harddisk image. + * Include the source code to a Master Boot Record (MBR) + functionally equivalent to the one installed DOS except it + includes EBIOS support, and should be resistant to geometry + changes. The MBR code is public domain. + * PXELINUX: Fix "double p" bug: if the tftp prefix was null, + all filenames would get a "p" preprended, e.g. + "ppxelinux.cfg" and "pvmlinux". + +Changes in 1.48: + * PXELINUX: Workaround for PXE ROMs based on the Intel PXE PDK + 3.0 build 071 and earlier: missing !PXE structure pointer. + * PXELINUX: Handle larger BOOTP/DHCP packages. + * PXELINUX: The command line passing was broken; fix. + * PXELINUX: Make COMBOOT images work. + * PXELINUX: Documentation on how to make booting work using + the PDK 3.0-derived clients, which aren't so generous as to + allow booting with only "PXEClient" specified. + +Changes in 1.47: + * PXELINUX: RFC 1123 states that a TFTP implementation MUST + use adaptive timeout, "at least an exponential backoff of + retransmission timeout is necessary." Implement a very + simple exponential backoff for retransmits. + * PXELINUX: Updated documentation, including pointer to new + TFTP server. + * PXELINUX: When sending ERROR due to bad OACK, use the proper + destination port number (why are TFTP port numbers so odd?) + * PXELINUX: If the boot dies in the middle somewhere, + eventually give up and reset the machine (unattended + operation.) + +Changes in 1.46: + * New program PXELINUX to do network booting using a + PXE-compliant (Pre-Execution Environment) network booting + PROM. See pxelinux.doc for details. + +Changes in 1.45: + * Serial console support. See syslinux.doc for details. + +Changes in 1.44: + * Change HIGHMEM_MAX to 38000000h to (hopefully) avoid the + kernel stepping on it; 3f000000h was apparently a higher + limit than the kernel used! + +Changes in 1.43: + * Add sys2ansi.pl script to display the contents of a + colorized SYSLINUX file. + * Changed the io_delay once again, after a report that the + old delay port causes hangs on some systems. + +Changes in 1.42: + * Frob the "fast A20 gate" port as well as the keyboard + controller; will this help systems with problems? + * Be even more paranoid about A20, unfortunately even this + seems to be not paranoid enough... what I don't understand + is that if there is hardware out there *this broken*, how + can it run Linux at all? Report an error message rather + than hang forever if A20 is stuck. + * Include some intermediate files in the distribution, plus + provide a "make installer" target for distributors to relink + the install programs only. I would prefer the syslinux boot + loader proper to be "binary clean" for debuggablity -- use + "make clean ; make installer" to rebuild the installers only. + +Changes in 1.41: + * Don't get confused by directories, volume labels, or VFAT + long names. + * Use INT 15h, AX=0E801h to query memory size before trying + INT 15h, AH=88h. This not only provides more headroom + between the kernel and the initrd on large-memory machines, + but it appears some recent BIOSes actually have started + returning garbage for the AH=88h (older) call. + * Trust high memory beyond the 15 MB mark if the user has + specified it, or if obtained with INT 15h, AH=0E801h (with + no memory holes above 1 MB.) + +Changes in 1.40: + * Increase A20M delay and put in a test to avoid problems on + certain IBM Thinkpads (thanks to Donnie Barnes of RedHat + for vital info on this one.) + * Support COMBOOT style boot command images. + * Support chain loading (foreign operating systems, e.g. DOS). + * Include a new "copybs" DOS utility to copy a boot sector to + a file (under Linux, use "dd".) + * Fix the DOS installer to work for disks over 32 MB. + * SYSLINUX should now handle disks with more than 65536 tracks. + +Changes in 1.37: + * Fix a bug that caused "label" statements in syslinux.cfg to + not be handled properly. + * Updated the documentation. Among other things, we now allow + up to 128 "label" statements. + +Changes in 1.36: + * Fix for booting old (pre-initrd) kernels. + * It seems at least some versions of OS/2 doesn't set up all + the fields in the superblock correctly. Account for that. + * Fix bug that caused boot failure when using the mem= option. + +Changes in 1.35: + * Loading from partitions now should work properly. (Actually + tested, this time. You should even be able to dd a floppy + to a partition and boot from it.) + * Removed large workaround code for an alleged ancient BIOS + bug I have never actually seen. The -s option should work + on those machines, anyway. + * Support for simple keyboard remappings, same as used by + LILO (once again to support localization.) The program + keytab-lilo.pl from the LILO distribution included to + generate such maps. + * Added a "safe, slow and stupid" (-s) option to the + installers. This option will lobotomize the boot sector to + hopefully work on even very buggy BIOSes. + +Changes in 1.34: + * Ability to load a VGA font on bootup (for localized Linux + distributions.) + +Changes in 1.33: + * Bug fix in the Linux installer. + * Added a workaround for a bug in certain AMI/Intel BIOSes + when booting from CD-ROM. + * Documentation changes. + +Changes in 1.32: + * FAT16 filesystems are now supported. + +Changes in 1.31: + * Now compiles under Linux, using NASM, rather than using + Turbo Assembler under DOS. See http://www.cryogen.com/Nasm + for information about NASM. + * Linux-hosted SYSLINUX installer, as well as a + rewritten DOS installer (now is written in assembler, so we + don't need Turbo C.) + +Changes in 1.30: + * Added support for loading bzImage and initrd loading, and made + SYSLINUX new-setup-code aware (SYSLINUX 1.30 id=0x31). + * Added LILO-style kernel labels; see the LABEL and IMPLICIT + keywords in README file. + * Added support for colorization of intro and help screens. + * The vga= option is now handled correctly. + * Massive rewrite of large chunks of the code in order to + support the first two new features. + +Changes in 1.20: + * Added simple online help at the "boot:" prompt. + * Removed 2880K image as I no longer have access to such a + floppy drive. (Donations accepted!!) + * Decided to distribute the source in a subdirectory rather + than in a nested zipfile. + +Changes in 1.11: + * Removed a sanity check which would cause booting to fail on + Phoenix BIOS version 4.03. Apparently this BIOS is buggy. + +Changes in 1.10: + * Added configuration file SYSLINUX.CFG. This file contains all + configurable options, and can be edited from any OS which can + access an MS-DOS filesystem; there is no longer a need to run + SYSLINUX.EXE except to write the boot sector. + * Default command line now given by "default" line in config + file. + * LINUXMSG.TXT and BOOTMSG.TXT hard-coded file names replaced by + "display" and "prompt" lines in config file. + * LILO-style option appending now supported ("append" line in + config file). + * Prompt timeout is now supported ("timeout" line in config + file). The timeout is cancelled when anything is typed on the + command line. + * Pressing <ESC> or <Ctrl-C> at the Loading... stage now aborts + the kernel loading in progress and returns the user to the + boot: prompt. + * The installer now automatically sets the READONLY flag on + LDLINUX.SYS. + * Added 2880K disk image. + +Changes in 1.03: + * Fixed bug that would prevent booting from double-density + floppies and other DOS filesystems with multiple sectors per + cluster. + * Added 720K disk image. + * Changed default kernel name on disk images to LINUX. + +Changes in 1.02: + * Fixed bug that would garble the command line on recent kernels + with more than 4 sectors of setup code (this wasn't really a + *bug*; rather, a kernel change broke the code. Unfortunately + the Linux boot interface is still sorely undocumented). + * Added BOOTMSG.TXT file support (message file which does not + force display of the boot prompt). + +Changes in 1.01: + * Fixed bug on some (most?) 386 BIOSes would require two boot + attempts. diff --git a/syslinux/README b/syslinux/README new file mode 100644 index 0000000..ea67e35 --- /dev/null +++ b/syslinux/README @@ -0,0 +1,31 @@ +See the following files for documentation about SYSLINUX: + + syslinux.doc - Usage instructions; manual. + distrib.doc - For creators of Linux distributions. + pxelinux.doc - Documentation specific to PXELINUX. + isolinux.doc - Documentation specific to ISOLINUX. + extlinux.doc - Documentation specific to EXTLINUX. + README.menu - About the menu systems. + README.usbkey - About using SYSLINUX on USB keys. + comboot.doc - About the extension API. + memdisk/memdisk.doc - Documentation about MEMDISK. + NEWS - List of changes from previous releases. + TODO - About features planned for future releases. + COPYING - For the license terms of this software. + +SYSLINUX now builds in a Linux environment, using nasm. You need nasm +version 0.98.38 or later to build SYSLINUX from source. See +http://nasm.sf.net/ for information about nasm. + +There is now a mailing list for SYSLINUX. See the end of syslinux.doc +for details. + +SYSLINUX is: + + Copyright 1994-2005 H. Peter Anvin - All Rights Reserved + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, Inc., 53 Temple Place Ste 330, + Boston MA 02111-1307, USA; either version 2 of the License, or + (at your option) any later version; incorporated herein by reference. diff --git a/syslinux/README.menu b/syslinux/README.menu new file mode 100644 index 0000000..ad4f3a9 --- /dev/null +++ b/syslinux/README.menu @@ -0,0 +1,119 @@ +$Id: README.menu,v 1.5 2005/01/21 01:35:33 hpa Exp $ + +There are two menu systems included with SYSLINUX, the advanced menu +system, and the simple menu system. + + ++++ THE ADVANCED MENU SYSTEM +++ + +The advanced menu system, written by Murali Krishnan Ganapathy, is +located in the menu/ subdirectly. It allows the user to create +hierarchial submenus, dynamic options, checkboxes, and just about +anything you want. It requires that the menu is compiled from a +simple C file, see menu/simple.c and menu/complex.c for examples. + +The advanced menu system doesn't support serial console at this time. + +See menu/README for more information. + + ++++ THE SIMPLE MENU SYSTEM +++ + +The simple menu system is a single module located at +com32/modules/menu.c32. It uses the same configuration file as the +regular SYSLINUX command line, and displays all the LABEL statements. + +To use the menu system, simply make sure menu.c32 is in the +appropriate location for your boot medium (the same directory as the +configuration file for SYSLINUX, EXTLINUX and ISOLINUX, and the same +directory as pxelinux.0 for PXELINUX), and put the following options +in your configuration file: + +DEFAULT menu.c32 +PROMPT 0 + + +There are a few menu additions to the command line, all starting with +the keyword MENU; like the rest of the SYSLINUX config file +language, it is case insensitive: + +MENU TITLE title + + Give the menu a title. The title is presented at the top of + the menu. + +MENU LABEL label + + (Only valid after a LABEL statement.) + Changes the label displayed for a specific entry. This allows + you to have a label that isn't suitable for the command line, + for example: + + # Soft Cap Linux + LABEL softcap + MENU LABEL Soft Cap ^Linux 9.6.36 + KERNEL softcap-9.6.36.bzi + APPEND whatever + + # A very dense operating system + LABEL brick + MENU LABEL ^Windows CE/ME/NT + KERNEL chain.c32 + APPEND hd0 2 + + The ^ symbol in a MENU LABEL statement defines a hotkey. + The hotkey will be highlighted in the menu and will move the + menu cursor immediately to that entry. + +MENU HIDE + + (Only valid after a LABEL statement.) + Suppresses a particular LABEL entry from the menu. + + +MENU DEFAULT + + (Only valid after a LABEL statement.) + Indicates that this entry should be the default. If no + default is specified, use the first one. + + +MENU PASSWD passwd + + (Only valid after a LABEL statement.) + Sets a password on this menu entry. "passwd" can be either a + cleartext password or a SHA-1 encrypted password; use the + included Perl script "sha1pass" to encrypt passwords. + (Obviously, if you don't encrypt your passwords they will not + be very secure at all.) + + If you are using passwords, you want to make sure you also use + the settings "NOESCAPE 1", "PROMPT 0", and either set + "ALLOWOPTIONS 0" or use a master password (see below.) + + If passwd is an empty string, this menu entry can only be + unlocked with the master password. + + +MENU MASTER PASSWD passwd + + Sets a master password. This password can be used to boot any + menu entry, and is required for the [Tab] and [Esc] keys to + work. + + +The menu system honours the TIMEOUT command; if TIMEOUT is specified +it will execute the ONTIMEOUT command if one exists, otherwise it will +pick the default menu option. + +Normally, the user can press [Tab] to edit the menu entry, and [Esc] +to return to the SYSLINUX command line. However, if the configuration +file specifies ALLOWOPTIONS 0, these keys will be disabled, and if +MENU MASTER PASSWD is set, they require the master password. + +The simple menu system supports serial console, using the normal +SERIAL directive. However, it can be quite slow over a slow serial +link; you probably want to set your baudrate to 38400 or higher if +possible. It requires a Linux/VT220/ANSI-compatible terminal on the +other end. + diff --git a/syslinux/README.usbkey b/syslinux/README.usbkey new file mode 100644 index 0000000..af6f9d6 --- /dev/null +++ b/syslinux/README.usbkey @@ -0,0 +1,49 @@ +$Id: README.usbkey,v 1.2 2004/12/30 23:31:14 hpa Exp $ + +The proper mode to boot a USB key drive in is "USB-HDD". That is the +ONLY mode in which the C/H/S geometry encoded on the disk itself +doesn't have to match what the BIOS thinks it is. Since geometry on +USB drives is completely arbitrary, and can vary from BIOS to BIOS, +this is the only mode which will work in general. + +Some BIOSes have been reported (in particular, certain versions of the +Award BIOS) that cannot boot USB keys in "USB-HDD" mode. This is a +very serious BIOS bug, but it is unfortunately rather typical of the +kind of quality we're seeing out of major BIOS vendors these days. On +these BIOSes, you're generally stuck booting them in USB-ZIP mode. + +THIS MEANS THE FILESYSTEM IMAGE ON THE DISK HAS TO HAVE A CORRECT +ZIPDRIVE-COMPATIBLE GEOMETRY. + +A standard zipdrive (both the 100 MB and the 250 MB varieties) have a +"geometry" of 64 heads, 32 sectors, and are partitioned devices with a +single partition 4 (unlike most other media of this type which uses +partition 1.) The 100 MB variety has 96 cylinders, and the 250 MB +variety has 239 cylinders; but any number of cylinders will do as +appropriate for the size device you have. For example, if your device +reports when inserted into a Linux system: + +usb-storage: device found at 4 + Vendor: 32MB Model: HardDrive Rev: 1.88 + Type: Direct-Access ANSI SCSI revision: 02 +SCSI device sda: 64000 512-byte hdwr sectors (33 MB) + +... you would have 64000/(64*32) = 31.25 cylinders; round down to 31. + +The script "mkdiskimage" which is supplied with the syslinux +distribution can be used to initialize USB keys in a Zip-like fashion. +To do that, calculate the correct number of cylinders (31 in the +example above), and, if your USB key is /dev/sda (CHECK THE KERNEL +MESSAGES CAREFULLY - IF YOU ENTER THE WRONG DISK DRIVE IT CANNOT BE +RECOVERED), run: + + mkdiskimage -4 /dev/sda 0 64 32 + +(The 0 means automatically determine the size of the device, and -4 +means mimic a zipdisk by using partition 4.) + +Then you should be able to run + + syslinux /dev/sda4 + +... and mount /dev/sda4 and put your files on it as needed. diff --git a/syslinux/TODO b/syslinux/TODO new file mode 100644 index 0000000..48c83da --- /dev/null +++ b/syslinux/TODO @@ -0,0 +1,30 @@ +$Id: TODO,v 1.29 2005/01/05 09:21:07 hpa Exp $ + +*** To do in the short term: + +- PXELINUX: Support changing the default server and boot file prefix? + +- Support loading a new configuration file. + +- "Shuffle and boot" extension, with the appropriate com32 library + support. + +- Library support for all the comboot system calls. + + +*** Future projects: + +- Clean up the command-line parsing. + +- Cleaned up documentation, with a real man page. + +- Subdirectory support in SYSLINUX. + +- Support files that span multiple input media (SYSLINUX) + -> Seems to be getting less important; floppies are dying? + +- Clean up the handling of sections + +- Add "localboot" support to SYSLINUX (using the ISOLINUX feature + set.) + OBSOLETE: chain.c32 is probably better. diff --git a/syslinux/bcopy32.inc b/syslinux/bcopy32.inc new file mode 100644 index 0000000..3e069e8 --- /dev/null +++ b/syslinux/bcopy32.inc @@ -0,0 +1,458 @@ +;; $Id: bcopy32.inc,v 1.16 2005/01/06 22:34:06 hpa Exp $ +;; ----------------------------------------------------------------------- +;; +;; Copyright 1994-2005 H. Peter Anvin - All Rights Reserved +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +;; Boston MA 02111-1307, USA; either version 2 of the License, or +;; (at your option) any later version; incorporated herein by reference. +;; +;; ----------------------------------------------------------------------- + +;; +;; bcopy32.inc +;; +;; 32-bit bcopy routine for real mode +;; + +; +; 32-bit bcopy routine for real mode +; +; We enter protected mode, set up a flat 32-bit environment, run rep movsd +; and then exit. IMPORTANT: This code assumes cs == 0. +; +; This code is probably excessively anal-retentive in its handling of +; segments, but this stuff is painful enough as it is without having to rely +; on everything happening "as it ought to." +; +; NOTE: this code is relocated into low memory, just after the .earlybss +; segment, in order to support to "bcopy over self" operation. +; + + section .bcopy32 + align 8 +__bcopy_start: + + ; This is in the .text segment since it needs to be + ; contiguous with the rest of the bcopy stuff + +bcopy_gdt: dw bcopy_gdt_size-1 ; Null descriptor - contains GDT + dd bcopy_gdt ; pointer for LGDT instruction + dw 0 + dd 0000ffffh ; Code segment, use16, readable, + dd 00009b00h ; present, dpl 0, cover 64K + dd 0000ffffh ; Data segment, use16, read/write, + dd 008f9300h ; present, dpl 0, cover all 4G + dd 0000ffffh ; Data segment, use16, read/write, + dd 00009300h ; present, dpl 0, cover 64K + ; The rest are used for COM32 only + dd 0000ffffh ; Code segment, use32, readable, + dd 00cf9b00h ; present, dpl 0, cover all 4G + dd 0000ffffh ; Data segment, use32, read/write, + dd 00cf9300h ; present, dpl 0, cover all 4G +bcopy_gdt_size: equ $-bcopy_gdt + +; +; bcopy: +; 32-bit copy, overlap safe +; +; Inputs: +; ESI - source pointer +; EDI - target pointer +; ECX - byte count +; DF - zero +; +; Outputs: +; ESI - first byte after source +; EDI - first byte after target +; ECX - zero +; +bcopy: push eax + push esi + push edi + push ecx + pushf ; Saves, among others, the IF flag + push ds + push es + + cli + call enable_a20 + + o32 lgdt [cs:bcopy_gdt] + mov eax,cr0 + or al,1 + mov cr0,eax ; Enter protected mode + jmp 08h:.in_pm + +.in_pm: mov ax,10h ; Data segment selector + mov es,ax + mov ds,ax + + ; Don't mess with ss, fs, and gs. They are never changed + ; and should be able to make it back out of protected mode. + ; This works because (and only because) we don't take + ; interrupt in protected mode. + + cmp esi,edi ; If source > destination, we might + ja .reverse ; have to copy backwards + +.forward: + mov al,cl ; Save low bits + and al,3 + shr ecx,2 ; Convert to dwords + a32 rep movsd ; Do our business + ; At this point ecx == 0 + + mov cl,al ; Copy any fractional dword + a32 rep movsb + jmp .exit + +.reverse: + std ; Reverse copy + lea esi,[esi+ecx-1] ; Point to final byte + lea edi,[edi+ecx-1] + mov eax,ecx + and ecx,3 + shr eax,2 + a32 rep movsb + + ; Change ESI/EDI to point to the last dword, instead + ; of the last byte. + sub esi,3 + sub edi,3 + mov ecx,eax + a32 rep movsd + + cld + +.exit: + mov ax,18h ; "Real-mode-like" data segment + mov es,ax + mov ds,ax + + mov eax,cr0 + and al,~1 + mov cr0,eax ; Disable protected mode + jmp 0:.in_rm + +.in_rm: ; Back in real mode + pop es + pop ds + call disable_a20 + + popf ; Re-enables interrupts + pop eax + pop edi + pop esi + add edi,eax + add esi,eax + pop eax + ret + +; +; Routines to enable and disable (yuck) A20. These routines are gathered +; from tips from a couple of sources, including the Linux kernel and +; http://www.x86.org/. The need for the delay to be as large as given here +; is indicated by Donnie Barnes of RedHat, the problematic system being an +; IBM ThinkPad 760EL. +; +; We typically toggle A20 twice for every 64K transferred. +; +%define io_delay call _io_delay +%define IO_DELAY_PORT 80h ; Invalid port (we hope!) +%define disable_wait 32 ; How long to wait for a disable + +; Note the skip of 2 here +%define A20_DUNNO 0 ; A20 type unknown +%define A20_NONE 2 ; A20 always on? +%define A20_BIOS 4 ; A20 BIOS enable +%define A20_KBC 6 ; A20 through KBC +%define A20_FAST 8 ; A20 through port 92h + +slow_out: out dx, al ; Fall through + +_io_delay: out IO_DELAY_PORT,al + out IO_DELAY_PORT,al + ret + +enable_a20: + pushad + mov byte [cs:A20Tries],255 ; Times to try to make this work + +try_enable_a20: +; +; Flush the caches +; +%if DO_WBINVD + call try_wbinvd +%endif + +; +; If the A20 type is known, jump straight to type +; + mov bp,[cs:A20Type] + jmp word [cs:bp+A20List] + +; +; First, see if we are on a system with no A20 gate +; +a20_dunno: +a20_none: + mov byte [cs:A20Type], A20_NONE + call a20_test + jnz a20_done + +; +; Next, try the BIOS (INT 15h AX=2401h) +; +a20_bios: + mov byte [cs:A20Type], A20_BIOS + mov ax,2401h + pushf ; Some BIOSes muck with IF + int 15h + popf + + call a20_test + jnz a20_done + +; +; Enable the keyboard controller A20 gate +; +a20_kbc: + mov dl, 1 ; Allow early exit + call empty_8042 + jnz a20_done ; A20 live, no need to use KBC + + mov byte [cs:A20Type], A20_KBC ; Starting KBC command sequence + + mov al,0D1h ; Command write + out 064h, al + call empty_8042_uncond + + mov al,0DFh ; A20 on + out 060h, al + call empty_8042_uncond + + ; Verify that A20 actually is enabled. Do that by + ; observing a word in low memory and the same word in + ; the HMA until they are no longer coherent. Note that + ; we don't do the same check in the disable case, because + ; we don't want to *require* A20 masking (SYSLINUX should + ; work fine without it, if the BIOS does.) +.kbc_wait: push cx + xor cx,cx +.kbc_wait_loop: + call a20_test + jnz a20_done_pop + loop .kbc_wait_loop + + pop cx +; +; Running out of options here. Final attempt: enable the "fast A20 gate" +; +a20_fast: + mov byte [cs:A20Type], A20_FAST ; Haven't used the KBC yet + in al, 092h + or al,02h + and al,~01h ; Don't accidentally reset the machine! + out 092h, al + +.fast_wait: push cx + xor cx,cx +.fast_wait_loop: + call a20_test + jnz a20_done_pop + loop .fast_wait_loop + + pop cx + +; +; Oh bugger. A20 is not responding. Try frobbing it again; eventually give up +; and report failure to the user. +; + + + dec byte [cs:A20Tries] + jnz try_enable_a20 + + mov si, err_a20 + jmp abort_load +; +; A20 unmasked, proceed... +; +a20_done_pop: pop cx +a20_done: popad + ret + +; +; This routine tests if A20 is enabled (ZF = 0). This routine +; must not destroy any register contents. +; +a20_test: + push es + push cx + push ax + mov cx,0FFFFh ; HMA = segment 0FFFFh + mov es,cx + mov cx,32 ; Loop count + mov ax,[cs:A20Test] +.a20_wait: inc ax + mov [cs:A20Test],ax + io_delay ; Serialize, and fix delay + cmp ax,[es:A20Test+10h] + loopz .a20_wait +.a20_done: pop ax + pop cx + pop es + ret + +disable_a20: + pushad +; +; Flush the caches +; +%if DO_WBINVD + call try_wbinvd +%endif + + mov bp,[cs:A20Type] + jmp word [cs:bp+A20DList] + +a20d_bios: + mov ax,2400h + pushf ; Some BIOSes muck with IF + int 15h + popf + jmp short a20d_snooze + +; +; Disable the "fast A20 gate" +; +a20d_fast: + in al, 092h + and al,~03h + out 092h, al + jmp short a20d_snooze + +; +; Disable the keyboard controller A20 gate +; +a20d_kbc: + call empty_8042_uncond + mov al,0D1h + out 064h, al ; Command write + call empty_8042_uncond + mov al,0DDh ; A20 off + out 060h, al + call empty_8042_uncond + ; Wait a bit for it to take effect +a20d_snooze: + push cx + mov cx, disable_wait +.delayloop: call a20_test + jz .disabled + loop .delayloop +.disabled: pop cx +a20d_dunno: +a20d_none: + popad + ret + +; +; Routine to empty the 8042 KBC controller. If dl != 0 +; then we will test A20 in the loop and exit if A20 is +; suddenly enabled. +; +empty_8042_uncond: + xor dl,dl +empty_8042: + call a20_test + jz .a20_on + and dl,dl + jnz .done +.a20_on: io_delay + in al, 064h ; Status port + test al,1 + jz .no_output + io_delay + in al, 060h ; Read input + jmp short empty_8042 +.no_output: + test al,2 + jnz empty_8042 + io_delay +.done: ret + +; +; Execute a WBINVD instruction if possible on this CPU +; +%if DO_WBINVD +try_wbinvd: + wbinvd + ret +%endif + +; +; bcopy_over_self: +; +; This routine is used to shuffle memory around, followed by +; invoking an entry point somewhere in low memory. This routine +; can clobber any memory above 7C00h, we therefore have to move +; necessary code into the trackbuf area before doing the copy, +; and do adjustments to anything except BSS area references. +; +; NOTE: Since PXELINUX relocates itself, put all these +; references in the ".earlybss" segment. +; +; After performing the copy, this routine resets the stack and +; jumps to the specified entrypoint. +; +; IMPORTANT: This routine does not canonicalize the stack or the +; SS register. That is the responsibility of the caller. +; +; Inputs: +; DS:BX -> Pointer to list of (dst, src, len) pairs +; AX -> Number of list entries +; [CS:EntryPoint] -> CS:IP to jump to +; On stack - initial state (fd, ad, ds, es, fs, gs) +; +shuffle_and_boot: + and ax,ax + jz .done +.loop: + mov edi,[bx] + mov esi,[bx+4] + mov ecx,[bx+8] + call bcopy + add bx,12 + dec ax + jnz .loop + +.done: + pop gs + pop fs + pop es + pop ds + popad + popfd + jmp far [cs:EntryPoint] + + align 2 +A20List dw a20_dunno, a20_none, a20_bios, a20_kbc, a20_fast +A20DList dw a20d_dunno, a20d_none, a20d_bios, a20d_kbc, a20d_fast +a20_adjust_cnt equ ($-A20List)/2 + +A20Type dw A20_NONE ; A20 type + + ; Total size of .bcopy32 section + alignb 4, db 0 ; Even number of dwords +__bcopy_size equ $-__bcopy_start + + section .earlybss + alignb 2 +EntryPoint resd 1 ; CS:IP for shuffle_and_boot +SavedSSSP resd 1 ; Saved real mode SS:SP +A20Test resw 1 ; Counter for testing status of A20 +A20Tries resb 1 ; Times until giving up on A20 diff --git a/syslinux/bin2c.pl b/syslinux/bin2c.pl new file mode 100644 index 0000000..01c2d26 --- /dev/null +++ b/syslinux/bin2c.pl @@ -0,0 +1,59 @@ +#!/usr/bin/perl +## $Id: bin2c.pl,v 1.6 2004/12/14 23:03:28 hpa Exp $ +## ----------------------------------------------------------------------- +## +## Copyright 1998-2004 H. Peter Anvin - All Rights Reserved +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, Inc., 53 Temple Place Ste 330, +## Boston MA 02111-1307, USA; either version 2 of the License, or +## (at your option) any later version; incorporated herein by reference. +## +## ----------------------------------------------------------------------- + +# +# bin2c.pl: binary file to C source converter +# + +eval { use bytes; }; +eval { binmode STDIN; }; + +if ( $#ARGV != 0 ) { + print STDERR "Usage: $0 table_name < input_file > output_file\n"; + exit 1; +} + +($table_name) = @ARGV; + +printf "unsigned char %s[] = {\n", $table_name; + +$pos = 0; +$linelen = 8; + +$total_len = 0; + +while ( ($n = read(STDIN, $data, 4096)) > 0 ) { + $total_len += $n; + for ( $i = 0 ; $i < $n ; $i++ ) { + $byte = substr($data, $i, 1); + if ( $pos >= $linelen ) { + print ",\n\t"; + $pos = 0; + } elsif ( $pos > 0 ) { + print ", "; + } else { + print "\t"; + } + printf("0x%02x", unpack("C", $byte)); + $pos++; + } +} + +printf "\n};\n\nunsigned int %s_len = %u;\n", $table_name, $total_len; + +@st = stat STDIN; + +printf "\nint %s_mtime = %d;\n", $table_name, $st[9]; + +exit 0; diff --git a/syslinux/bin2hex.pl b/syslinux/bin2hex.pl new file mode 100755 index 0000000..a211e53 --- /dev/null +++ b/syslinux/bin2hex.pl @@ -0,0 +1,46 @@ +#!/usr/bin/perl +## "$Id: bin2hex.pl,v 1.3 2003/07/01 00:49:31 hpa Exp $" +## ----------------------------------------------------------------------- +## +## Copyright 2003 H. Peter Anvin - All Rights Reserved +## +## Permission is hereby granted, free of charge, to any person +## obtaining a copy of this software and associated documentation +## files (the "Software"), to deal in the Software without +## restriction, including without limitation the rights to use, +## copy, modify, merge, publish, distribute, sublicense, and/or +## sell copies of the Software, and to permit persons to whom +## the Software is furnished to do so, subject to the following +## conditions: +## +## The above copyright notice and this permission notice shall +## be included in all copies or substantial portions of the Software. +## +## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +## OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +## HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +## WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +## FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +## OTHER DEALINGS IN THE SOFTWARE. +## +## ----------------------------------------------------------------------- + +eval { use bytes; }; eval { binmode STDIN; }; + +$len = 0; +while ( read(STDIN,$ch,1) ) { + $cc = ord($ch); + $len += printf ("%x", $cc); + if ( $len > 72 ) { + print "\n"; + $len = 0; + } else { + print " "; + $len++; + } +} +print "\n" if ( $len ); +exit 0; + diff --git a/syslinux/bios.inc b/syslinux/bios.inc new file mode 100644 index 0000000..8b11fc4 --- /dev/null +++ b/syslinux/bios.inc @@ -0,0 +1,40 @@ +;; $Id: bios.inc,v 1.3 2004/12/14 22:46:24 hpa Exp $ +;; ----------------------------------------------------------------------- +;; +;; Copyright 1994-2004 H. Peter Anvin - All Rights Reserved +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +;; Boston MA 02111-1307, USA; either version 2 of the License, or +;; (at your option) any later version; incorporated herein by reference. +;; +;; ----------------------------------------------------------------------- + +;; +;; bios.inc +;; +;; Header file for the BIOS data structures etc. +;; + +%ifndef _BIOS_INC +%define _BIOS_INC + + absolute 4*1Eh ; In the interrupt table +fdctab equ $ +fdctab1 resw 1 +fdctab2 resw 1 + absolute 0400h +serial_base resw 4 ; Base addresses for 4 serial ports + absolute 0413h +BIOS_fbm resw 1 ; Free Base Memory (kilobytes) + absolute 0462h +BIOS_page resb 1 ; Current video page + absolute 046Ch +BIOS_timer resw 1 ; Timer ticks + absolute 0472h +BIOS_magic resw 1 ; BIOS reset magic + absolute 0484h +BIOS_vidrows resb 1 ; Number of screen rows + +%endif ; _BIOS_INC diff --git a/syslinux/bootsect.inc b/syslinux/bootsect.inc new file mode 100644 index 0000000..dce9a59 --- /dev/null +++ b/syslinux/bootsect.inc @@ -0,0 +1,157 @@ +;; $Id: bootsect.inc,v 1.15 2005/01/12 00:34:54 hpa Exp $ +;; ----------------------------------------------------------------------- +;; +;; Copyright 1994-2005 H. Peter Anvin - All Rights Reserved +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +;; Boston MA 02111-1307, USA; either version 2 of the License, or +;; (at your option) any later version; incorporated herein by reference. +;; +;; ----------------------------------------------------------------------- + +;; +;; bootsect.inc +;; +;; Load a boot sector (or other bootstrap program.) +;; +;; Unlike previous versions of this software, this doesn't require that +;; the length is 512 bytes. This allows PXE bootstraps and WinNT +;; "CD boot sectors" to be invoked. +;; + +; +; Load a boot sector +; +is_bootsector: +%if IS_SYSLINUX || IS_MDSLINUX + ; Transfer zero bytes + mov byte [CopySuper],0 + jmp short load_bootsec + +is_bss_sector: + ; Transfer the superblock + mov byte [CopySuper],superblock_len +%endif +load_bootsec: + xchg dx,ax + shl eax,16 + xchg dx,ax ; Now EAX = file length + mov edi, 100000h + mov [trackbuf+4],edi ; Copy from this address + push edi ; Save load address + xor dx,dx ; No padding + call load_high + call crlf + + sub edi,100000h + mov [trackbuf+8],edi ; Save length + + mov eax,7C00h ; Entry point + mov [trackbuf],eax ; Copy to this address + mov [EntryPoint],eax ; Jump to this address when done + +%if IS_SYSLINUX || IS_MDSLINUX + movzx ecx,byte [CopySuper] + jcxz .not_bss + + ; For a BSS boot sector we have to patch. + mov esi,superblock + mov edi,100000h+(superblock-bootsec) + call bcopy + +.not_bss: +%endif + + xor edx,edx + xor esi,esi +%if IS_SYSLINUX || IS_MDSLINUX || IS_EXTLINUX + ; Restore original FDC table + mov eax,[OrigFDCTabPtr] + mov [fdctab],eax + + mov dl,[DriveNumber] + mov si,PartInfo ; Partition info buffer + mov di,800h-18 ; Put partition info here + push di + mov cx,8 ; 16 bytes + xor ax,ax + rep movsw + pop si ; DS:SI points to partition info +%elif IS_ISOLINUX + mov dl,[DriveNo] +%elif IS_PXELINUX + mov byte [KeepPXE],1 ; Chainloading another NBP + call reset_pxe +%endif + xor bx,bx + +; +; replace_bootstrap for the special case where we have exactly one +; descriptor, and it's the first entry in the trackbuf +; + +replace_bootstrap_one: + push word trackbuf ; Address of descriptor list + push word 1 ; Length of descriptor list + ; Fall through + +; +; Entrypoint for "shut down and replace bootstrap" -- also invoked by +; the COMBOOT API. This routine expects two words on the stack: +; address of the copy list (versus DS) and count. Additionally, +; the values of ESI and EDX are passed on to the new bootstrap; +; the value of BX becomes the new DS. +; +replace_bootstrap: + ; + ; Prepare for shutting down + ; + call vgaclearmode + + ; + ; Set up initial stack frame (not used by PXE if keeppxe is + ; set - we use the PXE stack then.) + ; AFTER THIS POINT ONLY .earlybss IS AVAILABLE, NOT .bss + ; + xor ax,ax + mov ds,ax + mov es,ax + +%if IS_PXELINUX + test byte [KeepPXE],01h + jz .stdstack + les di,[InitStack] ; Reset stack to PXE original + jmp .stackok +%endif +.stdstack: + mov di,7C00h-44 + push di + mov cx,22 ; 44 bytes + rep stosw + pop di +.stackok: + + mov [es:di+28],edx + mov [es:di+12],esi + mov [es:di+6],bx + + pop ax ; Copy list count + pop bx ; Copy from... + + cli + mov cx,es + mov ss,cx + movzx esp,di + + jmp shuffle_and_boot + +%if IS_SYSLINUX || IS_MDSLINUX + ; Nothing +%else +is_bss_sector: + mov si,err_bssimage + call cwritestr + jmp enter_command +%endif diff --git a/syslinux/cache.inc b/syslinux/cache.inc new file mode 100644 index 0000000..3e0fd8e --- /dev/null +++ b/syslinux/cache.inc @@ -0,0 +1,83 @@ +; -*- fundamental -*- --------------------------------------------------- +; +; Copyright 2004 H. Peter Anvin - All Rights Reserved +; +; This program is free software; you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +; Boston MA 02111-1307, USA; either version 2 of the License, or +; (at your option) any later version; incorporated herein by reference. +; +; ----------------------------------------------------------------------- +; $Id: cache.inc,v 1.3 2005/01/25 07:15:21 hpa Exp $ + + section .text +; +; initcache: Initialize the cache data structures +; +initcache: + xor eax,eax ; We don't care about sector 0 + mov di,CachePtrs + mov cx,65536/SECTOR_SIZE + rep stosd + ret + + +; +; getcachesector: Check for a particular sector (EAX) in the sector cache, +; and if it is already there, return a pointer in GS:SI +; otherwise load it and return said pointer. +; +; Assumes CS == DS. +; +getcachesector: + push cx + mov si,cache_seg + mov gs,si + mov si,CachePtrs ; Sector cache pointers + mov cx,65536/SECTOR_SIZE +.search: + cmp eax,[si] + jz .hit + add si,4 + loop .search + +.miss: + TRACER 'M' + ; Need to load it. Highly inefficient cache replacement + ; algorithm: Least Recently Written (LRW) + push bx + push es + push gs + pop es + mov bx,[NextCacheSlot] + inc bx + and bx,(1 << (16-SECTOR_SHIFT))-1 + mov [NextCacheSlot],bx + shl bx,2 + mov [CachePtrs+bx],eax + shl bx,SECTOR_SHIFT-2 + mov si,bx + pushad +%if IS_EXTLINUX + call getonesec_ext +%else + call getonesec +%endif + popad + pop es + pop bx + pop cx + ret + +.hit: ; We have it; get the pointer + TRACER 'H' + sub si,CachePtrs + shl si,SECTOR_SHIFT-2 + pop cx + ret + + section .bss + alignb 4 +CachePtrs resd 65536/SECTOR_SIZE ; Cached sector pointers +NextCacheSlot resw 1 ; Next cache slot to occupy diff --git a/syslinux/checksumiso.pl b/syslinux/checksumiso.pl new file mode 100755 index 0000000..b552742 --- /dev/null +++ b/syslinux/checksumiso.pl @@ -0,0 +1,36 @@ +#!/usr/bin/perl +# +# Construct a checksum for isolinux*.bin, compatible +# with an mkisofs boot-info-table +# + +use bytes; +use integer; + +($file) = @ARGV; + +open(FILE, '+<', $file) or die "$0: Cannot open $file: $!\n"; +binmode FILE; + +if ( !seek(FILE,64,0) ) { + die "$0: Cannot seek past header\n"; +} + +$csum = 0; +$bytes = 64; +while ( ($n = read(FILE, $dw, 4)) > 0 ) { + $dw .= "\0\0\0\0"; # Pad to at least 32 bits + ($v) = unpack("V", $dw); + $csum = ($csum + $v) & 0xffffffff; + $bytes += $n; +} + +if ( !seek(FILE,16,0) ) { + die "$0: Cannot seek to header\n"; +} + +print FILE pack("VV", $bytes, $csum); + +close(FILE); + +exit 0; diff --git a/syslinux/cmdline.inc b/syslinux/cmdline.inc new file mode 100644 index 0000000..628f8a3 --- /dev/null +++ b/syslinux/cmdline.inc @@ -0,0 +1,44 @@ +;; $Id: cmdline.inc,v 1.2 2004/12/14 22:46:24 hpa Exp $ +;; ----------------------------------------------------------------------- +;; +;; Copyright 2003 H. Peter Anvin - All Rights Reserved +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +;; Boston MA 02111-1307, USA; either version 2 of the License, or +;; (at your option) any later version; incorporated herein by reference. +;; +;; ----------------------------------------------------------------------- + +;; +;; cmdline.inc +;; +;; Common routine to assemble [null-terminated] command line into +;; real_mode_seg:cmd_line_here. +;; Not used by plain kernel due to BOOT_IMAGE= etc. +;; + +; +; Assumes DS == CS +make_plain_cmdline: + push es + ; ui.inc has already copied the actual command line + mov ax,real_mode_seg + mov es,ax + + mov si,[CmdOptPtr] + mov di,[CmdLinePtr] + +.loop: lodsb + stosb + and al,al + jnz .loop + + dec di + mov [CmdLinePtr],di + + pop es + ret + + diff --git a/syslinux/com32.inc b/syslinux/com32.inc new file mode 100644 index 0000000..f257b08 --- /dev/null +++ b/syslinux/com32.inc @@ -0,0 +1,359 @@ +;; $Id: com32.inc,v 1.9 2005/01/06 22:34:06 hpa Exp $ +;; ----------------------------------------------------------------------- +;; +;; Copyright 1994-2003 H. Peter Anvin - All Rights Reserved +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +;; Boston MA 02111-1307, USA; either version 2 of the License, or +;; (at your option) any later version; incorporated herein by reference. +;; +;; ----------------------------------------------------------------------- + +;; +;; com32.inc +;; +;; Common code for running a COM32 image +;; + +; +; Load a COM32 image. A COM32 image is the 32-bit analogue to a DOS +; .com file. A COM32 image is loaded at address 0x101000, with %esp +; set to the high end of usable memory. +; +; A COM32 image should begin with the magic bytes: +; B8 FF 4C CD 21, which is "mov eax,0x21cd4cff" in 32-bit mode and +; "mov ax,0x4cff; int 0x21" in 16-bit mode. This will abort the +; program with an error if run in 16-bit mode. +; +pm_idt: equ 0x100000 +pm_entry: equ 0x101000 + + bits 16 + section .data + align 2, db 0 +com32_pmidt: + dw 8*256 ; Limit + dd pm_idt ; Address + +com32_rmidt: + dw 0ffffh ; Limit + dd 0 ; Address + + section .text +is_com32_image: + push si ; Save file handle + push dx ; File length held in DX:AX + push ax + + call make_plain_cmdline + ; Copy the command line into the low cmdline buffer + mov ax,real_mode_seg + mov fs,ax + mov si,cmd_line_here + mov di,command_line + mov cx,[CmdLinePtr] + inc cx ; Include final null + sub cx,si + fs rep movsb + + call highmemsize ; We need the high memory size... + call comboot_setup_api ; Set up the COMBOOT-style API + + mov edi,pm_entry ; Load address + pop eax ; File length + pop si ; File handle + xor dx,dx ; No padding + call load_high + call crlf + +com32_start: + mov ebx,com32_call_start ; Where to go in PM + +com32_enter_pm: + cli + mov ax,cs + mov ds,ax + mov [SavedSSSP],sp + mov [SavedSSSP+2],ss + cld + call a20_test + jnz .a20ok + call enable_a20 + +.a20ok: + lgdt [bcopy_gdt] ; We can use the same GDT just fine + lidt [com32_pmidt] ; Set up the IDT + mov eax,cr0 + or al,1 + mov cr0,eax ; Enter protected mode + jmp 20h:.in_pm + + bits 32 +.in_pm: + xor eax,eax ; Available for future use... + mov fs,eax + mov gs,eax + + mov al,28h ; Set up data segments + mov es,eax + mov ds,eax + mov ss,eax + + mov esp,[PMESP] ; Load protmode %esp if available + jmp ebx ; Go to where we need to go + +; +; This is invoked right before the actually starting the COM32 +; progam, in 32-bit mode... +; +com32_call_start: + ; + ; Point the stack to the end of high memory + ; + mov esp,[word HighMemSize] + + ; + ; Set up the protmode IDT and the interrupt jump buffers + ; We set these up in the system area at 0x100000, + ; but we could also put them beyond the stack. + ; + mov edi,pm_idt + + ; Form an interrupt gate descriptor + mov eax,0x00200000+((pm_idt+8*256)&0x0000ffff) + mov ebx,0x0000ee00+((pm_idt+8*256)&0xffff0000) + xor ecx,ecx + inc ch ; ecx <- 256 + + push ecx +.make_idt: + stosd + add eax,8 + xchg eax,ebx + stosd + xchg eax,ebx + loop .make_idt + + pop ecx + + ; Each entry in the interrupt jump buffer contains + ; the following instructions: + ; + ; 00000000 60 pushad + ; 00000001 B0xx mov al,<interrupt#> + ; 00000003 E9xxxxxxxx jmp com32_handle_interrupt + + mov eax,0e900b060h + mov ebx,com32_handle_interrupt-(pm_idt+8*256+8) + +.make_ijb: + stosd + sub [edi-2],cl ; Interrupt # + xchg eax,ebx + stosd + sub eax,8 + xchg eax,ebx + loop .make_ijb + + ; Now everything is set up for interrupts... + + push dword com32_farcall ; Farcall entry point + push dword (1 << 16) ; 64K bounce buffer + push dword (comboot_seg << 4) ; Bounce buffer address + push dword com32_intcall ; Intcall entry point + push dword command_line ; Command line pointer + push dword 5 ; Argument count + sti ; Interrupts OK now + call pm_entry ; Run the program... + ; ... on return, fall through to com32_exit ... + +com32_exit: + mov bx,com32_done ; Return to command loop + +com32_enter_rm: + cli + cld + mov [PMESP],esp ; Save exit %esp + xor esp,esp ; Make sure the high bits are zero + jmp 08h:.in_pm16 ; Return to 16-bit mode first + + bits 16 +.in_pm16: + mov ax,18h ; Real-mode-like segment + mov es,ax + mov ds,ax + mov ss,ax + mov fs,ax + mov gs,ax + + lidt [com32_rmidt] ; Real-mode IDT (rm needs no GDT) + mov eax,cr0 + and al,~1 + mov cr0,eax + jmp 0:.in_rm + +.in_rm: ; Back in real mode + mov ax,cs ; Set up sane segments + mov ds,ax + mov es,ax + mov fs,ax + mov gs,ax + lss sp,[SavedSSSP] ; Restore stack + jmp bx ; Go to whereever we need to go... + +com32_done: + call disable_a20 + sti + jmp enter_command + +; +; 16-bit support code +; + bits 16 + +; +; 16-bit interrupt-handling code +; +com32_int_rm: + pushf ; Flags on stack + push cs ; Return segment + push word .cont ; Return address + push dword edx ; Segment:offset of IVT entry + retf ; Invoke IVT routine +.cont: ; ... on resume ... + mov ebx,com32_int_resume + jmp com32_enter_pm ; Go back to PM + +; +; 16-bit system call handling code +; +com32_sys_rm: + pop gs + pop fs + pop es + pop ds + popad + popfd + mov [cs:Com32SysSP],sp + retf ; Invoke routine +.return: + ; We clean up SP here because we don't know if the + ; routine returned with RET, RETF or IRET + mov sp,[cs:Com32SysSP] + pushfd + pushad + push ds + push es + push fs + push gs + mov ebx,com32_sys_resume + jmp com32_enter_pm + +; +; 32-bit support code +; + bits 32 + +; +; This is invoked on getting an interrupt in protected mode. At +; this point, we need to context-switch to real mode and invoke +; the interrupt routine. +; +; When this gets invoked, the registers are saved on the stack and +; AL contains the register number. +; +com32_handle_interrupt: + movzx eax,al + xor ebx,ebx ; Actually makes the code smaller + mov edx,[ebx+eax*4] ; Get the segment:offset of the routine + mov bx,com32_int_rm + jmp com32_enter_rm ; Go to real mode + +com32_int_resume: + popad + iret + +; +; Intcall/farcall invocation. We manifest a structure on the real-mode stack, +; containing the com32sys_t structure from <com32.h> as well as +; the following entries (from low to high address): +; - Target offset +; - Target segment +; - Return offset +; - Return segment (== real mode cs == 0) +; - Return flags +; +com32_farcall: + pushfd ; Save IF among other things... + pushad ; We only need to save some, but... + + mov eax,[esp+10*4] ; CS:IP + jmp com32_syscall + + +com32_intcall: + pushfd ; Save IF among other things... + pushad ; We only need to save some, but... + + movzx eax,byte [esp+10*4] ; INT number + mov eax,[eax*4] ; Get CS:IP from low memory + +com32_syscall: + cld + + movzx edi,word [word SavedSSSP] + movzx ebx,word [word SavedSSSP+2] + sub edi,54 ; Allocate 54 bytes + mov [word SavedSSSP],di + shl ebx,4 + add edi,ebx ; Create linear address + + mov esi,[esp+11*4] ; Source regs + xor ecx,ecx + mov cl,11 ; 44 bytes to copy + rep movsd + + ; EAX is already set up to be CS:IP + stosd ; Save in stack frame + mov eax,com32_sys_rm.return ; Return seg:offs + stosd ; Save in stack frame + mov eax,[edi-12] ; Return flags + and eax,0x200cd7 ; Mask (potentially) unsafe flags + mov [edi-12],eax ; Primary flags entry + stosw ; Return flags + + mov bx,com32_sys_rm + jmp com32_enter_rm ; Go to real mode + + ; On return, the 44-byte return structure is on the + ; real-mode stack, plus the 10 additional bytes used + ; by the target address (see above.) +com32_sys_resume: + movzx esi,word [word SavedSSSP] + movzx eax,word [word SavedSSSP+2] + mov edi,[esp+12*4] ; Dest regs + shl eax,4 + add esi,eax ; Create linear address + and edi,edi ; NULL pointer? + jnz .do_copy +.no_copy: mov edi,esi ; Do a dummy copy-to-self +.do_copy: xor ecx,ecx + mov cl,11 ; 44 bytes + rep movsd ; Copy register block + + add dword [word SavedSSSP],54 ; Remove from stack + + popad + popfd + ret ; Return to 32-bit program + + bits 16 + + section .bss + alignb 4 +PMESP resd 1 ; Protected-mode ESP +Com32SysSP resw 1 ; SP saved during COM32 syscall + + section .text diff --git a/syslinux/com32/LICENCE b/syslinux/com32/LICENCE new file mode 100644 index 0000000..b20d654 --- /dev/null +++ b/syslinux/com32/LICENCE @@ -0,0 +1,31 @@ +libcom32 and libutil are licensed under the MIT license: + +## ----------------------------------------------------------------------- +## +## Copyright 2004 H. Peter Anvin - All Rights Reserved +## +## Permission is hereby granted, free of charge, to any person +## obtaining a copy of this software and associated documentation +## files (the "Software"), to deal in the Software without +## restriction, including without limitation the rights to use, +## copy, modify, merge, publish, distribute, sublicense, and/or +## sell copies of the Software, and to permit persons to whom +## the Software is furnished to do so, subject to the following +## conditions: +## +## The above copyright notice and this permission notice shall +## be included in all copies or substantial portions of the Software. +## +## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +## OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +## HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +## WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +## FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +## OTHER DEALINGS IN THE SOFTWARE. +## +## ----------------------------------------------------------------------- + +The files in the samples and modules directories are mostly under the +GNU GPL (see the file COPYING in the directory above.) diff --git a/syslinux/com32/Makefile b/syslinux/com32/Makefile new file mode 100644 index 0000000..7e7bfcb --- /dev/null +++ b/syslinux/com32/Makefile @@ -0,0 +1,4 @@ +SUBDIRS = lib libutil modules samples + +all tidy clean spotless install: + for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done diff --git a/syslinux/com32/include/bitsize/limits.h b/syslinux/com32/include/bitsize/limits.h new file mode 100644 index 0000000..f90e524 --- /dev/null +++ b/syslinux/com32/include/bitsize/limits.h @@ -0,0 +1,14 @@ +/* + * bits32/limits.h + */ + +#ifndef _BITSIZE_LIMITS_H +#define _BITSIZE_LIMITS_H + +#define LONG_BIT 32 + +#define LONG_MIN (-2147483647L-1) +#define LONG_MAX 2147483647L +#define ULONG_MAX 4294967295UL + +#endif /* _BITSIZE_LIMITS_H */ diff --git a/syslinux/com32/include/bitsize/stddef.h b/syslinux/com32/include/bitsize/stddef.h new file mode 100644 index 0000000..c486041 --- /dev/null +++ b/syslinux/com32/include/bitsize/stddef.h @@ -0,0 +1,18 @@ +/* + * bits32/stddef.h + */ + +#ifndef _BITSIZE_STDDEF_H +#define _BITSIZE_STDDEF_H + +#define _SIZE_T +#if defined(__s390__) || defined(__hppa__) || defined(__cris__) +typedef unsigned long size_t; +#else +typedef unsigned int size_t; +#endif + +#define _PTRDIFF_T +typedef signed int ptrdiff_t; + +#endif /* _BITSIZE_STDDEF_H */ diff --git a/syslinux/com32/include/bitsize/stdint.h b/syslinux/com32/include/bitsize/stdint.h new file mode 100644 index 0000000..40b4649 --- /dev/null +++ b/syslinux/com32/include/bitsize/stdint.h @@ -0,0 +1,34 @@ +/* + * bits32/stdint.h + */ + +#ifndef _BITSIZE_STDINT_H +#define _BITSIZE_STDINT_H + +typedef signed char int8_t; +typedef short int int16_t; +typedef int int32_t; +typedef long long int int64_t; + +typedef unsigned char uint8_t; +typedef unsigned short int uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long int uint64_t; + +typedef int int_fast16_t; +typedef int int_fast32_t; + +typedef unsigned int uint_fast16_t; +typedef unsigned int uint_fast32_t; + +typedef int intptr_t; +typedef unsigned int uintptr_t; + +#define __INT64_C(c) c ## LL +#define __UINT64_C(c) c ## ULL + +#define __PRI64_RANK "ll" +#define __PRIFAST_RANK "" +#define __PRIPTR_RANK "" + +#endif /* _BITSIZE_STDINT_H */ diff --git a/syslinux/com32/include/bitsize/stdintconst.h b/syslinux/com32/include/bitsize/stdintconst.h new file mode 100644 index 0000000..8157dd0 --- /dev/null +++ b/syslinux/com32/include/bitsize/stdintconst.h @@ -0,0 +1,18 @@ +/* + * bits32/stdintconst.h + */ + +#ifndef _BITSIZE_STDINTCONST_H +#define _BITSIZE_STDINTCONST_H + +#define INT_FAST16_C(c) INT32_C(c) +#define INT_FAST32_C(c) INT32_C(c) + +#define UINT_FAST16_C(c) UINT32_C(c) +#define UINT_FAST32_C(c) UINT32_C(c) + +#define INTPTR_C(c) INT32_C(c) +#define UINTPTR_C(c) UINT32_C(c) +#define PTRDIFF_C(c) INT32_C(c) + +#endif /* _BITSIZE_STDINTCONST_H */ diff --git a/syslinux/com32/include/bitsize/stdintlimits.h b/syslinux/com32/include/bitsize/stdintlimits.h new file mode 100644 index 0000000..b44fe01 --- /dev/null +++ b/syslinux/com32/include/bitsize/stdintlimits.h @@ -0,0 +1,22 @@ +/* + * bits32/stdintlimits.h + */ + +#ifndef _BITSIZE_STDINTLIMITS_H +#define _BITSIZE_STDINTLIMITS_H + +#define INT_FAST16_MIN INT32_MIN +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST16_MAX INT32_MAX +#define INT_FAST32_MAX INT32_MAX +#define UINT_FAST16_MAX UINT32_MAX +#define UINT_FAST32_MAX UINT32_MAX + +#define INTPTR_MIN INT32_MIN +#define INTPTR_MAX INT32_MAX +#define UINTPTR_MAX UINT32_MAX + +#define PTRDIFF_MIN INT32_MIN +#define PTRDIFF_MAX INT32_MAX + +#endif /* _BITSIZE_STDINTLIMITS_H */ diff --git a/syslinux/com32/include/com32.h b/syslinux/com32/include/com32.h new file mode 100644 index 0000000..91799f6 --- /dev/null +++ b/syslinux/com32/include/com32.h @@ -0,0 +1,117 @@ +/* ----------------------------------------------------------------------- * + * Not Copyright 2002 H. Peter Anvin + * This file is in the public domain. + * ----------------------------------------------------------------------- */ + +/* + * com32.h + * + * Common declarations for com32 programs. + */ + +#ifndef _COM32_H +#define _COM32_H + +#include <stdint.h> +#include <klibc/compiler.h> /* For __cdecl */ + +/* + * This structure defines the register frame used by the + * system call interface. + * + * The syscall interface is: + * + * __intcall(interrupt_#, source_regs, return_regs) + * __farcall(seg, offs, source_regs, return_regs) + */ +typedef union { + uint32_t l; + uint16_t w[2]; + uint8_t b[4]; +} reg32_t; + +typedef struct { + uint16_t gs; /* Offset 0 */ + uint16_t fs; /* Offset 2 */ + uint16_t es; /* Offset 4 */ + uint16_t ds; /* Offset 6 */ + + reg32_t edi; /* Offset 8 */ + reg32_t esi; /* Offset 12 */ + reg32_t ebp; /* Offset 16 */ + reg32_t _unused; /* Offset 20 */ + reg32_t ebx; /* Offset 24 */ + reg32_t edx; /* Offset 28 */ + reg32_t ecx; /* Offset 32 */ + reg32_t eax; /* Offset 36 */ + + reg32_t eflags; /* Offset 40 */ +} com32sys_t; + +/* EFLAGS definitions */ +#define EFLAGS_CF 0x00000001 +#define EFLAGS_PF 0x00000004 +#define EFLAGS_AF 0x00000010 +#define EFLAGS_ZF 0x00000040 +#define EFLAGS_SF 0x00000080 +#define EFLAGS_TF 0x00000100 +#define EFLAGS_IF 0x00000200 +#define EFLAGS_DF 0x00000400 +#define EFLAGS_OF 0x00000800 +#define EFLAGS_IOPL 0x00003000 +#define EFLAGS_NT 0x00004000 +#define EFLAGS_RF 0x00010000 +#define EFLAGS_VM 0x00020000 +#define EFLAGS_AC 0x00040000 +#define EFLAGS_VIF 0x00080000 +#define EFLAGS_VIP 0x00100000 +#define EFLAGS_ID 0x00200000 + +extern struct com32_sys_args { + uint32_t cs_sysargs; + char *cs_cmdline; + void __cdecl (*cs_intcall)(uint8_t, const com32sys_t *, com32sys_t *); + void *cs_bounce; + uint32_t cs_bounce_size; + void __cdecl (*cs_farcall)(uint32_t, const com32sys_t *, com32sys_t *); +} __com32; + +/* + * System call macros + */ +static inline void +__intcall(uint8_t __i, const com32sys_t *__sr, com32sys_t *__dr) +{ + __com32.cs_intcall(__i, __sr, __dr); +} + +static inline void +__farcall(uint16_t __es, uint16_t __eo, + const com32sys_t *__sr, com32sys_t *__dr) +{ + __com32.cs_farcall((__es << 16) + __eo, __sr, __dr); +} + +/* + * These functions convert between linear pointers in the range + * 0..0xFFFFF and real-mode style SEG:OFFS pointers. Note that a + * 32-bit linear pointer is not compatible with a SEG:OFFS pointer + * stored in two consecutive 16-bit words. + */ +static inline uint16_t SEG(void *__p) +{ + return (uint16_t)(((uintptr_t)__p) >> 4); +} + +static inline uint16_t OFFS(void *__p) +{ + /* The double cast here is to shut up gcc */ + return (uint16_t)(uintptr_t)__p & 0x000F; +} + +static inline void *MK_PTR(uint16_t __seg, uint16_t __offs) +{ + return (void *)((__seg << 4) + __offs); +} + +#endif /* _COM32_H */ diff --git a/syslinux/com32/include/console.h b/syslinux/com32/include/console.h new file mode 100644 index 0000000..e7677ff --- /dev/null +++ b/syslinux/com32/include/console.h @@ -0,0 +1,60 @@ +#ident "$Id: console.h,v 1.4 2004/11/30 22:09:56 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * console.h + * + * Alternative consoles + */ + +#ifndef _CONSOLE_H +#define _CONSOLE_H + +#include <klibc/extern.h> +#include <dev.h> + +__extern int openconsole(const struct input_dev *, const struct output_dev *); + +/* Standard line-oriented console */ +extern const struct input_dev dev_stdcon_r; +extern const struct output_dev dev_stdcon_w; +/* Raw character-oriented console */ +extern const struct input_dev dev_rawcon_r; +extern const struct output_dev dev_rawcon_w; + +/* These are output-only consoles; combine with one of the input methods */ + +/* Serial port only */ +extern const struct output_dev dev_serial_w; +/* ANSI console (output only; combine with one of the input methods) */ +extern const struct output_dev dev_ansicon_w; +/* ANSI plus serial port */ +extern const struct output_dev dev_ansiserial_w; + +#endif /* _CONSOLE_H */ + diff --git a/syslinux/com32/include/ctype.h b/syslinux/com32/include/ctype.h new file mode 100644 index 0000000..daa6a8e --- /dev/null +++ b/syslinux/com32/include/ctype.h @@ -0,0 +1,119 @@ +/* + * ctype.h + * + * This assumes ISO 8859-1, being a reasonable superset of ASCII. + */ + +#ifndef _CTYPE_H +#define _CTYPE_H + +#ifndef __CTYPE_NO_INLINE +# define __ctype_inline extern __inline__ +#else +# define __ctype_inline +#endif + +/* + * This relies on the following definitions: + * + * cntrl = !print + * alpha = upper|lower + * graph = punct|alpha|digit + * blank = '\t' || ' ' (per POSIX requirement) + */ +enum { + __ctype_upper = (1 << 0), + __ctype_lower = (1 << 1), + __ctype_digit = (1 << 2), + __ctype_xdigit = (1 << 3), + __ctype_space = (1 << 4), + __ctype_print = (1 << 5), + __ctype_punct = (1 << 6), + __ctype_cntrl = (1 << 7), +}; + +extern const unsigned char __ctypes[]; + +__ctype_inline int isalnum(int __c) +{ + return __ctypes[__c+1] & + (__ctype_upper|__ctype_lower|__ctype_digit); +} + +__ctype_inline int isalpha(int __c) +{ + return __ctypes[__c+1] & + (__ctype_upper|__ctype_lower); +} + +__ctype_inline int isascii(int __c) +{ + return !(__c & ~0x7f); +} + +__ctype_inline int isblank(int __c) +{ + return (__c == '\t') || (__c == ' '); +} + +__ctype_inline int iscntrl(int __c) +{ + return __ctypes[__c+1] & __ctype_cntrl; +} + +__ctype_inline int isdigit(int __c) +{ + return ((unsigned)__c - '0') <= 9; +} + +__ctype_inline int isgraph(int __c) +{ + return __ctypes[__c+1] & + (__ctype_upper|__ctype_lower|__ctype_digit|__ctype_punct); +} + +__ctype_inline int islower(int __c) +{ + return __ctypes[__c+1] & __ctype_lower; +} + +__ctype_inline int isprint(int __c) +{ + return __ctypes[__c+1] & __ctype_print; +} + +__ctype_inline int ispunct(int __c) +{ + return __ctypes[__c+1] & __ctype_punct; +} + +__ctype_inline int isspace(int __c) +{ + return __ctypes[__c+1] & __ctype_space; +} + +__ctype_inline int isupper(int __c) +{ + return __ctypes[__c+1] & __ctype_upper; +} + +__ctype_inline int isxdigit(int __c) +{ + return __ctypes[__c+1] & __ctype_xdigit; +} + +/* Note: this is decimal, not hex, to avoid accidental promotion to unsigned */ +#define _toupper(__c) ((__c) & ~32) +#define _tolower(__c) ((__c) | 32) + +__ctype_inline int toupper(int __c) +{ + return islower(__c) ? _toupper(__c) : __c; +} + +__ctype_inline int tolower(int __c) +{ + return isupper(__c) ? _tolower(__c) : __c; +} + +#endif /* _CTYPE_H */ diff --git a/syslinux/com32/include/dev.h b/syslinux/com32/include/dev.h new file mode 100644 index 0000000..45a07f0 --- /dev/null +++ b/syslinux/com32/include/dev.h @@ -0,0 +1,57 @@ +#ident "$Id: dev.h,v 1.2 2004/11/30 22:09:56 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * console.h + * + * Alternative consoles + */ + +#ifndef _DEV_H +#define _DEV_H + +#include <klibc/extern.h> +#include <stdint.h> + +struct input_dev; +struct output_dev; + +__extern int opendev(const struct input_dev *, const struct output_dev *, int); + +/* Common generic devices */ + +/* Null device */ +extern const struct input_dev dev_null_r; +extern const struct output_dev dev_null_w; + +/* Error device */ +extern const struct input_dev dev_error_r; +extern const struct output_dev dev_error_w; + +#endif /* _DEV_H */ + diff --git a/syslinux/com32/include/errno.h b/syslinux/com32/include/errno.h new file mode 100644 index 0000000..d32f33f --- /dev/null +++ b/syslinux/com32/include/errno.h @@ -0,0 +1,135 @@ +#ifndef _ERRNO_H +#define _ERRNO_H + +extern int errno; + +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Arg list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No child processes */ +#define EAGAIN 11 /* Try again */ +#define ENOMEM 12 /* Out of memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device or resource busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* File table overflow */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math argument out of domain of func */ +#define ERANGE 34 /* Math result not representable */ +#define EDEADLK 35 /* Resource deadlock would occur */ +#define ENAMETOOLONG 36 /* File name too long */ +#define ENOLCK 37 /* No record locks available */ +#define ENOSYS 38 /* Function not implemented */ +#define ENOTEMPTY 39 /* Directory not empty */ +#define ELOOP 40 /* Too many symbolic links encountered */ +#define EWOULDBLOCK EAGAIN /* Operation would block */ +#define ENOMSG 42 /* No message of desired type */ +#define EIDRM 43 /* Identifier removed */ +#define ECHRNG 44 /* Channel number out of range */ +#define EL2NSYNC 45 /* Level 2 not synchronized */ +#define EL3HLT 46 /* Level 3 halted */ +#define EL3RST 47 /* Level 3 reset */ +#define ELNRNG 48 /* Link number out of range */ +#define EUNATCH 49 /* Protocol driver not attached */ +#define ENOCSI 50 /* No CSI structure available */ +#define EL2HLT 51 /* Level 2 halted */ +#define EBADE 52 /* Invalid exchange */ +#define EBADR 53 /* Invalid request descriptor */ +#define EXFULL 54 /* Exchange full */ +#define ENOANO 55 /* No anode */ +#define EBADRQC 56 /* Invalid request code */ +#define EBADSLT 57 /* Invalid slot */ + +#define EDEADLOCK EDEADLK + +#define EBFONT 59 /* Bad font file format */ +#define ENOSTR 60 /* Device not a stream */ +#define ENODATA 61 /* No data available */ +#define ETIME 62 /* Timer expired */ +#define ENOSR 63 /* Out of streams resources */ +#define ENONET 64 /* Machine is not on the network */ +#define ENOPKG 65 /* Package not installed */ +#define EREMOTE 66 /* Object is remote */ +#define ENOLINK 67 /* Link has been severed */ +#define EADV 68 /* Advertise error */ +#define ESRMNT 69 /* Srmount error */ +#define ECOMM 70 /* Communication error on send */ +#define EPROTO 71 /* Protocol error */ +#define EMULTIHOP 72 /* Multihop attempted */ +#define EDOTDOT 73 /* RFS specific error */ +#define EBADMSG 74 /* Not a data message */ +#define EOVERFLOW 75 /* Value too large for defined data type */ +#define ENOTUNIQ 76 /* Name not unique on network */ +#define EBADFD 77 /* File descriptor in bad state */ +#define EREMCHG 78 /* Remote address changed */ +#define ELIBACC 79 /* Can not access a needed shared library */ +#define ELIBBAD 80 /* Accessing a corrupted shared library */ +#define ELIBSCN 81 /* .lib section in a.out corrupted */ +#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ +#define ELIBEXEC 83 /* Cannot exec a shared library directly */ +#define EILSEQ 84 /* Illegal byte sequence */ +#define ERESTART 85 /* Interrupted system call should be restarted */ +#define ESTRPIPE 86 /* Streams pipe error */ +#define EUSERS 87 /* Too many users */ +#define ENOTSOCK 88 /* Socket operation on non-socket */ +#define EDESTADDRREQ 89 /* Destination address required */ +#define EMSGSIZE 90 /* Message too long */ +#define EPROTOTYPE 91 /* Protocol wrong type for socket */ +#define ENOPROTOOPT 92 /* Protocol not available */ +#define EPROTONOSUPPORT 93 /* Protocol not supported */ +#define ESOCKTNOSUPPORT 94 /* Socket type not supported */ +#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ +#define EPFNOSUPPORT 96 /* Protocol family not supported */ +#define EAFNOSUPPORT 97 /* Address family not supported by protocol */ +#define EADDRINUSE 98 /* Address already in use */ +#define EADDRNOTAVAIL 99 /* Cannot assign requested address */ +#define ENETDOWN 100 /* Network is down */ +#define ENETUNREACH 101 /* Network is unreachable */ +#define ENETRESET 102 /* Network dropped connection because of reset */ +#define ECONNABORTED 103 /* Software caused connection abort */ +#define ECONNRESET 104 /* Connection reset by peer */ +#define ENOBUFS 105 /* No buffer space available */ +#define EISCONN 106 /* Transport endpoint is already connected */ +#define ENOTCONN 107 /* Transport endpoint is not connected */ +#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ +#define ETOOMANYREFS 109 /* Too many references: cannot splice */ +#define ETIMEDOUT 110 /* Connection timed out */ +#define ECONNREFUSED 111 /* Connection refused */ +#define EHOSTDOWN 112 /* Host is down */ +#define EHOSTUNREACH 113 /* No route to host */ +#define EALREADY 114 /* Operation already in progress */ +#define EINPROGRESS 115 /* Operation now in progress */ +#define ESTALE 116 /* Stale NFS file handle */ +#define EUCLEAN 117 /* Structure needs cleaning */ +#define ENOTNAM 118 /* Not a XENIX named type file */ +#define ENAVAIL 119 /* No XENIX semaphores available */ +#define EISNAM 120 /* Is a named type file */ +#define EREMOTEIO 121 /* Remote I/O error */ +#define EDQUOT 122 /* Quota exceeded */ + +#define ENOMEDIUM 123 /* No medium found */ +#define EMEDIUMTYPE 124 /* Wrong medium type */ + +#endif /* _ERRNO_H */ + diff --git a/syslinux/com32/include/fcntl.h b/syslinux/com32/include/fcntl.h new file mode 100644 index 0000000..b691b5c --- /dev/null +++ b/syslinux/com32/include/fcntl.h @@ -0,0 +1,24 @@ +/* + * fcntl.h + */ + +#ifndef _FCNTL_H +#define _FCNTL_H + +#include <klibc/extern.h> +#include <klibc/compiler.h> +#include <sys/types.h> + +/* None of these are actually supported, although O_RDONLY works */ +/* Note this is different from the classical Unix way of doing it */ +#define O_RDONLY 1 +#define O_WRONLY 2 +#define O_RDWR 3 +#define O_CREAT 0100 +#define O_EXCL 0200 +#define O_TRUNC 01000 +#define O_APPEND 02000 + +__extern int open(const char *, int, ...); + +#endif /* _FCNTL_H */ diff --git a/syslinux/com32/include/inttypes.h b/syslinux/com32/include/inttypes.h new file mode 100644 index 0000000..e00fa63 --- /dev/null +++ b/syslinux/com32/include/inttypes.h @@ -0,0 +1,226 @@ +/* + * inttypes.h + */ + +#ifndef _INTTYPES_H +#define _INTTYPES_H + +#include <klibc/extern.h> +#include <stdint.h> +#include <stddef.h> + +static __inline__ intmax_t imaxabs(intmax_t __n) +{ + return (__n < (intmax_t)0) ? -__n : __n; +} + +__extern intmax_t strtoimax(const char *, char **, int); +__extern uintmax_t strtoumax(const char *, char **, int); + +/* extensions */ +__extern intmax_t strntoimax(const char *, char **, int, size_t); +__extern uintmax_t strntoumax(const char *, char **, int, size_t); + +#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) + +#define PRId8 "d" +#define PRId16 "d" +#define PRId32 "d" +#define PRId64 __PRI64_RANK "d" + +#define PRIdLEAST8 "d" +#define PRIdLEAST16 "d" +#define PRIdLEAST32 "d" +#define PRIdLEAST64 __PRI64_RANK "d" + +#define PRIdFAST8 "d" +#define PRIdFAST16 __PRIFAST_RANK "d" +#define PRIdFAST32 __PRIFAST_RANK "d" +#define PRIdFAST64 __PRI64_RANK "d" + +#define PRIdMAX __PRI64_RANK "d" +#define PRIdPTR __PRIPTR_RANK "d" + +#define PRIi8 "i" +#define PRIi16 "i" +#define PRIi32 "i" +#define PRIi64 __PRI64_RANK "i" + +#define PRIiLEAST8 "i" +#define PRIiLEAST16 "i" +#define PRIiLEAST32 "i" +#define PRIiLEAST64 __PRI64_RANK "i" + +#define PRIiFAST8 "i" +#define PRIiFAST16 __PRIFAST_RANK "i" +#define PRIiFAST32 __PRIFAST_RANK "i" +#define PRIiFAST64 __PRI64_RANK "i" + +#define PRIiMAX __PRI64_RANK "i" +#define PRIiPTR __PRIPTR_RANK "i" + +#define PRIo8 "o" +#define PRIo16 "o" +#define PRIo32 "o" +#define PRIo64 __PRI64_RANK "o" + +#define PRIoLEAST8 "o" +#define PRIoLEAST16 "o" +#define PRIoLEAST32 "o" +#define PRIoLEAST64 __PRI64_RANK "o" + +#define PRIoFAST8 "o" +#define PRIoFAST16 __PRIFAST_RANK "o" +#define PRIoFAST32 __PRIFAST_RANK "o" +#define PRIoFAST64 __PRI64_RANK "o" + +#define PRIoMAX __PRI64_RANK "o" +#define PRIoPTR __PRIPTR_RANK "o" + +#define PRIu8 "u" +#define PRIu16 "u" +#define PRIu32 "u" +#define PRIu64 __PRI64_RANK "u" + +#define PRIuLEAST8 "u" +#define PRIuLEAST16 "u" +#define PRIuLEAST32 "u" +#define PRIuLEAST64 __PRI64_RANK "u" + +#define PRIuFAST8 "u" +#define PRIuFAST16 __PRIFAST_RANK "u" +#define PRIuFAST32 __PRIFAST_RANK "u" +#define PRIuFAST64 __PRI64_RANK "u" + +#define PRIuMAX __PRI64_RANK "u" +#define PRIuPTR __PRIPTR_RANK "u" + +#define PRIx8 "x" +#define PRIx16 "x" +#define PRIx32 "x" +#define PRIx64 __PRI64_RANK "x" + +#define PRIxLEAST8 "x" +#define PRIxLEAST16 "x" +#define PRIxLEAST32 "x" +#define PRIxLEAST64 __PRI64_RANK "x" + +#define PRIxFAST8 "x" +#define PRIxFAST16 __PRIFAST_RANK "x" +#define PRIxFAST32 __PRIFAST_RANK "x" +#define PRIxFAST64 __PRI64_RANK "x" + +#define PRIxMAX __PRI64_RANK "x" +#define PRIxPTR __PRIPTR_RANK "x" + +#define PRIX8 "X" +#define PRIX16 "X" +#define PRIX32 "X" +#define PRIX64 __PRI64_RANK "X" + +#define PRIXLEAST8 "X" +#define PRIXLEAST16 "X" +#define PRIXLEAST32 "X" +#define PRIXLEAST64 __PRI64_RANK "X" + +#define PRIXFAST8 "X" +#define PRIXFAST16 __PRIFAST_RANK "X" +#define PRIXFAST32 __PRIFAST_RANK "X" +#define PRIXFAST64 __PRI64_RANK "X" + +#define PRIXMAX __PRI64_RANK "X" +#define PRIXPTR __PRIPTR_RANK "X" + +#define SCNd8 "hhd" +#define SCNd16 "hd" +#define SCNd32 "d" +#define SCNd64 __PRI64_RANK "d" + +#define SCNdLEAST8 "hhd" +#define SCNdLEAST16 "hd" +#define SCNdLEAST32 "d" +#define SCNdLEAST64 __PRI64_RANK "d" + +#define SCNdFAST8 "hhd" +#define SCNdFAST16 __PRIFAST_RANK "d" +#define SCNdFAST32 __PRIFAST_RANK "d" +#define SCNdFAST64 __PRI64_RANK "d" + +#define SCNdMAX __PRI64_RANK "d" +#define SCNdPTR __PRIPTR_RANK "d" + +#define SCNi8 "hhi" +#define SCNi16 "hi" +#define SCNi32 "i" +#define SCNi64 __PRI64_RANK "i" + +#define SCNiLEAST8 "hhi" +#define SCNiLEAST16 "hi" +#define SCNiLEAST32 "i" +#define SCNiLEAST64 __PRI64_RANK "i" + +#define SCNiFAST8 "hhi" +#define SCNiFAST16 __PRIFAST_RANK "i" +#define SCNiFAST32 __PRIFAST_RANK "i" +#define SCNiFAST64 __PRI64_RANK "i" + +#define SCNiMAX __PRI64_RANK "i" +#define SCNiPTR __PRIPTR_RANK "i" + +#define SCNo8 "hho" +#define SCNo16 "ho" +#define SCNo32 "o" +#define SCNo64 __PRI64_RANK "o" + +#define SCNoLEAST8 "hho" +#define SCNoLEAST16 "ho" +#define SCNoLEAST32 "o" +#define SCNoLEAST64 __PRI64_RANK "o" + +#define SCNoFAST8 "hho" +#define SCNoFAST16 __PRIFAST_RANK "o" +#define SCNoFAST32 __PRIFAST_RANK "o" +#define SCNoFAST64 __PRI64_RANK "o" + +#define SCNoMAX __PRI64_RANK "o" +#define SCNoPTR __PRIPTR_RANK "o" + +#define SCNu8 "hhu" +#define SCNu16 "hu" +#define SCNu32 "u" +#define SCNu64 __PRI64_RANK "u" + +#define SCNuLEAST8 "hhu" +#define SCNuLEAST16 "hu" +#define SCNuLEAST32 "u" +#define SCNuLEAST64 __PRI64_RANK "u" + +#define SCNuFAST8 "hhu" +#define SCNuFAST16 __PRIFAST_RANK "u" +#define SCNuFAST32 __PRIFAST_RANK "u" +#define SCNuFAST64 __PRI64_RANK "u" + +#define SCNuMAX __PRI64_RANK "u" +#define SCNuPTR __PRIPTR_RANK "u" + +#define SCNx8 "hhx" +#define SCNx16 "hx" +#define SCNx32 "x" +#define SCNx64 __PRI64_RANK "x" + +#define SCNxLEAST8 "hhx" +#define SCNxLEAST16 "hx" +#define SCNxLEAST32 "x" +#define SCNxLEAST64 __PRI64_RANK "x" + +#define SCNxFAST8 "hhx" +#define SCNxFAST16 __PRIFAST_RANK "x" +#define SCNxFAST32 __PRIFAST_RANK "x" +#define SCNxFAST64 __PRI64_RANK "x" + +#define SCNxMAX __PRI64_RANK "x" +#define SCNxPTR __PRIPTR_RANK "x" + +#endif + +#endif /* _INTTYPES_H */ diff --git a/syslinux/com32/include/klibc/compiler.h b/syslinux/com32/include/klibc/compiler.h new file mode 100644 index 0000000..f806506 --- /dev/null +++ b/syslinux/com32/include/klibc/compiler.h @@ -0,0 +1,115 @@ +/* + * klibc/compiler.h + * + * Various compiler features + */ + +#ifndef _KLIBC_COMPILER_H +#define _KLIBC_COMPILER_H + +#define __user + +/* Specific calling conventions */ +/* __cdecl is used when we want varadic and non-varadic functions to have + the same binary calling convention. */ +#ifdef __i386__ +# ifdef __GNUC__ +# define __cdecl __attribute__((cdecl,regparm(0))) +# else + /* Most other C compilers have __cdecl as a keyword */ +# endif +#else +# define __cdecl /* Meaningless on non-i386 */ +#endif + +/* How to declare a function that *must* be inlined */ +#ifdef __GNUC__ +# if __GNUC_MAJOR__ >= 3 +# define __must_inline static __inline__ __attribute__((always_inline)) +# else +# define __must_inline extern __inline__ +# endif +#else +# define __must_inline inline /* Just hope this works... */ +#endif + +/* How to declare a function that does not return */ +#ifdef __GNUC__ +# define __noreturn void __attribute__((noreturn)) +#else +# define __noreturn void +#endif + +/* "const" function: + + Many functions do not examine any values except their arguments, + and have no effects except the return value. Basically this is + just slightly more strict class than the `pure' attribute above, + since function is not allowed to read global memory. + + Note that a function that has pointer arguments and examines the + data pointed to must _not_ be declared `const'. Likewise, a + function that calls a non-`const' function usually must not be + `const'. It does not make sense for a `const' function to return + `void'. +*/ +#ifdef __GNUC__ +# define __constfunc __attribute__((const)) +#else +# define __constfunc +#endif +#undef __attribute_const__ +#define __attribute_const__ __constfunc + +/* "pure" function: + + Many functions have no effects except the return value and their + return value depends only on the parameters and/or global + variables. Such a function can be subject to common subexpression + elimination and loop optimization just as an arithmetic operator + would be. These functions should be declared with the attribute + `pure'. +*/ +#ifdef __GNUC__ +# define __purefunc __attribute__((pure)) +#else +# define __purefunc +#endif +#undef __attribute_pure__ +#define __attribute_pure__ __purefunc + +/* Format attribute */ +#ifdef __GNUC__ +# define __formatfunc(t,f,a) __attribute__((format(t,f,a))) +#else +# define __formatfunc(t,f,a) +#endif + +/* malloc() function (returns unaliased pointer) */ +#if defined(__GNUC__) && (__GNUC_MAJOR__ >= 3) +# define __mallocfunc __attribute__((malloc)) +#else +# define __mallocfunc +#endif + +/* likely/unlikely */ +#if defined(__GNUC__) && (__GNUC_MAJOR__ > 2 || (__GNUC_MAJOR__ == 2 && __GNUC_MINOR__ >= 95)) +# define __likely(x) __builtin_expect((x), 1) +# define __unlikely(x) __builtin_expect((x), 0) +#else +# define __likely(x) (x) +# define __unlikely(x) (x) +#endif + +/* Possibly unused function */ +#ifdef __GNUC__ +# define __unusedfunc __attribute__((unused)) +#else +# define __unusedfunc +#endif + +/* Constructors and destructors */ +#define __constructor __attribute__((constructor)) +#define __destructor __attribute__((destructor)) + +#endif diff --git a/syslinux/com32/include/klibc/diverr.h b/syslinux/com32/include/klibc/diverr.h new file mode 100644 index 0000000..a4bbedd --- /dev/null +++ b/syslinux/com32/include/klibc/diverr.h @@ -0,0 +1,4 @@ +static inline void __divide_error(void) +{ + asm volatile("int $0"); /* Divide by zero */ +} diff --git a/syslinux/com32/include/klibc/extern.h b/syslinux/com32/include/klibc/extern.h new file mode 100644 index 0000000..f9c3467 --- /dev/null +++ b/syslinux/com32/include/klibc/extern.h @@ -0,0 +1,14 @@ +/* + * klibc/extern.h + */ + +#ifndef _KLIBC_EXTERN_H +#define _KLIBC_EXTERN_H + +#ifdef __cplusplus +#define __extern extern "C" +#else +#define __extern extern +#endif + +#endif /* _KLIBC_EXTERN_H */ diff --git a/syslinux/com32/include/klibc/sysconfig.h b/syslinux/com32/include/klibc/sysconfig.h new file mode 100644 index 0000000..efaaaf5 --- /dev/null +++ b/syslinux/com32/include/klibc/sysconfig.h @@ -0,0 +1,34 @@ +/* + * klibc/sysconfig.h + * + * Allows for definitions of some things which may be system-dependent + */ + +#ifndef _KLIBC_SYSCONFIG_H +#define _KLIBC_SYSCONFIG_H + +/* + * Define this to obtain memory using sbrk() instead + * of mmap(). This should make it friendlier on + * non-MMU architectures. This should become a + * per-architecture configurable. + */ +#define MALLOC_USING_SBRK + +/* + * This is the minimum chunk size we will ask the kernel for using + * malloc(); this should be a multiple of the page size on all + * architectures. + */ +#define MALLOC_CHUNK_SIZE 4096 +#define MALLOC_CHUNK_MASK (MALLOC_CHUNK_SIZE-1) + +/* + * This is the minimum alignment for the memory returned by sbrk(). + * It must be a power of 2. If MALLOC_USING_SBRK is defined it should + * be no smaller than the size of struct arena_header in malloc.h (4 + * pointers.) + */ +#define SBRK_ALIGNMENT 32 + +#endif /* _KLIBC_SYSCONFIG_H */ diff --git a/syslinux/com32/include/limits.h b/syslinux/com32/include/limits.h new file mode 100644 index 0000000..64ef974 --- /dev/null +++ b/syslinux/com32/include/limits.h @@ -0,0 +1,39 @@ +/* + * limits.h + */ + +#ifndef _LIMITS_H +#define _LIMITS_H + +#define CHAR_BIT 8 +#define SHRT_BIT 16 +#define INT_BIT 32 +#define LONGLONG_BIT 64 + +#define SCHAR_MIN (-128) +#define SCHAR_MAX 127 +#define UCHAR_MAX 255 + +#ifdef __CHAR_UNSIGNED__ +# define CHAR_MIN 0 +# define CHAR_MAX UCHAR_MAX +#else +# define CHAR_MIN SCHAR_MIN +# define CHAR_MAX SCHAR_MAX +#endif + +#define SHRT_MIN (-32768) +#define SHRT_MAX 32767 +#define USHRT_MAX 65535 + +#define INT_MIN (-2147483647-1) +#define INT_MAX 2147483647 +#define UINT_MAX 4294967295U + +#define LONGLONG_MIN (-9223372036854775807LL-1) +#define LONGLONG_MAX 9223372036854775807LL +#define ULONGLONG_MAX 18446744073709551615ULL + +#include <bitsize/limits.h> + +#endif /* _LIMITS_H */ diff --git a/syslinux/com32/include/minmax.h b/syslinux/com32/include/minmax.h new file mode 100644 index 0000000..3785094 --- /dev/null +++ b/syslinux/com32/include/minmax.h @@ -0,0 +1,44 @@ +#ident "$Id: minmax.h,v 1.1 2004/11/10 22:31:50 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +#ifndef _MINMAX_H +#define _MINMAX_H + +/* + * minmax.h: Type-independent safe min/max macros + */ + +#define min(x,y) ({ __typeof(x) xx = (x); \ + __typeof(y) yy = (y); \ + xx < yy ? xx : yy; }) +#define max(x,y) ({ __typeof(x) xx = (x); \ + __typeof(y) yy = (y); \ + xx > yy ? xx : yy; }) + +#endif /* _MINMAX_H */ + diff --git a/syslinux/com32/include/netinet/in.h b/syslinux/com32/include/netinet/in.h new file mode 100644 index 0000000..325bd4c --- /dev/null +++ b/syslinux/com32/include/netinet/in.h @@ -0,0 +1,43 @@ +#ifndef _NETINET_IN_H +#define _NETINET_IN_H + +/* COM32 will be running on an i386 platform */ + +#include <stdint.h> + +static inline uint16_t __htons(uint16_t v) +{ + return ((v) << 8) | ((v) >> 8); +} + +#define htons(x) __htons(x) +#define ntohs(x) __htons(x) + +static inline uint32_t __htonl(uint32_t v) +{ + if ( __builtin_constant_p(v) ) { + return (((v) & 0x000000ff) << 24) | + (((v) & 0x0000ff00) << 8) | + (((v) & 0x00ff0000) >> 8) | + (((v) & 0xff000000) >> 24); + } else { + asm("xchgb %h0,%b0 ; roll $16,%0 ; xchgb %h0,%b0" : "+abcd" (v)); + return v; + } +} + +#define htonl(x) __htonl(x) +#define ntohl(x) __htonl(x) + +static inline uint64_t __htonq(uint64_t v) +{ + return ((uint64_t) __htonl(v) << 32) | __htonl(v >> 32); +} + +#define htonq(x) __htonq(x) +#define ntohq(x) __htonq(x) + +#endif /* _NETINET_IN_H */ + + + diff --git a/syslinux/com32/include/png.h b/syslinux/com32/include/png.h new file mode 100644 index 0000000..e87a301 --- /dev/null +++ b/syslinux/com32/include/png.h @@ -0,0 +1,3419 @@ +/* png.h - header file for PNG reference library + * + * libpng version 1.2.8 - December 3, 2004 + * Copyright (c) 1998-2004 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * Authors and maintainers: + * libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat + * libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger + * libpng versions 0.97, January 1998, through 1.2.8 - December 3, 2004: Glenn + * See also "Contributing Authors", below. + * + * Note about libpng version numbers: + * + * Due to various miscommunications, unforeseen code incompatibilities + * and occasional factors outside the authors' control, version numbering + * on the library has not always been consistent and straightforward. + * The following table summarizes matters since version 0.89c, which was + * the first widely used release: + * + * source png.h png.h shared-lib + * version string int version + * ------- ------ ----- ---------- + * 0.89c "1.0 beta 3" 0.89 89 1.0.89 + * 0.90 "1.0 beta 4" 0.90 90 0.90 [should have been 2.0.90] + * 0.95 "1.0 beta 5" 0.95 95 0.95 [should have been 2.0.95] + * 0.96 "1.0 beta 6" 0.96 96 0.96 [should have been 2.0.96] + * 0.97b "1.00.97 beta 7" 1.00.97 97 1.0.1 [should have been 2.0.97] + * 0.97c 0.97 97 2.0.97 + * 0.98 0.98 98 2.0.98 + * 0.99 0.99 98 2.0.99 + * 0.99a-m 0.99 99 2.0.99 + * 1.00 1.00 100 2.1.0 [100 should be 10000] + * 1.0.0 (from here on, the 100 2.1.0 [100 should be 10000] + * 1.0.1 png.h string is 10001 2.1.0 + * 1.0.1a-e identical to the 10002 from here on, the shared library + * 1.0.2 source version) 10002 is 2.V where V is the source code + * 1.0.2a-b 10003 version, except as noted. + * 1.0.3 10003 + * 1.0.3a-d 10004 + * 1.0.4 10004 + * 1.0.4a-f 10005 + * 1.0.5 (+ 2 patches) 10005 + * 1.0.5a-d 10006 + * 1.0.5e-r 10100 (not source compatible) + * 1.0.5s-v 10006 (not binary compatible) + * 1.0.6 (+ 3 patches) 10006 (still binary incompatible) + * 1.0.6d-f 10007 (still binary incompatible) + * 1.0.6g 10007 + * 1.0.6h 10007 10.6h (testing xy.z so-numbering) + * 1.0.6i 10007 10.6i + * 1.0.6j 10007 2.1.0.6j (incompatible with 1.0.0) + * 1.0.7beta11-14 DLLNUM 10007 2.1.0.7beta11-14 (binary compatible) + * 1.0.7beta15-18 1 10007 2.1.0.7beta15-18 (binary compatible) + * 1.0.7rc1-2 1 10007 2.1.0.7rc1-2 (binary compatible) + * 1.0.7 1 10007 (still compatible) + * 1.0.8beta1-4 1 10008 2.1.0.8beta1-4 + * 1.0.8rc1 1 10008 2.1.0.8rc1 + * 1.0.8 1 10008 2.1.0.8 + * 1.0.9beta1-6 1 10009 2.1.0.9beta1-6 + * 1.0.9rc1 1 10009 2.1.0.9rc1 + * 1.0.9beta7-10 1 10009 2.1.0.9beta7-10 + * 1.0.9rc2 1 10009 2.1.0.9rc2 + * 1.0.9 1 10009 2.1.0.9 + * 1.0.10beta1 1 10010 2.1.0.10beta1 + * 1.0.10rc1 1 10010 2.1.0.10rc1 + * 1.0.10 1 10010 2.1.0.10 + * 1.0.11beta1-3 1 10011 2.1.0.11beta1-3 + * 1.0.11rc1 1 10011 2.1.0.11rc1 + * 1.0.11 1 10011 2.1.0.11 + * 1.0.12beta1-2 2 10012 2.1.0.12beta1-2 + * 1.0.12rc1 2 10012 2.1.0.12rc1 + * 1.0.12 2 10012 2.1.0.12 + * 1.1.0a-f - 10100 2.1.1.0a-f (branch abandoned) + * 1.2.0beta1-2 2 10200 2.1.2.0beta1-2 + * 1.2.0beta3-5 3 10200 3.1.2.0beta3-5 + * 1.2.0rc1 3 10200 3.1.2.0rc1 + * 1.2.0 3 10200 3.1.2.0 + * 1.2.1beta1-4 3 10201 3.1.2.1beta1-4 + * 1.2.1rc1-2 3 10201 3.1.2.1rc1-2 + * 1.2.1 3 10201 3.1.2.1 + * 1.2.2beta1-6 12 10202 12.so.0.1.2.2beta1-6 + * 1.0.13beta1 10 10013 10.so.0.1.0.13beta1 + * 1.0.13rc1 10 10013 10.so.0.1.0.13rc1 + * 1.2.2rc1 12 10202 12.so.0.1.2.2rc1 + * 1.0.13 10 10013 10.so.0.1.0.13 + * 1.2.2 12 10202 12.so.0.1.2.2 + * 1.2.3rc1-6 12 10203 12.so.0.1.2.3rc1-6 + * 1.2.3 12 10203 12.so.0.1.2.3 + * 1.2.4beta1-3 13 10204 12.so.0.1.2.4beta1-3 + * 1.0.14rc1 13 10014 10.so.0.1.0.14rc1 + * 1.2.4rc1 13 10204 12.so.0.1.2.4rc1 + * 1.0.14 10 10014 10.so.0.1.0.14 + * 1.2.4 13 10204 12.so.0.1.2.4 + * 1.2.5beta1-2 13 10205 12.so.0.1.2.5beta1-2 + * 1.0.15rc1-3 10 10015 10.so.0.1.0.15rc1-3 + * 1.2.5rc1-3 13 10205 12.so.0.1.2.5rc1-3 + * 1.0.15 10 10015 10.so.0.1.0.15 + * 1.2.5 13 10205 12.so.0.1.2.5 + * 1.2.6beta1-4 13 10206 12.so.0.1.2.6beta1-4 + * 1.0.16 10 10016 10.so.0.1.0.16 + * 1.2.6 13 10206 12.so.0.1.2.6 + * 1.2.7beta1-2 13 10207 12.so.0.1.2.7beta1-2 + * 1.0.17rc1 10 10017 12.so.0.1.0.17rc1 + * 1.2.7rc1 13 10207 12.so.0.1.2.7rc1 + * 1.0.17 10 10017 12.so.0.1.0.17 + * 1.2.7 13 10207 12.so.0.1.2.7 + * 1.2.8beta1-5 13 10208 12.so.0.1.2.8beta1-5 + * 1.0.18rc1-5 10 10018 12.so.0.1.0.18rc1-5 + * 1.2.8rc1-5 13 10208 12.so.0.1.2.8rc1-5 + * 1.0.18 10 10018 12.so.0.1.0.18 + * 1.2.8 13 10208 12.so.0.1.2.8 + * + * Henceforth the source version will match the shared-library major + * and minor numbers; the shared-library major version number will be + * used for changes in backward compatibility, as it is intended. The + * PNG_LIBPNG_VER macro, which is not used within libpng but is available + * for applications, is an unsigned integer of the form xyyzz corresponding + * to the source version x.y.z (leading zeros in y and z). Beta versions + * were given the previous public release number plus a letter, until + * version 1.0.6j; from then on they were given the upcoming public + * release number plus "betaNN" or "rcN". + * + * Binary incompatibility exists only when applications make direct access + * to the info_ptr or png_ptr members through png.h, and the compiled + * application is loaded with a different version of the library. + * + * DLLNUM will change each time there are forward or backward changes + * in binary compatibility (e.g., when a new feature is added). + * + * See libpng.txt or libpng.3 for more information. The PNG specification + * is available as a W3C Recommendation and as an ISO Specification, + * <http://www.w3.org/TR/2003/REC-PNG-20031110/ + */ + +/* + * COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: + * + * If you modify libpng you may insert additional notices immediately following + * this sentence. + * + * libpng versions 1.2.6, August 15, 2004, through 1.2.8, December 3, 2004, are + * Copyright (c) 2004 Glenn Randers-Pehrson, and are + * distributed according to the same disclaimer and license as libpng-1.2.5 + * with the following individual added to the list of Contributing Authors: + * + * Cosmin Truta + * + * libpng versions 1.0.7, July 1, 2000, through 1.2.5, October 3, 2002, are + * Copyright (c) 2000-2002 Glenn Randers-Pehrson, and are + * distributed according to the same disclaimer and license as libpng-1.0.6 + * with the following individuals added to the list of Contributing Authors: + * + * Simon-Pierre Cadieux + * Eric S. Raymond + * Gilles Vollant + * + * and with the following additions to the disclaimer: + * + * There is no warranty against interference with your enjoyment of the + * library or against infringement. There is no warranty that our + * efforts or the library will fulfill any of your particular purposes + * or needs. This library is provided with all faults, and the entire + * risk of satisfactory quality, performance, accuracy, and effort is with + * the user. + * + * libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are + * Copyright (c) 1998, 1999, 2000 Glenn Randers-Pehrson, and are + * distributed according to the same disclaimer and license as libpng-0.96, + * with the following individuals added to the list of Contributing Authors: + * + * Tom Lane + * Glenn Randers-Pehrson + * Willem van Schaik + * + * libpng versions 0.89, June 1996, through 0.96, May 1997, are + * Copyright (c) 1996, 1997 Andreas Dilger + * Distributed according to the same disclaimer and license as libpng-0.88, + * with the following individuals added to the list of Contributing Authors: + * + * John Bowler + * Kevin Bracey + * Sam Bushell + * Magnus Holmgren + * Greg Roelofs + * Tom Tanner + * + * libpng versions 0.5, May 1995, through 0.88, January 1996, are + * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. + * + * For the purposes of this copyright and license, "Contributing Authors" + * is defined as the following set of individuals: + * + * Andreas Dilger + * Dave Martindale + * Guy Eric Schalnat + * Paul Schmidt + * Tim Wegner + * + * The PNG Reference Library is supplied "AS IS". The Contributing Authors + * and Group 42, Inc. disclaim all warranties, expressed or implied, + * including, without limitation, the warranties of merchantability and of + * fitness for any purpose. The Contributing Authors and Group 42, Inc. + * assume no liability for direct, indirect, incidental, special, exemplary, + * or consequential damages, which may result from the use of the PNG + * Reference Library, even if advised of the possibility of such damage. + * + * Permission is hereby granted to use, copy, modify, and distribute this + * source code, or portions hereof, for any purpose, without fee, subject + * to the following restrictions: + * + * 1. The origin of this source code must not be misrepresented. + * + * 2. Altered versions must be plainly marked as such and + * must not be misrepresented as being the original source. + * + * 3. This Copyright notice may not be removed or altered from + * any source or altered source distribution. + * + * The Contributing Authors and Group 42, Inc. specifically permit, without + * fee, and encourage the use of this source code as a component to + * supporting the PNG file format in commercial products. If you use this + * source code in a product, acknowledgment is not required but would be + * appreciated. + */ + +/* + * A "png_get_copyright" function is available, for convenient use in "about" + * boxes and the like: + * + * printf("%s",png_get_copyright(NULL)); + * + * Also, the PNG logo (in PNG format, of course) is supplied in the + * files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31). + */ + +/* + * Libpng is OSI Certified Open Source Software. OSI Certified is a + * certification mark of the Open Source Initiative. + */ + +/* + * The contributing authors would like to thank all those who helped + * with testing, bug fixes, and patience. This wouldn't have been + * possible without all of you. + * + * Thanks to Frank J. T. Wojcik for helping with the documentation. + */ + +/* + * Y2K compliance in libpng: + * ========================= + * + * December 3, 2004 + * + * Since the PNG Development group is an ad-hoc body, we can't make + * an official declaration. + * + * This is your unofficial assurance that libpng from version 0.71 and + * upward through 1.2.8 are Y2K compliant. It is my belief that earlier + * versions were also Y2K compliant. + * + * Libpng only has three year fields. One is a 2-byte unsigned integer + * that will hold years up to 65535. The other two hold the date in text + * format, and will hold years up to 9999. + * + * The integer is + * "png_uint_16 year" in png_time_struct. + * + * The strings are + * "png_charp time_buffer" in png_struct and + * "near_time_buffer", which is a local character string in png.c. + * + * There are seven time-related functions: + * png.c: png_convert_to_rfc_1123() in png.c + * (formerly png_convert_to_rfc_1152() in error) + * png_convert_from_struct_tm() in pngwrite.c, called in pngwrite.c + * png_convert_from_time_t() in pngwrite.c + * png_get_tIME() in pngget.c + * png_handle_tIME() in pngrutil.c, called in pngread.c + * png_set_tIME() in pngset.c + * png_write_tIME() in pngwutil.c, called in pngwrite.c + * + * All handle dates properly in a Y2K environment. The + * png_convert_from_time_t() function calls gmtime() to convert from system + * clock time, which returns (year - 1900), which we properly convert to + * the full 4-digit year. There is a possibility that applications using + * libpng are not passing 4-digit years into the png_convert_to_rfc_1123() + * function, or that they are incorrectly passing only a 2-digit year + * instead of "year - 1900" into the png_convert_from_struct_tm() function, + * but this is not under our control. The libpng documentation has always + * stated that it works with 4-digit years, and the APIs have been + * documented as such. + * + * The tIME chunk itself is also Y2K compliant. It uses a 2-byte unsigned + * integer to hold the year, and can hold years as large as 65535. + * + * zlib, upon which libpng depends, is also Y2K compliant. It contains + * no date-related code. + * + * Glenn Randers-Pehrson + * libpng maintainer + * PNG Development Group + */ + +#ifndef PNG_H +#define PNG_H + +/* This is not the place to learn how to use libpng. The file libpng.txt + * describes how to use libpng, and the file example.c summarizes it + * with some code on which to build. This file is useful for looking + * at the actual function definitions and structure components. + */ + +/* Version information for png.h - this should match the version in png.c */ +#define PNG_LIBPNG_VER_STRING "1.2.8" +#define PNG_HEADER_VERSION_STRING \ + " libpng version 1.2.8 - December 3, 2004 (header)\n" + +#define PNG_LIBPNG_VER_SONUM 0 +#define PNG_LIBPNG_VER_DLLNUM 13 + +/* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */ +#define PNG_LIBPNG_VER_MAJOR 1 +#define PNG_LIBPNG_VER_MINOR 2 +#define PNG_LIBPNG_VER_RELEASE 8 +/* This should match the numeric part of the final component of + * PNG_LIBPNG_VER_STRING, omitting any leading zero: */ + +#define PNG_LIBPNG_VER_BUILD 0 + +/* Release Status */ +#define PNG_LIBPNG_BUILD_ALPHA 1 +#define PNG_LIBPNG_BUILD_BETA 2 +#define PNG_LIBPNG_BUILD_RC 3 +#define PNG_LIBPNG_BUILD_STABLE 4 +#define PNG_LIBPNG_BUILD_RELEASE_STATUS_MASK 7 + +/* Release-Specific Flags */ +#define PNG_LIBPNG_BUILD_PATCH 8 /* Can be OR'ed with + PNG_LIBPNG_BUILD_STABLE only */ +#define PNG_LIBPNG_BUILD_PRIVATE 16 /* Cannot be OR'ed with + PNG_LIBPNG_BUILD_SPECIAL */ +#define PNG_LIBPNG_BUILD_SPECIAL 32 /* Cannot be OR'ed with + PNG_LIBPNG_BUILD_PRIVATE */ + +#define PNG_LIBPNG_BUILD_BASE_TYPE PNG_LIBPNG_BUILD_STABLE + +/* Careful here. At one time, Guy wanted to use 082, but that would be octal. + * We must not include leading zeros. + * Versions 0.7 through 1.0.0 were in the range 0 to 100 here (only + * version 1.0.0 was mis-numbered 100 instead of 10000). From + * version 1.0.1 it's xxyyzz, where x=major, y=minor, z=release */ +#define PNG_LIBPNG_VER 10208 /* 1.2.8 */ + +#ifndef PNG_VERSION_INFO_ONLY +/* include the compression library's header */ +#include "zlib.h" +#endif + +/* include all user configurable info, including optional assembler routines */ +#include "pngconf.h" + +/* + * Added at libpng-1.2.8 */ +/* Ref MSDN: Private as priority over Special + * VS_FF_PRIVATEBUILD File *was not* built using standard release + * procedures. If this value is given, the StringFileInfo block must + * contain a PrivateBuild string. + * + * VS_FF_SPECIALBUILD File *was* built by the original company using + * standard release procedures but is a variation of the standard + * file of the same version number. If this value is given, the + * StringFileInfo block must contain a SpecialBuild string. + */ + +#if defined(PNG_USER_PRIVATEBUILD) +# define PNG_LIBPNG_BUILD_TYPE PNG_LIBPNG_BUILD_BASE_TYPE | \ + PNG_LIBPNG_BUILD_PRIVATE +#else +# if defined(PNG_LIBPNG_SPECIALBUILD) +# define PNG_LIBPNG_BUILD_TYPE PNG_LIBPNG_BUILD_BASE_TYPE | \ + PNG_LIBPNG_BUILD_SPECIAL +# else +# define PNG_LIBPNG_BUILD_TYPE PNG_LIBPNG_BUILD_BASE_TYPE +# endif +#endif + +#ifndef PNG_VERSION_INFO_ONLY + +/* Inhibit C++ name-mangling for libpng functions but not for system calls. */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* This file is arranged in several sections. The first section contains + * structure and type definitions. The second section contains the external + * library functions, while the third has the internal library functions, + * which applications aren't expected to use directly. + */ + +#ifndef PNG_NO_TYPECAST_NULL +#define int_p_NULL (int *)NULL +#define png_bytep_NULL (png_bytep)NULL +#define png_bytepp_NULL (png_bytepp)NULL +#define png_doublep_NULL (png_doublep)NULL +#define png_error_ptr_NULL (png_error_ptr)NULL +#define png_flush_ptr_NULL (png_flush_ptr)NULL +#define png_free_ptr_NULL (png_free_ptr)NULL +#define png_infopp_NULL (png_infopp)NULL +#define png_malloc_ptr_NULL (png_malloc_ptr)NULL +#define png_read_status_ptr_NULL (png_read_status_ptr)NULL +#define png_rw_ptr_NULL (png_rw_ptr)NULL +#define png_structp_NULL (png_structp)NULL +#define png_uint_16p_NULL (png_uint_16p)NULL +#define png_voidp_NULL (png_voidp)NULL +#define png_write_status_ptr_NULL (png_write_status_ptr)NULL +#else +#define int_p_NULL NULL +#define png_bytep_NULL NULL +#define png_bytepp_NULL NULL +#define png_doublep_NULL NULL +#define png_error_ptr_NULL NULL +#define png_flush_ptr_NULL NULL +#define png_free_ptr_NULL NULL +#define png_infopp_NULL NULL +#define png_malloc_ptr_NULL NULL +#define png_read_status_ptr_NULL NULL +#define png_rw_ptr_NULL NULL +#define png_structp_NULL NULL +#define png_uint_16p_NULL NULL +#define png_voidp_NULL NULL +#define png_write_status_ptr_NULL NULL +#endif + +/* variables declared in png.c - only it needs to define PNG_NO_EXTERN */ +#if !defined(PNG_NO_EXTERN) || defined(PNG_ALWAYS_EXTERN) +/* Version information for C files, stored in png.c. This had better match + * the version above. + */ +#ifdef PNG_USE_GLOBAL_ARRAYS +PNG_EXPORT_VAR (const char) png_libpng_ver[18]; + /* need room for 99.99.99beta99z */ +#else +#define png_libpng_ver png_get_header_ver(NULL) +#endif + +#ifdef PNG_USE_GLOBAL_ARRAYS +/* This was removed in version 1.0.5c */ +/* Structures to facilitate easy interlacing. See png.c for more details */ +PNG_EXPORT_VAR (const int FARDATA) png_pass_start[7]; +PNG_EXPORT_VAR (const int FARDATA) png_pass_inc[7]; +PNG_EXPORT_VAR (const int FARDATA) png_pass_ystart[7]; +PNG_EXPORT_VAR (const int FARDATA) png_pass_yinc[7]; +PNG_EXPORT_VAR (const int FARDATA) png_pass_mask[7]; +PNG_EXPORT_VAR (const int FARDATA) png_pass_dsp_mask[7]; +#ifdef PNG_HAVE_ASSEMBLER_COMBINE_ROW +PNG_EXPORT_VAR (const int FARDATA) png_pass_width[7]; +#endif +/* This isn't currently used. If you need it, see png.c for more details. +PNG_EXPORT_VAR (const int FARDATA) png_pass_height[7]; +*/ +#endif + +#endif /* PNG_NO_EXTERN */ + +/* Three color definitions. The order of the red, green, and blue, (and the + * exact size) is not important, although the size of the fields need to + * be png_byte or png_uint_16 (as defined below). + */ +typedef struct png_color_struct +{ + png_byte red; + png_byte green; + png_byte blue; +} png_color; +typedef png_color FAR * png_colorp; +typedef png_color FAR * FAR * png_colorpp; + +typedef struct png_color_16_struct +{ + png_byte index; /* used for palette files */ + png_uint_16 red; /* for use in red green blue files */ + png_uint_16 green; + png_uint_16 blue; + png_uint_16 gray; /* for use in grayscale files */ +} png_color_16; +typedef png_color_16 FAR * png_color_16p; +typedef png_color_16 FAR * FAR * png_color_16pp; + +typedef struct png_color_8_struct +{ + png_byte red; /* for use in red green blue files */ + png_byte green; + png_byte blue; + png_byte gray; /* for use in grayscale files */ + png_byte alpha; /* for alpha channel files */ +} png_color_8; +typedef png_color_8 FAR * png_color_8p; +typedef png_color_8 FAR * FAR * png_color_8pp; + +/* + * The following two structures are used for the in-core representation + * of sPLT chunks. + */ +typedef struct png_sPLT_entry_struct +{ + png_uint_16 red; + png_uint_16 green; + png_uint_16 blue; + png_uint_16 alpha; + png_uint_16 frequency; +} png_sPLT_entry; +typedef png_sPLT_entry FAR * png_sPLT_entryp; +typedef png_sPLT_entry FAR * FAR * png_sPLT_entrypp; + +/* When the depth of the sPLT palette is 8 bits, the color and alpha samples + * occupy the LSB of their respective members, and the MSB of each member + * is zero-filled. The frequency member always occupies the full 16 bits. + */ + +typedef struct png_sPLT_struct +{ + png_charp name; /* palette name */ + png_byte depth; /* depth of palette samples */ + png_sPLT_entryp entries; /* palette entries */ + png_int_32 nentries; /* number of palette entries */ +} png_sPLT_t; +typedef png_sPLT_t FAR * png_sPLT_tp; +typedef png_sPLT_t FAR * FAR * png_sPLT_tpp; + +#ifdef PNG_TEXT_SUPPORTED +/* png_text holds the contents of a text/ztxt/itxt chunk in a PNG file, + * and whether that contents is compressed or not. The "key" field + * points to a regular zero-terminated C string. The "text", "lang", and + * "lang_key" fields can be regular C strings, empty strings, or NULL pointers. + * However, the * structure returned by png_get_text() will always contain + * regular zero-terminated C strings (possibly empty), never NULL pointers, + * so they can be safely used in printf() and other string-handling functions. + */ +typedef struct png_text_struct +{ + int compression; /* compression value: + -1: tEXt, none + 0: zTXt, deflate + 1: iTXt, none + 2: iTXt, deflate */ + png_charp key; /* keyword, 1-79 character description of "text" */ + png_charp text; /* comment, may be an empty string (ie "") + or a NULL pointer */ + png_size_t text_length; /* length of the text string */ +#ifdef PNG_iTXt_SUPPORTED + png_size_t itxt_length; /* length of the itxt string */ + png_charp lang; /* language code, 0-79 characters + or a NULL pointer */ + png_charp lang_key; /* keyword translated UTF-8 string, 0 or more + chars or a NULL pointer */ +#endif +} png_text; +typedef png_text FAR * png_textp; +typedef png_text FAR * FAR * png_textpp; +#endif + +/* Supported compression types for text in PNG files (tEXt, and zTXt). + * The values of the PNG_TEXT_COMPRESSION_ defines should NOT be changed. */ +#define PNG_TEXT_COMPRESSION_NONE_WR -3 +#define PNG_TEXT_COMPRESSION_zTXt_WR -2 +#define PNG_TEXT_COMPRESSION_NONE -1 +#define PNG_TEXT_COMPRESSION_zTXt 0 +#define PNG_ITXT_COMPRESSION_NONE 1 +#define PNG_ITXT_COMPRESSION_zTXt 2 +#define PNG_TEXT_COMPRESSION_LAST 3 /* Not a valid value */ + +/* png_time is a way to hold the time in an machine independent way. + * Two conversions are provided, both from time_t and struct tm. There + * is no portable way to convert to either of these structures, as far + * as I know. If you know of a portable way, send it to me. As a side + * note - PNG has always been Year 2000 compliant! + */ +typedef struct png_time_struct +{ + png_uint_16 year; /* full year, as in, 1995 */ + png_byte month; /* month of year, 1 - 12 */ + png_byte day; /* day of month, 1 - 31 */ + png_byte hour; /* hour of day, 0 - 23 */ + png_byte minute; /* minute of hour, 0 - 59 */ + png_byte second; /* second of minute, 0 - 60 (for leap seconds) */ +} png_time; +typedef png_time FAR * png_timep; +typedef png_time FAR * FAR * png_timepp; + +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) +/* png_unknown_chunk is a structure to hold queued chunks for which there is + * no specific support. The idea is that we can use this to queue + * up private chunks for output even though the library doesn't actually + * know about their semantics. + */ +typedef struct png_unknown_chunk_t +{ + png_byte name[5]; + png_byte *data; + png_size_t size; + + /* libpng-using applications should NOT directly modify this byte. */ + png_byte location; /* mode of operation at read time */ +} +png_unknown_chunk; +typedef png_unknown_chunk FAR * png_unknown_chunkp; +typedef png_unknown_chunk FAR * FAR * png_unknown_chunkpp; +#endif + +/* png_info is a structure that holds the information in a PNG file so + * that the application can find out the characteristics of the image. + * If you are reading the file, this structure will tell you what is + * in the PNG file. If you are writing the file, fill in the information + * you want to put into the PNG file, then call png_write_info(). + * The names chosen should be very close to the PNG specification, so + * consult that document for information about the meaning of each field. + * + * With libpng < 0.95, it was only possible to directly set and read the + * the values in the png_info_struct, which meant that the contents and + * order of the values had to remain fixed. With libpng 0.95 and later, + * however, there are now functions that abstract the contents of + * png_info_struct from the application, so this makes it easier to use + * libpng with dynamic libraries, and even makes it possible to use + * libraries that don't have all of the libpng ancillary chunk-handing + * functionality. + * + * In any case, the order of the parameters in png_info_struct should NOT + * be changed for as long as possible to keep compatibility with applications + * that use the old direct-access method with png_info_struct. + * + * The following members may have allocated storage attached that should be + * cleaned up before the structure is discarded: palette, trans, text, + * pcal_purpose, pcal_units, pcal_params, hist, iccp_name, iccp_profile, + * splt_palettes, scal_unit, row_pointers, and unknowns. By default, these + * are automatically freed when the info structure is deallocated, if they were + * allocated internally by libpng. This behavior can be changed by means + * of the png_data_freer() function. + * + * More allocation details: all the chunk-reading functions that + * change these members go through the corresponding png_set_* + * functions. A function to clear these members is available: see + * png_free_data(). The png_set_* functions do not depend on being + * able to point info structure members to any of the storage they are + * passed (they make their own copies), EXCEPT that the png_set_text + * functions use the same storage passed to them in the text_ptr or + * itxt_ptr structure argument, and the png_set_rows and png_set_unknowns + * functions do not make their own copies. + */ +typedef struct png_info_struct +{ + /* the following are necessary for every PNG file */ + png_uint_32 width; /* width of image in pixels (from IHDR) */ + png_uint_32 height; /* height of image in pixels (from IHDR) */ + png_uint_32 valid; /* valid chunk data (see PNG_INFO_ below) */ + png_uint_32 rowbytes; /* bytes needed to hold an untransformed row */ + png_colorp palette; /* array of color values (valid & PNG_INFO_PLTE) */ + png_uint_16 num_palette; /* number of color entries in "palette" (PLTE) */ + png_uint_16 num_trans; /* number of transparent palette color (tRNS) */ + png_byte bit_depth; /* 1, 2, 4, 8, or 16 bits/channel (from IHDR) */ + png_byte color_type; /* see PNG_COLOR_TYPE_ below (from IHDR) */ + /* The following three should have been named *_method not *_type */ + png_byte compression_type; /* must be PNG_COMPRESSION_TYPE_BASE (IHDR) */ + png_byte filter_type; /* must be PNG_FILTER_TYPE_BASE (from IHDR) */ + png_byte interlace_type; /* One of PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */ + + /* The following is informational only on read, and not used on writes. */ + png_byte channels; /* number of data channels per pixel (1, 2, 3, 4) */ + png_byte pixel_depth; /* number of bits per pixel */ + png_byte spare_byte; /* to align the data, and for future use */ + png_byte signature[8]; /* magic bytes read by libpng from start of file */ + + /* The rest of the data is optional. If you are reading, check the + * valid field to see if the information in these are valid. If you + * are writing, set the valid field to those chunks you want written, + * and initialize the appropriate fields below. + */ + +#if defined(PNG_gAMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED) + /* The gAMA chunk describes the gamma characteristics of the system + * on which the image was created, normally in the range [1.0, 2.5]. + * Data is valid if (valid & PNG_INFO_gAMA) is non-zero. + */ + float gamma; /* gamma value of image, if (valid & PNG_INFO_gAMA) */ +#endif + +#if defined(PNG_sRGB_SUPPORTED) + /* GR-P, 0.96a */ + /* Data valid if (valid & PNG_INFO_sRGB) non-zero. */ + png_byte srgb_intent; /* sRGB rendering intent [0, 1, 2, or 3] */ +#endif + +#if defined(PNG_TEXT_SUPPORTED) + /* The tEXt, and zTXt chunks contain human-readable textual data in + * uncompressed, compressed, and optionally compressed forms, respectively. + * The data in "text" is an array of pointers to uncompressed, + * null-terminated C strings. Each chunk has a keyword that describes the + * textual data contained in that chunk. Keywords are not required to be + * unique, and the text string may be empty. Any number of text chunks may + * be in an image. + */ + int num_text; /* number of comments read/to write */ + int max_text; /* current size of text array */ + png_textp text; /* array of comments read/to write */ +#endif /* PNG_TEXT_SUPPORTED */ + +#if defined(PNG_tIME_SUPPORTED) + /* The tIME chunk holds the last time the displayed image data was + * modified. See the png_time struct for the contents of this struct. + */ + png_time mod_time; +#endif + +#if defined(PNG_sBIT_SUPPORTED) + /* The sBIT chunk specifies the number of significant high-order bits + * in the pixel data. Values are in the range [1, bit_depth], and are + * only specified for the channels in the pixel data. The contents of + * the low-order bits is not specified. Data is valid if + * (valid & PNG_INFO_sBIT) is non-zero. + */ + png_color_8 sig_bit; /* significant bits in color channels */ +#endif + +#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_EXPAND_SUPPORTED) || \ +defined(PNG_READ_BACKGROUND_SUPPORTED) + /* The tRNS chunk supplies transparency data for paletted images and + * other image types that don't need a full alpha channel. There are + * "num_trans" transparency values for a paletted image, stored in the + * same order as the palette colors, starting from index 0. Values + * for the data are in the range [0, 255], ranging from fully transparent + * to fully opaque, respectively. For non-paletted images, there is a + * single color specified that should be treated as fully transparent. + * Data is valid if (valid & PNG_INFO_tRNS) is non-zero. + */ + png_bytep trans; /* transparent values for paletted image */ + png_color_16 trans_values; /* transparent color for non-palette image */ +#endif + +#if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + /* The bKGD chunk gives the suggested image background color if the + * display program does not have its own background color and the image + * is needs to composited onto a background before display. The colors + * in "background" are normally in the same color space/depth as the + * pixel data. Data is valid if (valid & PNG_INFO_bKGD) is non-zero. + */ + png_color_16 background; +#endif + +#if defined(PNG_oFFs_SUPPORTED) + /* The oFFs chunk gives the offset in "offset_unit_type" units rightwards + * and downwards from the top-left corner of the display, page, or other + * application-specific co-ordinate space. See the PNG_OFFSET_ defines + * below for the unit types. Valid if (valid & PNG_INFO_oFFs) non-zero. + */ + png_int_32 x_offset; /* x offset on page */ + png_int_32 y_offset; /* y offset on page */ + png_byte offset_unit_type; /* offset units type */ +#endif + +#if defined(PNG_pHYs_SUPPORTED) + /* The pHYs chunk gives the physical pixel density of the image for + * display or printing in "phys_unit_type" units (see PNG_RESOLUTION_ + * defines below). Data is valid if (valid & PNG_INFO_pHYs) is non-zero. + */ + png_uint_32 x_pixels_per_unit; /* horizontal pixel density */ + png_uint_32 y_pixels_per_unit; /* vertical pixel density */ + png_byte phys_unit_type; /* resolution type (see PNG_RESOLUTION_ below) */ +#endif + +#if defined(PNG_hIST_SUPPORTED) + /* The hIST chunk contains the relative frequency or importance of the + * various palette entries, so that a viewer can intelligently select a + * reduced-color palette, if required. Data is an array of "num_palette" + * values in the range [0,65535]. Data valid if (valid & PNG_INFO_hIST) + * is non-zero. + */ + png_uint_16p hist; +#endif + +#ifdef PNG_cHRM_SUPPORTED + /* The cHRM chunk describes the CIE color characteristics of the monitor + * on which the PNG was created. This data allows the viewer to do gamut + * mapping of the input image to ensure that the viewer sees the same + * colors in the image as the creator. Values are in the range + * [0.0, 0.8]. Data valid if (valid & PNG_INFO_cHRM) non-zero. + */ +#ifdef PNG_FLOATING_POINT_SUPPORTED + float x_white; + float y_white; + float x_red; + float y_red; + float x_green; + float y_green; + float x_blue; + float y_blue; +#endif +#endif + +#if defined(PNG_pCAL_SUPPORTED) + /* The pCAL chunk describes a transformation between the stored pixel + * values and original physical data values used to create the image. + * The integer range [0, 2^bit_depth - 1] maps to the floating-point + * range given by [pcal_X0, pcal_X1], and are further transformed by a + * (possibly non-linear) transformation function given by "pcal_type" + * and "pcal_params" into "pcal_units". Please see the PNG_EQUATION_ + * defines below, and the PNG-Group's PNG extensions document for a + * complete description of the transformations and how they should be + * implemented, and for a description of the ASCII parameter strings. + * Data values are valid if (valid & PNG_INFO_pCAL) non-zero. + */ + png_charp pcal_purpose; /* pCAL chunk description string */ + png_int_32 pcal_X0; /* minimum value */ + png_int_32 pcal_X1; /* maximum value */ + png_charp pcal_units; /* Latin-1 string giving physical units */ + png_charpp pcal_params; /* ASCII strings containing parameter values */ + png_byte pcal_type; /* equation type (see PNG_EQUATION_ below) */ + png_byte pcal_nparams; /* number of parameters given in pcal_params */ +#endif + +/* New members added in libpng-1.0.6 */ +#ifdef PNG_FREE_ME_SUPPORTED + png_uint_32 free_me; /* flags items libpng is responsible for freeing */ +#endif + +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) + /* storage for unknown chunks that the library doesn't recognize. */ + png_unknown_chunkp unknown_chunks; + png_size_t unknown_chunks_num; +#endif + +#if defined(PNG_iCCP_SUPPORTED) + /* iCCP chunk data. */ + png_charp iccp_name; /* profile name */ + png_charp iccp_profile; /* International Color Consortium profile data */ + /* Note to maintainer: should be png_bytep */ + png_uint_32 iccp_proflen; /* ICC profile data length */ + png_byte iccp_compression; /* Always zero */ +#endif + +#if defined(PNG_sPLT_SUPPORTED) + /* data on sPLT chunks (there may be more than one). */ + png_sPLT_tp splt_palettes; + png_uint_32 splt_palettes_num; +#endif + +#if defined(PNG_sCAL_SUPPORTED) + /* The sCAL chunk describes the actual physical dimensions of the + * subject matter of the graphic. The chunk contains a unit specification + * a byte value, and two ASCII strings representing floating-point + * values. The values are width and height corresponsing to one pixel + * in the image. This external representation is converted to double + * here. Data values are valid if (valid & PNG_INFO_sCAL) is non-zero. + */ + png_byte scal_unit; /* unit of physical scale */ +#ifdef PNG_FLOATING_POINT_SUPPORTED + double scal_pixel_width; /* width of one pixel */ + double scal_pixel_height; /* height of one pixel */ +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + png_charp scal_s_width; /* string containing height */ + png_charp scal_s_height; /* string containing width */ +#endif +#endif + +#if defined(PNG_INFO_IMAGE_SUPPORTED) + /* Memory has been allocated if (valid & PNG_ALLOCATED_INFO_ROWS) non-zero */ + /* Data valid if (valid & PNG_INFO_IDAT) non-zero */ + png_bytepp row_pointers; /* the image bits */ +#endif + +#if defined(PNG_FIXED_POINT_SUPPORTED) && defined(PNG_gAMA_SUPPORTED) + png_fixed_point int_gamma; /* gamma of image, if (valid & PNG_INFO_gAMA) */ +#endif + +#if defined(PNG_cHRM_SUPPORTED) && defined(PNG_FIXED_POINT_SUPPORTED) + png_fixed_point int_x_white; + png_fixed_point int_y_white; + png_fixed_point int_x_red; + png_fixed_point int_y_red; + png_fixed_point int_x_green; + png_fixed_point int_y_green; + png_fixed_point int_x_blue; + png_fixed_point int_y_blue; +#endif + +} png_info; + +typedef png_info FAR * png_infop; +typedef png_info FAR * FAR * png_infopp; + +/* Maximum positive integer used in PNG is (2^31)-1 */ +#define PNG_UINT_31_MAX ((png_uint_32)0x7fffffffL) +#define PNG_UINT_32_MAX ((png_uint_32)(-1)) +#define PNG_SIZE_MAX ((png_size_t)(-1)) +/* PNG_MAX_UINT is deprecated; use PNG_UINT_31_MAX instead. */ +#define PNG_MAX_UINT PNG_UINT_31_MAX + +/* These describe the color_type field in png_info. */ +/* color type masks */ +#define PNG_COLOR_MASK_PALETTE 1 +#define PNG_COLOR_MASK_COLOR 2 +#define PNG_COLOR_MASK_ALPHA 4 + +/* color types. Note that not all combinations are legal */ +#define PNG_COLOR_TYPE_GRAY 0 +#define PNG_COLOR_TYPE_PALETTE (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE) +#define PNG_COLOR_TYPE_RGB (PNG_COLOR_MASK_COLOR) +#define PNG_COLOR_TYPE_RGB_ALPHA (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_ALPHA) +#define PNG_COLOR_TYPE_GRAY_ALPHA (PNG_COLOR_MASK_ALPHA) +/* aliases */ +#define PNG_COLOR_TYPE_RGBA PNG_COLOR_TYPE_RGB_ALPHA +#define PNG_COLOR_TYPE_GA PNG_COLOR_TYPE_GRAY_ALPHA + +/* This is for compression type. PNG 1.0-1.2 only define the single type. */ +#define PNG_COMPRESSION_TYPE_BASE 0 /* Deflate method 8, 32K window */ +#define PNG_COMPRESSION_TYPE_DEFAULT PNG_COMPRESSION_TYPE_BASE + +/* This is for filter type. PNG 1.0-1.2 only define the single type. */ +#define PNG_FILTER_TYPE_BASE 0 /* Single row per-byte filtering */ +#define PNG_INTRAPIXEL_DIFFERENCING 64 /* Used only in MNG datastreams */ +#define PNG_FILTER_TYPE_DEFAULT PNG_FILTER_TYPE_BASE + +/* These are for the interlacing type. These values should NOT be changed. */ +#define PNG_INTERLACE_NONE 0 /* Non-interlaced image */ +#define PNG_INTERLACE_ADAM7 1 /* Adam7 interlacing */ +#define PNG_INTERLACE_LAST 2 /* Not a valid value */ + +/* These are for the oFFs chunk. These values should NOT be changed. */ +#define PNG_OFFSET_PIXEL 0 /* Offset in pixels */ +#define PNG_OFFSET_MICROMETER 1 /* Offset in micrometers (1/10^6 meter) */ +#define PNG_OFFSET_LAST 2 /* Not a valid value */ + +/* These are for the pCAL chunk. These values should NOT be changed. */ +#define PNG_EQUATION_LINEAR 0 /* Linear transformation */ +#define PNG_EQUATION_BASE_E 1 /* Exponential base e transform */ +#define PNG_EQUATION_ARBITRARY 2 /* Arbitrary base exponential transform */ +#define PNG_EQUATION_HYPERBOLIC 3 /* Hyperbolic sine transformation */ +#define PNG_EQUATION_LAST 4 /* Not a valid value */ + +/* These are for the sCAL chunk. These values should NOT be changed. */ +#define PNG_SCALE_UNKNOWN 0 /* unknown unit (image scale) */ +#define PNG_SCALE_METER 1 /* meters per pixel */ +#define PNG_SCALE_RADIAN 2 /* radians per pixel */ +#define PNG_SCALE_LAST 3 /* Not a valid value */ + +/* These are for the pHYs chunk. These values should NOT be changed. */ +#define PNG_RESOLUTION_UNKNOWN 0 /* pixels/unknown unit (aspect ratio) */ +#define PNG_RESOLUTION_METER 1 /* pixels/meter */ +#define PNG_RESOLUTION_LAST 2 /* Not a valid value */ + +/* These are for the sRGB chunk. These values should NOT be changed. */ +#define PNG_sRGB_INTENT_PERCEPTUAL 0 +#define PNG_sRGB_INTENT_RELATIVE 1 +#define PNG_sRGB_INTENT_SATURATION 2 +#define PNG_sRGB_INTENT_ABSOLUTE 3 +#define PNG_sRGB_INTENT_LAST 4 /* Not a valid value */ + +/* This is for text chunks */ +#define PNG_KEYWORD_MAX_LENGTH 79 + +/* Maximum number of entries in PLTE/sPLT/tRNS arrays */ +#define PNG_MAX_PALETTE_LENGTH 256 + +/* These determine if an ancillary chunk's data has been successfully read + * from the PNG header, or if the application has filled in the corresponding + * data in the info_struct to be written into the output file. The values + * of the PNG_INFO_<chunk> defines should NOT be changed. + */ +#define PNG_INFO_gAMA 0x0001 +#define PNG_INFO_sBIT 0x0002 +#define PNG_INFO_cHRM 0x0004 +#define PNG_INFO_PLTE 0x0008 +#define PNG_INFO_tRNS 0x0010 +#define PNG_INFO_bKGD 0x0020 +#define PNG_INFO_hIST 0x0040 +#define PNG_INFO_pHYs 0x0080 +#define PNG_INFO_oFFs 0x0100 +#define PNG_INFO_tIME 0x0200 +#define PNG_INFO_pCAL 0x0400 +#define PNG_INFO_sRGB 0x0800 /* GR-P, 0.96a */ +#define PNG_INFO_iCCP 0x1000 /* ESR, 1.0.6 */ +#define PNG_INFO_sPLT 0x2000 /* ESR, 1.0.6 */ +#define PNG_INFO_sCAL 0x4000 /* ESR, 1.0.6 */ +#define PNG_INFO_IDAT 0x8000L /* ESR, 1.0.6 */ + +/* This is used for the transformation routines, as some of them + * change these values for the row. It also should enable using + * the routines for other purposes. + */ +typedef struct png_row_info_struct +{ + png_uint_32 width; /* width of row */ + png_uint_32 rowbytes; /* number of bytes in row */ + png_byte color_type; /* color type of row */ + png_byte bit_depth; /* bit depth of row */ + png_byte channels; /* number of channels (1, 2, 3, or 4) */ + png_byte pixel_depth; /* bits per pixel (depth * channels) */ +} png_row_info; + +typedef png_row_info FAR * png_row_infop; +typedef png_row_info FAR * FAR * png_row_infopp; + +/* These are the function types for the I/O functions and for the functions + * that allow the user to override the default I/O functions with his or her + * own. The png_error_ptr type should match that of user-supplied warning + * and error functions, while the png_rw_ptr type should match that of the + * user read/write data functions. + */ +typedef struct png_struct_def png_struct; +typedef png_struct FAR * png_structp; + +typedef void (PNGAPI *png_error_ptr) PNGARG((png_structp, png_const_charp)); +typedef void (PNGAPI *png_rw_ptr) PNGARG((png_structp, png_bytep, png_size_t)); +typedef void (PNGAPI *png_flush_ptr) PNGARG((png_structp)); +typedef void (PNGAPI *png_read_status_ptr) PNGARG((png_structp, png_uint_32, + int)); +typedef void (PNGAPI *png_write_status_ptr) PNGARG((png_structp, png_uint_32, + int)); + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +typedef void (PNGAPI *png_progressive_info_ptr) PNGARG((png_structp, png_infop)); +typedef void (PNGAPI *png_progressive_end_ptr) PNGARG((png_structp, png_infop)); +typedef void (PNGAPI *png_progressive_row_ptr) PNGARG((png_structp, png_bytep, + png_uint_32, int)); +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_LEGACY_SUPPORTED) +typedef void (PNGAPI *png_user_transform_ptr) PNGARG((png_structp, + png_row_infop, png_bytep)); +#endif + +#if defined(PNG_USER_CHUNKS_SUPPORTED) +typedef int (PNGAPI *png_user_chunk_ptr) PNGARG((png_structp, png_unknown_chunkp)); +#endif +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) +typedef void (PNGAPI *png_unknown_chunk_ptr) PNGARG((png_structp)); +#endif + +/* Transform masks for the high-level interface */ +#define PNG_TRANSFORM_IDENTITY 0x0000 /* read and write */ +#define PNG_TRANSFORM_STRIP_16 0x0001 /* read only */ +#define PNG_TRANSFORM_STRIP_ALPHA 0x0002 /* read only */ +#define PNG_TRANSFORM_PACKING 0x0004 /* read and write */ +#define PNG_TRANSFORM_PACKSWAP 0x0008 /* read and write */ +#define PNG_TRANSFORM_EXPAND 0x0010 /* read only */ +#define PNG_TRANSFORM_INVERT_MONO 0x0020 /* read and write */ +#define PNG_TRANSFORM_SHIFT 0x0040 /* read and write */ +#define PNG_TRANSFORM_BGR 0x0080 /* read and write */ +#define PNG_TRANSFORM_SWAP_ALPHA 0x0100 /* read and write */ +#define PNG_TRANSFORM_SWAP_ENDIAN 0x0200 /* read and write */ +#define PNG_TRANSFORM_INVERT_ALPHA 0x0400 /* read and write */ +#define PNG_TRANSFORM_STRIP_FILLER 0x0800 /* WRITE only */ + +/* Flags for MNG supported features */ +#define PNG_FLAG_MNG_EMPTY_PLTE 0x01 +#define PNG_FLAG_MNG_FILTER_64 0x04 +#define PNG_ALL_MNG_FEATURES 0x05 + +typedef png_voidp (*png_malloc_ptr) PNGARG((png_structp, png_size_t)); +typedef void (*png_free_ptr) PNGARG((png_structp, png_voidp)); + +/* The structure that holds the information to read and write PNG files. + * The only people who need to care about what is inside of this are the + * people who will be modifying the library for their own special needs. + * It should NOT be accessed directly by an application, except to store + * the jmp_buf. + */ + +struct png_struct_def +{ +#ifdef PNG_SETJMP_SUPPORTED + jmp_buf jmpbuf; /* used in png_error */ +#endif + png_error_ptr error_fn; /* function for printing errors and aborting */ + png_error_ptr warning_fn; /* function for printing warnings */ + png_voidp error_ptr; /* user supplied struct for error functions */ + png_rw_ptr write_data_fn; /* function for writing output data */ + png_rw_ptr read_data_fn; /* function for reading input data */ + png_voidp io_ptr; /* ptr to application struct for I/O functions */ + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) + png_user_transform_ptr read_user_transform_fn; /* user read transform */ +#endif + +#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) + png_user_transform_ptr write_user_transform_fn; /* user write transform */ +#endif + +/* These were added in libpng-1.0.2 */ +#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) + png_voidp user_transform_ptr; /* user supplied struct for user transform */ + png_byte user_transform_depth; /* bit depth of user transformed pixels */ + png_byte user_transform_channels; /* channels in user transformed pixels */ +#endif +#endif + + png_uint_32 mode; /* tells us where we are in the PNG file */ + png_uint_32 flags; /* flags indicating various things to libpng */ + png_uint_32 transformations; /* which transformations to perform */ + + z_stream zstream; /* pointer to decompression structure (below) */ + png_bytep zbuf; /* buffer for zlib */ + png_size_t zbuf_size; /* size of zbuf */ + int zlib_level; /* holds zlib compression level */ + int zlib_method; /* holds zlib compression method */ + int zlib_window_bits; /* holds zlib compression window bits */ + int zlib_mem_level; /* holds zlib compression memory level */ + int zlib_strategy; /* holds zlib compression strategy */ + + png_uint_32 width; /* width of image in pixels */ + png_uint_32 height; /* height of image in pixels */ + png_uint_32 num_rows; /* number of rows in current pass */ + png_uint_32 usr_width; /* width of row at start of write */ + png_uint_32 rowbytes; /* size of row in bytes */ + png_uint_32 irowbytes; /* size of current interlaced row in bytes */ + png_uint_32 iwidth; /* width of current interlaced row in pixels */ + png_uint_32 row_number; /* current row in interlace pass */ + png_bytep prev_row; /* buffer to save previous (unfiltered) row */ + png_bytep row_buf; /* buffer to save current (unfiltered) row */ + png_bytep sub_row; /* buffer to save "sub" row when filtering */ + png_bytep up_row; /* buffer to save "up" row when filtering */ + png_bytep avg_row; /* buffer to save "avg" row when filtering */ + png_bytep paeth_row; /* buffer to save "Paeth" row when filtering */ + png_row_info row_info; /* used for transformation routines */ + + png_uint_32 idat_size; /* current IDAT size for read */ + png_uint_32 crc; /* current chunk CRC value */ + png_colorp palette; /* palette from the input file */ + png_uint_16 num_palette; /* number of color entries in palette */ + png_uint_16 num_trans; /* number of transparency values */ + png_byte chunk_name[5]; /* null-terminated name of current chunk */ + png_byte compression; /* file compression type (always 0) */ + png_byte filter; /* file filter type (always 0) */ + png_byte interlaced; /* PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */ + png_byte pass; /* current interlace pass (0 - 6) */ + png_byte do_filter; /* row filter flags (see PNG_FILTER_ below ) */ + png_byte color_type; /* color type of file */ + png_byte bit_depth; /* bit depth of file */ + png_byte usr_bit_depth; /* bit depth of users row */ + png_byte pixel_depth; /* number of bits per pixel */ + png_byte channels; /* number of channels in file */ + png_byte usr_channels; /* channels at start of write */ + png_byte sig_bytes; /* magic bytes read/written from start of file */ + +#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) +#ifdef PNG_LEGACY_SUPPORTED + png_byte filler; /* filler byte for pixel expansion */ +#else + png_uint_16 filler; /* filler bytes for pixel expansion */ +#endif +#endif + +#if defined(PNG_bKGD_SUPPORTED) + png_byte background_gamma_type; +# ifdef PNG_FLOATING_POINT_SUPPORTED + float background_gamma; +# endif + png_color_16 background; /* background color in screen gamma space */ +#if defined(PNG_READ_GAMMA_SUPPORTED) + png_color_16 background_1; /* background normalized to gamma 1.0 */ +#endif +#endif /* PNG_bKGD_SUPPORTED */ + +#if defined(PNG_WRITE_FLUSH_SUPPORTED) + png_flush_ptr output_flush_fn;/* Function for flushing output */ + png_uint_32 flush_dist; /* how many rows apart to flush, 0 - no flush */ + png_uint_32 flush_rows; /* number of rows written since last flush */ +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + int gamma_shift; /* number of "insignificant" bits 16-bit gamma */ +#ifdef PNG_FLOATING_POINT_SUPPORTED + float gamma; /* file gamma value */ + float screen_gamma; /* screen gamma value (display_exponent) */ +#endif +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + png_bytep gamma_table; /* gamma table for 8-bit depth files */ + png_bytep gamma_from_1; /* converts from 1.0 to screen */ + png_bytep gamma_to_1; /* converts from file to 1.0 */ + png_uint_16pp gamma_16_table; /* gamma table for 16-bit depth files */ + png_uint_16pp gamma_16_from_1; /* converts from 1.0 to screen */ + png_uint_16pp gamma_16_to_1; /* converts from file to 1.0 */ +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_sBIT_SUPPORTED) + png_color_8 sig_bit; /* significant bits in each available channel */ +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) + png_color_8 shift; /* shift for significant bit tranformation */ +#endif + +#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) \ + || defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + png_bytep trans; /* transparency values for paletted files */ + png_color_16 trans_values; /* transparency values for non-paletted files */ +#endif + + png_read_status_ptr read_row_fn; /* called after each row is decoded */ + png_write_status_ptr write_row_fn; /* called after each row is encoded */ +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED + png_progressive_info_ptr info_fn; /* called after header data fully read */ + png_progressive_row_ptr row_fn; /* called after each prog. row is decoded */ + png_progressive_end_ptr end_fn; /* called after image is complete */ + png_bytep save_buffer_ptr; /* current location in save_buffer */ + png_bytep save_buffer; /* buffer for previously read data */ + png_bytep current_buffer_ptr; /* current location in current_buffer */ + png_bytep current_buffer; /* buffer for recently used data */ + png_uint_32 push_length; /* size of current input chunk */ + png_uint_32 skip_length; /* bytes to skip in input data */ + png_size_t save_buffer_size; /* amount of data now in save_buffer */ + png_size_t save_buffer_max; /* total size of save_buffer */ + png_size_t buffer_size; /* total amount of available input data */ + png_size_t current_buffer_size; /* amount of data now in current_buffer */ + int process_mode; /* what push library is currently doing */ + int cur_palette; /* current push library palette index */ + +# if defined(PNG_TEXT_SUPPORTED) + png_size_t current_text_size; /* current size of text input data */ + png_size_t current_text_left; /* how much text left to read in input */ + png_charp current_text; /* current text chunk buffer */ + png_charp current_text_ptr; /* current location in current_text */ +# endif /* PNG_PROGRESSIVE_READ_SUPPORTED && PNG_TEXT_SUPPORTED */ + +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ + +#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__) +/* for the Borland special 64K segment handler */ + png_bytepp offset_table_ptr; + png_bytep offset_table; + png_uint_16 offset_table_number; + png_uint_16 offset_table_count; + png_uint_16 offset_table_count_free; +#endif + +#if defined(PNG_READ_DITHER_SUPPORTED) + png_bytep palette_lookup; /* lookup table for dithering */ + png_bytep dither_index; /* index translation for palette files */ +#endif + +#if defined(PNG_READ_DITHER_SUPPORTED) || defined(PNG_hIST_SUPPORTED) + png_uint_16p hist; /* histogram */ +#endif + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) + png_byte heuristic_method; /* heuristic for row filter selection */ + png_byte num_prev_filters; /* number of weights for previous rows */ + png_bytep prev_filters; /* filter type(s) of previous row(s) */ + png_uint_16p filter_weights; /* weight(s) for previous line(s) */ + png_uint_16p inv_filter_weights; /* 1/weight(s) for previous line(s) */ + png_uint_16p filter_costs; /* relative filter calculation cost */ + png_uint_16p inv_filter_costs; /* 1/relative filter calculation cost */ +#endif + +#if defined(PNG_TIME_RFC1123_SUPPORTED) + png_charp time_buffer; /* String to hold RFC 1123 time text */ +#endif + +/* New members added in libpng-1.0.6 */ + +#ifdef PNG_FREE_ME_SUPPORTED + png_uint_32 free_me; /* flags items libpng is responsible for freeing */ +#endif + +#if defined(PNG_USER_CHUNKS_SUPPORTED) + png_voidp user_chunk_ptr; + png_user_chunk_ptr read_user_chunk_fn; /* user read chunk handler */ +#endif + +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) + int num_chunk_list; + png_bytep chunk_list; +#endif + +/* New members added in libpng-1.0.3 */ +#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + png_byte rgb_to_gray_status; + /* These were changed from png_byte in libpng-1.0.6 */ + png_uint_16 rgb_to_gray_red_coeff; + png_uint_16 rgb_to_gray_green_coeff; + png_uint_16 rgb_to_gray_blue_coeff; +#endif + +/* New member added in libpng-1.0.4 (renamed in 1.0.9) */ +#if defined(PNG_MNG_FEATURES_SUPPORTED) || \ + defined(PNG_READ_EMPTY_PLTE_SUPPORTED) || \ + defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) +/* changed from png_byte to png_uint_32 at version 1.2.0 */ +#ifdef PNG_1_0_X + png_byte mng_features_permitted; +#else + png_uint_32 mng_features_permitted; +#endif /* PNG_1_0_X */ +#endif + +/* New member added in libpng-1.0.7 */ +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + png_fixed_point int_gamma; +#endif + +/* New member added in libpng-1.0.9, ifdef'ed out in 1.0.12, enabled in 1.2.0 */ +#if defined(PNG_MNG_FEATURES_SUPPORTED) + png_byte filter_type; +#endif + +#if defined(PNG_1_0_X) || (defined(PNG_DEBUG) && defined(PNG_USE_PNGGCCRD)) +/* New member added in libpng-1.0.10, ifdef'ed out in 1.2.0 */ + png_uint_32 row_buf_size; +#endif + +/* New members added in libpng-1.2.0 */ +#if !defined(PNG_1_0_X) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) + png_byte mmx_bitdepth_threshold; + png_uint_32 mmx_rowbytes_threshold; + png_uint_32 asm_flags; +#endif + +/* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */ +#ifdef PNG_USER_MEM_SUPPORTED + png_voidp mem_ptr; /* user supplied struct for mem functions */ + png_malloc_ptr malloc_fn; /* function for allocating memory */ + png_free_ptr free_fn; /* function for freeing memory */ +#endif + +/* New member added in libpng-1.0.13 and 1.2.0 */ + png_bytep big_row_buf; /* buffer to save current (unfiltered) row */ + +#if defined(PNG_READ_DITHER_SUPPORTED) +/* The following three members were added at version 1.0.14 and 1.2.4 */ + png_bytep dither_sort; /* working sort array */ + png_bytep index_to_palette; /* where the original index currently is */ + /* in the palette */ + png_bytep palette_to_index; /* which original index points to this */ + /* palette color */ +#endif + +/* New members added in libpng-1.0.16 and 1.2.6 */ + png_byte compression_type; + +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + png_uint_32 user_width_max; + png_uint_32 user_height_max; +#endif + +}; + + +/* This triggers a compiler error in png.c, if png.c and png.h + * do not agree upon the version number. + */ +typedef png_structp version_1_2_8; + +typedef png_struct FAR * FAR * png_structpp; + +/* Here are the function definitions most commonly used. This is not + * the place to find out how to use libpng. See libpng.txt for the + * full explanation, see example.c for the summary. This just provides + * a simple one line description of the use of each function. + */ + +/* Returns the version number of the library */ +extern PNG_EXPORT(png_uint_32,png_access_version_number) PNGARG((void)); + +/* Tell lib we have already handled the first <num_bytes> magic bytes. + * Handling more than 8 bytes from the beginning of the file is an error. + */ +extern PNG_EXPORT(void,png_set_sig_bytes) PNGARG((png_structp png_ptr, + int num_bytes)); + +/* Check sig[start] through sig[start + num_to_check - 1] to see if it's a + * PNG file. Returns zero if the supplied bytes match the 8-byte PNG + * signature, and non-zero otherwise. Having num_to_check == 0 or + * start > 7 will always fail (ie return non-zero). + */ +extern PNG_EXPORT(int,png_sig_cmp) PNGARG((png_bytep sig, png_size_t start, + png_size_t num_to_check)); + +/* Simple signature checking function. This is the same as calling + * png_check_sig(sig, n) := !png_sig_cmp(sig, 0, n). + */ +extern PNG_EXPORT(int,png_check_sig) PNGARG((png_bytep sig, int num)); + +/* Allocate and initialize png_ptr struct for reading, and any other memory. */ +extern PNG_EXPORT(png_structp,png_create_read_struct) + PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn)); + +/* Allocate and initialize png_ptr struct for writing, and any other memory */ +extern PNG_EXPORT(png_structp,png_create_write_struct) + PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn)); + +#ifdef PNG_WRITE_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_compression_buffer_size) + PNGARG((png_structp png_ptr)); +#endif + +#ifdef PNG_WRITE_SUPPORTED +extern PNG_EXPORT(void,png_set_compression_buffer_size) + PNGARG((png_structp png_ptr, png_uint_32 size)); +#endif + +/* Reset the compression stream */ +extern PNG_EXPORT(int,png_reset_zstream) PNGARG((png_structp png_ptr)); + +/* New functions added in libpng-1.0.2 (not enabled by default until 1.2.0) */ +#ifdef PNG_USER_MEM_SUPPORTED +extern PNG_EXPORT(png_structp,png_create_read_struct_2) + PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn)); +extern PNG_EXPORT(png_structp,png_create_write_struct_2) + PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn)); +#endif + +/* Write a PNG chunk - size, type, (optional) data, CRC. */ +extern PNG_EXPORT(void,png_write_chunk) PNGARG((png_structp png_ptr, + png_bytep chunk_name, png_bytep data, png_size_t length)); + +/* Write the start of a PNG chunk - length and chunk name. */ +extern PNG_EXPORT(void,png_write_chunk_start) PNGARG((png_structp png_ptr, + png_bytep chunk_name, png_uint_32 length)); + +/* Write the data of a PNG chunk started with png_write_chunk_start(). */ +extern PNG_EXPORT(void,png_write_chunk_data) PNGARG((png_structp png_ptr, + png_bytep data, png_size_t length)); + +/* Finish a chunk started with png_write_chunk_start() (includes CRC). */ +extern PNG_EXPORT(void,png_write_chunk_end) PNGARG((png_structp png_ptr)); + +/* Allocate and initialize the info structure */ +extern PNG_EXPORT(png_infop,png_create_info_struct) + PNGARG((png_structp png_ptr)); + +/* Initialize the info structure (old interface - DEPRECATED) */ +extern PNG_EXPORT(void,png_info_init) PNGARG((png_infop info_ptr)); +#undef png_info_init +#define png_info_init(info_ptr) png_info_init_3(&info_ptr,\ + png_sizeof(png_info)); +extern PNG_EXPORT(void,png_info_init_3) PNGARG((png_infopp info_ptr, + png_size_t png_info_struct_size)); + +/* Writes all the PNG information before the image. */ +extern PNG_EXPORT(void,png_write_info_before_PLTE) PNGARG((png_structp png_ptr, + png_infop info_ptr)); +extern PNG_EXPORT(void,png_write_info) PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED +/* read the information before the actual image data. */ +extern PNG_EXPORT(void,png_read_info) PNGARG((png_structp png_ptr, + png_infop info_ptr)); +#endif + +#if defined(PNG_TIME_RFC1123_SUPPORTED) +extern PNG_EXPORT(png_charp,png_convert_to_rfc1123) + PNGARG((png_structp png_ptr, png_timep ptime)); +#endif + +#if !defined(_WIN32_WCE) +/* "time.h" functions are not supported on WindowsCE */ +#if defined(PNG_WRITE_tIME_SUPPORTED) +/* convert from a struct tm to png_time */ +extern PNG_EXPORT(void,png_convert_from_struct_tm) PNGARG((png_timep ptime, + struct tm FAR * ttime)); + +/* convert from time_t to png_time. Uses gmtime() */ +extern PNG_EXPORT(void,png_convert_from_time_t) PNGARG((png_timep ptime, + time_t ttime)); +#endif /* PNG_WRITE_tIME_SUPPORTED */ +#endif /* _WIN32_WCE */ + +#if defined(PNG_READ_EXPAND_SUPPORTED) +/* Expand data to 24-bit RGB, or 8-bit grayscale, with alpha if available. */ +extern PNG_EXPORT(void,png_set_expand) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_set_gray_1_2_4_to_8) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_set_palette_to_rgb) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_set_tRNS_to_alpha) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +/* Use blue, green, red order for pixels. */ +extern PNG_EXPORT(void,png_set_bgr) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) +/* Expand the grayscale to 24-bit RGB if necessary. */ +extern PNG_EXPORT(void,png_set_gray_to_rgb) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) +/* Reduce RGB to grayscale. */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_rgb_to_gray) PNGARG((png_structp png_ptr, + int error_action, double red, double green )); +#endif +extern PNG_EXPORT(void,png_set_rgb_to_gray_fixed) PNGARG((png_structp png_ptr, + int error_action, png_fixed_point red, png_fixed_point green )); +extern PNG_EXPORT(png_byte,png_get_rgb_to_gray_status) PNGARG((png_structp + png_ptr)); +#endif + +extern PNG_EXPORT(void,png_build_grayscale_palette) PNGARG((int bit_depth, + png_colorp palette)); + +#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED) +extern PNG_EXPORT(void,png_set_strip_alpha) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) +extern PNG_EXPORT(void,png_set_swap_alpha) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) +extern PNG_EXPORT(void,png_set_invert_alpha) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) +/* Add a filler byte to 8-bit Gray or 24-bit RGB images. */ +extern PNG_EXPORT(void,png_set_filler) PNGARG((png_structp png_ptr, + png_uint_32 filler, int flags)); +/* The values of the PNG_FILLER_ defines should NOT be changed */ +#define PNG_FILLER_BEFORE 0 +#define PNG_FILLER_AFTER 1 +/* Add an alpha byte to 8-bit Gray or 24-bit RGB images. */ +#if !defined(PNG_1_0_X) +extern PNG_EXPORT(void,png_set_add_alpha) PNGARG((png_structp png_ptr, + png_uint_32 filler, int flags)); +#endif +#endif /* PNG_READ_FILLER_SUPPORTED || PNG_WRITE_FILLER_SUPPORTED */ + +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +/* Swap bytes in 16-bit depth files. */ +extern PNG_EXPORT(void,png_set_swap) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) +/* Use 1 byte per pixel in 1, 2, or 4-bit depth files. */ +extern PNG_EXPORT(void,png_set_packing) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) || defined(PNG_WRITE_PACKSWAP_SUPPORTED) +/* Swap packing order of pixels in bytes. */ +extern PNG_EXPORT(void,png_set_packswap) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) +/* Converts files to legal bit depths. */ +extern PNG_EXPORT(void,png_set_shift) PNGARG((png_structp png_ptr, + png_color_8p true_bits)); +#endif + +#if defined(PNG_READ_INTERLACING_SUPPORTED) || \ + defined(PNG_WRITE_INTERLACING_SUPPORTED) +/* Have the code handle the interlacing. Returns the number of passes. */ +extern PNG_EXPORT(int,png_set_interlace_handling) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) +/* Invert monochrome files */ +extern PNG_EXPORT(void,png_set_invert_mono) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) +/* Handle alpha and tRNS by replacing with a background color. */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_background) PNGARG((png_structp png_ptr, + png_color_16p background_color, int background_gamma_code, + int need_expand, double background_gamma)); +#endif +#define PNG_BACKGROUND_GAMMA_UNKNOWN 0 +#define PNG_BACKGROUND_GAMMA_SCREEN 1 +#define PNG_BACKGROUND_GAMMA_FILE 2 +#define PNG_BACKGROUND_GAMMA_UNIQUE 3 +#endif + +#if defined(PNG_READ_16_TO_8_SUPPORTED) +/* strip the second byte of information from a 16-bit depth file. */ +extern PNG_EXPORT(void,png_set_strip_16) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_DITHER_SUPPORTED) +/* Turn on dithering, and reduce the palette to the number of colors available. */ +extern PNG_EXPORT(void,png_set_dither) PNGARG((png_structp png_ptr, + png_colorp palette, int num_palette, int maximum_colors, + png_uint_16p histogram, int full_dither)); +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) +/* Handle gamma correction. Screen_gamma=(display_exponent) */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_gamma) PNGARG((png_structp png_ptr, + double screen_gamma, double default_file_gamma)); +#endif +#endif + +#if defined(PNG_READ_EMPTY_PLTE_SUPPORTED) || \ + defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) +/* Permit or disallow empty PLTE (0: not permitted, 1: permitted) */ +/* Deprecated and will be removed. Use png_permit_mng_features() instead. */ +extern PNG_EXPORT(void,png_permit_empty_plte) PNGARG((png_structp png_ptr, + int empty_plte_permitted)); +#endif + +#if defined(PNG_WRITE_FLUSH_SUPPORTED) +/* Set how many lines between output flushes - 0 for no flushing */ +extern PNG_EXPORT(void,png_set_flush) PNGARG((png_structp png_ptr, int nrows)); +/* Flush the current PNG output buffer */ +extern PNG_EXPORT(void,png_write_flush) PNGARG((png_structp png_ptr)); +#endif + +/* optional update palette with requested transformations */ +extern PNG_EXPORT(void,png_start_read_image) PNGARG((png_structp png_ptr)); + +/* optional call to update the users info structure */ +extern PNG_EXPORT(void,png_read_update_info) PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED +/* read one or more rows of image data. */ +extern PNG_EXPORT(void,png_read_rows) PNGARG((png_structp png_ptr, + png_bytepp row, png_bytepp display_row, png_uint_32 num_rows)); +#endif + +#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED +/* read a row of data. */ +extern PNG_EXPORT(void,png_read_row) PNGARG((png_structp png_ptr, + png_bytep row, + png_bytep display_row)); +#endif + +#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED +/* read the whole image into memory at once. */ +extern PNG_EXPORT(void,png_read_image) PNGARG((png_structp png_ptr, + png_bytepp image)); +#endif + +/* write a row of image data */ +extern PNG_EXPORT(void,png_write_row) PNGARG((png_structp png_ptr, + png_bytep row)); + +/* write a few rows of image data */ +extern PNG_EXPORT(void,png_write_rows) PNGARG((png_structp png_ptr, + png_bytepp row, png_uint_32 num_rows)); + +/* write the image data */ +extern PNG_EXPORT(void,png_write_image) PNGARG((png_structp png_ptr, + png_bytepp image)); + +/* writes the end of the PNG file. */ +extern PNG_EXPORT(void,png_write_end) PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED +/* read the end of the PNG file. */ +extern PNG_EXPORT(void,png_read_end) PNGARG((png_structp png_ptr, + png_infop info_ptr)); +#endif + +/* free any memory associated with the png_info_struct */ +extern PNG_EXPORT(void,png_destroy_info_struct) PNGARG((png_structp png_ptr, + png_infopp info_ptr_ptr)); + +/* free any memory associated with the png_struct and the png_info_structs */ +extern PNG_EXPORT(void,png_destroy_read_struct) PNGARG((png_structpp + png_ptr_ptr, png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr)); + +/* free all memory used by the read (old method - NOT DLL EXPORTED) */ +extern void png_read_destroy PNGARG((png_structp png_ptr, png_infop info_ptr, + png_infop end_info_ptr)); + +/* free any memory associated with the png_struct and the png_info_structs */ +extern PNG_EXPORT(void,png_destroy_write_struct) + PNGARG((png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)); + +/* free any memory used in png_ptr struct (old method - NOT DLL EXPORTED) */ +extern void png_write_destroy PNGARG((png_structp png_ptr)); + +/* set the libpng method of handling chunk CRC errors */ +extern PNG_EXPORT(void,png_set_crc_action) PNGARG((png_structp png_ptr, + int crit_action, int ancil_action)); + +/* Values for png_set_crc_action() to say how to handle CRC errors in + * ancillary and critical chunks, and whether to use the data contained + * therein. Note that it is impossible to "discard" data in a critical + * chunk. For versions prior to 0.90, the action was always error/quit, + * whereas in version 0.90 and later, the action for CRC errors in ancillary + * chunks is warn/discard. These values should NOT be changed. + * + * value action:critical action:ancillary + */ +#define PNG_CRC_DEFAULT 0 /* error/quit warn/discard data */ +#define PNG_CRC_ERROR_QUIT 1 /* error/quit error/quit */ +#define PNG_CRC_WARN_DISCARD 2 /* (INVALID) warn/discard data */ +#define PNG_CRC_WARN_USE 3 /* warn/use data warn/use data */ +#define PNG_CRC_QUIET_USE 4 /* quiet/use data quiet/use data */ +#define PNG_CRC_NO_CHANGE 5 /* use current value use current value */ + +/* These functions give the user control over the scan-line filtering in + * libpng and the compression methods used by zlib. These functions are + * mainly useful for testing, as the defaults should work with most users. + * Those users who are tight on memory or want faster performance at the + * expense of compression can modify them. See the compression library + * header file (zlib.h) for an explination of the compression functions. + */ + +/* set the filtering method(s) used by libpng. Currently, the only valid + * value for "method" is 0. + */ +extern PNG_EXPORT(void,png_set_filter) PNGARG((png_structp png_ptr, int method, + int filters)); + +/* Flags for png_set_filter() to say which filters to use. The flags + * are chosen so that they don't conflict with real filter types + * below, in case they are supplied instead of the #defined constants. + * These values should NOT be changed. + */ +#define PNG_NO_FILTERS 0x00 +#define PNG_FILTER_NONE 0x08 +#define PNG_FILTER_SUB 0x10 +#define PNG_FILTER_UP 0x20 +#define PNG_FILTER_AVG 0x40 +#define PNG_FILTER_PAETH 0x80 +#define PNG_ALL_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP | \ + PNG_FILTER_AVG | PNG_FILTER_PAETH) + +/* Filter values (not flags) - used in pngwrite.c, pngwutil.c for now. + * These defines should NOT be changed. + */ +#define PNG_FILTER_VALUE_NONE 0 +#define PNG_FILTER_VALUE_SUB 1 +#define PNG_FILTER_VALUE_UP 2 +#define PNG_FILTER_VALUE_AVG 3 +#define PNG_FILTER_VALUE_PAETH 4 +#define PNG_FILTER_VALUE_LAST 5 + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) /* EXPERIMENTAL */ +/* The "heuristic_method" is given by one of the PNG_FILTER_HEURISTIC_ + * defines, either the default (minimum-sum-of-absolute-differences), or + * the experimental method (weighted-minimum-sum-of-absolute-differences). + * + * Weights are factors >= 1.0, indicating how important it is to keep the + * filter type consistent between rows. Larger numbers mean the current + * filter is that many times as likely to be the same as the "num_weights" + * previous filters. This is cumulative for each previous row with a weight. + * There needs to be "num_weights" values in "filter_weights", or it can be + * NULL if the weights aren't being specified. Weights have no influence on + * the selection of the first row filter. Well chosen weights can (in theory) + * improve the compression for a given image. + * + * Costs are factors >= 1.0 indicating the relative decoding costs of a + * filter type. Higher costs indicate more decoding expense, and are + * therefore less likely to be selected over a filter with lower computational + * costs. There needs to be a value in "filter_costs" for each valid filter + * type (given by PNG_FILTER_VALUE_LAST), or it can be NULL if you aren't + * setting the costs. Costs try to improve the speed of decompression without + * unduly increasing the compressed image size. + * + * A negative weight or cost indicates the default value is to be used, and + * values in the range [0.0, 1.0) indicate the value is to remain unchanged. + * The default values for both weights and costs are currently 1.0, but may + * change if good general weighting/cost heuristics can be found. If both + * the weights and costs are set to 1.0, this degenerates the WEIGHTED method + * to the UNWEIGHTED method, but with added encoding time/computation. + */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_filter_heuristics) PNGARG((png_structp png_ptr, + int heuristic_method, int num_weights, png_doublep filter_weights, + png_doublep filter_costs)); +#endif +#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ + +/* Heuristic used for row filter selection. These defines should NOT be + * changed. + */ +#define PNG_FILTER_HEURISTIC_DEFAULT 0 /* Currently "UNWEIGHTED" */ +#define PNG_FILTER_HEURISTIC_UNWEIGHTED 1 /* Used by libpng < 0.95 */ +#define PNG_FILTER_HEURISTIC_WEIGHTED 2 /* Experimental feature */ +#define PNG_FILTER_HEURISTIC_LAST 3 /* Not a valid value */ + +/* Set the library compression level. Currently, valid values range from + * 0 - 9, corresponding directly to the zlib compression levels 0 - 9 + * (0 - no compression, 9 - "maximal" compression). Note that tests have + * shown that zlib compression levels 3-6 usually perform as well as level 9 + * for PNG images, and do considerably fewer caclulations. In the future, + * these values may not correspond directly to the zlib compression levels. + */ +extern PNG_EXPORT(void,png_set_compression_level) PNGARG((png_structp png_ptr, + int level)); + +extern PNG_EXPORT(void,png_set_compression_mem_level) + PNGARG((png_structp png_ptr, int mem_level)); + +extern PNG_EXPORT(void,png_set_compression_strategy) + PNGARG((png_structp png_ptr, int strategy)); + +extern PNG_EXPORT(void,png_set_compression_window_bits) + PNGARG((png_structp png_ptr, int window_bits)); + +extern PNG_EXPORT(void,png_set_compression_method) PNGARG((png_structp png_ptr, + int method)); + +/* These next functions are called for input/output, memory, and error + * handling. They are in the file pngrio.c, pngwio.c, and pngerror.c, + * and call standard C I/O routines such as fread(), fwrite(), and + * fprintf(). These functions can be made to use other I/O routines + * at run time for those applications that need to handle I/O in a + * different manner by calling png_set_???_fn(). See libpng.txt for + * more information. + */ + +#if !defined(PNG_NO_STDIO) +/* Initialize the input/output for the PNG file to the default functions. */ +extern PNG_EXPORT(void,png_init_io) PNGARG((png_structp png_ptr, png_FILE_p fp)); +#endif + +/* Replace the (error and abort), and warning functions with user + * supplied functions. If no messages are to be printed you must still + * write and use replacement functions. The replacement error_fn should + * still do a longjmp to the last setjmp location if you are using this + * method of error handling. If error_fn or warning_fn is NULL, the + * default function will be used. + */ + +extern PNG_EXPORT(void,png_set_error_fn) PNGARG((png_structp png_ptr, + png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warning_fn)); + +/* Return the user pointer associated with the error functions */ +extern PNG_EXPORT(png_voidp,png_get_error_ptr) PNGARG((png_structp png_ptr)); + +/* Replace the default data output functions with a user supplied one(s). + * If buffered output is not used, then output_flush_fn can be set to NULL. + * If PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile time + * output_flush_fn will be ignored (and thus can be NULL). + */ +extern PNG_EXPORT(void,png_set_write_fn) PNGARG((png_structp png_ptr, + png_voidp io_ptr, png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn)); + +/* Replace the default data input function with a user supplied one. */ +extern PNG_EXPORT(void,png_set_read_fn) PNGARG((png_structp png_ptr, + png_voidp io_ptr, png_rw_ptr read_data_fn)); + +/* Return the user pointer associated with the I/O functions */ +extern PNG_EXPORT(png_voidp,png_get_io_ptr) PNGARG((png_structp png_ptr)); + +extern PNG_EXPORT(void,png_set_read_status_fn) PNGARG((png_structp png_ptr, + png_read_status_ptr read_row_fn)); + +extern PNG_EXPORT(void,png_set_write_status_fn) PNGARG((png_structp png_ptr, + png_write_status_ptr write_row_fn)); + +#ifdef PNG_USER_MEM_SUPPORTED +/* Replace the default memory allocation functions with user supplied one(s). */ +extern PNG_EXPORT(void,png_set_mem_fn) PNGARG((png_structp png_ptr, + png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn)); +/* Return the user pointer associated with the memory functions */ +extern PNG_EXPORT(png_voidp,png_get_mem_ptr) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_LEGACY_SUPPORTED) +extern PNG_EXPORT(void,png_set_read_user_transform_fn) PNGARG((png_structp + png_ptr, png_user_transform_ptr read_user_transform_fn)); +#endif + +#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_LEGACY_SUPPORTED) +extern PNG_EXPORT(void,png_set_write_user_transform_fn) PNGARG((png_structp + png_ptr, png_user_transform_ptr write_user_transform_fn)); +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_LEGACY_SUPPORTED) +extern PNG_EXPORT(void,png_set_user_transform_info) PNGARG((png_structp + png_ptr, png_voidp user_transform_ptr, int user_transform_depth, + int user_transform_channels)); +/* Return the user pointer associated with the user transform functions */ +extern PNG_EXPORT(png_voidp,png_get_user_transform_ptr) + PNGARG((png_structp png_ptr)); +#endif + +#ifdef PNG_USER_CHUNKS_SUPPORTED +extern PNG_EXPORT(void,png_set_read_user_chunk_fn) PNGARG((png_structp png_ptr, + png_voidp user_chunk_ptr, png_user_chunk_ptr read_user_chunk_fn)); +extern PNG_EXPORT(png_voidp,png_get_user_chunk_ptr) PNGARG((png_structp + png_ptr)); +#endif + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +/* Sets the function callbacks for the push reader, and a pointer to a + * user-defined structure available to the callback functions. + */ +extern PNG_EXPORT(void,png_set_progressive_read_fn) PNGARG((png_structp png_ptr, + png_voidp progressive_ptr, + png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn, + png_progressive_end_ptr end_fn)); + +/* returns the user pointer associated with the push read functions */ +extern PNG_EXPORT(png_voidp,png_get_progressive_ptr) + PNGARG((png_structp png_ptr)); + +/* function to be called when data becomes available */ +extern PNG_EXPORT(void,png_process_data) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_bytep buffer, png_size_t buffer_size)); + +/* function that combines rows. Not very much different than the + * png_combine_row() call. Is this even used????? + */ +extern PNG_EXPORT(void,png_progressive_combine_row) PNGARG((png_structp png_ptr, + png_bytep old_row, png_bytep new_row)); +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ + +extern PNG_EXPORT(png_voidp,png_malloc) PNGARG((png_structp png_ptr, + png_uint_32 size)); + +#if defined(PNG_1_0_X) +# define png_malloc_warn png_malloc +#else +/* Added at libpng version 1.2.4 */ +extern PNG_EXPORT(png_voidp,png_malloc_warn) PNGARG((png_structp png_ptr, + png_uint_32 size)); +#endif + +/* frees a pointer allocated by png_malloc() */ +extern PNG_EXPORT(void,png_free) PNGARG((png_structp png_ptr, png_voidp ptr)); + +#if defined(PNG_1_0_X) +/* Function to allocate memory for zlib. */ +extern PNG_EXPORT(voidpf,png_zalloc) PNGARG((voidpf png_ptr, uInt items, + uInt size)); + +/* Function to free memory for zlib */ +extern PNG_EXPORT(void,png_zfree) PNGARG((voidpf png_ptr, voidpf ptr)); +#endif + +/* Free data that was allocated internally */ +extern PNG_EXPORT(void,png_free_data) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 free_me, int num)); +#ifdef PNG_FREE_ME_SUPPORTED +/* Reassign responsibility for freeing existing data, whether allocated + * by libpng or by the application */ +extern PNG_EXPORT(void,png_data_freer) PNGARG((png_structp png_ptr, + png_infop info_ptr, int freer, png_uint_32 mask)); +#endif +/* assignments for png_data_freer */ +#define PNG_DESTROY_WILL_FREE_DATA 1 +#define PNG_SET_WILL_FREE_DATA 1 +#define PNG_USER_WILL_FREE_DATA 2 +/* Flags for png_ptr->free_me and info_ptr->free_me */ +#define PNG_FREE_HIST 0x0008 +#define PNG_FREE_ICCP 0x0010 +#define PNG_FREE_SPLT 0x0020 +#define PNG_FREE_ROWS 0x0040 +#define PNG_FREE_PCAL 0x0080 +#define PNG_FREE_SCAL 0x0100 +#define PNG_FREE_UNKN 0x0200 +#define PNG_FREE_LIST 0x0400 +#define PNG_FREE_PLTE 0x1000 +#define PNG_FREE_TRNS 0x2000 +#define PNG_FREE_TEXT 0x4000 +#define PNG_FREE_ALL 0x7fff +#define PNG_FREE_MUL 0x4220 /* PNG_FREE_SPLT|PNG_FREE_TEXT|PNG_FREE_UNKN */ + +#ifdef PNG_USER_MEM_SUPPORTED +extern PNG_EXPORT(png_voidp,png_malloc_default) PNGARG((png_structp png_ptr, + png_uint_32 size)); +extern PNG_EXPORT(void,png_free_default) PNGARG((png_structp png_ptr, + png_voidp ptr)); +#endif + +extern PNG_EXPORT(png_voidp,png_memcpy_check) PNGARG((png_structp png_ptr, + png_voidp s1, png_voidp s2, png_uint_32 size)); + +extern PNG_EXPORT(png_voidp,png_memset_check) PNGARG((png_structp png_ptr, + png_voidp s1, int value, png_uint_32 size)); + +#if defined(USE_FAR_KEYWORD) /* memory model conversion function */ +extern void *png_far_to_near PNGARG((png_structp png_ptr,png_voidp ptr, + int check)); +#endif /* USE_FAR_KEYWORD */ + +/* Fatal error in PNG image of libpng - can't continue */ +extern PNG_EXPORT(void,png_error) PNGARG((png_structp png_ptr, + png_const_charp error_message)); + +/* The same, but the chunk name is prepended to the error string. */ +extern PNG_EXPORT(void,png_chunk_error) PNGARG((png_structp png_ptr, + png_const_charp error_message)); + +/* Non-fatal error in libpng. Can continue, but may have a problem. */ +extern PNG_EXPORT(void,png_warning) PNGARG((png_structp png_ptr, + png_const_charp warning_message)); + +/* Non-fatal error in libpng, chunk name is prepended to message. */ +extern PNG_EXPORT(void,png_chunk_warning) PNGARG((png_structp png_ptr, + png_const_charp warning_message)); + +/* The png_set_<chunk> functions are for storing values in the png_info_struct. + * Similarly, the png_get_<chunk> calls are used to read values from the + * png_info_struct, either storing the parameters in the passed variables, or + * setting pointers into the png_info_struct where the data is stored. The + * png_get_<chunk> functions return a non-zero value if the data was available + * in info_ptr, or return zero and do not change any of the parameters if the + * data was not available. + * + * These functions should be used instead of directly accessing png_info + * to avoid problems with future changes in the size and internal layout of + * png_info_struct. + */ +/* Returns "flag" if chunk data is valid in info_ptr. */ +extern PNG_EXPORT(png_uint_32,png_get_valid) PNGARG((png_structp png_ptr, +png_infop info_ptr, png_uint_32 flag)); + +/* Returns number of bytes needed to hold a transformed row. */ +extern PNG_EXPORT(png_uint_32,png_get_rowbytes) PNGARG((png_structp png_ptr, +png_infop info_ptr)); + +#if defined(PNG_INFO_IMAGE_SUPPORTED) +/* Returns row_pointers, which is an array of pointers to scanlines that was +returned from png_read_png(). */ +extern PNG_EXPORT(png_bytepp,png_get_rows) PNGARG((png_structp png_ptr, +png_infop info_ptr)); +/* Set row_pointers, which is an array of pointers to scanlines for use +by png_write_png(). */ +extern PNG_EXPORT(void,png_set_rows) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_bytepp row_pointers)); +#endif + +/* Returns number of color channels in image. */ +extern PNG_EXPORT(png_byte,png_get_channels) PNGARG((png_structp png_ptr, +png_infop info_ptr)); + +#ifdef PNG_EASY_ACCESS_SUPPORTED +/* Returns image width in pixels. */ +extern PNG_EXPORT(png_uint_32, png_get_image_width) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image height in pixels. */ +extern PNG_EXPORT(png_uint_32, png_get_image_height) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image bit_depth. */ +extern PNG_EXPORT(png_byte, png_get_bit_depth) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image color_type. */ +extern PNG_EXPORT(png_byte, png_get_color_type) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image filter_type. */ +extern PNG_EXPORT(png_byte, png_get_filter_type) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image interlace_type. */ +extern PNG_EXPORT(png_byte, png_get_interlace_type) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image compression_type. */ +extern PNG_EXPORT(png_byte, png_get_compression_type) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image resolution in pixels per meter, from pHYs chunk data. */ +extern PNG_EXPORT(png_uint_32, png_get_pixels_per_meter) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +extern PNG_EXPORT(png_uint_32, png_get_x_pixels_per_meter) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +extern PNG_EXPORT(png_uint_32, png_get_y_pixels_per_meter) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns pixel aspect ratio, computed from pHYs chunk data. */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(float, png_get_pixel_aspect_ratio) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +#endif + +/* Returns image x, y offset in pixels or microns, from oFFs chunk data. */ +extern PNG_EXPORT(png_int_32, png_get_x_offset_pixels) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +extern PNG_EXPORT(png_int_32, png_get_y_offset_pixels) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +extern PNG_EXPORT(png_int_32, png_get_x_offset_microns) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +extern PNG_EXPORT(png_int_32, png_get_y_offset_microns) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +#endif /* PNG_EASY_ACCESS_SUPPORTED */ + +/* Returns pointer to signature string read from PNG header */ +extern PNG_EXPORT(png_bytep,png_get_signature) PNGARG((png_structp png_ptr, +png_infop info_ptr)); + +#if defined(PNG_bKGD_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_bKGD) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_color_16p *background)); +#endif + +#if defined(PNG_bKGD_SUPPORTED) +extern PNG_EXPORT(void,png_set_bKGD) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_color_16p background)); +#endif + +#if defined(PNG_cHRM_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_cHRM) PNGARG((png_structp png_ptr, + png_infop info_ptr, double *white_x, double *white_y, double *red_x, + double *red_y, double *green_x, double *green_y, double *blue_x, + double *blue_y)); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_cHRM_fixed) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_fixed_point *int_white_x, png_fixed_point + *int_white_y, png_fixed_point *int_red_x, png_fixed_point *int_red_y, + png_fixed_point *int_green_x, png_fixed_point *int_green_y, png_fixed_point + *int_blue_x, png_fixed_point *int_blue_y)); +#endif +#endif + +#if defined(PNG_cHRM_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_cHRM) PNGARG((png_structp png_ptr, + png_infop info_ptr, double white_x, double white_y, double red_x, + double red_y, double green_x, double green_y, double blue_x, double blue_y)); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_cHRM_fixed) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_fixed_point int_white_x, png_fixed_point int_white_y, + png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point + int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x, + png_fixed_point int_blue_y)); +#endif +#endif + +#if defined(PNG_gAMA_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_gAMA) PNGARG((png_structp png_ptr, + png_infop info_ptr, double *file_gamma)); +#endif +extern PNG_EXPORT(png_uint_32,png_get_gAMA_fixed) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_fixed_point *int_file_gamma)); +#endif + +#if defined(PNG_gAMA_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_gAMA) PNGARG((png_structp png_ptr, + png_infop info_ptr, double file_gamma)); +#endif +extern PNG_EXPORT(void,png_set_gAMA_fixed) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_fixed_point int_file_gamma)); +#endif + +#if defined(PNG_hIST_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_hIST) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_16p *hist)); +#endif + +#if defined(PNG_hIST_SUPPORTED) +extern PNG_EXPORT(void,png_set_hIST) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_16p hist)); +#endif + +extern PNG_EXPORT(png_uint_32,png_get_IHDR) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 *width, png_uint_32 *height, + int *bit_depth, int *color_type, int *interlace_method, + int *compression_method, int *filter_method)); + +extern PNG_EXPORT(void,png_set_IHDR) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_method, int compression_method, + int filter_method)); + +#if defined(PNG_oFFs_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_oFFs) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_int_32 *offset_x, png_int_32 *offset_y, + int *unit_type)); +#endif + +#if defined(PNG_oFFs_SUPPORTED) +extern PNG_EXPORT(void,png_set_oFFs) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_int_32 offset_x, png_int_32 offset_y, + int unit_type)); +#endif + +#if defined(PNG_pCAL_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_pCAL) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_charp *purpose, png_int_32 *X0, png_int_32 *X1, + int *type, int *nparams, png_charp *units, png_charpp *params)); +#endif + +#if defined(PNG_pCAL_SUPPORTED) +extern PNG_EXPORT(void,png_set_pCAL) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_charp purpose, png_int_32 X0, png_int_32 X1, + int type, int nparams, png_charp units, png_charpp params)); +#endif + +#if defined(PNG_pHYs_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_pHYs) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)); +#endif + +#if defined(PNG_pHYs_SUPPORTED) +extern PNG_EXPORT(void,png_set_pHYs) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 res_x, png_uint_32 res_y, int unit_type)); +#endif + +extern PNG_EXPORT(png_uint_32,png_get_PLTE) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_colorp *palette, int *num_palette)); + +extern PNG_EXPORT(void,png_set_PLTE) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_colorp palette, int num_palette)); + +#if defined(PNG_sBIT_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_sBIT) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_color_8p *sig_bit)); +#endif + +#if defined(PNG_sBIT_SUPPORTED) +extern PNG_EXPORT(void,png_set_sBIT) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_color_8p sig_bit)); +#endif + +#if defined(PNG_sRGB_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_sRGB) PNGARG((png_structp png_ptr, + png_infop info_ptr, int *intent)); +#endif + +#if defined(PNG_sRGB_SUPPORTED) +extern PNG_EXPORT(void,png_set_sRGB) PNGARG((png_structp png_ptr, + png_infop info_ptr, int intent)); +extern PNG_EXPORT(void,png_set_sRGB_gAMA_and_cHRM) PNGARG((png_structp png_ptr, + png_infop info_ptr, int intent)); +#endif + +#if defined(PNG_iCCP_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_iCCP) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_charpp name, int *compression_type, + png_charpp profile, png_uint_32 *proflen)); + /* Note to maintainer: profile should be png_bytepp */ +#endif + +#if defined(PNG_iCCP_SUPPORTED) +extern PNG_EXPORT(void,png_set_iCCP) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_charp name, int compression_type, + png_charp profile, png_uint_32 proflen)); + /* Note to maintainer: profile should be png_bytep */ +#endif + +#if defined(PNG_sPLT_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_sPLT) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_sPLT_tpp entries)); +#endif + +#if defined(PNG_sPLT_SUPPORTED) +extern PNG_EXPORT(void,png_set_sPLT) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_sPLT_tp entries, int nentries)); +#endif + +#if defined(PNG_TEXT_SUPPORTED) +/* png_get_text also returns the number of text chunks in *num_text */ +extern PNG_EXPORT(png_uint_32,png_get_text) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_textp *text_ptr, int *num_text)); +#endif + +/* + * Note while png_set_text() will accept a structure whose text, + * language, and translated keywords are NULL pointers, the structure + * returned by png_get_text will always contain regular + * zero-terminated C strings. They might be empty strings but + * they will never be NULL pointers. + */ + +#if defined(PNG_TEXT_SUPPORTED) +extern PNG_EXPORT(void,png_set_text) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_textp text_ptr, int num_text)); +#endif + +#if defined(PNG_tIME_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_tIME) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_timep *mod_time)); +#endif + +#if defined(PNG_tIME_SUPPORTED) +extern PNG_EXPORT(void,png_set_tIME) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_timep mod_time)); +#endif + +#if defined(PNG_tRNS_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_tRNS) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_bytep *trans, int *num_trans, + png_color_16p *trans_values)); +#endif + +#if defined(PNG_tRNS_SUPPORTED) +extern PNG_EXPORT(void,png_set_tRNS) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_bytep trans, int num_trans, + png_color_16p trans_values)); +#endif + +#if defined(PNG_tRNS_SUPPORTED) +#endif + +#if defined(PNG_sCAL_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_sCAL) PNGARG((png_structp png_ptr, + png_infop info_ptr, int *unit, double *width, double *height)); +#else +#ifdef PNG_FIXED_POINT_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_sCAL_s) PNGARG((png_structp png_ptr, + png_infop info_ptr, int *unit, png_charpp swidth, png_charpp sheight)); +#endif +#endif +#endif /* PNG_sCAL_SUPPORTED */ + +#if defined(PNG_sCAL_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_sCAL) PNGARG((png_structp png_ptr, + png_infop info_ptr, int unit, double width, double height)); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_sCAL_s) PNGARG((png_structp png_ptr, + png_infop info_ptr, int unit, png_charp swidth, png_charp sheight)); +#endif +#endif /* PNG_sCAL_SUPPORTED || PNG_WRITE_sCAL_SUPPORTED */ + +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) +/* provide a list of chunks and how they are to be handled, if the built-in + handling or default unknown chunk handling is not desired. Any chunks not + listed will be handled in the default manner. The IHDR and IEND chunks + must not be listed. + keep = 0: follow default behavour + = 1: do not keep + = 2: keep only if safe-to-copy + = 3: keep even if unsafe-to-copy +*/ +extern PNG_EXPORT(void, png_set_keep_unknown_chunks) PNGARG((png_structp + png_ptr, int keep, png_bytep chunk_list, int num_chunks)); +extern PNG_EXPORT(void, png_set_unknown_chunks) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_unknown_chunkp unknowns, int num_unknowns)); +extern PNG_EXPORT(void, png_set_unknown_chunk_location) + PNGARG((png_structp png_ptr, png_infop info_ptr, int chunk, int location)); +extern PNG_EXPORT(png_uint_32,png_get_unknown_chunks) PNGARG((png_structp + png_ptr, png_infop info_ptr, png_unknown_chunkpp entries)); +#endif +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +PNG_EXPORT(int,png_handle_as_unknown) PNGARG((png_structp png_ptr, png_bytep + chunk_name)); +#endif + +/* Png_free_data() will turn off the "valid" flag for anything it frees. + If you need to turn it off for a chunk that your application has freed, + you can use png_set_invalid(png_ptr, info_ptr, PNG_INFO_CHNK); */ +extern PNG_EXPORT(void, png_set_invalid) PNGARG((png_structp png_ptr, + png_infop info_ptr, int mask)); + +#if defined(PNG_INFO_IMAGE_SUPPORTED) +/* The "params" pointer is currently not used and is for future expansion. */ +extern PNG_EXPORT(void, png_read_png) PNGARG((png_structp png_ptr, + png_infop info_ptr, + int transforms, + png_voidp params)); +extern PNG_EXPORT(void, png_write_png) PNGARG((png_structp png_ptr, + png_infop info_ptr, + int transforms, + png_voidp params)); +#endif + +/* Define PNG_DEBUG at compile time for debugging information. Higher + * numbers for PNG_DEBUG mean more debugging information. This has + * only been added since version 0.95 so it is not implemented throughout + * libpng yet, but more support will be added as needed. + */ +#ifdef PNG_DEBUG +#if (PNG_DEBUG > 0) +#if !defined(PNG_DEBUG_FILE) && defined(_MSC_VER) +#include <crtdbg.h> +#if (PNG_DEBUG > 1) +#define png_debug(l,m) _RPT0(_CRT_WARN,m) +#define png_debug1(l,m,p1) _RPT1(_CRT_WARN,m,p1) +#define png_debug2(l,m,p1,p2) _RPT2(_CRT_WARN,m,p1,p2) +#endif +#else /* PNG_DEBUG_FILE || !_MSC_VER */ +#ifndef PNG_DEBUG_FILE +#define PNG_DEBUG_FILE stderr +#endif /* PNG_DEBUG_FILE */ +#if (PNG_DEBUG > 1) +#define png_debug(l,m) \ +{ \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s"m,(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":"")))); \ +} +#define png_debug1(l,m,p1) \ +{ \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s"m,(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1); \ +} +#define png_debug2(l,m,p1,p2) \ +{ \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s"m,(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1,p2); \ +} +#endif /* (PNG_DEBUG > 1) */ +#endif /* _MSC_VER */ +#endif /* (PNG_DEBUG > 0) */ +#endif /* PNG_DEBUG */ +#ifndef png_debug +#define png_debug(l, m) +#endif +#ifndef png_debug1 +#define png_debug1(l, m, p1) +#endif +#ifndef png_debug2 +#define png_debug2(l, m, p1, p2) +#endif + +extern PNG_EXPORT(png_bytep,png_sig_bytes) PNGARG((void)); + +extern PNG_EXPORT(png_charp,png_get_copyright) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(png_charp,png_get_header_ver) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(png_charp,png_get_header_version) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(png_charp,png_get_libpng_ver) PNGARG((png_structp png_ptr)); + +#ifdef PNG_MNG_FEATURES_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_permit_mng_features) PNGARG((png_structp + png_ptr, png_uint_32 mng_features_permitted)); +#endif + +/* For use in png_set_keep_unknown, added to version 1.2.6 */ +#define PNG_HANDLE_CHUNK_AS_DEFAULT 0 +#define PNG_HANDLE_CHUNK_NEVER 1 +#define PNG_HANDLE_CHUNK_IF_SAFE 2 +#define PNG_HANDLE_CHUNK_ALWAYS 3 + +/* Added to version 1.2.0 */ +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) +#define PNG_ASM_FLAG_MMX_SUPPORT_COMPILED 0x01 /* not user-settable */ +#define PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU 0x02 /* not user-settable */ +#define PNG_ASM_FLAG_MMX_READ_COMBINE_ROW 0x04 +#define PNG_ASM_FLAG_MMX_READ_INTERLACE 0x08 +#define PNG_ASM_FLAG_MMX_READ_FILTER_SUB 0x10 +#define PNG_ASM_FLAG_MMX_READ_FILTER_UP 0x20 +#define PNG_ASM_FLAG_MMX_READ_FILTER_AVG 0x40 +#define PNG_ASM_FLAG_MMX_READ_FILTER_PAETH 0x80 +#define PNG_ASM_FLAGS_INITIALIZED 0x80000000 /* not user-settable */ + +#define PNG_MMX_READ_FLAGS ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \ + | PNG_ASM_FLAG_MMX_READ_INTERLACE \ + | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \ + | PNG_ASM_FLAG_MMX_READ_FILTER_UP \ + | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \ + | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ) +#define PNG_MMX_WRITE_FLAGS ( 0 ) + +#define PNG_MMX_FLAGS ( PNG_ASM_FLAG_MMX_SUPPORT_COMPILED \ + | PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU \ + | PNG_MMX_READ_FLAGS \ + | PNG_MMX_WRITE_FLAGS ) + +#define PNG_SELECT_READ 1 +#define PNG_SELECT_WRITE 2 + +#if !defined(PNG_1_0_X) +/* pngget.c */ +extern PNG_EXPORT(png_uint_32,png_get_mmx_flagmask) + PNGARG((int flag_select, int *compilerID)); + +/* pngget.c */ +extern PNG_EXPORT(png_uint_32,png_get_asm_flagmask) + PNGARG((int flag_select)); + +/* pngget.c */ +extern PNG_EXPORT(png_uint_32,png_get_asm_flags) + PNGARG((png_structp png_ptr)); + +/* pngget.c */ +extern PNG_EXPORT(png_byte,png_get_mmx_bitdepth_threshold) + PNGARG((png_structp png_ptr)); + +/* pngget.c */ +extern PNG_EXPORT(png_uint_32,png_get_mmx_rowbytes_threshold) + PNGARG((png_structp png_ptr)); + +/* pngset.c */ +extern PNG_EXPORT(void,png_set_asm_flags) + PNGARG((png_structp png_ptr, png_uint_32 asm_flags)); + +/* pngset.c */ +extern PNG_EXPORT(void,png_set_mmx_thresholds) + PNGARG((png_structp png_ptr, png_byte mmx_bitdepth_threshold, + png_uint_32 mmx_rowbytes_threshold)); + +#endif /* PNG_1_0_X */ +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ + +#if !defined(PNG_1_0_X) +/* png.c, pnggccrd.c, or pngvcrd.c */ +extern PNG_EXPORT(int,png_mmx_support) PNGARG((void)); + +/* Strip the prepended error numbers ("#nnn ") from error and warning + * messages before passing them to the error or warning handler. */ +#ifdef PNG_ERROR_NUMBERS_SUPPORTED +extern PNG_EXPORT(void,png_set_strip_error_numbers) PNGARG((png_structp + png_ptr, png_uint_32 strip_mode)); +#endif + +#endif /* PNG_1_0_X */ + +/* Added at libpng-1.2.6 */ +#ifdef PNG_SET_USER_LIMITS_SUPPORTED +extern PNG_EXPORT(void,png_set_user_limits) PNGARG((png_structp + png_ptr, png_uint_32 user_width_max, png_uint_32 user_height_max)); +extern PNG_EXPORT(png_uint_32,png_get_user_width_max) PNGARG((png_structp + png_ptr)); +extern PNG_EXPORT(png_uint_32,png_get_user_height_max) PNGARG((png_structp + png_ptr)); +#endif + +/* Maintainer: Put new public prototypes here ^, in libpng.3, and project defs */ + +#ifdef PNG_READ_COMPOSITE_NODIV_SUPPORTED +/* With these routines we avoid an integer divide, which will be slower on + * most machines. However, it does take more operations than the corresponding + * divide method, so it may be slower on a few RISC systems. There are two + * shifts (by 8 or 16 bits) and an addition, versus a single integer divide. + * + * Note that the rounding factors are NOT supposed to be the same! 128 and + * 32768 are correct for the NODIV code; 127 and 32767 are correct for the + * standard method. + * + * [Optimized code by Greg Roelofs and Mark Adler...blame us for bugs. :-) ] + */ + + /* fg and bg should be in `gamma 1.0' space; alpha is the opacity */ + +# define png_composite(composite, fg, alpha, bg) \ + { png_uint_16 temp = (png_uint_16)((png_uint_16)(fg) * (png_uint_16)(alpha) \ + + (png_uint_16)(bg)*(png_uint_16)(255 - \ + (png_uint_16)(alpha)) + (png_uint_16)128); \ + (composite) = (png_byte)((temp + (temp >> 8)) >> 8); } + +# define png_composite_16(composite, fg, alpha, bg) \ + { png_uint_32 temp = (png_uint_32)((png_uint_32)(fg) * (png_uint_32)(alpha) \ + + (png_uint_32)(bg)*(png_uint_32)(65535L - \ + (png_uint_32)(alpha)) + (png_uint_32)32768L); \ + (composite) = (png_uint_16)((temp + (temp >> 16)) >> 16); } + +#else /* standard method using integer division */ + +# define png_composite(composite, fg, alpha, bg) \ + (composite) = (png_byte)(((png_uint_16)(fg) * (png_uint_16)(alpha) + \ + (png_uint_16)(bg) * (png_uint_16)(255 - (png_uint_16)(alpha)) + \ + (png_uint_16)127) / 255) + +# define png_composite_16(composite, fg, alpha, bg) \ + (composite) = (png_uint_16)(((png_uint_32)(fg) * (png_uint_32)(alpha) + \ + (png_uint_32)(bg)*(png_uint_32)(65535L - (png_uint_32)(alpha)) + \ + (png_uint_32)32767) / (png_uint_32)65535L) + +#endif /* PNG_READ_COMPOSITE_NODIV_SUPPORTED */ + +/* These next functions are used internally in the code. They generally + * shouldn't be used unless you are writing code to add or replace some + * functionality in libpng. More information about most functions can + * be found in the files where the functions are located. + */ + +#if defined(PNG_INTERNAL) + +/* Various modes of operation. Note that after an init, mode is set to + * zero automatically when the structure is created. + */ +#define PNG_HAVE_IHDR 0x01 +#define PNG_HAVE_PLTE 0x02 +#define PNG_HAVE_IDAT 0x04 +#define PNG_AFTER_IDAT 0x08 +#define PNG_HAVE_IEND 0x10 +#define PNG_HAVE_gAMA 0x20 +#define PNG_HAVE_cHRM 0x40 +#define PNG_HAVE_sRGB 0x80 +#define PNG_HAVE_CHUNK_HEADER 0x100 +#define PNG_WROTE_tIME 0x200 +#define PNG_WROTE_INFO_BEFORE_PLTE 0x400 +#define PNG_BACKGROUND_IS_GRAY 0x800 +#define PNG_HAVE_PNG_SIGNATURE 0x1000 + +/* flags for the transformations the PNG library does on the image data */ +#define PNG_BGR 0x0001 +#define PNG_INTERLACE 0x0002 +#define PNG_PACK 0x0004 +#define PNG_SHIFT 0x0008 +#define PNG_SWAP_BYTES 0x0010 +#define PNG_INVERT_MONO 0x0020 +#define PNG_DITHER 0x0040 +#define PNG_BACKGROUND 0x0080 +#define PNG_BACKGROUND_EXPAND 0x0100 + /* 0x0200 unused */ +#define PNG_16_TO_8 0x0400 +#define PNG_RGBA 0x0800 +#define PNG_EXPAND 0x1000 +#define PNG_GAMMA 0x2000 +#define PNG_GRAY_TO_RGB 0x4000 +#define PNG_FILLER 0x8000L +#define PNG_PACKSWAP 0x10000L +#define PNG_SWAP_ALPHA 0x20000L +#define PNG_STRIP_ALPHA 0x40000L +#define PNG_INVERT_ALPHA 0x80000L +#define PNG_USER_TRANSFORM 0x100000L +#define PNG_RGB_TO_GRAY_ERR 0x200000L +#define PNG_RGB_TO_GRAY_WARN 0x400000L +#define PNG_RGB_TO_GRAY 0x600000L /* two bits, RGB_TO_GRAY_ERR|WARN */ + /* 0x800000L Unused */ +#define PNG_ADD_ALPHA 0x1000000L /* Added to libpng-1.2.7 */ + /* 0x2000000L unused */ + /* 0x4000000L unused */ + /* 0x8000000L unused */ + /* 0x10000000L unused */ + /* 0x20000000L unused */ + /* 0x40000000L unused */ + +/* flags for png_create_struct */ +#define PNG_STRUCT_PNG 0x0001 +#define PNG_STRUCT_INFO 0x0002 + +/* Scaling factor for filter heuristic weighting calculations */ +#define PNG_WEIGHT_SHIFT 8 +#define PNG_WEIGHT_FACTOR (1<<(PNG_WEIGHT_SHIFT)) +#define PNG_COST_SHIFT 3 +#define PNG_COST_FACTOR (1<<(PNG_COST_SHIFT)) + +/* flags for the png_ptr->flags rather than declaring a byte for each one */ +#define PNG_FLAG_ZLIB_CUSTOM_STRATEGY 0x0001 +#define PNG_FLAG_ZLIB_CUSTOM_LEVEL 0x0002 +#define PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL 0x0004 +#define PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS 0x0008 +#define PNG_FLAG_ZLIB_CUSTOM_METHOD 0x0010 +#define PNG_FLAG_ZLIB_FINISHED 0x0020 +#define PNG_FLAG_ROW_INIT 0x0040 +#define PNG_FLAG_FILLER_AFTER 0x0080 +#define PNG_FLAG_CRC_ANCILLARY_USE 0x0100 +#define PNG_FLAG_CRC_ANCILLARY_NOWARN 0x0200 +#define PNG_FLAG_CRC_CRITICAL_USE 0x0400 +#define PNG_FLAG_CRC_CRITICAL_IGNORE 0x0800 +#define PNG_FLAG_FREE_PLTE 0x1000 +#define PNG_FLAG_FREE_TRNS 0x2000 +#define PNG_FLAG_FREE_HIST 0x4000 +#define PNG_FLAG_KEEP_UNKNOWN_CHUNKS 0x8000L +#define PNG_FLAG_KEEP_UNSAFE_CHUNKS 0x10000L +#define PNG_FLAG_LIBRARY_MISMATCH 0x20000L +#define PNG_FLAG_STRIP_ERROR_NUMBERS 0x40000L +#define PNG_FLAG_STRIP_ERROR_TEXT 0x80000L +#define PNG_FLAG_MALLOC_NULL_MEM_OK 0x100000L +#define PNG_FLAG_ADD_ALPHA 0x200000L /* Added to libpng-1.2.8 */ +#define PNG_FLAG_STRIP_ALPHA 0x400000L /* Added to libpng-1.2.8 */ + /* 0x800000L unused */ + /* 0x1000000L unused */ + /* 0x2000000L unused */ + /* 0x4000000L unused */ + /* 0x8000000L unused */ + /* 0x10000000L unused */ + /* 0x20000000L unused */ + /* 0x40000000L unused */ + +#define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \ + PNG_FLAG_CRC_ANCILLARY_NOWARN) + +#define PNG_FLAG_CRC_CRITICAL_MASK (PNG_FLAG_CRC_CRITICAL_USE | \ + PNG_FLAG_CRC_CRITICAL_IGNORE) + +#define PNG_FLAG_CRC_MASK (PNG_FLAG_CRC_ANCILLARY_MASK | \ + PNG_FLAG_CRC_CRITICAL_MASK) + +/* save typing and make code easier to understand */ + +#define PNG_COLOR_DIST(c1, c2) (abs((int)((c1).red) - (int)((c2).red)) + \ + abs((int)((c1).green) - (int)((c2).green)) + \ + abs((int)((c1).blue) - (int)((c2).blue))) + +/* Added to libpng-1.2.6 JB */ +#define PNG_ROWBYTES(pixel_bits, width) \ + ((pixel_bits) >= 8 ? \ + ((width) * (((png_uint_32)(pixel_bits)) >> 3)) : \ + (( ((width) * ((png_uint_32)(pixel_bits))) + 7) >> 3) ) + +/* PNG_OUT_OF_RANGE returns true if value is outside the range + ideal-delta..ideal+delta. Each argument is evaluated twice. + "ideal" and "delta" should be constants, normally simple + integers, "value" a variable. Added to libpng-1.2.6 JB */ +#define PNG_OUT_OF_RANGE(value, ideal, delta) \ + ( (value) < (ideal)-(delta) || (value) > (ideal)+(delta) ) + +/* variables declared in png.c - only it needs to define PNG_NO_EXTERN */ +#if !defined(PNG_NO_EXTERN) || defined(PNG_ALWAYS_EXTERN) +/* place to hold the signature string for a PNG file. */ +#ifdef PNG_USE_GLOBAL_ARRAYS + PNG_EXPORT_VAR (const png_byte FARDATA) png_sig[8]; +#else +#define png_sig png_sig_bytes(NULL) +#endif +#endif /* PNG_NO_EXTERN */ + +/* Constant strings for known chunk types. If you need to add a chunk, + * define the name here, and add an invocation of the macro in png.c and + * wherever it's needed. + */ +#define PNG_IHDR const png_byte png_IHDR[5] = { 73, 72, 68, 82, '\0'} +#define PNG_IDAT const png_byte png_IDAT[5] = { 73, 68, 65, 84, '\0'} +#define PNG_IEND const png_byte png_IEND[5] = { 73, 69, 78, 68, '\0'} +#define PNG_PLTE const png_byte png_PLTE[5] = { 80, 76, 84, 69, '\0'} +#define PNG_bKGD const png_byte png_bKGD[5] = { 98, 75, 71, 68, '\0'} +#define PNG_cHRM const png_byte png_cHRM[5] = { 99, 72, 82, 77, '\0'} +#define PNG_gAMA const png_byte png_gAMA[5] = {103, 65, 77, 65, '\0'} +#define PNG_hIST const png_byte png_hIST[5] = {104, 73, 83, 84, '\0'} +#define PNG_iCCP const png_byte png_iCCP[5] = {105, 67, 67, 80, '\0'} +#define PNG_iTXt const png_byte png_iTXt[5] = {105, 84, 88, 116, '\0'} +#define PNG_oFFs const png_byte png_oFFs[5] = {111, 70, 70, 115, '\0'} +#define PNG_pCAL const png_byte png_pCAL[5] = {112, 67, 65, 76, '\0'} +#define PNG_sCAL const png_byte png_sCAL[5] = {115, 67, 65, 76, '\0'} +#define PNG_pHYs const png_byte png_pHYs[5] = {112, 72, 89, 115, '\0'} +#define PNG_sBIT const png_byte png_sBIT[5] = {115, 66, 73, 84, '\0'} +#define PNG_sPLT const png_byte png_sPLT[5] = {115, 80, 76, 84, '\0'} +#define PNG_sRGB const png_byte png_sRGB[5] = {115, 82, 71, 66, '\0'} +#define PNG_tEXt const png_byte png_tEXt[5] = {116, 69, 88, 116, '\0'} +#define PNG_tIME const png_byte png_tIME[5] = {116, 73, 77, 69, '\0'} +#define PNG_tRNS const png_byte png_tRNS[5] = {116, 82, 78, 83, '\0'} +#define PNG_zTXt const png_byte png_zTXt[5] = {122, 84, 88, 116, '\0'} + +#ifdef PNG_USE_GLOBAL_ARRAYS +PNG_EXPORT_VAR (const png_byte FARDATA) png_IHDR[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_IDAT[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_IEND[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_PLTE[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_bKGD[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_cHRM[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_gAMA[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_hIST[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_iCCP[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_iTXt[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_oFFs[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_pCAL[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_sCAL[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_pHYs[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_sBIT[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_sPLT[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_sRGB[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_tEXt[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_tIME[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_tRNS[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_zTXt[5]; +#endif /* PNG_USE_GLOBAL_ARRAYS */ + + +/* Inline macros to do direct reads of bytes from the input buffer. These + * require that you are using an architecture that uses PNG byte ordering + * (MSB first) and supports unaligned data storage. I think that PowerPC + * in big-endian mode and 680x0 are the only ones that will support this. + * The x86 line of processors definitely do not. The png_get_int_32() + * routine also assumes we are using two's complement format for negative + * values, which is almost certainly true. + */ +#if defined(PNG_READ_BIG_ENDIAN_SUPPORTED) +# if defined(PNG_pCAL_SUPPORTED) || defined(PNG_oFFs_SUPPORTED) +# define png_get_int_32(buf) ( *((png_int_32p) (buf))) +# endif +# define png_get_uint_32(buf) ( *((png_uint_32p) (buf))) +# define png_get_uint_16(buf) ( *((png_uint_16p) (buf))) +#else +# if defined(PNG_pCAL_SUPPORTED) || defined(PNG_oFFs_SUPPORTED) +PNG_EXTERN png_int_32 png_get_int_32 PNGARG((png_bytep buf)); +# endif +PNG_EXTERN png_uint_32 png_get_uint_32 PNGARG((png_bytep buf)); +PNG_EXTERN png_uint_16 png_get_uint_16 PNGARG((png_bytep buf)); +#endif /* !PNG_READ_BIG_ENDIAN_SUPPORTED */ +PNG_EXTERN png_uint_32 png_get_uint_31 PNGARG((png_structp png_ptr, + png_bytep buf)); + +/* Initialize png_ptr struct for reading, and allocate any other memory. + * (old interface - DEPRECATED - use png_create_read_struct instead). + */ +extern PNG_EXPORT(void,png_read_init) PNGARG((png_structp png_ptr)); +#undef png_read_init +#define png_read_init(png_ptr) png_read_init_3(&png_ptr, \ + PNG_LIBPNG_VER_STRING, png_sizeof(png_struct)); +extern PNG_EXPORT(void,png_read_init_3) PNGARG((png_structpp ptr_ptr, + png_const_charp user_png_ver, png_size_t png_struct_size)); +extern PNG_EXPORT(void,png_read_init_2) PNGARG((png_structp png_ptr, + png_const_charp user_png_ver, png_size_t png_struct_size, png_size_t + png_info_size)); + +/* Initialize png_ptr struct for writing, and allocate any other memory. + * (old interface - DEPRECATED - use png_create_write_struct instead). + */ +extern PNG_EXPORT(void,png_write_init) PNGARG((png_structp png_ptr)); +#undef png_write_init +#define png_write_init(png_ptr) png_write_init_3(&png_ptr, \ + PNG_LIBPNG_VER_STRING, png_sizeof(png_struct)); +extern PNG_EXPORT(void,png_write_init_3) PNGARG((png_structpp ptr_ptr, + png_const_charp user_png_ver, png_size_t png_struct_size)); +extern PNG_EXPORT(void,png_write_init_2) PNGARG((png_structp png_ptr, + png_const_charp user_png_ver, png_size_t png_struct_size, png_size_t + png_info_size)); + +/* Allocate memory for an internal libpng struct */ +PNG_EXTERN png_voidp png_create_struct PNGARG((int type)); + +/* Free memory from internal libpng struct */ +PNG_EXTERN void png_destroy_struct PNGARG((png_voidp struct_ptr)); + +PNG_EXTERN png_voidp png_create_struct_2 PNGARG((int type, png_malloc_ptr + malloc_fn, png_voidp mem_ptr)); +PNG_EXTERN void png_destroy_struct_2 PNGARG((png_voidp struct_ptr, + png_free_ptr free_fn, png_voidp mem_ptr)); + +/* Free any memory that info_ptr points to and reset struct. */ +PNG_EXTERN void png_info_destroy PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +#ifndef PNG_1_0_X +/* Function to allocate memory for zlib. */ +PNG_EXTERN voidpf png_zalloc PNGARG((voidpf png_ptr, uInt items, uInt size)); + +/* Function to free memory for zlib */ +PNG_EXTERN void png_zfree PNGARG((voidpf png_ptr, voidpf ptr)); + +#ifdef PNG_SIZE_T +/* Function to convert a sizeof an item to png_sizeof item */ + PNG_EXTERN png_size_t PNGAPI png_convert_size PNGARG((size_t size)); +#endif + +/* Next four functions are used internally as callbacks. PNGAPI is required + * but not PNG_EXPORT. PNGAPI added at libpng version 1.2.3. */ + +PNG_EXTERN void PNGAPI png_default_read_data PNGARG((png_structp png_ptr, + png_bytep data, png_size_t length)); + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +PNG_EXTERN void PNGAPI png_push_fill_buffer PNGARG((png_structp png_ptr, + png_bytep buffer, png_size_t length)); +#endif + +PNG_EXTERN void PNGAPI png_default_write_data PNGARG((png_structp png_ptr, + png_bytep data, png_size_t length)); + +#if defined(PNG_WRITE_FLUSH_SUPPORTED) +#if !defined(PNG_NO_STDIO) +PNG_EXTERN void PNGAPI png_default_flush PNGARG((png_structp png_ptr)); +#endif +#endif +#else /* PNG_1_0_X */ +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +PNG_EXTERN void png_push_fill_buffer PNGARG((png_structp png_ptr, + png_bytep buffer, png_size_t length)); +#endif +#endif /* PNG_1_0_X */ + +/* Reset the CRC variable */ +PNG_EXTERN void png_reset_crc PNGARG((png_structp png_ptr)); + +/* Write the "data" buffer to whatever output you are using. */ +PNG_EXTERN void png_write_data PNGARG((png_structp png_ptr, png_bytep data, + png_size_t length)); + +/* Read data from whatever input you are using into the "data" buffer */ +PNG_EXTERN void png_read_data PNGARG((png_structp png_ptr, png_bytep data, + png_size_t length)); + +/* Read bytes into buf, and update png_ptr->crc */ +PNG_EXTERN void png_crc_read PNGARG((png_structp png_ptr, png_bytep buf, + png_size_t length)); + +/* Decompress data in a chunk that uses compression */ +#if defined(PNG_zTXt_SUPPORTED) || defined(PNG_iTXt_SUPPORTED) || \ + defined(PNG_iCCP_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) +PNG_EXTERN png_charp png_decompress_chunk PNGARG((png_structp png_ptr, + int comp_type, png_charp chunkdata, png_size_t chunklength, + png_size_t prefix_length, png_size_t *data_length)); +#endif + +/* Read "skip" bytes, read the file crc, and (optionally) verify png_ptr->crc */ +PNG_EXTERN int png_crc_finish PNGARG((png_structp png_ptr, png_uint_32 skip)); + +/* Read the CRC from the file and compare it to the libpng calculated CRC */ +PNG_EXTERN int png_crc_error PNGARG((png_structp png_ptr)); + +/* Calculate the CRC over a section of data. Note that we are only + * passing a maximum of 64K on systems that have this as a memory limit, + * since this is the maximum buffer size we can specify. + */ +PNG_EXTERN void png_calculate_crc PNGARG((png_structp png_ptr, png_bytep ptr, + png_size_t length)); + +#if defined(PNG_WRITE_FLUSH_SUPPORTED) +PNG_EXTERN void png_flush PNGARG((png_structp png_ptr)); +#endif + + +/* Place a 32-bit number into a buffer in PNG byte order (big-endian). + * The only currently known PNG chunks that use signed numbers are + * the ancillary extension chunks, oFFs and pCAL. + */ +PNG_EXTERN void png_save_uint_32 PNGARG((png_bytep buf, png_uint_32 i)); + +#if defined(PNG_WRITE_pCAL_SUPPORTED) || defined(PNG_WRITE_oFFs_SUPPORTED) +PNG_EXTERN void png_save_int_32 PNGARG((png_bytep buf, png_int_32 i)); +#endif + +/* Place a 16-bit number into a buffer in PNG byte order. + * The parameter is declared unsigned int, not png_uint_16, + * just to avoid potential problems on pre-ANSI C compilers. + */ +PNG_EXTERN void png_save_uint_16 PNGARG((png_bytep buf, unsigned int i)); + +/* simple function to write the signature */ +PNG_EXTERN void png_write_sig PNGARG((png_structp png_ptr)); + +/* write various chunks */ + +/* Write the IHDR chunk, and update the png_struct with the necessary + * information. + */ +PNG_EXTERN void png_write_IHDR PNGARG((png_structp png_ptr, png_uint_32 width, + png_uint_32 height, + int bit_depth, int color_type, int compression_method, int filter_method, + int interlace_method)); + +PNG_EXTERN void png_write_PLTE PNGARG((png_structp png_ptr, png_colorp palette, + png_uint_32 num_pal)); + +PNG_EXTERN void png_write_IDAT PNGARG((png_structp png_ptr, png_bytep data, + png_size_t length)); + +PNG_EXTERN void png_write_IEND PNGARG((png_structp png_ptr)); + +#if defined(PNG_WRITE_gAMA_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +PNG_EXTERN void png_write_gAMA PNGARG((png_structp png_ptr, double file_gamma)); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +PNG_EXTERN void png_write_gAMA_fixed PNGARG((png_structp png_ptr, png_fixed_point + file_gamma)); +#endif +#endif + +#if defined(PNG_WRITE_sBIT_SUPPORTED) +PNG_EXTERN void png_write_sBIT PNGARG((png_structp png_ptr, png_color_8p sbit, + int color_type)); +#endif + +#if defined(PNG_WRITE_cHRM_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +PNG_EXTERN void png_write_cHRM PNGARG((png_structp png_ptr, + double white_x, double white_y, + double red_x, double red_y, double green_x, double green_y, + double blue_x, double blue_y)); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +PNG_EXTERN void png_write_cHRM_fixed PNGARG((png_structp png_ptr, + png_fixed_point int_white_x, png_fixed_point int_white_y, + png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point + int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x, + png_fixed_point int_blue_y)); +#endif +#endif + +#if defined(PNG_WRITE_sRGB_SUPPORTED) +PNG_EXTERN void png_write_sRGB PNGARG((png_structp png_ptr, + int intent)); +#endif + +#if defined(PNG_WRITE_iCCP_SUPPORTED) +PNG_EXTERN void png_write_iCCP PNGARG((png_structp png_ptr, + png_charp name, int compression_type, + png_charp profile, int proflen)); + /* Note to maintainer: profile should be png_bytep */ +#endif + +#if defined(PNG_WRITE_sPLT_SUPPORTED) +PNG_EXTERN void png_write_sPLT PNGARG((png_structp png_ptr, + png_sPLT_tp palette)); +#endif + +#if defined(PNG_WRITE_tRNS_SUPPORTED) +PNG_EXTERN void png_write_tRNS PNGARG((png_structp png_ptr, png_bytep trans, + png_color_16p values, int number, int color_type)); +#endif + +#if defined(PNG_WRITE_bKGD_SUPPORTED) +PNG_EXTERN void png_write_bKGD PNGARG((png_structp png_ptr, + png_color_16p values, int color_type)); +#endif + +#if defined(PNG_WRITE_hIST_SUPPORTED) +PNG_EXTERN void png_write_hIST PNGARG((png_structp png_ptr, png_uint_16p hist, + int num_hist)); +#endif + +#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \ + defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) +PNG_EXTERN png_size_t png_check_keyword PNGARG((png_structp png_ptr, + png_charp key, png_charpp new_key)); +#endif + +#if defined(PNG_WRITE_tEXt_SUPPORTED) +PNG_EXTERN void png_write_tEXt PNGARG((png_structp png_ptr, png_charp key, + png_charp text, png_size_t text_len)); +#endif + +#if defined(PNG_WRITE_zTXt_SUPPORTED) +PNG_EXTERN void png_write_zTXt PNGARG((png_structp png_ptr, png_charp key, + png_charp text, png_size_t text_len, int compression)); +#endif + +#if defined(PNG_WRITE_iTXt_SUPPORTED) +PNG_EXTERN void png_write_iTXt PNGARG((png_structp png_ptr, + int compression, png_charp key, png_charp lang, png_charp lang_key, + png_charp text)); +#endif + +#if defined(PNG_TEXT_SUPPORTED) /* Added at version 1.0.14 and 1.2.4 */ +PNG_EXTERN int png_set_text_2 PNGARG((png_structp png_ptr, + png_infop info_ptr, png_textp text_ptr, int num_text)); +#endif + +#if defined(PNG_WRITE_oFFs_SUPPORTED) +PNG_EXTERN void png_write_oFFs PNGARG((png_structp png_ptr, + png_int_32 x_offset, png_int_32 y_offset, int unit_type)); +#endif + +#if defined(PNG_WRITE_pCAL_SUPPORTED) +PNG_EXTERN void png_write_pCAL PNGARG((png_structp png_ptr, png_charp purpose, + png_int_32 X0, png_int_32 X1, int type, int nparams, + png_charp units, png_charpp params)); +#endif + +#if defined(PNG_WRITE_pHYs_SUPPORTED) +PNG_EXTERN void png_write_pHYs PNGARG((png_structp png_ptr, + png_uint_32 x_pixels_per_unit, png_uint_32 y_pixels_per_unit, + int unit_type)); +#endif + +#if defined(PNG_WRITE_tIME_SUPPORTED) +PNG_EXTERN void png_write_tIME PNGARG((png_structp png_ptr, + png_timep mod_time)); +#endif + +#if defined(PNG_WRITE_sCAL_SUPPORTED) +#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO) +PNG_EXTERN void png_write_sCAL PNGARG((png_structp png_ptr, + int unit, double width, double height)); +#else +#ifdef PNG_FIXED_POINT_SUPPORTED +PNG_EXTERN void png_write_sCAL_s PNGARG((png_structp png_ptr, + int unit, png_charp width, png_charp height)); +#endif +#endif +#endif + +/* Called when finished processing a row of data */ +PNG_EXTERN void png_write_finish_row PNGARG((png_structp png_ptr)); + +/* Internal use only. Called before first row of data */ +PNG_EXTERN void png_write_start_row PNGARG((png_structp png_ptr)); + +#if defined(PNG_READ_GAMMA_SUPPORTED) +PNG_EXTERN void png_build_gamma_table PNGARG((png_structp png_ptr)); +#endif + +/* combine a row of data, dealing with alpha, etc. if requested */ +PNG_EXTERN void png_combine_row PNGARG((png_structp png_ptr, png_bytep row, + int mask)); + +#if defined(PNG_READ_INTERLACING_SUPPORTED) +/* expand an interlaced row */ +/* OLD pre-1.0.9 interface: +PNG_EXTERN void png_do_read_interlace PNGARG((png_row_infop row_info, + png_bytep row, int pass, png_uint_32 transformations)); + */ +PNG_EXTERN void png_do_read_interlace PNGARG((png_structp png_ptr)); +#endif + +/* GRR TO DO (2.0 or whenever): simplify other internal calling interfaces */ + +#if defined(PNG_WRITE_INTERLACING_SUPPORTED) +/* grab pixels out of a row for an interlaced pass */ +PNG_EXTERN void png_do_write_interlace PNGARG((png_row_infop row_info, + png_bytep row, int pass)); +#endif + +/* unfilter a row */ +PNG_EXTERN void png_read_filter_row PNGARG((png_structp png_ptr, + png_row_infop row_info, png_bytep row, png_bytep prev_row, int filter)); + +/* Choose the best filter to use and filter the row data */ +PNG_EXTERN void png_write_find_filter PNGARG((png_structp png_ptr, + png_row_infop row_info)); + +/* Write out the filtered row. */ +PNG_EXTERN void png_write_filtered_row PNGARG((png_structp png_ptr, + png_bytep filtered_row)); +/* finish a row while reading, dealing with interlacing passes, etc. */ +PNG_EXTERN void png_read_finish_row PNGARG((png_structp png_ptr)); + +/* initialize the row buffers, etc. */ +PNG_EXTERN void png_read_start_row PNGARG((png_structp png_ptr)); +/* optional call to update the users info structure */ +PNG_EXTERN void png_read_transform_info PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +/* these are the functions that do the transformations */ +#if defined(PNG_READ_FILLER_SUPPORTED) +PNG_EXTERN void png_do_read_filler PNGARG((png_row_infop row_info, + png_bytep row, png_uint_32 filler, png_uint_32 flags)); +#endif + +#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) +PNG_EXTERN void png_do_read_swap_alpha PNGARG((png_row_infop row_info, + png_bytep row)); +#endif + +#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) +PNG_EXTERN void png_do_write_swap_alpha PNGARG((png_row_infop row_info, + png_bytep row)); +#endif + +#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) +PNG_EXTERN void png_do_read_invert_alpha PNGARG((png_row_infop row_info, + png_bytep row)); +#endif + +#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) +PNG_EXTERN void png_do_write_invert_alpha PNGARG((png_row_infop row_info, + png_bytep row)); +#endif + +#if defined(PNG_WRITE_FILLER_SUPPORTED) || \ + defined(PNG_READ_STRIP_ALPHA_SUPPORTED) +PNG_EXTERN void png_do_strip_filler PNGARG((png_row_infop row_info, + png_bytep row, png_uint_32 flags)); +#endif + +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +PNG_EXTERN void png_do_swap PNGARG((png_row_infop row_info, png_bytep row)); +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) || defined(PNG_WRITE_PACKSWAP_SUPPORTED) +PNG_EXTERN void png_do_packswap PNGARG((png_row_infop row_info, png_bytep row)); +#endif + +#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) +PNG_EXTERN int png_do_rgb_to_gray PNGARG((png_structp png_ptr, png_row_infop + row_info, png_bytep row)); +#endif + +#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) +PNG_EXTERN void png_do_gray_to_rgb PNGARG((png_row_infop row_info, + png_bytep row)); +#endif + +#if defined(PNG_READ_PACK_SUPPORTED) +PNG_EXTERN void png_do_unpack PNGARG((png_row_infop row_info, png_bytep row)); +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) +PNG_EXTERN void png_do_unshift PNGARG((png_row_infop row_info, png_bytep row, + png_color_8p sig_bits)); +#endif + +#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) +PNG_EXTERN void png_do_invert PNGARG((png_row_infop row_info, png_bytep row)); +#endif + +#if defined(PNG_READ_16_TO_8_SUPPORTED) +PNG_EXTERN void png_do_chop PNGARG((png_row_infop row_info, png_bytep row)); +#endif + +#if defined(PNG_READ_DITHER_SUPPORTED) +PNG_EXTERN void png_do_dither PNGARG((png_row_infop row_info, + png_bytep row, png_bytep palette_lookup, png_bytep dither_lookup)); + +# if defined(PNG_CORRECT_PALETTE_SUPPORTED) +PNG_EXTERN void png_correct_palette PNGARG((png_structp png_ptr, + png_colorp palette, int num_palette)); +# endif +#endif + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +PNG_EXTERN void png_do_bgr PNGARG((png_row_infop row_info, png_bytep row)); +#endif + +#if defined(PNG_WRITE_PACK_SUPPORTED) +PNG_EXTERN void png_do_pack PNGARG((png_row_infop row_info, + png_bytep row, png_uint_32 bit_depth)); +#endif + +#if defined(PNG_WRITE_SHIFT_SUPPORTED) +PNG_EXTERN void png_do_shift PNGARG((png_row_infop row_info, png_bytep row, + png_color_8p bit_depth)); +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) +#if defined(PNG_READ_GAMMA_SUPPORTED) +PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info, png_bytep row, + png_color_16p trans_values, png_color_16p background, + png_color_16p background_1, + png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1, + png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1, + png_uint_16pp gamma_16_to_1, int gamma_shift)); +#else +PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info, png_bytep row, + png_color_16p trans_values, png_color_16p background)); +#endif +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) +PNG_EXTERN void png_do_gamma PNGARG((png_row_infop row_info, png_bytep row, + png_bytep gamma_table, png_uint_16pp gamma_16_table, + int gamma_shift)); +#endif + +#if defined(PNG_READ_EXPAND_SUPPORTED) +PNG_EXTERN void png_do_expand_palette PNGARG((png_row_infop row_info, + png_bytep row, png_colorp palette, png_bytep trans, int num_trans)); +PNG_EXTERN void png_do_expand PNGARG((png_row_infop row_info, + png_bytep row, png_color_16p trans_value)); +#endif + +/* The following decodes the appropriate chunks, and does error correction, + * then calls the appropriate callback for the chunk if it is valid. + */ + +/* decode the IHDR chunk */ +PNG_EXTERN void png_handle_IHDR PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +PNG_EXTERN void png_handle_PLTE PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +PNG_EXTERN void png_handle_IEND PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); + +#if defined(PNG_READ_bKGD_SUPPORTED) +PNG_EXTERN void png_handle_bKGD PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_cHRM_SUPPORTED) +PNG_EXTERN void png_handle_cHRM PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_gAMA_SUPPORTED) +PNG_EXTERN void png_handle_gAMA PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_hIST_SUPPORTED) +PNG_EXTERN void png_handle_hIST PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_iCCP_SUPPORTED) +extern void png_handle_iCCP PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif /* PNG_READ_iCCP_SUPPORTED */ + +#if defined(PNG_READ_iTXt_SUPPORTED) +PNG_EXTERN void png_handle_iTXt PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_oFFs_SUPPORTED) +PNG_EXTERN void png_handle_oFFs PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_pCAL_SUPPORTED) +PNG_EXTERN void png_handle_pCAL PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_pHYs_SUPPORTED) +PNG_EXTERN void png_handle_pHYs PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_sBIT_SUPPORTED) +PNG_EXTERN void png_handle_sBIT PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_sCAL_SUPPORTED) +PNG_EXTERN void png_handle_sCAL PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_sPLT_SUPPORTED) +extern void png_handle_sPLT PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif /* PNG_READ_sPLT_SUPPORTED */ + +#if defined(PNG_READ_sRGB_SUPPORTED) +PNG_EXTERN void png_handle_sRGB PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_tEXt_SUPPORTED) +PNG_EXTERN void png_handle_tEXt PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_tIME_SUPPORTED) +PNG_EXTERN void png_handle_tIME PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_tRNS_SUPPORTED) +PNG_EXTERN void png_handle_tRNS PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_zTXt_SUPPORTED) +PNG_EXTERN void png_handle_zTXt PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +PNG_EXTERN void png_handle_unknown PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)); + +PNG_EXTERN void png_check_chunk_name PNGARG((png_structp png_ptr, + png_bytep chunk_name)); + +/* handle the transformations for reading and writing */ +PNG_EXTERN void png_do_read_transformations PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_do_write_transformations PNGARG((png_structp png_ptr)); + +PNG_EXTERN void png_init_read_transformations PNGARG((png_structp png_ptr)); + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +PNG_EXTERN void png_push_read_chunk PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_push_read_sig PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_push_check_crc PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_push_crc_skip PNGARG((png_structp png_ptr, + png_uint_32 length)); +PNG_EXTERN void png_push_crc_finish PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_push_save_buffer PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_push_restore_buffer PNGARG((png_structp png_ptr, + png_bytep buffer, png_size_t buffer_length)); +PNG_EXTERN void png_push_read_IDAT PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_process_IDAT_data PNGARG((png_structp png_ptr, + png_bytep buffer, png_size_t buffer_length)); +PNG_EXTERN void png_push_process_row PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_push_handle_unknown PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_push_have_info PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_push_have_end PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_push_have_row PNGARG((png_structp png_ptr, png_bytep row)); +PNG_EXTERN void png_push_read_end PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_process_some_data PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_read_push_finish_row PNGARG((png_structp png_ptr)); +#if defined(PNG_READ_tEXt_SUPPORTED) +PNG_EXTERN void png_push_handle_tEXt PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_push_read_tEXt PNGARG((png_structp png_ptr, + png_infop info_ptr)); +#endif +#if defined(PNG_READ_zTXt_SUPPORTED) +PNG_EXTERN void png_push_handle_zTXt PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_push_read_zTXt PNGARG((png_structp png_ptr, + png_infop info_ptr)); +#endif +#if defined(PNG_READ_iTXt_SUPPORTED) +PNG_EXTERN void png_push_handle_iTXt PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_push_read_iTXt PNGARG((png_structp png_ptr, + png_infop info_ptr)); +#endif + +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ + +#ifdef PNG_MNG_FEATURES_SUPPORTED +PNG_EXTERN void png_do_read_intrapixel PNGARG((png_row_infop row_info, + png_bytep row)); +PNG_EXTERN void png_do_write_intrapixel PNGARG((png_row_infop row_info, + png_bytep row)); +#endif + +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) +/* png.c */ /* PRIVATE */ +PNG_EXTERN void png_init_mmx_flags PNGARG((png_structp png_ptr)); +#endif +/* Maintainer: Put new private prototypes here ^ and in libpngpf.3 */ + +#endif /* PNG_INTERNAL */ + +#ifdef __cplusplus +} +#endif + +#endif /* PNG_VERSION_INFO_ONLY */ +/* do not put anything past this line */ +#endif /* PNG_H */ diff --git a/syslinux/com32/include/pngconf.h b/syslinux/com32/include/pngconf.h new file mode 100644 index 0000000..7f4cbed --- /dev/null +++ b/syslinux/com32/include/pngconf.h @@ -0,0 +1,1437 @@ + +/* pngconf.h - machine configurable file for libpng + * + * libpng version 1.2.8 - December 3, 2004 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2004 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + */ + +/* Any machine specific code is near the front of this file, so if you + * are configuring libpng for a machine, you may want to read the section + * starting here down to where it starts to typedef png_color, png_text, + * and png_info. + */ + +#ifndef PNGCONF_H +#define PNGCONF_H + +#define PNG_1_2_X + +/* + * PNG_USER_CONFIG has to be defined on the compiler command line. This + * includes the resource compiler for Windows DLL configurations. + */ +#ifdef PNG_USER_CONFIG +#include "pngusr.h" +#endif + +/* + * Added at libpng-1.2.8 + * + * If you create a private DLL you need to define in "pngusr.h" the followings: + * #define PNG_USER_PRIVATEBUILD <Describes by whom and why this version of + * the DLL was built> + * e.g. #define PNG_USER_PRIVATEBUILD "Build by MyCompany for xyz reasons." + * #define PNG_USER_DLLFNAME_POSTFIX <two-letter postfix that serve to + * distinguish your DLL from those of the official release. These + * correspond to the trailing letters that come after the version + * number and must match your private DLL name> + * e.g. // private DLL "libpng13gx.dll" + * #define PNG_USER_DLLFNAME_POSTFIX "gx" + * + * The following macros are also at your disposal if you want to complete the + * DLL VERSIONINFO structure. + * - PNG_USER_VERSIONINFO_COMMENTS + * - PNG_USER_VERSIONINFO_COMPANYNAME + * - PNG_USER_VERSIONINFO_LEGALTRADEMARKS + */ + +#ifdef __STDC__ +#ifdef SPECIALBUILD +# pragma message("PNG_LIBPNG_SPECIALBUILD (and deprecated SPECIALBUILD)\ + are now LIBPNG reserved macros. Use PNG_USER_PRIVATEBUILD instead.") +#endif + +#ifdef PRIVATEBUILD +# pragma message("PRIVATEBUILD is deprecated. Use\ + PNG_USER_PRIVATEBUILD instead.") +# define PNG_USER_PRIVATEBUILD PRIVATEBUILD +#endif +#endif /* __STDC__ */ + +#ifndef PNG_VERSION_INFO_ONLY + +/* End of material added to libpng-1.2.8 */ + +/* This is the size of the compression buffer, and thus the size of + * an IDAT chunk. Make this whatever size you feel is best for your + * machine. One of these will be allocated per png_struct. When this + * is full, it writes the data to the disk, and does some other + * calculations. Making this an extremely small size will slow + * the library down, but you may want to experiment to determine + * where it becomes significant, if you are concerned with memory + * usage. Note that zlib allocates at least 32Kb also. For readers, + * this describes the size of the buffer available to read the data in. + * Unless this gets smaller than the size of a row (compressed), + * it should not make much difference how big this is. + */ + +#ifndef PNG_ZBUF_SIZE +# define PNG_ZBUF_SIZE 8192 +#endif + +/* Enable if you want a write-only libpng */ + +#ifndef PNG_NO_READ_SUPPORTED +# define PNG_READ_SUPPORTED +#endif + +/* Enable if you want a read-only libpng */ + +#ifndef PNG_NO_WRITE_SUPPORTED +# define PNG_WRITE_SUPPORTED +#endif + +/* Enabled by default in 1.2.0. You can disable this if you don't need to + support PNGs that are embedded in MNG datastreams */ +#if !defined(PNG_1_0_X) && !defined(PNG_NO_MNG_FEATURES) +# ifndef PNG_MNG_FEATURES_SUPPORTED +# define PNG_MNG_FEATURES_SUPPORTED +# endif +#endif + +#ifndef PNG_NO_FLOATING_POINT_SUPPORTED +# ifndef PNG_FLOATING_POINT_SUPPORTED +# define PNG_FLOATING_POINT_SUPPORTED +# endif +#endif + +/* If you are running on a machine where you cannot allocate more + * than 64K of memory at once, uncomment this. While libpng will not + * normally need that much memory in a chunk (unless you load up a very + * large file), zlib needs to know how big of a chunk it can use, and + * libpng thus makes sure to check any memory allocation to verify it + * will fit into memory. +#define PNG_MAX_MALLOC_64K + */ +#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K) +# define PNG_MAX_MALLOC_64K +#endif + +/* Special munging to support doing things the 'cygwin' way: + * 'Normal' png-on-win32 defines/defaults: + * PNG_BUILD_DLL -- building dll + * PNG_USE_DLL -- building an application, linking to dll + * (no define) -- building static library, or building an + * application and linking to the static lib + * 'Cygwin' defines/defaults: + * PNG_BUILD_DLL -- (ignored) building the dll + * (no define) -- (ignored) building an application, linking to the dll + * PNG_STATIC -- (ignored) building the static lib, or building an + * application that links to the static lib. + * ALL_STATIC -- (ignored) building various static libs, or building an + * application that links to the static libs. + * Thus, + * a cygwin user should define either PNG_BUILD_DLL or PNG_STATIC, and + * this bit of #ifdefs will define the 'correct' config variables based on + * that. If a cygwin user *wants* to define 'PNG_USE_DLL' that's okay, but + * unnecessary. + * + * Also, the precedence order is: + * ALL_STATIC (since we can't #undef something outside our namespace) + * PNG_BUILD_DLL + * PNG_STATIC + * (nothing) == PNG_USE_DLL + * + * CYGWIN (2002-01-20): The preceding is now obsolete. With the advent + * of auto-import in binutils, we no longer need to worry about + * __declspec(dllexport) / __declspec(dllimport) and friends. Therefore, + * we don't need to worry about PNG_STATIC or ALL_STATIC when it comes + * to __declspec() stuff. However, we DO need to worry about + * PNG_BUILD_DLL and PNG_STATIC because those change some defaults + * such as CONSOLE_IO and whether GLOBAL_ARRAYS are allowed. + */ +#if defined(__CYGWIN__) +# if defined(ALL_STATIC) +# if defined(PNG_BUILD_DLL) +# undef PNG_BUILD_DLL +# endif +# if defined(PNG_USE_DLL) +# undef PNG_USE_DLL +# endif +# if defined(PNG_DLL) +# undef PNG_DLL +# endif +# if !defined(PNG_STATIC) +# define PNG_STATIC +# endif +# else +# if defined (PNG_BUILD_DLL) +# if defined(PNG_STATIC) +# undef PNG_STATIC +# endif +# if defined(PNG_USE_DLL) +# undef PNG_USE_DLL +# endif +# if !defined(PNG_DLL) +# define PNG_DLL +# endif +# else +# if defined(PNG_STATIC) +# if defined(PNG_USE_DLL) +# undef PNG_USE_DLL +# endif +# if defined(PNG_DLL) +# undef PNG_DLL +# endif +# else +# if !defined(PNG_USE_DLL) +# define PNG_USE_DLL +# endif +# if !defined(PNG_DLL) +# define PNG_DLL +# endif +# endif +# endif +# endif +#endif + +/* This protects us against compilers that run on a windowing system + * and thus don't have or would rather us not use the stdio types: + * stdin, stdout, and stderr. The only one currently used is stderr + * in png_error() and png_warning(). #defining PNG_NO_CONSOLE_IO will + * prevent these from being compiled and used. #defining PNG_NO_STDIO + * will also prevent these, plus will prevent the entire set of stdio + * macros and functions (FILE *, printf, etc.) from being compiled and used, + * unless (PNG_DEBUG > 0) has been #defined. + * + * #define PNG_NO_CONSOLE_IO + * #define PNG_NO_STDIO + */ + +#if defined(_WIN32_WCE) +# include <windows.h> + /* Console I/O functions are not supported on WindowsCE */ +# define PNG_NO_CONSOLE_IO +# ifdef PNG_DEBUG +# undef PNG_DEBUG +# endif +#endif + +#ifdef PNG_BUILD_DLL +# ifndef PNG_CONSOLE_IO_SUPPORTED +# ifndef PNG_NO_CONSOLE_IO +# define PNG_NO_CONSOLE_IO +# endif +# endif +#endif + +# ifdef PNG_NO_STDIO +# ifndef PNG_NO_CONSOLE_IO +# define PNG_NO_CONSOLE_IO +# endif +# ifdef PNG_DEBUG +# if (PNG_DEBUG > 0) +# include <stdio.h> +# endif +# endif +# else +# if !defined(_WIN32_WCE) +/* "stdio.h" functions are not supported on WindowsCE */ +# include <stdio.h> +# endif +# endif + +/* This macro protects us against machines that don't have function + * prototypes (ie K&R style headers). If your compiler does not handle + * function prototypes, define this macro and use the included ansi2knr. + * I've always been able to use _NO_PROTO as the indicator, but you may + * need to drag the empty declaration out in front of here, or change the + * ifdef to suit your own needs. + */ +#ifndef PNGARG + +#ifdef OF /* zlib prototype munger */ +# define PNGARG(arglist) OF(arglist) +#else + +#ifdef _NO_PROTO +# define PNGARG(arglist) () +# ifndef PNG_TYPECAST_NULL +# define PNG_TYPECAST_NULL +# endif +#else +# define PNGARG(arglist) arglist +#endif /* _NO_PROTO */ + +#endif /* OF */ + +#endif /* PNGARG */ + +/* Try to determine if we are compiling on a Mac. Note that testing for + * just __MWERKS__ is not good enough, because the Codewarrior is now used + * on non-Mac platforms. + */ +#ifndef MACOS +# if (defined(__MWERKS__) && defined(macintosh)) || defined(applec) || \ + defined(THINK_C) || defined(__SC__) || defined(TARGET_OS_MAC) +# define MACOS +# endif +#endif + +/* enough people need this for various reasons to include it here */ +#if !defined(MACOS) && !defined(RISCOS) && !defined(_WIN32_WCE) +# include <sys/types.h> +#endif + +#if !defined(PNG_SETJMP_NOT_SUPPORTED) && !defined(PNG_NO_SETJMP_SUPPORTED) +# define PNG_SETJMP_SUPPORTED +#endif + +#ifdef PNG_SETJMP_SUPPORTED +/* This is an attempt to force a single setjmp behaviour on Linux. If + * the X config stuff didn't define _BSD_SOURCE we wouldn't need this. + */ + +# ifdef __linux__ +# ifdef _BSD_SOURCE +# define PNG_SAVE_BSD_SOURCE +# undef _BSD_SOURCE +# endif +# ifdef _SETJMP_H + /* If you encounter a compiler error here, see the explanation + * near the end of INSTALL. + */ + __png.h__ already includes setjmp.h; + __dont__ include it again.; +# endif +# endif /* __linux__ */ + + /* include setjmp.h for error handling */ +# include <setjmp.h> + +# ifdef __linux__ +# ifdef PNG_SAVE_BSD_SOURCE +# define _BSD_SOURCE +# undef PNG_SAVE_BSD_SOURCE +# endif +# endif /* __linux__ */ +#endif /* PNG_SETJMP_SUPPORTED */ + +#ifdef BSD +# include <strings.h> +#else +# include <string.h> +#endif + +/* Other defines for things like memory and the like can go here. */ +#ifdef PNG_INTERNAL + +#include <stdlib.h> + +/* The functions exported by PNG_EXTERN are PNG_INTERNAL functions, which + * aren't usually used outside the library (as far as I know), so it is + * debatable if they should be exported at all. In the future, when it is + * possible to have run-time registry of chunk-handling functions, some of + * these will be made available again. +#define PNG_EXTERN extern + */ +#define PNG_EXTERN + +/* Other defines specific to compilers can go here. Try to keep + * them inside an appropriate ifdef/endif pair for portability. + */ + +#if defined(PNG_FLOATING_POINT_SUPPORTED) +# if defined(MACOS) + /* We need to check that <math.h> hasn't already been included earlier + * as it seems it doesn't agree with <fp.h>, yet we should really use + * <fp.h> if possible. + */ +# if !defined(__MATH_H__) && !defined(__MATH_H) && !defined(__cmath__) +# include <fp.h> +# endif +# else +# include <math.h> +# endif +# if defined(_AMIGA) && defined(__SASC) && defined(_M68881) + /* Amiga SAS/C: We must include builtin FPU functions when compiling using + * MATH=68881 + */ +# include <m68881.h> +# endif +#endif + +/* Codewarrior on NT has linking problems without this. */ +#if (defined(__MWERKS__) && defined(WIN32)) || defined(__STDC__) +# define PNG_ALWAYS_EXTERN +#endif + +/* This provides the non-ANSI (far) memory allocation routines. */ +#if defined(__TURBOC__) && defined(__MSDOS__) +# include <mem.h> +# include <alloc.h> +#endif + +/* I have no idea why is this necessary... */ +#if defined(_MSC_VER) && (defined(WIN32) || defined(_Windows) || \ + defined(_WINDOWS) || defined(_WIN32) || defined(__WIN32__)) +# include <malloc.h> +#endif + +/* This controls how fine the dithering gets. As this allocates + * a largish chunk of memory (32K), those who are not as concerned + * with dithering quality can decrease some or all of these. + */ +#ifndef PNG_DITHER_RED_BITS +# define PNG_DITHER_RED_BITS 5 +#endif +#ifndef PNG_DITHER_GREEN_BITS +# define PNG_DITHER_GREEN_BITS 5 +#endif +#ifndef PNG_DITHER_BLUE_BITS +# define PNG_DITHER_BLUE_BITS 5 +#endif + +/* This controls how fine the gamma correction becomes when you + * are only interested in 8 bits anyway. Increasing this value + * results in more memory being used, and more pow() functions + * being called to fill in the gamma tables. Don't set this value + * less then 8, and even that may not work (I haven't tested it). + */ + +#ifndef PNG_MAX_GAMMA_8 +# define PNG_MAX_GAMMA_8 11 +#endif + +/* This controls how much a difference in gamma we can tolerate before + * we actually start doing gamma conversion. + */ +#ifndef PNG_GAMMA_THRESHOLD +# define PNG_GAMMA_THRESHOLD 0.05 +#endif + +#endif /* PNG_INTERNAL */ + +/* The following uses const char * instead of char * for error + * and warning message functions, so some compilers won't complain. + * If you do not want to use const, define PNG_NO_CONST here. + */ + +#ifndef PNG_NO_CONST +# define PNG_CONST const +#else +# define PNG_CONST +#endif + +/* The following defines give you the ability to remove code from the + * library that you will not be using. I wish I could figure out how to + * automate this, but I can't do that without making it seriously hard + * on the users. So if you are not using an ability, change the #define + * to and #undef, and that part of the library will not be compiled. If + * your linker can't find a function, you may want to make sure the + * ability is defined here. Some of these depend upon some others being + * defined. I haven't figured out all the interactions here, so you may + * have to experiment awhile to get everything to compile. If you are + * creating or using a shared library, you probably shouldn't touch this, + * as it will affect the size of the structures, and this will cause bad + * things to happen if the library and/or application ever change. + */ + +/* Any features you will not be using can be undef'ed here */ + +/* GR-P, 0.96a: Set "*TRANSFORMS_SUPPORTED as default but allow user + * to turn it off with "*TRANSFORMS_NOT_SUPPORTED" or *PNG_NO_*_TRANSFORMS + * on the compile line, then pick and choose which ones to define without + * having to edit this file. It is safe to use the *TRANSFORMS_NOT_SUPPORTED + * if you only want to have a png-compliant reader/writer but don't need + * any of the extra transformations. This saves about 80 kbytes in a + * typical installation of the library. (PNG_NO_* form added in version + * 1.0.1c, for consistency) + */ + +/* The size of the png_text structure changed in libpng-1.0.6 when + * iTXt is supported. It is turned off by default, to support old apps + * that malloc the png_text structure instead of calling png_set_text() + * and letting libpng malloc it. It will be turned on by default in + * libpng-1.3.0. + */ + +#ifndef PNG_iTXt_SUPPORTED +# if !defined(PNG_READ_iTXt_SUPPORTED) && !defined(PNG_NO_READ_iTXt) +# define PNG_NO_READ_iTXt +# endif +# if !defined(PNG_WRITE_iTXt_SUPPORTED) && !defined(PNG_NO_WRITE_iTXt) +# define PNG_NO_WRITE_iTXt +# endif +#endif + +/* The following support, added after version 1.0.0, can be turned off here en + * masse by defining PNG_LEGACY_SUPPORTED in case you need binary compatibility + * with old applications that require the length of png_struct and png_info + * to remain unchanged. + */ + +#ifdef PNG_LEGACY_SUPPORTED +# define PNG_NO_FREE_ME +# define PNG_NO_READ_UNKNOWN_CHUNKS +# define PNG_NO_WRITE_UNKNOWN_CHUNKS +# define PNG_NO_READ_USER_CHUNKS +# define PNG_NO_READ_iCCP +# define PNG_NO_WRITE_iCCP +# define PNG_NO_READ_iTXt +# define PNG_NO_WRITE_iTXt +# define PNG_NO_READ_sCAL +# define PNG_NO_WRITE_sCAL +# define PNG_NO_READ_sPLT +# define PNG_NO_WRITE_sPLT +# define PNG_NO_INFO_IMAGE +# define PNG_NO_READ_RGB_TO_GRAY +# define PNG_NO_READ_USER_TRANSFORM +# define PNG_NO_WRITE_USER_TRANSFORM +# define PNG_NO_USER_MEM +# define PNG_NO_READ_EMPTY_PLTE +# define PNG_NO_MNG_FEATURES +# define PNG_NO_FIXED_POINT_SUPPORTED +#endif + +/* Ignore attempt to turn off both floating and fixed point support */ +#if !defined(PNG_FLOATING_POINT_SUPPORTED) || \ + !defined(PNG_NO_FIXED_POINT_SUPPORTED) +# define PNG_FIXED_POINT_SUPPORTED +#endif + +#ifndef PNG_NO_FREE_ME +# define PNG_FREE_ME_SUPPORTED +#endif + +#if defined(PNG_READ_SUPPORTED) + +#if !defined(PNG_READ_TRANSFORMS_NOT_SUPPORTED) && \ + !defined(PNG_NO_READ_TRANSFORMS) +# define PNG_READ_TRANSFORMS_SUPPORTED +#endif + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +# ifndef PNG_NO_READ_EXPAND +# define PNG_READ_EXPAND_SUPPORTED +# endif +# ifndef PNG_NO_READ_SHIFT +# define PNG_READ_SHIFT_SUPPORTED +# endif +# ifndef PNG_NO_READ_PACK +# define PNG_READ_PACK_SUPPORTED +# endif +# ifndef PNG_NO_READ_BGR +# define PNG_READ_BGR_SUPPORTED +# endif +# ifndef PNG_NO_READ_SWAP +# define PNG_READ_SWAP_SUPPORTED +# endif +# ifndef PNG_NO_READ_PACKSWAP +# define PNG_READ_PACKSWAP_SUPPORTED +# endif +# ifndef PNG_NO_READ_INVERT +# define PNG_READ_INVERT_SUPPORTED +# endif +# ifndef PNG_NO_READ_DITHER +# define PNG_READ_DITHER_SUPPORTED +# endif +# ifndef PNG_NO_READ_BACKGROUND +# define PNG_READ_BACKGROUND_SUPPORTED +# endif +# ifndef PNG_NO_READ_16_TO_8 +# define PNG_READ_16_TO_8_SUPPORTED +# endif +# ifndef PNG_NO_READ_FILLER +# define PNG_READ_FILLER_SUPPORTED +# endif +# ifndef PNG_NO_READ_GAMMA +# define PNG_READ_GAMMA_SUPPORTED +# endif +# ifndef PNG_NO_READ_GRAY_TO_RGB +# define PNG_READ_GRAY_TO_RGB_SUPPORTED +# endif +# ifndef PNG_NO_READ_SWAP_ALPHA +# define PNG_READ_SWAP_ALPHA_SUPPORTED +# endif +# ifndef PNG_NO_READ_INVERT_ALPHA +# define PNG_READ_INVERT_ALPHA_SUPPORTED +# endif +# ifndef PNG_NO_READ_STRIP_ALPHA +# define PNG_READ_STRIP_ALPHA_SUPPORTED +# endif +# ifndef PNG_NO_READ_USER_TRANSFORM +# define PNG_READ_USER_TRANSFORM_SUPPORTED +# endif +# ifndef PNG_NO_READ_RGB_TO_GRAY +# define PNG_READ_RGB_TO_GRAY_SUPPORTED +# endif +#endif /* PNG_READ_TRANSFORMS_SUPPORTED */ + +#if !defined(PNG_NO_PROGRESSIVE_READ) && \ + !defined(PNG_PROGRESSIVE_READ_NOT_SUPPORTED) /* if you don't do progressive */ +# define PNG_PROGRESSIVE_READ_SUPPORTED /* reading. This is not talking */ +#endif /* about interlacing capability! You'll */ + /* still have interlacing unless you change the following line: */ + +#define PNG_READ_INTERLACING_SUPPORTED /* required for PNG-compliant decoders */ + +#ifndef PNG_NO_READ_COMPOSITE_NODIV +# ifndef PNG_NO_READ_COMPOSITED_NODIV /* libpng-1.0.x misspelling */ +# define PNG_READ_COMPOSITE_NODIV_SUPPORTED /* well tested on Intel, SGI */ +# endif +#endif + +/* Deprecated, will be removed from version 2.0.0. + Use PNG_MNG_FEATURES_SUPPORTED instead. */ +#ifndef PNG_NO_READ_EMPTY_PLTE +# define PNG_READ_EMPTY_PLTE_SUPPORTED +#endif + +#endif /* PNG_READ_SUPPORTED */ + +#if defined(PNG_WRITE_SUPPORTED) + +# if !defined(PNG_WRITE_TRANSFORMS_NOT_SUPPORTED) && \ + !defined(PNG_NO_WRITE_TRANSFORMS) +# define PNG_WRITE_TRANSFORMS_SUPPORTED +#endif + +#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED +# ifndef PNG_NO_WRITE_SHIFT +# define PNG_WRITE_SHIFT_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_PACK +# define PNG_WRITE_PACK_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_BGR +# define PNG_WRITE_BGR_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_SWAP +# define PNG_WRITE_SWAP_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_PACKSWAP +# define PNG_WRITE_PACKSWAP_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_INVERT +# define PNG_WRITE_INVERT_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_FILLER +# define PNG_WRITE_FILLER_SUPPORTED /* same as WRITE_STRIP_ALPHA */ +# endif +# ifndef PNG_NO_WRITE_SWAP_ALPHA +# define PNG_WRITE_SWAP_ALPHA_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_INVERT_ALPHA +# define PNG_WRITE_INVERT_ALPHA_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_USER_TRANSFORM +# define PNG_WRITE_USER_TRANSFORM_SUPPORTED +# endif +#endif /* PNG_WRITE_TRANSFORMS_SUPPORTED */ + +#define PNG_WRITE_INTERLACING_SUPPORTED /* not required for PNG-compliant + encoders, but can cause trouble + if left undefined */ + +#if !defined(PNG_NO_WRITE_WEIGHTED_FILTER) && \ + defined(PNG_FLOATING_POINT_SUPPORTED) +# define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED +#endif + +#ifndef PNG_NO_WRITE_FLUSH +# define PNG_WRITE_FLUSH_SUPPORTED +#endif + +/* Deprecated, see PNG_MNG_FEATURES_SUPPORTED, above */ +#ifndef PNG_NO_WRITE_EMPTY_PLTE +# define PNG_WRITE_EMPTY_PLTE_SUPPORTED +#endif + +#endif /* PNG_WRITE_SUPPORTED */ + +#ifndef PNG_1_0_X +# ifndef PNG_NO_ERROR_NUMBERS +# define PNG_ERROR_NUMBERS_SUPPORTED +# endif +#endif /* PNG_1_0_X */ + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) +# ifndef PNG_NO_USER_TRANSFORM_PTR +# define PNG_USER_TRANSFORM_PTR_SUPPORTED +# endif +#endif + +#ifndef PNG_NO_STDIO +# define PNG_TIME_RFC1123_SUPPORTED +#endif + +/* This adds extra functions in pngget.c for accessing data from the + * info pointer (added in version 0.99) + * png_get_image_width() + * png_get_image_height() + * png_get_bit_depth() + * png_get_color_type() + * png_get_compression_type() + * png_get_filter_type() + * png_get_interlace_type() + * png_get_pixel_aspect_ratio() + * png_get_pixels_per_meter() + * png_get_x_offset_pixels() + * png_get_y_offset_pixels() + * png_get_x_offset_microns() + * png_get_y_offset_microns() + */ +#if !defined(PNG_NO_EASY_ACCESS) && !defined(PNG_EASY_ACCESS_SUPPORTED) +# define PNG_EASY_ACCESS_SUPPORTED +#endif + +/* PNG_ASSEMBLER_CODE was enabled by default in version 1.2.0 + even when PNG_USE_PNGVCRD or PNG_USE_PNGGCCRD is not defined */ +#if defined(PNG_READ_SUPPORTED) && !defined(PNG_NO_ASSEMBLER_CODE) +# ifndef PNG_ASSEMBLER_CODE_SUPPORTED +# define PNG_ASSEMBLER_CODE_SUPPORTED +# endif +# if !defined(PNG_MMX_CODE_SUPPORTED) && !defined(PNG_NO_MMX_CODE) +# define PNG_MMX_CODE_SUPPORTED +# endif +#endif + +/* If you are sure that you don't need thread safety and you are compiling + with PNG_USE_PNGCCRD for an MMX application, you can define this for + faster execution. See pnggccrd.c. +#define PNG_THREAD_UNSAFE_OK +*/ + +#if !defined(PNG_1_0_X) +#if !defined(PNG_NO_USER_MEM) && !defined(PNG_USER_MEM_SUPPORTED) +# define PNG_USER_MEM_SUPPORTED +#endif +#endif /* PNG_1_0_X */ + +/* Added at libpng-1.2.6 */ +#if !defined(PNG_1_0_X) +#ifndef PNG_SET_USER_LIMITS_SUPPORTED +#if !defined(PNG_NO_SET_USER_LIMITS) && !defined(PNG_SET_USER_LIMITS_SUPPORTED) +# define PNG_SET_USER_LIMITS_SUPPORTED +#endif +#endif +#endif /* PNG_1_0_X */ + +/* Added at libpng-1.0.16 and 1.2.6. To accept all valid PNGS no matter + * how large, set these limits to 0x7fffffffL + */ +#ifndef PNG_USER_WIDTH_MAX +# define PNG_USER_WIDTH_MAX 1000000L +#endif +#ifndef PNG_USER_HEIGHT_MAX +# define PNG_USER_HEIGHT_MAX 1000000L +#endif + +/* These are currently experimental features, define them if you want */ + +/* very little testing */ +/* +#ifdef PNG_READ_SUPPORTED +# ifndef PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED +# define PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED +# endif +#endif +*/ + +/* This is only for PowerPC big-endian and 680x0 systems */ +/* some testing */ +/* +#ifndef PNG_READ_BIG_ENDIAN_SUPPORTED +# define PNG_READ_BIG_ENDIAN_SUPPORTED +#endif +*/ + +/* Buggy compilers (e.g., gcc 2.7.2.2) need this */ +/* +#define PNG_NO_POINTER_INDEXING +*/ + +/* These functions are turned off by default, as they will be phased out. */ +/* +#define PNG_USELESS_TESTS_SUPPORTED +#define PNG_CORRECT_PALETTE_SUPPORTED +*/ + +/* Any chunks you are not interested in, you can undef here. The + * ones that allocate memory may be expecially important (hIST, + * tEXt, zTXt, tRNS, pCAL). Others will just save time and make png_info + * a bit smaller. + */ + +#if defined(PNG_READ_SUPPORTED) && \ + !defined(PNG_READ_ANCILLARY_CHUNKS_NOT_SUPPORTED) && \ + !defined(PNG_NO_READ_ANCILLARY_CHUNKS) +# define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED +#endif + +#if defined(PNG_WRITE_SUPPORTED) && \ + !defined(PNG_WRITE_ANCILLARY_CHUNKS_NOT_SUPPORTED) && \ + !defined(PNG_NO_WRITE_ANCILLARY_CHUNKS) +# define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED +#endif + +#ifdef PNG_READ_ANCILLARY_CHUNKS_SUPPORTED + +#ifdef PNG_NO_READ_TEXT +# define PNG_NO_READ_iTXt +# define PNG_NO_READ_tEXt +# define PNG_NO_READ_zTXt +#endif +#ifndef PNG_NO_READ_bKGD +# define PNG_READ_bKGD_SUPPORTED +# define PNG_bKGD_SUPPORTED +#endif +#ifndef PNG_NO_READ_cHRM +# define PNG_READ_cHRM_SUPPORTED +# define PNG_cHRM_SUPPORTED +#endif +#ifndef PNG_NO_READ_gAMA +# define PNG_READ_gAMA_SUPPORTED +# define PNG_gAMA_SUPPORTED +#endif +#ifndef PNG_NO_READ_hIST +# define PNG_READ_hIST_SUPPORTED +# define PNG_hIST_SUPPORTED +#endif +#ifndef PNG_NO_READ_iCCP +# define PNG_READ_iCCP_SUPPORTED +# define PNG_iCCP_SUPPORTED +#endif +#ifndef PNG_NO_READ_iTXt +# ifndef PNG_READ_iTXt_SUPPORTED +# define PNG_READ_iTXt_SUPPORTED +# endif +# ifndef PNG_iTXt_SUPPORTED +# define PNG_iTXt_SUPPORTED +# endif +#endif +#ifndef PNG_NO_READ_oFFs +# define PNG_READ_oFFs_SUPPORTED +# define PNG_oFFs_SUPPORTED +#endif +#ifndef PNG_NO_READ_pCAL +# define PNG_READ_pCAL_SUPPORTED +# define PNG_pCAL_SUPPORTED +#endif +#ifndef PNG_NO_READ_sCAL +# define PNG_READ_sCAL_SUPPORTED +# define PNG_sCAL_SUPPORTED +#endif +#ifndef PNG_NO_READ_pHYs +# define PNG_READ_pHYs_SUPPORTED +# define PNG_pHYs_SUPPORTED +#endif +#ifndef PNG_NO_READ_sBIT +# define PNG_READ_sBIT_SUPPORTED +# define PNG_sBIT_SUPPORTED +#endif +#ifndef PNG_NO_READ_sPLT +# define PNG_READ_sPLT_SUPPORTED +# define PNG_sPLT_SUPPORTED +#endif +#ifndef PNG_NO_READ_sRGB +# define PNG_READ_sRGB_SUPPORTED +# define PNG_sRGB_SUPPORTED +#endif +#ifndef PNG_NO_READ_tEXt +# define PNG_READ_tEXt_SUPPORTED +# define PNG_tEXt_SUPPORTED +#endif +#ifndef PNG_NO_READ_tIME +# define PNG_READ_tIME_SUPPORTED +# define PNG_tIME_SUPPORTED +#endif +#ifndef PNG_NO_READ_tRNS +# define PNG_READ_tRNS_SUPPORTED +# define PNG_tRNS_SUPPORTED +#endif +#ifndef PNG_NO_READ_zTXt +# define PNG_READ_zTXt_SUPPORTED +# define PNG_zTXt_SUPPORTED +#endif +#ifndef PNG_NO_READ_UNKNOWN_CHUNKS +# define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED +# ifndef PNG_UNKNOWN_CHUNKS_SUPPORTED +# define PNG_UNKNOWN_CHUNKS_SUPPORTED +# endif +# ifndef PNG_NO_HANDLE_AS_UNKNOWN +# define PNG_HANDLE_AS_UNKNOWN_SUPPORTED +# endif +#endif +#if !defined(PNG_NO_READ_USER_CHUNKS) && \ + defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) +# define PNG_READ_USER_CHUNKS_SUPPORTED +# define PNG_USER_CHUNKS_SUPPORTED +# ifdef PNG_NO_READ_UNKNOWN_CHUNKS +# undef PNG_NO_READ_UNKNOWN_CHUNKS +# endif +# ifdef PNG_NO_HANDLE_AS_UNKNOWN +# undef PNG_NO_HANDLE_AS_UNKNOWN +# endif +#endif +#ifndef PNG_NO_READ_OPT_PLTE +# define PNG_READ_OPT_PLTE_SUPPORTED /* only affects support of the */ +#endif /* optional PLTE chunk in RGB and RGBA images */ +#if defined(PNG_READ_iTXt_SUPPORTED) || defined(PNG_READ_tEXt_SUPPORTED) || \ + defined(PNG_READ_zTXt_SUPPORTED) +# define PNG_READ_TEXT_SUPPORTED +# define PNG_TEXT_SUPPORTED +#endif + +#endif /* PNG_READ_ANCILLARY_CHUNKS_SUPPORTED */ + +#ifdef PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED + +#ifdef PNG_NO_WRITE_TEXT +# define PNG_NO_WRITE_iTXt +# define PNG_NO_WRITE_tEXt +# define PNG_NO_WRITE_zTXt +#endif +#ifndef PNG_NO_WRITE_bKGD +# define PNG_WRITE_bKGD_SUPPORTED +# ifndef PNG_bKGD_SUPPORTED +# define PNG_bKGD_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_cHRM +# define PNG_WRITE_cHRM_SUPPORTED +# ifndef PNG_cHRM_SUPPORTED +# define PNG_cHRM_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_gAMA +# define PNG_WRITE_gAMA_SUPPORTED +# ifndef PNG_gAMA_SUPPORTED +# define PNG_gAMA_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_hIST +# define PNG_WRITE_hIST_SUPPORTED +# ifndef PNG_hIST_SUPPORTED +# define PNG_hIST_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_iCCP +# define PNG_WRITE_iCCP_SUPPORTED +# ifndef PNG_iCCP_SUPPORTED +# define PNG_iCCP_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_iTXt +# ifndef PNG_WRITE_iTXt_SUPPORTED +# define PNG_WRITE_iTXt_SUPPORTED +# endif +# ifndef PNG_iTXt_SUPPORTED +# define PNG_iTXt_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_oFFs +# define PNG_WRITE_oFFs_SUPPORTED +# ifndef PNG_oFFs_SUPPORTED +# define PNG_oFFs_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_pCAL +# define PNG_WRITE_pCAL_SUPPORTED +# ifndef PNG_pCAL_SUPPORTED +# define PNG_pCAL_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_sCAL +# define PNG_WRITE_sCAL_SUPPORTED +# ifndef PNG_sCAL_SUPPORTED +# define PNG_sCAL_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_pHYs +# define PNG_WRITE_pHYs_SUPPORTED +# ifndef PNG_pHYs_SUPPORTED +# define PNG_pHYs_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_sBIT +# define PNG_WRITE_sBIT_SUPPORTED +# ifndef PNG_sBIT_SUPPORTED +# define PNG_sBIT_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_sPLT +# define PNG_WRITE_sPLT_SUPPORTED +# ifndef PNG_sPLT_SUPPORTED +# define PNG_sPLT_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_sRGB +# define PNG_WRITE_sRGB_SUPPORTED +# ifndef PNG_sRGB_SUPPORTED +# define PNG_sRGB_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_tEXt +# define PNG_WRITE_tEXt_SUPPORTED +# ifndef PNG_tEXt_SUPPORTED +# define PNG_tEXt_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_tIME +# define PNG_WRITE_tIME_SUPPORTED +# ifndef PNG_tIME_SUPPORTED +# define PNG_tIME_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_tRNS +# define PNG_WRITE_tRNS_SUPPORTED +# ifndef PNG_tRNS_SUPPORTED +# define PNG_tRNS_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_zTXt +# define PNG_WRITE_zTXt_SUPPORTED +# ifndef PNG_zTXt_SUPPORTED +# define PNG_zTXt_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_UNKNOWN_CHUNKS +# define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED +# ifndef PNG_UNKNOWN_CHUNKS_SUPPORTED +# define PNG_UNKNOWN_CHUNKS_SUPPORTED +# endif +# ifndef PNG_NO_HANDLE_AS_UNKNOWN +# ifndef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +# define PNG_HANDLE_AS_UNKNOWN_SUPPORTED +# endif +# endif +#endif +#if defined(PNG_WRITE_iTXt_SUPPORTED) || defined(PNG_WRITE_tEXt_SUPPORTED) || \ + defined(PNG_WRITE_zTXt_SUPPORTED) +# define PNG_WRITE_TEXT_SUPPORTED +# ifndef PNG_TEXT_SUPPORTED +# define PNG_TEXT_SUPPORTED +# endif +#endif + +#endif /* PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED */ + +/* Turn this off to disable png_read_png() and + * png_write_png() and leave the row_pointers member + * out of the info structure. + */ +#ifndef PNG_NO_INFO_IMAGE +# define PNG_INFO_IMAGE_SUPPORTED +#endif + +/* need the time information for reading tIME chunks */ +#if defined(PNG_tIME_SUPPORTED) +# if !defined(_WIN32_WCE) && !defined(__COM32__) + /* "time.h" functions are not supported on WindowsCE */ +# include <time.h> +# endif +#endif + +/* Some typedefs to get us started. These should be safe on most of the + * common platforms. The typedefs should be at least as large as the + * numbers suggest (a png_uint_32 must be at least 32 bits long), but they + * don't have to be exactly that size. Some compilers dislike passing + * unsigned shorts as function parameters, so you may be better off using + * unsigned int for png_uint_16. Likewise, for 64-bit systems, you may + * want to have unsigned int for png_uint_32 instead of unsigned long. + */ + +typedef unsigned long png_uint_32; +typedef long png_int_32; +typedef unsigned short png_uint_16; +typedef short png_int_16; +typedef unsigned char png_byte; + +/* This is usually size_t. It is typedef'ed just in case you need it to + change (I'm not sure if you will or not, so I thought I'd be safe) */ +#ifdef PNG_SIZE_T + typedef PNG_SIZE_T png_size_t; +# define png_sizeof(x) png_convert_size(sizeof (x)) +#else + typedef size_t png_size_t; +# define png_sizeof(x) sizeof (x) +#endif + +/* The following is needed for medium model support. It cannot be in the + * PNG_INTERNAL section. Needs modification for other compilers besides + * MSC. Model independent support declares all arrays and pointers to be + * large using the far keyword. The zlib version used must also support + * model independent data. As of version zlib 1.0.4, the necessary changes + * have been made in zlib. The USE_FAR_KEYWORD define triggers other + * changes that are needed. (Tim Wegner) + */ + +/* Separate compiler dependencies (problem here is that zlib.h always + defines FAR. (SJT) */ +#ifdef __BORLANDC__ +# if defined(__LARGE__) || defined(__HUGE__) || defined(__COMPACT__) +# define LDATA 1 +# else +# define LDATA 0 +# endif + /* GRR: why is Cygwin in here? Cygwin is not Borland C... */ +# if !defined(__WIN32__) && !defined(__FLAT__) && !defined(__CYGWIN__) +# define PNG_MAX_MALLOC_64K +# if (LDATA != 1) +# ifndef FAR +# define FAR __far +# endif +# define USE_FAR_KEYWORD +# endif /* LDATA != 1 */ + /* Possibly useful for moving data out of default segment. + * Uncomment it if you want. Could also define FARDATA as + * const if your compiler supports it. (SJT) +# define FARDATA FAR + */ +# endif /* __WIN32__, __FLAT__, __CYGWIN__ */ +#endif /* __BORLANDC__ */ + + +/* Suggest testing for specific compiler first before testing for + * FAR. The Watcom compiler defines both __MEDIUM__ and M_I86MM, + * making reliance oncertain keywords suspect. (SJT) + */ + +/* MSC Medium model */ +#if defined(FAR) +# if defined(M_I86MM) +# define USE_FAR_KEYWORD +# define FARDATA FAR +# include <dos.h> +# endif +#endif + +/* SJT: default case */ +#ifndef FAR +# define FAR +#endif + +/* At this point FAR is always defined */ +#ifndef FARDATA +# define FARDATA +#endif + +/* Typedef for floating-point numbers that are converted + to fixed-point with a multiple of 100,000, e.g., int_gamma */ +typedef png_int_32 png_fixed_point; + +/* Add typedefs for pointers */ +typedef void FAR * png_voidp; +typedef png_byte FAR * png_bytep; +typedef png_uint_32 FAR * png_uint_32p; +typedef png_int_32 FAR * png_int_32p; +typedef png_uint_16 FAR * png_uint_16p; +typedef png_int_16 FAR * png_int_16p; +typedef PNG_CONST char FAR * png_const_charp; +typedef char FAR * png_charp; +typedef png_fixed_point FAR * png_fixed_point_p; + +#ifndef PNG_NO_STDIO +#if defined(_WIN32_WCE) +typedef HANDLE png_FILE_p; +#else +typedef FILE * png_FILE_p; +#endif +#endif + +#ifdef PNG_FLOATING_POINT_SUPPORTED +typedef double FAR * png_doublep; +#endif + +/* Pointers to pointers; i.e. arrays */ +typedef png_byte FAR * FAR * png_bytepp; +typedef png_uint_32 FAR * FAR * png_uint_32pp; +typedef png_int_32 FAR * FAR * png_int_32pp; +typedef png_uint_16 FAR * FAR * png_uint_16pp; +typedef png_int_16 FAR * FAR * png_int_16pp; +typedef PNG_CONST char FAR * FAR * png_const_charpp; +typedef char FAR * FAR * png_charpp; +typedef png_fixed_point FAR * FAR * png_fixed_point_pp; +#ifdef PNG_FLOATING_POINT_SUPPORTED +typedef double FAR * FAR * png_doublepp; +#endif + +/* Pointers to pointers to pointers; i.e., pointer to array */ +typedef char FAR * FAR * FAR * png_charppp; + +#if defined(PNG_1_0_X) || defined(PNG_1_2_X) +/* SPC - Is this stuff deprecated? */ +/* It'll be removed as of libpng-1.3.0 - GR-P */ +/* libpng typedefs for types in zlib. If zlib changes + * or another compression library is used, then change these. + * Eliminates need to change all the source files. + */ +typedef charf * png_zcharp; +typedef charf * FAR * png_zcharpp; +typedef z_stream FAR * png_zstreamp; +#endif /* (PNG_1_0_X) || defined(PNG_1_2_X) */ + +/* + * Define PNG_BUILD_DLL if the module being built is a Windows + * LIBPNG DLL. + * + * Define PNG_USE_DLL if you want to *link* to the Windows LIBPNG DLL. + * It is equivalent to Microsoft predefined macro _DLL that is + * automatically defined when you compile using the share + * version of the CRT (C Run-Time library) + * + * The cygwin mods make this behavior a little different: + * Define PNG_BUILD_DLL if you are building a dll for use with cygwin + * Define PNG_STATIC if you are building a static library for use with cygwin, + * -or- if you are building an application that you want to link to the + * static library. + * PNG_USE_DLL is defined by default (no user action needed) unless one of + * the other flags is defined. + */ + +#if !defined(PNG_DLL) && (defined(PNG_BUILD_DLL) || defined(PNG_USE_DLL)) +# define PNG_DLL +#endif +/* If CYGWIN, then disallow GLOBAL ARRAYS unless building a static lib. + * When building a static lib, default to no GLOBAL ARRAYS, but allow + * command-line override + */ +#if defined(__CYGWIN__) +# if !defined(PNG_STATIC) +# if defined(PNG_USE_GLOBAL_ARRAYS) +# undef PNG_USE_GLOBAL_ARRAYS +# endif +# if !defined(PNG_USE_LOCAL_ARRAYS) +# define PNG_USE_LOCAL_ARRAYS +# endif +# else +# if defined(PNG_USE_LOCAL_ARRAYS) || defined(PNG_NO_GLOBAL_ARRAYS) +# if defined(PNG_USE_GLOBAL_ARRAYS) +# undef PNG_USE_GLOBAL_ARRAYS +# endif +# endif +# endif +# if !defined(PNG_USE_LOCAL_ARRAYS) && !defined(PNG_USE_GLOBAL_ARRAYS) +# define PNG_USE_LOCAL_ARRAYS +# endif +#endif + +/* Do not use global arrays (helps with building DLL's) + * They are no longer used in libpng itself, since version 1.0.5c, + * but might be required for some pre-1.0.5c applications. + */ +#if !defined(PNG_USE_LOCAL_ARRAYS) && !defined(PNG_USE_GLOBAL_ARRAYS) +# if defined(PNG_NO_GLOBAL_ARRAYS) || (defined(__GNUC__) && defined(PNG_DLL)) +# define PNG_USE_LOCAL_ARRAYS +# else +# define PNG_USE_GLOBAL_ARRAYS +# endif +#endif + +#if defined(__CYGWIN__) +# undef PNGAPI +# define PNGAPI __cdecl +# undef PNG_IMPEXP +# define PNG_IMPEXP +#endif + +/* If you define PNGAPI, e.g., with compiler option "-DPNGAPI=__stdcall", + * you may get warnings regarding the linkage of png_zalloc and png_zfree. + * Don't ignore those warnings; you must also reset the default calling + * convention in your compiler to match your PNGAPI, and you must build + * zlib and your applications the same way you build libpng. + */ + +#if defined(__MINGW32__) && !defined(PNG_MODULEDEF) +# ifndef PNG_NO_MODULEDEF +# define PNG_NO_MODULEDEF +# endif +#endif + +#if !defined(PNG_IMPEXP) && defined(PNG_BUILD_DLL) && !defined(PNG_NO_MODULEDEF) +# define PNG_IMPEXP +#endif + +#if defined(PNG_DLL) || defined(_DLL) || defined(__DLL__ ) || \ + (( defined(_Windows) || defined(_WINDOWS) || \ + defined(WIN32) || defined(_WIN32) || defined(__WIN32__) )) + +# ifndef PNGAPI +# if defined(__GNUC__) || (defined (_MSC_VER) && (_MSC_VER >= 800)) +# define PNGAPI __cdecl +# else +# define PNGAPI _cdecl +# endif +# endif + +# if !defined(PNG_IMPEXP) && (!defined(PNG_DLL) || \ + 0 /* WINCOMPILER_WITH_NO_SUPPORT_FOR_DECLIMPEXP */) +# define PNG_IMPEXP +# endif + +# if !defined(PNG_IMPEXP) + +# define PNG_EXPORT_TYPE1(type,symbol) PNG_IMPEXP type PNGAPI symbol +# define PNG_EXPORT_TYPE2(type,symbol) type PNG_IMPEXP PNGAPI symbol + + /* Borland/Microsoft */ +# if defined(_MSC_VER) || defined(__BORLANDC__) +# if (_MSC_VER >= 800) || (__BORLANDC__ >= 0x500) +# define PNG_EXPORT PNG_EXPORT_TYPE1 +# else +# define PNG_EXPORT PNG_EXPORT_TYPE2 +# if defined(PNG_BUILD_DLL) +# define PNG_IMPEXP __export +# else +# define PNG_IMPEXP /*__import */ /* doesn't exist AFAIK in + VC++ */ +# endif /* Exists in Borland C++ for + C++ classes (== huge) */ +# endif +# endif + +# if !defined(PNG_IMPEXP) +# if defined(PNG_BUILD_DLL) +# define PNG_IMPEXP __declspec(dllexport) +# else +# define PNG_IMPEXP __declspec(dllimport) +# endif +# endif +# endif /* PNG_IMPEXP */ +#else /* !(DLL || non-cygwin WINDOWS) */ +# if (defined(__IBMC__) || defined(__IBMCPP__)) && defined(__OS2__) +# ifndef PNGAPI +# define PNGAPI _System +# endif +# else +# if 0 /* ... other platforms, with other meanings */ +# endif +# endif +#endif + +#ifndef PNGAPI +# define PNGAPI +#endif +#ifndef PNG_IMPEXP +# define PNG_IMPEXP +#endif + +#ifdef PNG_BUILDSYMS +# ifndef PNG_EXPORT +# define PNG_EXPORT(type,symbol) PNG_FUNCTION_EXPORT symbol END +# endif +# ifdef PNG_USE_GLOBAL_ARRAYS +# ifndef PNG_EXPORT_VAR +# define PNG_EXPORT_VAR(type) PNG_DATA_EXPORT +# endif +# endif +#endif + +#ifndef PNG_EXPORT +# define PNG_EXPORT(type,symbol) PNG_IMPEXP type PNGAPI symbol +#endif + +#ifdef PNG_USE_GLOBAL_ARRAYS +# ifndef PNG_EXPORT_VAR +# define PNG_EXPORT_VAR(type) extern PNG_IMPEXP type +# endif +#endif + +/* User may want to use these so they are not in PNG_INTERNAL. Any library + * functions that are passed far data must be model independent. + */ + +#ifndef PNG_ABORT +# define PNG_ABORT() abort() +#endif + +#ifdef PNG_SETJMP_SUPPORTED +# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) +#else +# define png_jmpbuf(png_ptr) \ + (LIBPNG_WAS_COMPILED_WITH__PNG_SETJMP_NOT_SUPPORTED) +#endif + +#if defined(USE_FAR_KEYWORD) /* memory model independent fns */ +/* use this to make far-to-near assignments */ +# define CHECK 1 +# define NOCHECK 0 +# define CVT_PTR(ptr) (png_far_to_near(png_ptr,ptr,CHECK)) +# define CVT_PTR_NOCHECK(ptr) (png_far_to_near(png_ptr,ptr,NOCHECK)) +# define png_strcpy _fstrcpy +# define png_strncpy _fstrncpy /* Added to v 1.2.6 */ +# define png_strlen _fstrlen +# define png_memcmp _fmemcmp /* SJT: added */ +# define png_memcpy _fmemcpy +# define png_memset _fmemset +#else /* use the usual functions */ +# define CVT_PTR(ptr) (ptr) +# define CVT_PTR_NOCHECK(ptr) (ptr) +# define png_strcpy strcpy +# define png_strncpy strncpy /* Added to v 1.2.6 */ +# define png_strlen strlen +# define png_memcmp memcmp /* SJT: added */ +# define png_memcpy memcpy +# define png_memset memset +#endif +/* End of memory model independent support */ + +/* Just a little check that someone hasn't tried to define something + * contradictory. + */ +#if (PNG_ZBUF_SIZE > 65536L) && defined(PNG_MAX_MALLOC_64K) +# undef PNG_ZBUF_SIZE +# define PNG_ZBUF_SIZE 65536L +#endif + +#ifdef PNG_READ_SUPPORTED +/* Prior to libpng-1.0.9, this block was in pngasmrd.h */ +#if defined(PNG_INTERNAL) + +/* These are the default thresholds before the MMX code kicks in; if either + * rowbytes or bitdepth is below the threshold, plain C code is used. These + * can be overridden at runtime via the png_set_mmx_thresholds() call in + * libpng 1.2.0 and later. The values below were chosen by Intel. + */ + +#ifndef PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT +# define PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT 128 /* >= */ +#endif +#ifndef PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT +# define PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT 9 /* >= */ +#endif + +/* Set this in the makefile for VC++ on Pentium, not here. */ +/* Platform must be Pentium. Makefile must assemble and load pngvcrd.c . + * MMX will be detected at run time and used if present. + */ +#ifdef PNG_USE_PNGVCRD +# define PNG_HAVE_ASSEMBLER_COMBINE_ROW +# define PNG_HAVE_ASSEMBLER_READ_INTERLACE +# define PNG_HAVE_ASSEMBLER_READ_FILTER_ROW +#endif + +/* Set this in the makefile for gcc/as on Pentium, not here. */ +/* Platform must be Pentium. Makefile must assemble and load pnggccrd.c . + * MMX will be detected at run time and used if present. + */ +#ifdef PNG_USE_PNGGCCRD +# define PNG_HAVE_ASSEMBLER_COMBINE_ROW +# define PNG_HAVE_ASSEMBLER_READ_INTERLACE +# define PNG_HAVE_ASSEMBLER_READ_FILTER_ROW +#endif +/* - see pnggccrd.c for info about what is currently enabled */ + +#endif /* PNG_INTERNAL */ +#endif /* PNG_READ_SUPPORTED */ + +/* Added at libpng-1.2.8 */ +#endif /* PNG_VERSION_INFO_ONLY */ + +#endif /* PNGCONF_H */ diff --git a/syslinux/com32/include/stdarg.h b/syslinux/com32/include/stdarg.h new file mode 100644 index 0000000..cc324b8 --- /dev/null +++ b/syslinux/com32/include/stdarg.h @@ -0,0 +1,14 @@ +/* + * stdarg.h + * + * This is just a wrapper for the gcc one, but defines va_copy() + * even if gcc doesn't. + */ + +/* Note: the _STDARG_H macro belongs to the gcc header... */ +#include_next <stdarg.h> + +/* Older gcc considers this an extension, so it's double underbar only */ +#ifndef va_copy +#define va_copy(d,s) __va_copy(d,s) +#endif diff --git a/syslinux/com32/include/stdbool.h b/syslinux/com32/include/stdbool.h new file mode 100644 index 0000000..7e0cac5 --- /dev/null +++ b/syslinux/com32/include/stdbool.h @@ -0,0 +1,33 @@ +/* + * $Id: stdbool.h,v 1.1 2003/04/16 06:32:31 hpa Exp $ + * + * stdbool.h + */ + +#ifndef _STDBOOL_H +#define _STDBOOL_H + +#ifndef __cplusplus + +#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) +# if !defined(__GNUC__) ||(__GNUC__ < 3) + typedef char _Bool; /* For C compilers without _Bool */ +# endif +#endif + +#define bool _Bool +#define true 1 +#define false 0 + +#else + +/* C++ */ +#define bool bool +#define true true +#define false false + +#endif + +#define __bool_true_false_are_defined 1 + +#endif /* _STDBOOL_H */ diff --git a/syslinux/com32/include/stddef.h b/syslinux/com32/include/stddef.h new file mode 100644 index 0000000..125d235 --- /dev/null +++ b/syslinux/com32/include/stddef.h @@ -0,0 +1,24 @@ +/* + * stddef.h + */ + +#ifndef _STDDEF_H +#define _STDDEF_H + +#ifndef __KLIBC__ +# define __KLIBC__ 1 +#endif + +#include <bitsize/stddef.h> + +#undef NULL +#ifdef __cplusplus +# define NULL 0 +#else +# define NULL ((void *)0) +#endif + +#undef offsetof +#define offsetof(t,m) ((size_t)&((t *)0)->m) + +#endif /* _STDDEF_H */ diff --git a/syslinux/com32/include/stdint.h b/syslinux/com32/include/stdint.h new file mode 100644 index 0000000..bfe8032 --- /dev/null +++ b/syslinux/com32/include/stdint.h @@ -0,0 +1,146 @@ +/* + * stdint.h + */ + +#ifndef _STDINT_H +#define _STDINT_H + +/* Exact types */ + +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef signed long long int64_t; + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +/* Small types */ + +typedef signed char int_least8_t; +typedef signed short int_least16_t; +typedef signed int int_least32_t; +typedef signed long long int_least64_t; + +typedef unsigned char uint_least8_t; +typedef unsigned short uint_least16_t; +typedef unsigned int uint_least32_t; +typedef unsigned long long uint_least64_t; + +/* Fast types */ + +typedef signed char int_fast8_t; +typedef signed short int_fast16_t; +typedef signed int int_fast32_t; +typedef signed long long int_fast64_t; + +typedef unsigned char uint_fast8_t; +typedef unsigned short uint_fast16_t; +typedef unsigned int uint_fast32_t; +typedef unsigned long long uint_fast64_t; + +/* Pointer types */ + +typedef int32_t intptr_t; +typedef uint32_t uintptr_t; + +/* Maximal types */ + +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + +/* + * To be strictly correct... + */ +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) + +# define INT8_MIN (-128) +# define INT16_MIN (-32767-1) +# define INT32_MIN (-2147483647-1) +# define INT64_MIN (-9223372036854775807LL-1) + +# define INT8_MAX (127) +# define INT16_MAX (32767) +# define INT32_MAX (2147483647) +# define INT64_MAX (9223372036854775807LL) + +# define UINT8_MAX (255U) +# define UINT16_MAX (65535U) +# define UINT32_MAX (4294967295U) +# define UINT64_MAX (18446744073709551615ULL) + +# define INT_LEAST8_MIN (-128) +# define INT_LEAST16_MIN (-32767-1) +# define INT_LEAST32_MIN (-2147483647-1) +# define INT_LEAST64_MIN (-9223372036854775807LL-1) + +# define INT_LEAST8_MAX (127) +# define INT_LEAST16_MAX (32767) +# define INT_LEAST32_MAX (2147483647) +# define INT_LEAST64_MAX (9223372036854775807LL) + +# define UINT_LEAST8_MAX (255U) +# define UINT_LEAST16_MAX (65535U) +# define UINT_LEAST32_MAX (4294967295U) +# define UINT_LEAST64_MAX (18446744073709551615ULL) + +# define INT_FAST8_MIN (-128) +# define INT_FAST16_MIN (-32767-1) +# define INT_FAST32_MIN (-2147483647-1) +# define INT_FAST64_MIN (-9223372036854775807LL-1) + +# define INT_FAST8_MAX (127) +# define INT_FAST16_MAX (32767) +# define INT_FAST32_MAX (2147483647) +# define INT_FAST64_MAX (9223372036854775807LL) + +# define UINT_FAST8_MAX (255U) +# define UINT_FAST16_MAX (65535U) +# define UINT_FAST32_MAX (4294967295U) +# define UINT_FAST64_MAX (18446744073709551615ULL) + +# define INTPTR_MIN (-2147483647-1) +# define INTPTR_MAX (2147483647) +# define UINTPTR_MAX (4294967295U) + +# define INTMAX_MIN (-9223372036854775807LL-1) +# define INTMAX_MAX (9223372036854775807LL) +# define UINTMAX_MAX (18446744073709551615ULL) + +/* ptrdiff_t limit */ +# define PTRDIFF_MIN (-2147483647-1) +# define PTRDIFF_MAX (2147483647) + +/* sig_atomic_t limit */ +# define SIG_ATOMIC_MIN (-2147483647-1) +# define SIG_ATOMIC_MAX (2147483647) + +/* size_t limit */ +# define SIZE_MAX (4294967295U) + +#endif /* STDC_LIMIT_MACROS */ + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) + +# define INT8_C(n) n +# define INT16_C(n) n +# define INT32_C(n) n +# define INT64_C(n) n ## LL + +# define UINT8_C(n) n ## U +# define UINT16_C(n) n ## U +# define UINT32_C(n) n ## U +# define UINT64_C(n) n ## ULL + +# define INTMAX_C(n) n ## LL +# define UINTMAX_C(n) n ## ULL + +#endif /* STDC_CONSTANT_MACROS */ + +#endif /* _STDINT_H */ + + + + diff --git a/syslinux/com32/include/stdio.h b/syslinux/com32/include/stdio.h new file mode 100644 index 0000000..7cbb4b8 --- /dev/null +++ b/syslinux/com32/include/stdio.h @@ -0,0 +1,120 @@ +/* + * stdio.h + */ + +#ifndef _STDIO_H +#define _STDIO_H + +#include <klibc/extern.h> +#include <stdarg.h> +#include <stddef.h> + +/* This structure doesn't really exist, but it gives us something + to define FILE * with */ +struct _IO_file; +typedef struct _IO_file FILE; + +#ifndef EOF +# define EOF (-1) +#endif + +#ifndef BUFSIZ +# define BUFSIZ 4096 +#endif + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +/* + * Convert between a FILE * and a file descriptor. We don't actually + * have any in-memory data, so we just abuse the pointer itself to + * hold the data. Note, however, that for file descriptors, -1 is + * error and 0 is a valid value; for FILE *, NULL (0) is error and + * non-NULL are valid. + */ +static __inline__ int fileno(FILE *__f) +{ + /* This should really be intptr_t, but size_t should be the same size */ + return (int)(size_t)__f - 1; +} + +/* This is a macro so it can be used as initializer */ +#define __create_file(__fd) ((FILE *)(size_t)((__fd) + 1)) + +#define stdin __create_file(0) +#define stdout __create_file(1) +#define stderr __create_file(2) + +__extern FILE *fopen(const char *, const char *); +struct dev_info; +__extern FILE *fopendev(const struct dev_info *, const char *); + +static __inline__ FILE *fdopen(int __fd, const char *__m) +{ + (void)__m; return __create_file(__fd); +} +static __inline__ int fclose(FILE *__f) +{ + extern int close(int); + return close(fileno(__f)); +} + +__extern int fputs(const char *, FILE *); +__extern int puts(const char *); +__extern int fputc(int, FILE *); +#define putc(c,f) fputc((c),(f)) +#define putchar(c) fputc((c),stdout) + +__extern int fgetc(FILE *); +__extern char * fgets(char *, int, FILE *); +#define getc(f) fgetc(f) + +__extern size_t _fread(void *, size_t, FILE *); +__extern size_t _fwrite(const void *, size_t, FILE *); + +#ifndef __NO_FREAD_FWRITE_INLINES +extern __inline__ size_t +fread(void *__p, size_t __s, size_t __n, FILE *__f) +{ + return _fread(__p, __s*__n, __f)/__s; +} + +extern __inline__ size_t +fwrite(void *__p, size_t __s, size_t __n, FILE *__f) +{ + return _fwrite(__p, __s*__n, __f)/__s; +} +#endif + +/* No seek, but we can tell */ +__extern long ftell(FILE *); + +__extern int printf(const char *, ...); +__extern int vprintf(const char *, va_list); +__extern int fprintf(FILE *, const char *, ...); +__extern int vfprintf(FILE *, const char *, va_list); +__extern int sprintf(char *, const char *, ...); +__extern int vsprintf(char *, const char *, va_list); +__extern int snprintf(char *, size_t n, const char *, ...); +__extern int vsnprintf(char *, size_t n, const char *, va_list); + +__extern int asprintf(char **, const char *, ...); +__extern int vasprintf(char **, const char *, va_list); + +/* No buffering, so no flushing needed */ +extern __inline__ int +fflush(FILE *__f) +{ + (void)__f; + return 0; +} + +__extern int sscanf(const char *, const char *, ...); +__extern int vsscanf(const char *, const char *, va_list); + +__extern void perror(const char *); + +__extern int rename(const char *, const char *); + +#endif /* _STDIO_H */ diff --git a/syslinux/com32/include/stdlib.h b/syslinux/com32/include/stdlib.h new file mode 100644 index 0000000..be4e76e --- /dev/null +++ b/syslinux/com32/include/stdlib.h @@ -0,0 +1,90 @@ +/* + * stdlib.h + */ + +#ifndef _STDLIB_H +#define _STDLIB_H + +#include <klibc/extern.h> +#include <klibc/compiler.h> +#include <stddef.h> + +#define EXIT_FAILURE 1 +#define EXIT_SUCCESS 0 + +static __inline__ __noreturn _Exit(int __n) { + __extern __noreturn _exit(int); + _exit(__n); + for(;;); /* Some gcc versions are stupid */ +} +__extern __noreturn abort(void); +static __inline__ int abs(int __n) { + return (__n < 0) ? -__n : __n; +} +__extern int atexit(void (*)(void)); +__extern int on_exit(void (*)(int, void *), void *); +__extern int atoi(const char *); +__extern long atol(const char *); +__extern long long atoll(const char *); +__extern __noreturn exit(int); +__extern void free(void *); +static __inline__ long labs(long __n) { + return (__n < 0L) ? -__n : __n; +} + +static __inline__ long long llabs(long long __n) { + return (__n < 0LL) ? -__n : __n; +} + +__extern __mallocfunc void *malloc(size_t); +__extern __mallocfunc void *calloc(size_t, size_t); +__extern __mallocfunc void *realloc(void *, size_t); +__extern long strtol(const char *, char **, int); +__extern long long strtoll(const char *, char **, int); +__extern unsigned long strtoul(const char *, char **, int); +__extern unsigned long long strtoull(const char *, char **, int); + +__extern char *getenv(const char *); +__extern int putenv(const char *); +__extern int setenv(const char *, const char *, int); +__extern int unsetenv(const char *); + +__extern void qsort(void *, size_t, size_t, int (*)(const void *, const void *)); + + +__extern long jrand48(unsigned short *); +__extern long mrand48(void); +__extern long nrand48(unsigned short *); +__extern long lrand48(void); +__extern unsigned short *seed48(const unsigned short *); +__extern void srand48(long); + +#define RAND_MAX 0x7fffffff +static __inline__ int rand(void) { + return (int)lrand48(); +} +static __inline__ void srand(unsigned int __s) { + srand48(__s); +} +static __inline__ long random(void) +{ + return lrand48(); +} +static __inline__ void srandom(unsigned int __s) +{ + srand48(__s); +} + +/* Basic PTY functions. These only work if devpts is mounted! */ + +__extern int unlockpt(int); +__extern char *ptsname(int); +__extern int getpt(void); + +static __inline__ int grantpt(int __fd) +{ + (void)__fd; + return 0; /* devpts does this all for us! */ +} + +#endif /* _STDLIB_H */ diff --git a/syslinux/com32/include/string.h b/syslinux/com32/include/string.h new file mode 100644 index 0000000..3bbb217 --- /dev/null +++ b/syslinux/com32/include/string.h @@ -0,0 +1,43 @@ +/* + * string.h + */ + +#ifndef _STRING_H +#define _STRING_H + +#include <klibc/extern.h> +#include <stddef.h> + +__extern void *memccpy(void *, const void *, int, size_t); +__extern void *memchr(const void *, int, size_t); +__extern int memcmp(const void *, const void *, size_t); +__extern void *memcpy(void *, const void *, size_t); +__extern void *memmove(void *, const void *, size_t); +__extern void *memset(void *, int, size_t); +__extern void *memmem(const void *, size_t, const void *, size_t); +__extern void memswap(void *, void *, size_t); +__extern int strcasecmp(const char *, const char *); +__extern int strncasecmp(const char *, const char *, size_t); +__extern char *strcat(char *, const char *); +__extern char *strchr(const char *, int); +__extern int strcmp(const char *, const char *); +__extern char *strcpy(char *, const char *); +__extern size_t strcspn(const char *, const char *); +__extern char *strdup(const char *); +__extern char *strndup(const char *, size_t); +__extern char *strerror(int); +__extern size_t strlen(const char *); +__extern size_t strnlen(const char *, size_t); +__extern char *strncat(char *, const char *, size_t); +__extern size_t strlcat(char *, const char *, size_t); +__extern int strncmp(const char *, const char *, size_t); +__extern char *strncpy(char *, const char *, size_t); +__extern size_t strlcpy(char *, const char *, size_t); +__extern char *strpbrk(const char *, const char *); +__extern char *strrchr(const char *, int); +__extern char *strsep(char **, const char *); +__extern size_t strspn(const char *, const char *); +__extern char *strstr(const char *, const char *); +__extern char *strtok(char *, const char *); + +#endif /* _STRING_H */ diff --git a/syslinux/com32/include/sys/cpu.h b/syslinux/com32/include/sys/cpu.h new file mode 100644 index 0000000..1af2db7 --- /dev/null +++ b/syslinux/com32/include/sys/cpu.h @@ -0,0 +1,78 @@ +#ifndef _CPU_H +#define _CPU_H + +#include <inttypes.h> + +static inline uint64_t rdtsc(void) +{ + uint64_t v; + asm volatile("rdtsc" : "=A" (v)); + return v; +} + +static inline uint32_t rdtscl(void) +{ + uint32_t v; + asm volatile("rdtsc" : "=a" (v) : : "edx"); + return v; +} + +static inline uint32_t cpuid_eax(uint32_t level) +{ + uint32_t v; + + asm("cpuid" : "=a" (v) : "a" (level) : "ebx", "ecx", "edx"); + return v; +} +static inline uint32_t cpuid_ebx(uint32_t level) +{ + uint32_t v; + + asm("cpuid" : "=b" (v), "+a" (level) : : "ecx", "edx"); + return v; +} +static inline uint32_t cpuid_ecx(uint32_t level) +{ + uint32_t v; + + asm("cpuid" : "=c" (v), "+a" (level) : : "ebx", "edx"); + return v; +} +static inline uint32_t cpuid_edx(uint32_t level) +{ + uint32_t v; + + asm("cpuid" : "=d" (v), "+a" (level) : : "ebx", "ecx"); + return v; +} + +static inline uint64_t rdmsr(uint32_t msr) +{ + uint64_t v; + + asm volatile("rdmsr" : "=A" (v) : "c" (msr)); + return v; +} +static inline void wrmsr(uint64_t v, uint32_t msr) +{ + asm volatile("wrmsr" : : "A" (v), "c" (msr)); +} + +static inline void cpu_relax(void) +{ + asm volatile("rep ; nop"); +} + +/* These are local cli/sti; not SMP-safe!!! */ + +static inline void cli(void) +{ + asm volatile("cli"); +} + +static inline void sti(void) +{ + asm volatile("sti"); +} + +#endif diff --git a/syslinux/com32/include/sys/io.h b/syslinux/com32/include/sys/io.h new file mode 100644 index 0000000..460f230 --- /dev/null +++ b/syslinux/com32/include/sys/io.h @@ -0,0 +1,42 @@ +#ifndef _SYS_IO_H +#define _SYS_IO_H + +#include <inttypes.h> + +static inline uint8_t inb(uint16_t p) +{ + uint8_t v; + asm volatile("inb %1,%0" : "=a" (v) : "Nd" (p)); + return v; +} + +static inline uint16_t inw(uint16_t p) +{ + uint16_t v; + asm volatile("inw %1,%0" : "=a" (v) : "Nd" (p)); + return v; +} + +static inline uint32_t inl(uint16_t p) +{ + uint32_t v; + asm volatile("inl %1,%0" : "=a" (v) : "Nd" (p)); + return v; +} + +static inline void outb(uint8_t v, uint16_t p) +{ + asm volatile("outb %0,%1" : : "a" (v), "Nd" (p)); +} + +static inline void outw(uint16_t v, uint16_t p) +{ + asm volatile("outw %0,%1" : : "a" (v), "Nd" (p)); +} + +static inline void outl(uint32_t v, uint16_t p) +{ + asm volatile("outl %0,%1" : : "a" (v), "Nd" (p)); +} + +#endif /* _SYS_IO_H */ diff --git a/syslinux/com32/include/sys/pci.h b/syslinux/com32/include/sys/pci.h new file mode 100644 index 0000000..bfa7e60 --- /dev/null +++ b/syslinux/com32/include/sys/pci.h @@ -0,0 +1,31 @@ +#ifndef _SYS_PCI_H +#define _SYS_PCI_H + +#include <inttypes.h> +#include <sys/io.h> + +typedef uint32_t pciaddr_t; + +static inline pciaddr_t pci_mkaddr(uint32_t bus, uint32_t dev, + uint32_t func, uint32_t reg) +{ + return 0x80000000 | ((bus & 0xff) << 16) | ((dev & 0x1f) << 11) | + ((func & 0x07) << 8) | (reg & 0xff); +} + +enum pci_config_type { + PCI_CFG_AUTO = 0, /* autodetect */ + PCI_CFG_TYPE1 = 1, + PCI_CFG_TYPE2 = 2, +}; + +void pci_set_config_type(enum pci_config_type); + +uint8_t pci_readb(pciaddr_t); +uint16_t pci_readw(pciaddr_t); +uint32_t pci_readl(pciaddr_t); +void pci_writeb(uint8_t, pciaddr_t); +void pci_writew(uint16_t, pciaddr_t); +void pci_writel(uint32_t, pciaddr_t); + +#endif /* _SYS_PCI_H */ diff --git a/syslinux/com32/include/sys/stat.h b/syslinux/com32/include/sys/stat.h new file mode 100644 index 0000000..c0afb91 --- /dev/null +++ b/syslinux/com32/include/sys/stat.h @@ -0,0 +1,43 @@ +/* + * sys/stat.h + */ + +#ifndef _SYS_STAT_H +#define _SYS_STAT_H + +#include <sys/types.h> + +/* We don't use this, but it's there for compatibility */ + +#define S_IFMT 00170000 +#define S_IFSOCK 0140000 +#define S_IFLNK 0120000 +#define S_IFREG 0100000 +#define S_IFBLK 0060000 +#define S_IFDIR 0040000 +#define S_IFCHR 0020000 +#define S_IFIFO 0010000 +#define S_ISUID 0004000 +#define S_ISGID 0002000 +#define S_ISVTX 0001000 +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) +#define S_IRWXU 00700 +#define S_IRUSR 00400 +#define S_IWUSR 00200 +#define S_IXUSR 00100 +#define S_IRWXG 00070 +#define S_IRGRP 00040 +#define S_IWGRP 00020 +#define S_IXGRP 00010 +#define S_IRWXO 00007 +#define S_IROTH 00004 +#define S_IWOTH 00002 +#define S_IXOTH 00001 + +#endif /* _SYS_STAT_H */ diff --git a/syslinux/com32/include/sys/times.h b/syslinux/com32/include/sys/times.h new file mode 100644 index 0000000..8d03af0 --- /dev/null +++ b/syslinux/com32/include/sys/times.h @@ -0,0 +1,21 @@ +/* + * sys/times.h + */ + +#ifndef _SYS_TIMES_H +#define _SYS_TIMES_H + +#include <stdint.h> + +struct tms { + /* Empty */ +}; + +#define HZ 18 /* Piddly resolution... */ +#define CLK_TCK HZ + +typedef uint16_t clock_t; + +clock_t times(struct tms *); + +#endif /* _SYS_TIMES_H */ diff --git a/syslinux/com32/include/sys/types.h b/syslinux/com32/include/sys/types.h new file mode 100644 index 0000000..d7e9cba --- /dev/null +++ b/syslinux/com32/include/sys/types.h @@ -0,0 +1,16 @@ +/* + * sys/types.h + */ + +#ifndef _SYS_TYPES_H +#define _SYS_TYPES_H + +#include <klibc/compiler.h> +#include <stddef.h> +#include <stdint.h> + +typedef ptrdiff_t ssize_t; +typedef int mode_t; +typedef int64_t off_t; + +#endif diff --git a/syslinux/com32/include/syslinux.h b/syslinux/com32/include/syslinux.h new file mode 100644 index 0000000..614c0e9 --- /dev/null +++ b/syslinux/com32/include/syslinux.h @@ -0,0 +1,40 @@ +#ident "$Id: syslinux.h,v 1.1 2005/01/20 18:41:12 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2005 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * syslinux.h + * + * SYSLINUX-specific functions + */ + +#ifndef _SYSLINUX_H +#define _SYSLINUX_H + +void syslinux_idle(void); + +#endif diff --git a/syslinux/com32/include/time.h b/syslinux/com32/include/time.h new file mode 100644 index 0000000..e69de29 diff --git a/syslinux/com32/include/unistd.h b/syslinux/com32/include/unistd.h new file mode 100644 index 0000000..84120d3 --- /dev/null +++ b/syslinux/com32/include/unistd.h @@ -0,0 +1,29 @@ +/* + * unistd.h + */ + +#ifndef _UNISTD_H +#define _UNISTD_H + +#include <klibc/extern.h> +#include <klibc/compiler.h> +#include <stddef.h> +#include <sys/types.h> + +__extern __noreturn _exit(int); + +__extern int open(const char *, int, ...); +__extern int close(int); + +__extern ssize_t read(int, void *, size_t); +__extern ssize_t write(int, const void *, size_t); + +__extern int isatty(int); + + +/* Standard file descriptor numbers. */ +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 + +#endif /* _UNISTD_H */ diff --git a/syslinux/com32/include/zconf.h b/syslinux/com32/include/zconf.h new file mode 100644 index 0000000..01f0d30 --- /dev/null +++ b/syslinux/com32/include/zconf.h @@ -0,0 +1,323 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zconf.h,v 1.1 2005/01/12 04:56:23 hpa Exp $ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflatePrime z_deflatePrime +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table + +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) +# define WIN32 +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include <windows.h> + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include <sys/types.h> /* for off_t */ +# include <unistd.h> /* for SEEK_* and off_t */ +# ifdef VMS +# include <unixio.h> /* for off_t */ +# endif +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +#define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/syslinux/com32/include/zlib.h b/syslinux/com32/include/zlib.h new file mode 100644 index 0000000..92edf96 --- /dev/null +++ b/syslinux/com32/include/zlib.h @@ -0,0 +1,1200 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.1, November 17th, 2003 + + Copyright (C) 1995-2003 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.1" +#define ZLIB_VERNUM 0x1210 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by the in-memory functions is the zlib + format, which is a zlib wrapper documented in RFC 1950, wrapped around a + deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + This library does not provide any functions to write gzip files in memory. + However such functions could be easily written using zlib's deflate function, + the documentation in the gzip RFC, and the examples in gzio.c. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: ascii or binary */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_ASCII 1 +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + the compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + the value returned by deflateBound (see below). If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update data_type if it can make a good guess about + the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, + Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() stop + if and when it get to the next deflate block boundary. When decoding the zlib + or gzip format, this will cause inflate() to return immediately after the + header and before the first block. When doing a raw inflate, inflate() will + go ahead and process the first block, and will return when it gets to the end + of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 + if inflate() is currently decoding the last block in the deflate stream, + plus 128 if inflate() returned immediately after decoding an end-of-block + code or decoding the complete header up to just before the first byte of the + deflate stream. The end-of-block will not be indicated until all of the + uncompressed data from that block has been written to strm->next_out. The + number of unused bits may in general be greater than seven, except when + bit 7 of data_type is set, in which case the number of unused bits will be + less than eight. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster approach + may be used for the single inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm-adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() will decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically. Any information + contained in the gzip header is not retained, so applications that need that + information should instead use raw inflate, see inflateInit2() below, or + inflateBack() and perform their own processing of the gzip header and + trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may then + call inflateSync() to look for a good compression block if a partial recovery + of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), + no header crc, and the operating system will be set to 255 (unknown). + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as + Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy + parameter only affects the compression ratio but not the correctness of the + compressed output even if it is not set appropriately. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() + or deflateInit2(). This would be used to allocate an output buffer + for deflation in a single pass, and so would be called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the + bits leftover from a previous deflate stream when appending to it. As such, + this function can only be used for raw deflate, and must be used before the + first deflate() call after a deflateInit2() or deflateReset(). bits must be + less than or equal to 16, and that many of the least significant bits of + value will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative + memLevel). msg is set to null if there is no error message. inflateInit2 + does not perform any decompression apart from reading the zlib header if + present: this will be done by inflate(). (So next_in and avail_in may be + modified, but next_out and avail_out are unchanged.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate + if this call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by this call of + inflate. The compressor and decompressor must use exactly the same + dictionary (see deflateSetDictionary). + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_stream FAR *strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not + be allocated, or Z_VERSION_ERROR if the version of the library does not + match the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_stream FAR *strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free + the allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects + only the raw deflate stream to decompress. This is different from the + normal behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format + error in the deflate stream (in which case strm->msg is set to indicate the + nature of the error), or Z_STREAM_ERROR if the stream was not properly + initialized. In the case of Z_BUF_ERROR, an input or output error can be + distinguished using strm->next_in which will be Z_NULL only if in() returned + an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to + out() returning non-zero. (in() will always be called before out(), so + strm->next_in is assured to be defined if out() returns non-zero.) Note + that inflateBack() cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_stream FAR *strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least the value returned + by compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before + a compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h", or 'R' for run-length encoding + as in "wb1R". (See the description of deflateInit2 for more information + about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). The number of + uncompressed bytes written is limited to 4095. The caller should assure that + this limit is not exceeded. If it is exceeded, then gzprintf() will return + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read again later. + Only one character of push-back is allowed. gzungetc() returns the + character pushed, or -1 on failure. gzungetc() will fail if a + character has been pushed but not read yet, or if c is -1. The pushed + character will be discarded if the stream is repositioned with gzseek() + or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); + +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running crc with the bytes buf[0..len-1] and return the updated + crc. If buf is NULL, this function returns the required initial value + for the crc. Pre- and post-conditioning (one's complement) is performed + within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_stream FAR *strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int err)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/syslinux/com32/lib/MCONFIG b/syslinux/com32/lib/MCONFIG new file mode 100644 index 0000000..5086f73 --- /dev/null +++ b/syslinux/com32/lib/MCONFIG @@ -0,0 +1,66 @@ +# -*- makefile -*- +# $Id: MCONFIG,v 1.6 2005/01/08 05:58:20 hpa Exp $ + +CC = gcc +LD = ld +INCLUDE = -I. +AR = ar +RANLIB = ranlib +NM = nm +PERL = perl +STRIP = strip --strip-all -R .comment -R .note +OBJCOPY = objcopy + +# zlib and libpng configuration flags +LIBFLAGS = -DDYNAMIC_CRC_TABLE -DPNG_NO_CONSOLE_IO \ + -DPNG_NO_MNG_FEATURES -DPNG_NO_FLOATING_POINT_SUPPORTED \ + -DPNG_NO_WRITE_FLUSH -DPNG_NO_WRITE_tIME -DPNG_NO_READ_tIME + +REQFLAGS = -g -m32 -mregparm=3 -DREGPARM=3 -D__COM32__ -I. -I./sys -I../include +OPTFLAGS = -Os -march=i386 -falign-functions=0 -falign-jumps=0 \ + -falign-labels=0 -finline-limit=1000 +WARNFLAGS = -W -Wall -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Winline + +CFLAGS = -Wp,-MT,$@,-MD,$(dir $@).$(notdir $@).d $(OPTFLAGS) \ + $(REQFLAGS) $(WARNFLAGS) $(LIBFLAGS) +LDFLAGS = -m elf32_i386 + +.SUFFIXES: .c .o .a .so .lo .i .S .s .ls .ss .lss + +% : %.c # Cancel default rule + +% : %.S + +.c.o: + $(CC) $(CFLAGS) -c -o $@ $< + +.c.i: + $(CC) $(CFLAGS) -E -o $@ $< + +.c.s: + $(CC) $(CFLAGS) -S -o $@ $< + +.S.o: + $(CC) $(CFLAGS) -D__ASSEMBLY__ -c -o $@ $< + +.S.s: + $(CC) $(CFLAGS) -D__ASSEMBLY__ -E -o $@ $< + +.S.lo: + $(CC) $(CFLAGS) $(SOFLAGS) -D__ASSEMBLY__ -c -o $@ $< + +.S.ls: + $(CC) $(CFLAGS) $(SOFLAGS) -D__ASSEMBLY__ -E -o $@ $< + +.s.o: + $(CC) $(CFLAGS) -x assembler -c -o $@ $< + +.ls.lo: + $(CC) $(CFLAGS) $(SOFLAGS) -x assembler -c -o $@ $< + +.c.lo: + $(CC) $(CFLAGS) $(SOFLAGS) -c -o $@ $< + +.c.ls: + $(CC) $(CFLAGS) $(SOFLAGS) -S -o $@ $< + diff --git a/syslinux/com32/lib/Makefile b/syslinux/com32/lib/Makefile new file mode 100644 index 0000000..7dea7af --- /dev/null +++ b/syslinux/com32/lib/Makefile @@ -0,0 +1,70 @@ +# Include configuration rules +include MCONFIG + +LIBOBJS = abort.o atexit.o atoi.o atol.o atoll.o calloc.o creat.o \ + ctypes.o errno.o fgetc.o fgets.o fopen.o fprintf.o fputc.o \ + putchar.o \ + fputs.o fread2.o fread.o free.o fwrite2.o fwrite.o getopt.o \ + lrand48.o malloc.o stack.o memccpy.o memchr.o memcmp.o \ + memcpy.o memmem.o memmove.o memset.o memswap.o exit.o onexit.o \ + perror.o printf.o puts.o qsort.o realloc.o seed48.o snprintf.o \ + sprintf.o srand48.o sscanf.o stack.o strcasecmp.o strcat.o \ + strchr.o strcmp.o strcpy.o strdup.o strerror.o strlen.o \ + strncasecmp.o strncat.o strncmp.o strncpy.o strndup.o \ + strntoimax.o strntoumax.o strrchr.o strsep.o strspn.o strstr.o \ + strtoimax.o strtok.o strtol.o strtoll.o strtoul.o strtoull.o \ + strtoumax.o vfprintf.o vprintf.o vsnprintf.o vsprintf.o \ + asprintf.o vasprintf.o strlcpy.o strlcat.o \ + vsscanf.o libgcc/__ashldi3.o libgcc/__udivdi3.o \ + libgcc/__negdi2.o libgcc/__ashrdi3.o libgcc/__lshrdi3.o \ + libgcc/__muldi3.o libgcc/__udivmoddi4.o libgcc/__umoddi3.o \ + libgcc/__divdi3.o libgcc/__moddi3.o \ + sys/entry.o sys/exit.o sys/argv.o sys/times.o sys/idle.o \ + sys/fileinfo.o sys/opendev.o sys/read.o sys/write.o sys/ftell.o \ + sys/close.o sys/open.o sys/fileread.o sys/fileclose.o \ + sys/isatty.o sys/openconsole.o sys/line_input.o \ + sys/stdcon_read.o sys/stdcon_write.o sys/rawcon_read.o \ + sys/rawcon_write.o sys/err_read.o sys/err_write.o \ + sys/null_read.o sys/null_write.o sys/serial_write.o \ + sys/ansicon_write.o sys/ansiserial_write.o \ + pci/cfgtype.o pci/readb.o pci/readw.o pci/readl.o \ + pci/writeb.o pci/writew.o pci/writel.o \ + zlib/adler32.o zlib/compress.o zlib/crc32.o zlib/gzio.o \ + zlib/uncompr.o zlib/deflate.o zlib/trees.o zlib/zutil.o \ + zlib/inflate.o zlib/infback.o zlib/inftrees.o zlib/inffast.o \ + libpng/png.o libpng/pngset.o libpng/pngrutil.o \ + libpng/pngtrans.o libpng/pngwutil.o libpng/pngread.o \ + libpng/pngrio.o libpng/pngwio.o libpng/pngwrite.o \ + libpng/pngrtran.o libpng/pngwtran.o libpng/pngmem.o \ + libpng/pngerror.o libpng/pngpread.o + +BINDIR = /usr/bin +LIBDIR = /usr/lib +AUXDIR = $(LIBDIR)/syslinux +INCDIR = /usr/include +COM32DIR = $(AUXDIR)/com32 + +all: libcom32.a + +libcom32.a : $(LIBOBJS) + rm -f $@ + $(AR) cq $@ $^ + $(RANLIB) $@ + +tidy: + rm -f *.o .*.d */*.o */.*.d + +clean: tidy + rm -f *.a + +spotless: clean + rm -f *~ \#* */*~ */\#* + +install: all + mkdir -m 755 -p $(INSTALLROOT)$(COM32DIR) + install -m 644 libcom32.a com32.ld $(INSTALLROOT)$(COM32DIR) + -rm -rf $(INSTALLROOT)$(COM32DIR)/include + cp -r ../include $(INSTALLROOT)$(COM32DIR) + +-include .*.d */.*.d + diff --git a/syslinux/com32/lib/abort.c b/syslinux/com32/lib/abort.c new file mode 100644 index 0000000..aacfbbf --- /dev/null +++ b/syslinux/com32/lib/abort.c @@ -0,0 +1,12 @@ +/* + * abort.c + */ + +#include <stdlib.h> +#include <unistd.h> + +void abort(void) +{ + _exit(255); +} + diff --git a/syslinux/com32/lib/asprintf.c b/syslinux/com32/lib/asprintf.c new file mode 100644 index 0000000..6002b57 --- /dev/null +++ b/syslinux/com32/lib/asprintf.c @@ -0,0 +1,30 @@ +/* + * asprintf.c + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> + +int asprintf(char **bufp, const char *format, ...) +{ + va_list ap, ap1; + int rv; + int bytes; + char *p; + + va_start(ap, format); + va_copy(ap1, ap); + + bytes = vsnprintf(NULL, 0, format, ap1) + 1; + va_end(ap1); + + *bufp = p = malloc(bytes); + if ( !p ) + return -1; + + rv = vsnprintf(p, bytes, format, ap); + va_end(ap); + + return rv; +} diff --git a/syslinux/com32/lib/atexit.c b/syslinux/com32/lib/atexit.c new file mode 100644 index 0000000..078dd8b --- /dev/null +++ b/syslinux/com32/lib/atexit.c @@ -0,0 +1,10 @@ +/* + * atexit.c + */ + +#include <stdlib.h> + +int atexit(void (*fctn)(void)) +{ + return on_exit((void (*)(int, void *))fctn, NULL); +} diff --git a/syslinux/com32/lib/atexit.h b/syslinux/com32/lib/atexit.h new file mode 100644 index 0000000..792141d --- /dev/null +++ b/syslinux/com32/lib/atexit.h @@ -0,0 +1,17 @@ +/* + * atexit.h + * + * atexit()/on_exit() internal definitions + */ + +#ifndef ATEXIT_H +#define ATEXIT_H + +struct atexit { + void (*fctn)(int, void *); + void *arg; /* on_exit() parameter */ + struct atexit *next; +}; + +#endif /* ATEXIT_H */ + diff --git a/syslinux/com32/lib/atoi.c b/syslinux/com32/lib/atoi.c new file mode 100644 index 0000000..a6ec0bf --- /dev/null +++ b/syslinux/com32/lib/atoi.c @@ -0,0 +1,3 @@ +#define TYPE int +#define NAME atoi +#include "atox.c" diff --git a/syslinux/com32/lib/atol.c b/syslinux/com32/lib/atol.c new file mode 100644 index 0000000..e65484e --- /dev/null +++ b/syslinux/com32/lib/atol.c @@ -0,0 +1,3 @@ +#define TYPE long +#define NAME atol +#include "atox.c" diff --git a/syslinux/com32/lib/atoll.c b/syslinux/com32/lib/atoll.c new file mode 100644 index 0000000..25df79e --- /dev/null +++ b/syslinux/com32/lib/atoll.c @@ -0,0 +1,3 @@ +#define TYPE long long +#define NAME atoll +#include "atox.c" diff --git a/syslinux/com32/lib/atox.c b/syslinux/com32/lib/atox.c new file mode 100644 index 0000000..56f8d93 --- /dev/null +++ b/syslinux/com32/lib/atox.c @@ -0,0 +1,14 @@ +/* + * atox.c + * + * atoi(), atol(), atoll() + */ + +#include <inttypes.h> +#include <stdlib.h> +#include <stdio.h> + +TYPE NAME (const char *nptr) +{ + return (TYPE) strntoumax(nptr, (char **)NULL, 10, ~(size_t)0); +} diff --git a/syslinux/com32/lib/calloc.c b/syslinux/com32/lib/calloc.c new file mode 100644 index 0000000..228a1b7 --- /dev/null +++ b/syslinux/com32/lib/calloc.c @@ -0,0 +1,21 @@ +/* + * calloc.c + */ + +#include <stdlib.h> +#include <string.h> + +/* FIXME: This should look for multiplication overflow */ + +void *calloc(size_t nmemb, size_t size) +{ + void *ptr; + + size *= nmemb; + ptr = malloc(size); + if ( ptr ) + memset(ptr, 0, size); + + return ptr; +} + diff --git a/syslinux/com32/lib/com32.ld b/syslinux/com32/lib/com32.ld new file mode 100644 index 0000000..36d5b6e --- /dev/null +++ b/syslinux/com32/lib/com32.ld @@ -0,0 +1,127 @@ +/* + * Linker script for COM32 binaries using libcom32 + */ + +/* Script for -z combreloc: combine and sort reloc sections */ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", + "elf32-i386") +OUTPUT_ARCH(i386) +EXTERN(_start) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x101000; + PROVIDE (__executable_start = .); + + .init : + { + KEEP (*(.init)) + } =0x90909090 + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } =0x90909090 + .fini : + { + KEEP (*(.fini)) + } =0x90909090 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + + /* Ensure the __preinit_array_start label is properly aligned. We + could instead move the label definition inside the section, but + the linker would then create the section even if it turns out to + be empty, which isn't pretty. */ + . = ALIGN(4); + PROVIDE (__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE (__fini_array_end = .); + PROVIDE (__ctors_start = .); + .ctors : + { + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + PROVIDE (__ctors_end = .); + PROVIDE (__dtors_start = .); + .dtors : + { + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + PROVIDE (__dtors_end = .); + + /* Adjust the address for the data segment. Avoid mixing code and + data within same 128-byte chunk. */ + . = ALIGN(128); + + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN(32 / 8); + } + . = ALIGN(32 / 8); + _end = .; + PROVIDE (end = .); + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /DISCARD/ : { *(.note.GNU-stack) } +} diff --git a/syslinux/com32/lib/creat.c b/syslinux/com32/lib/creat.c new file mode 100644 index 0000000..9bd2217 --- /dev/null +++ b/syslinux/com32/lib/creat.c @@ -0,0 +1,12 @@ +/* + * creat.c + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +int creat(const char *pathname, mode_t mode) +{ + return open(pathname, O_CREAT|O_WRONLY|O_TRUNC, mode); +} diff --git a/syslinux/com32/lib/ctypes.c b/syslinux/com32/lib/ctypes.c new file mode 100644 index 0000000..acfa05a --- /dev/null +++ b/syslinux/com32/lib/ctypes.c @@ -0,0 +1,284 @@ +/* + * ctypes.c + * + * This is the array that defines <ctype.h> classes. + * This assumes ISO 8859-1. + */ + +#include <ctype.h> + +const unsigned char __ctypes[257] = { + 0, /* EOF */ + + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl|__ctype_space, /* BS */ + __ctype_cntrl|__ctype_space, /* TAB */ + __ctype_cntrl|__ctype_space, /* LF */ + __ctype_cntrl|__ctype_space, /* VT */ + __ctype_cntrl|__ctype_space, /* FF */ + __ctype_cntrl|__ctype_space, /* CR */ + __ctype_cntrl, /* control character */ + + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + + __ctype_print|__ctype_space, /* space */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + + __ctype_print|__ctype_digit|__ctype_xdigit, /* digit */ + __ctype_print|__ctype_digit|__ctype_xdigit, /* digit */ + __ctype_print|__ctype_digit|__ctype_xdigit, /* digit */ + __ctype_print|__ctype_digit|__ctype_xdigit, /* digit */ + __ctype_print|__ctype_digit|__ctype_xdigit, /* digit */ + __ctype_print|__ctype_digit|__ctype_xdigit, /* digit */ + __ctype_print|__ctype_digit|__ctype_xdigit, /* digit */ + __ctype_print|__ctype_digit|__ctype_xdigit, /* digit */ + __ctype_print|__ctype_digit|__ctype_xdigit, /* digit */ + __ctype_print|__ctype_digit|__ctype_xdigit, /* digit */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_upper|__ctype_xdigit, /* A-F */ + __ctype_print|__ctype_upper|__ctype_xdigit, /* A-F */ + __ctype_print|__ctype_upper|__ctype_xdigit, /* A-F */ + __ctype_print|__ctype_upper|__ctype_xdigit, /* A-F */ + __ctype_print|__ctype_upper|__ctype_xdigit, /* A-F */ + __ctype_print|__ctype_upper|__ctype_xdigit, /* A-F */ + __ctype_print|__ctype_upper, /* G-Z */ + __ctype_print|__ctype_upper, /* G-Z */ + __ctype_print|__ctype_upper, /* G-Z */ + __ctype_print|__ctype_upper, /* G-Z */ + __ctype_print|__ctype_upper, /* G-Z */ + __ctype_print|__ctype_upper, /* G-Z */ + __ctype_print|__ctype_upper, /* G-Z */ + __ctype_print|__ctype_upper, /* G-Z */ + __ctype_print|__ctype_upper, /* G-Z */ + + __ctype_print|__ctype_upper, /* G-Z */ + __ctype_print|__ctype_upper, /* G-Z */ + __ctype_print|__ctype_upper, /* G-Z */ + __ctype_print|__ctype_upper, /* G-Z */ + __ctype_print|__ctype_upper, /* G-Z */ + __ctype_print|__ctype_upper, /* G-Z */ + __ctype_print|__ctype_upper, /* G-Z */ + __ctype_print|__ctype_upper, /* G-Z */ + __ctype_print|__ctype_upper, /* G-Z */ + __ctype_print|__ctype_upper, /* G-Z */ + __ctype_print|__ctype_upper, /* G-Z */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_lower|__ctype_xdigit, /* a-f */ + __ctype_print|__ctype_lower|__ctype_xdigit, /* a-f */ + __ctype_print|__ctype_lower|__ctype_xdigit, /* a-f */ + __ctype_print|__ctype_lower|__ctype_xdigit, /* a-f */ + __ctype_print|__ctype_lower|__ctype_xdigit, /* a-f */ + __ctype_print|__ctype_lower|__ctype_xdigit, /* a-f */ + __ctype_print|__ctype_lower, /* g-z */ + __ctype_print|__ctype_lower, /* g-z */ + __ctype_print|__ctype_lower, /* g-z */ + __ctype_print|__ctype_lower, /* g-z */ + __ctype_print|__ctype_lower, /* g-z */ + __ctype_print|__ctype_lower, /* g-z */ + __ctype_print|__ctype_lower, /* g-z */ + __ctype_print|__ctype_lower, /* g-z */ + __ctype_print|__ctype_lower, /* g-z */ + + __ctype_print|__ctype_lower, /* g-z */ + __ctype_print|__ctype_lower, /* g-z */ + __ctype_print|__ctype_lower, /* g-z */ + __ctype_print|__ctype_lower, /* g-z */ + __ctype_print|__ctype_lower, /* g-z */ + __ctype_print|__ctype_lower, /* g-z */ + __ctype_print|__ctype_lower, /* g-z */ + __ctype_print|__ctype_lower, /* g-z */ + __ctype_print|__ctype_lower, /* g-z */ + __ctype_print|__ctype_lower, /* g-z */ + __ctype_print|__ctype_lower, /* g-z */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_cntrl, /* control character */ + + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + __ctype_cntrl, /* control character */ + + __ctype_print|__ctype_space, /* NBSP */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_punct, /* punctuation */ + + __ctype_print|__ctype_upper, /* upper accented */ + __ctype_print|__ctype_upper, /* upper accented */ + __ctype_print|__ctype_upper, /* upper accented */ + __ctype_print|__ctype_upper, /* upper accented */ + __ctype_print|__ctype_upper, /* upper accented */ + __ctype_print|__ctype_upper, /* upper accented */ + __ctype_print|__ctype_upper, /* upper accented */ + __ctype_print|__ctype_upper, /* upper accented */ + __ctype_print|__ctype_upper, /* upper accented */ + __ctype_print|__ctype_upper, /* upper accented */ + __ctype_print|__ctype_upper, /* upper accented */ + __ctype_print|__ctype_upper, /* upper accented */ + __ctype_print|__ctype_upper, /* upper accented */ + __ctype_print|__ctype_upper, /* upper accented */ + __ctype_print|__ctype_upper, /* upper accented */ + __ctype_print|__ctype_upper, /* upper accented */ + + __ctype_print|__ctype_upper, /* upper accented */ + __ctype_print|__ctype_upper, /* upper accented */ + __ctype_print|__ctype_upper, /* upper accented */ + __ctype_print|__ctype_upper, /* upper accented */ + __ctype_print|__ctype_upper, /* upper accented */ + __ctype_print|__ctype_upper, /* upper accented */ + __ctype_print|__ctype_upper, /* upper accented */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_upper, /* upper accented */ + __ctype_print|__ctype_upper, /* upper accented */ + __ctype_print|__ctype_upper, /* upper accented */ + __ctype_print|__ctype_upper, /* upper accented */ + __ctype_print|__ctype_upper, /* upper accented */ + __ctype_print|__ctype_upper, /* upper accented */ + __ctype_print|__ctype_upper, /* upper accented */ + __ctype_print|__ctype_lower, /* lower accented */ + + __ctype_print|__ctype_lower, /* lower accented */ + __ctype_print|__ctype_lower, /* lower accented */ + __ctype_print|__ctype_lower, /* lower accented */ + __ctype_print|__ctype_lower, /* lower accented */ + __ctype_print|__ctype_lower, /* lower accented */ + __ctype_print|__ctype_lower, /* lower accented */ + __ctype_print|__ctype_lower, /* lower accented */ + __ctype_print|__ctype_lower, /* lower accented */ + __ctype_print|__ctype_lower, /* lower accented */ + __ctype_print|__ctype_lower, /* lower accented */ + __ctype_print|__ctype_lower, /* lower accented */ + __ctype_print|__ctype_lower, /* lower accented */ + __ctype_print|__ctype_lower, /* lower accented */ + __ctype_print|__ctype_lower, /* lower accented */ + __ctype_print|__ctype_lower, /* lower accented */ + __ctype_print|__ctype_lower, /* lower accented */ + + __ctype_print|__ctype_lower, /* lower accented */ + __ctype_print|__ctype_lower, /* lower accented */ + __ctype_print|__ctype_lower, /* lower accented */ + __ctype_print|__ctype_lower, /* lower accented */ + __ctype_print|__ctype_lower, /* lower accented */ + __ctype_print|__ctype_lower, /* lower accented */ + __ctype_print|__ctype_lower, /* lower accented */ + __ctype_print|__ctype_punct, /* punctuation */ + __ctype_print|__ctype_lower, /* lower accented */ + __ctype_print|__ctype_lower, /* lower accented */ + __ctype_print|__ctype_lower, /* lower accented */ + __ctype_print|__ctype_lower, /* lower accented */ + __ctype_print|__ctype_lower, /* lower accented */ + __ctype_print|__ctype_lower, /* lower accented */ + __ctype_print|__ctype_lower, /* lower accented */ + __ctype_print|__ctype_lower, /* lower accented */ +}; diff --git a/syslinux/com32/lib/errno.c b/syslinux/com32/lib/errno.c new file mode 100644 index 0000000..f280e30 --- /dev/null +++ b/syslinux/com32/lib/errno.c @@ -0,0 +1,7 @@ +/* + * errno.c + * + */ +#include <errno.h> + +int errno; diff --git a/syslinux/com32/lib/exit.c b/syslinux/com32/lib/exit.c new file mode 100644 index 0000000..3d206ef --- /dev/null +++ b/syslinux/com32/lib/exit.c @@ -0,0 +1,42 @@ +#ident "$Id: exit.c,v 1.2 2004/12/01 02:44:34 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * exit.c + * + * The regular exit + */ + +#include <stdlib.h> + +extern __noreturn (*__exit_handler)(int); + +__noreturn exit(int rv) +{ + __exit_handler(rv); +} diff --git a/syslinux/com32/lib/fgetc.c b/syslinux/com32/lib/fgetc.c new file mode 100644 index 0000000..83eee16 --- /dev/null +++ b/syslinux/com32/lib/fgetc.c @@ -0,0 +1,20 @@ +/* + * fgetc.c + * + * Extremely slow fgetc implementation, using _fread(). If people + * actually need character-oriented input to be fast, we may actually + * have to implement buffering. Sigh. + */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <errno.h> + +int fgetc(FILE *f) +{ + unsigned char ch; + + return (_fread(&ch, 1, f) == 1) ? (int)ch : EOF; +} + diff --git a/syslinux/com32/lib/fgets.c b/syslinux/com32/lib/fgets.c new file mode 100644 index 0000000..88a145a --- /dev/null +++ b/syslinux/com32/lib/fgets.c @@ -0,0 +1,33 @@ +/* + * fgets.c + * + * This will be very slow due to the implementation of getc(), + * but we can't afford to drain characters we don't need from + * the input. + */ + +#include <stdio.h> + +char *fgets(char *s, int n, FILE *f) +{ + int ch; + char *p = s; + + while ( n > 1 ) { + ch = getc(f); + if ( ch == EOF ) { + *p = '\0'; + return NULL; + } + *p++ = ch; + if ( ch == '\n' ) + break; + } + if ( n ) + *p = '\0'; + + return s; +} + + + diff --git a/syslinux/com32/lib/fopen.c b/syslinux/com32/lib/fopen.c new file mode 100644 index 0000000..bf1e452 --- /dev/null +++ b/syslinux/com32/lib/fopen.c @@ -0,0 +1,43 @@ +/* + * fopen.c + */ + +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> + +FILE *fopen(const char *file, const char *mode) +{ + int flags = O_RDONLY; + int plus = 0; + int fd; + + while ( *mode ) { + switch ( *mode ) { + case 'r': + flags = O_RDONLY; + break; + case 'w': + flags = O_WRONLY|O_CREAT|O_TRUNC; + break; + case 'a': + flags = O_WRONLY|O_CREAT|O_APPEND; + break; + case '+': + plus = 1; + break; + } + mode++; + } + + if ( plus ) { + flags = (flags & ~(O_RDONLY|O_WRONLY)) | O_RDWR; + } + + fd = open(file, flags, 0666); + + if ( fd < 0 ) + return NULL; + else + return fdopen(fd, mode); +} diff --git a/syslinux/com32/lib/fopendev.c b/syslinux/com32/lib/fopendev.c new file mode 100644 index 0000000..2eb2a5a --- /dev/null +++ b/syslinux/com32/lib/fopendev.c @@ -0,0 +1,43 @@ +/* + * fopendev.c + */ + +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> + +FILE *fopendev(const struct dev_info *dev, const char *mode) +{ + int flags = O_RDONLY; + int plus = 0; + int fd; + + while ( *mode ) { + switch ( *mode ) { + case 'r': + flags = O_RDONLY; + break; + case 'w': + flags = O_WRONLY|O_CREAT|O_TRUNC; + break; + case 'a': + flags = O_WRONLY|O_CREAT|O_APPEND; + break; + case '+': + plus = 1; + break; + } + mode++; + } + + if ( plus ) { + flags = (flags & ~(O_RDONLY|O_WRONLY)) | O_RDWR; + } + + fd = opendev(file, flags); + + if ( fd < 0 ) + return NULL; + else + return fdopen(fd, mode); +} diff --git a/syslinux/com32/lib/fprintf.c b/syslinux/com32/lib/fprintf.c new file mode 100644 index 0000000..df3823e --- /dev/null +++ b/syslinux/com32/lib/fprintf.c @@ -0,0 +1,19 @@ +/* + * fprintf.c + */ + +#include <stdio.h> +#include <stdarg.h> + +#define BUFFER_SIZE 16384 + +int fprintf(FILE *file, const char *format, ...) +{ + va_list ap; + int rv; + + va_start(ap, format); + rv = vfprintf(file, format, ap); + va_end(ap); + return rv; +} diff --git a/syslinux/com32/lib/fputc.c b/syslinux/com32/lib/fputc.c new file mode 100644 index 0000000..61aff16 --- /dev/null +++ b/syslinux/com32/lib/fputc.c @@ -0,0 +1,14 @@ +/* + * fputc.c + * + * gcc "printf decompilation" expects this to exist... + */ + +#include <stdio.h> + +int fputc(int c, FILE *f) +{ + unsigned char ch = c; + + return _fwrite(&ch, 1, f) == 1 ? ch : EOF; +} diff --git a/syslinux/com32/lib/fputs.c b/syslinux/com32/lib/fputs.c new file mode 100644 index 0000000..4b68f96 --- /dev/null +++ b/syslinux/com32/lib/fputs.c @@ -0,0 +1,15 @@ +/* + * fputs.c + * + * This isn't quite fputs() in the stdio sense, since we don't + * have stdio, but it takes a file descriptor argument instead + * of the FILE *. + */ + +#include <stdio.h> +#include <string.h> + +int fputs(const char *s, FILE *file) +{ + return _fwrite(s, strlen(s), file); +} diff --git a/syslinux/com32/lib/fread.c b/syslinux/com32/lib/fread.c new file mode 100644 index 0000000..76fdda8 --- /dev/null +++ b/syslinux/com32/lib/fread.c @@ -0,0 +1,32 @@ +/* + * fread.c + */ + +#include <errno.h> +#include <unistd.h> +#include <stdio.h> + +size_t _fread(void *buf, size_t count, FILE *f) +{ + size_t bytes = 0; + ssize_t rv; + char *p = buf; + + while ( count ) { + rv = read(fileno(f), p, count); + if ( rv == -1 ) { + if ( errno == EINTR || errno == EAGAIN ) + continue; + else + break; + } else if ( rv == 0 ) { + break; + } + + p += rv; + bytes += rv; + count -= rv; + } + + return bytes; +} diff --git a/syslinux/com32/lib/fread2.c b/syslinux/com32/lib/fread2.c new file mode 100644 index 0000000..9e5ac81 --- /dev/null +++ b/syslinux/com32/lib/fread2.c @@ -0,0 +1,13 @@ +/* + * fread2.c + * + * The actual fread() function as a non-inline + */ + +#define __NO_FREAD_FWRITE_INLINES +#include <stdio.h> + +size_t fread(void *ptr, size_t size, size_t nmemb, FILE *f) +{ + return _fread(ptr, size*nmemb, f)/size; +} diff --git a/syslinux/com32/lib/free.c b/syslinux/com32/lib/free.c new file mode 100644 index 0000000..aa17080 --- /dev/null +++ b/syslinux/com32/lib/free.c @@ -0,0 +1,78 @@ +/* + * free.c + * + * Very simple linked-list based malloc()/free(). + */ + +#include <stdlib.h> +#include "malloc.h" + +static struct free_arena_header * +__free_block(struct free_arena_header *ah) +{ + struct free_arena_header *pah, *nah; + + pah = ah->a.prev; + nah = ah->a.next; + if ( pah->a.type == ARENA_TYPE_FREE && + (char *)pah+pah->a.size == (char *)ah ) { + /* Coalesce into the previous block */ + pah->a.size += ah->a.size; + pah->a.next = nah; + nah->a.prev = pah; + +#ifdef DEBUG_MALLOC + ah->a.type = ARENA_TYPE_DEAD; +#endif + + ah = pah; + pah = ah->a.prev; + } else { + /* Need to add this block to the free chain */ + ah->a.type = ARENA_TYPE_FREE; + + ah->next_free = __malloc_head.next_free; + ah->prev_free = &__malloc_head; + __malloc_head.next_free = ah; + ah->next_free->prev_free = ah; + } + + /* In either of the previous cases, we might be able to merge + with the subsequent block... */ + if ( nah->a.type == ARENA_TYPE_FREE && + (char *)ah+ah->a.size == (char *)nah ) { + ah->a.size += nah->a.size; + + /* Remove the old block from the chains */ + nah->next_free->prev_free = nah->prev_free; + nah->prev_free->next_free = nah->next_free; + ah->a.next = nah->a.next; + nah->a.next->a.prev = ah; + +#ifdef DEBUG_MALLOC + nah->a.type = ARENA_TYPE_DEAD; +#endif + } + + /* Return the block that contains the called block */ + return ah; +} + +void free(void *ptr) +{ + struct free_arena_header *ah; + + if ( !ptr ) + return; + + ah = (struct free_arena_header *) + ((struct arena_header *)ptr - 1); + +#ifdef DEBUG_MALLOC + assert( ah->a.type == ARENA_TYPE_USED ); +#endif + + __free_block(ah); + + /* Here we could insert code to return memory to the system. */ +} diff --git a/syslinux/com32/lib/fwrite.c b/syslinux/com32/lib/fwrite.c new file mode 100644 index 0000000..fd7dab7 --- /dev/null +++ b/syslinux/com32/lib/fwrite.c @@ -0,0 +1,32 @@ +/* + * fwrite.c + */ + +#include <errno.h> +#include <unistd.h> +#include <stdio.h> + +size_t _fwrite(const void *buf, size_t count, FILE *f) +{ + size_t bytes = 0; + ssize_t rv; + const char *p = buf; + + while ( count ) { + rv = write(fileno(f), p, count); + if ( rv == -1 ) { + if ( errno == EINTR || errno == EAGAIN ) + continue; + else + break; + } else if ( rv == 0 ) { + break; + } + + p += rv; + bytes += rv; + count -= rv; + } + + return bytes; +} diff --git a/syslinux/com32/lib/fwrite2.c b/syslinux/com32/lib/fwrite2.c new file mode 100644 index 0000000..82ec832 --- /dev/null +++ b/syslinux/com32/lib/fwrite2.c @@ -0,0 +1,13 @@ +/* + * fwrite2.c + * + * The actual fwrite() function as a non-inline + */ + +#define __NO_FREAD_FWRITE_INLINES +#include <stdio.h> + +size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *f) +{ + return _fwrite(ptr, size*nmemb, f)/size; +} diff --git a/syslinux/com32/lib/getopt.c b/syslinux/com32/lib/getopt.c new file mode 100644 index 0000000..5a992dc --- /dev/null +++ b/syslinux/com32/lib/getopt.c @@ -0,0 +1,74 @@ +/* + * getopt.c + * + * Simple POSIX getopt(), no GNU extensions... + */ + +#include <stdint.h> +#include <unistd.h> +#include <string.h> + +char *optarg; +int optind = 1; +int opterr, optopt; +static const char *__optptr; + +int getopt(int argc, char * const *argv, const char *optstring) +{ + const char *carg = argv[optind]; + const char *osptr; + int opt; + + /* We don't actually need argc */ + (void)argc; + + /* First, eliminate all non-option cases */ + + if ( !carg || carg[0] != '-' || !carg[1] ) { + return -1; + } + + if ( carg[1] == '-' && !carg[2] ) { + optind++; + return -1; + } + + if ( (uintptr_t)(__optptr-carg) > (uintptr_t)strlen(carg) ) + __optptr = carg+1; /* Someone frobbed optind, change to new opt. */ + + opt = *__optptr++; + + if ( opt != ':' && (osptr = strchr(optstring, opt)) ) { + if ( osptr[1] == ':' ) { + if ( *__optptr ) { + /* Argument-taking option with attached argument */ + optarg = (char *)__optptr; + optind++; + } else { + /* Argument-taking option with non-attached argument */ + if ( argv[optind+1] ) { + optarg = (char *)argv[optind+1]; + optind += 2; + } else { + /* Missing argument */ + return (optstring[0] == ':') ? ':' : '?'; + } + } + return opt; + } else { + /* Non-argument-taking option */ + /* __optptr will remember the exact position to resume at */ + if ( ! *__optptr ) + optind++; + return opt; + } + } else { + /* Unknown option */ + optopt = opt; + if ( ! *__optptr ) + optind++; + return '?'; + } +} + + diff --git a/syslinux/com32/lib/init.h b/syslinux/com32/lib/init.h new file mode 100644 index 0000000..2d98342 --- /dev/null +++ b/syslinux/com32/lib/init.h @@ -0,0 +1,15 @@ +/* + * init.h + * + * Magic to set up initializers + */ + +#ifndef _INIT_H +#define _INIT_H 1 + +#include <inttypes.h> + +#define COM32_INIT(x) static const void * const __COM32_INIT \ + __attribute__((section(".init_array"),unused)) = (const void * const)&x + +#endif /* _INIT_H */ diff --git a/syslinux/com32/lib/libgcc/__ashldi3.S b/syslinux/com32/lib/libgcc/__ashldi3.S new file mode 100644 index 0000000..80ed4be --- /dev/null +++ b/syslinux/com32/lib/libgcc/__ashldi3.S @@ -0,0 +1,29 @@ +/* + * arch/i386/libgcc/__ashldi3.S + * + * 64-bit shl + */ + .text + .align 4 + .globl __ashldi3 + .type __ashldi3,@function +__ashldi3: +#ifndef REGPARM + movl 4(%esp),%eax + movl 8(%esp),%edx + movb 12(%esp),%cl +#endif + cmpb $32,%cl + jae 1f + + shldl %cl,%eax,%edx + shl %cl,%eax + ret + +1: + xorl %edx,%edx + shl %cl,%eax + xchgl %edx,%eax + ret + + .size __ashldi3,.-__ashldi3 diff --git a/syslinux/com32/lib/libgcc/__ashrdi3.S b/syslinux/com32/lib/libgcc/__ashrdi3.S new file mode 100644 index 0000000..ba43f90 --- /dev/null +++ b/syslinux/com32/lib/libgcc/__ashrdi3.S @@ -0,0 +1,29 @@ +/* + * arch/i386/libgcc/__ashrdi3.S + * + * 64-bit sar + */ + .text + .align 4 + .globl __ashrdi3 + .type __ashrdi3,@function +__ashrdi3: +#ifndef REGPARM + movl 4(%esp),%eax + movl 8(%esp),%edx + movb 12(%esp),%cl +#endif + cmpb $32,%cl + jae 1f + + shrdl %cl,%edx,%eax + sarl %cl,%edx + ret + +1: + sarl %cl,%edx + movl %edx,%eax + cdq + ret + + .size __ashrdi3,.-__ashrdi3 diff --git a/syslinux/com32/lib/libgcc/__divdi3.c b/syslinux/com32/lib/libgcc/__divdi3.c new file mode 100644 index 0000000..be13cae --- /dev/null +++ b/syslinux/com32/lib/libgcc/__divdi3.c @@ -0,0 +1,29 @@ +/* + * arch/i386/libgcc/__divdi3.c + */ + +#include <stdint.h> +#include <stddef.h> + +extern uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t *rem); + +int64_t __divdi3(int64_t num, int64_t den) +{ + int minus = 0; + int64_t v; + + if ( num < 0 ) { + num = -num; + minus = 1; + } + if ( den < 0 ) { + den = -den; + minus ^= 1; + } + + v = __udivmoddi4(num, den, NULL); + if ( minus ) + v = -v; + + return v; +} diff --git a/syslinux/com32/lib/libgcc/__lshrdi3.S b/syslinux/com32/lib/libgcc/__lshrdi3.S new file mode 100644 index 0000000..6e521ac --- /dev/null +++ b/syslinux/com32/lib/libgcc/__lshrdi3.S @@ -0,0 +1,29 @@ +/* + * arch/i386/libgcc/__lshrdi3.S + * + * 64-bit shr + */ + .text + .align 4 + .globl __lshrdi3 + .type __lshrdi3,@function +__lshrdi3: +#ifndef REGPARM + movl 4(%esp),%eax + movl 8(%esp),%edx + movb 12(%esp),%cl +#endif + cmpb $32,%cl + jae 1f + + shrdl %cl,%edx,%eax + shrl %cl,%edx + ret + +1: + shrl %cl,%edx + xorl %eax,%eax + xchgl %edx,%eax + ret + + .size __lshrdi3,.-__lshrdi3 diff --git a/syslinux/com32/lib/libgcc/__moddi3.c b/syslinux/com32/lib/libgcc/__moddi3.c new file mode 100644 index 0000000..c41d4f4 --- /dev/null +++ b/syslinux/com32/lib/libgcc/__moddi3.c @@ -0,0 +1,29 @@ +/* + * arch/i386/libgcc/__moddi3.c + */ + +#include <stdint.h> +#include <stddef.h> + +extern uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t *rem); + +int64_t __moddi3(int64_t num, int64_t den) +{ + int minus = 0; + int64_t v; + + if ( num < 0 ) { + num = -num; + minus = 1; + } + if ( den < 0 ) { + den = -den; + minus ^= 1; + } + + (void) __udivmoddi4(num, den, (uint64_t *)&v); + if ( minus ) + v = -v; + + return v; +} diff --git a/syslinux/com32/lib/libgcc/__muldi3.S b/syslinux/com32/lib/libgcc/__muldi3.S new file mode 100644 index 0000000..c164588 --- /dev/null +++ b/syslinux/com32/lib/libgcc/__muldi3.S @@ -0,0 +1,34 @@ +/* + * arch/i386/libgcc/__muldi3.S + * + * 64*64 = 64 bit unsigned multiplication + */ + + .text + .align 4 + .globl __muldi3 + .type __muldi3,@function +__muldi3: + push %esi +#ifndef REGPARM + movl 8(%esp),%eax + movl %eax,%esi + movl 16(%esp),%ecx + mull %ecx + imull 12(%esp),%ecx + imull 20(%esp),%esi + addl %ecx,%edx + addl %esi,%edx +#else + movl %eax,%esi + push %edx + mull %ecx + imull 8(%esp),%esi + addl %esi,%edx + pop %esi + imull %esi,%ecx + addl %ecx,%edx +#endif + pop %esi + ret + .size __muldi3,.-__muldi3 diff --git a/syslinux/com32/lib/libgcc/__negdi2.S b/syslinux/com32/lib/libgcc/__negdi2.S new file mode 100644 index 0000000..6c95cb2 --- /dev/null +++ b/syslinux/com32/lib/libgcc/__negdi2.S @@ -0,0 +1,21 @@ +/* + * arch/i386/libgcc/__negdi2.S + * + * 64-bit negation + */ + + .text + .align 4 + .globl __negdi2 + .type __negdi2,@function +__negdi2: +#ifndef REGPARM + movl 4(%esp),%eax + movl 8(%esp),%edx +#endif + negl %edx + negl %eax + sbbl $0,%edx + ret + + .size __negdi2,.-__negdi2 diff --git a/syslinux/com32/lib/libgcc/__udivdi3.c b/syslinux/com32/lib/libgcc/__udivdi3.c new file mode 100644 index 0000000..901ce2a --- /dev/null +++ b/syslinux/com32/lib/libgcc/__udivdi3.c @@ -0,0 +1,13 @@ +/* + * arch/i386/libgcc/__divdi3.c + */ + +#include <stdint.h> +#include <stddef.h> + +extern uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t *rem); + +uint64_t __udivdi3(uint64_t num, uint64_t den) +{ + return __udivmoddi4(num, den, NULL); +} diff --git a/syslinux/com32/lib/libgcc/__udivmoddi4.c b/syslinux/com32/lib/libgcc/__udivmoddi4.c new file mode 100644 index 0000000..1c45654 --- /dev/null +++ b/syslinux/com32/lib/libgcc/__udivmoddi4.c @@ -0,0 +1,32 @@ +#include <klibc/diverr.h> +#include <stdint.h> + +uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t *rem_p) +{ + uint64_t quot = 0, qbit = 1; + + if ( den == 0 ) { + __divide_error(); + return 0; /* If trap returns... */ + } + + /* Left-justify denominator and count shift */ + while ( (int64_t)den >= 0 ) { + den <<= 1; + qbit <<= 1; + } + + while ( qbit ) { + if ( den <= num ) { + num -= den; + quot += qbit; + } + den >>= 1; + qbit >>= 1; + } + + if ( rem_p ) + *rem_p = num; + + return quot; +} diff --git a/syslinux/com32/lib/libgcc/__umoddi3.c b/syslinux/com32/lib/libgcc/__umoddi3.c new file mode 100644 index 0000000..c007d48 --- /dev/null +++ b/syslinux/com32/lib/libgcc/__umoddi3.c @@ -0,0 +1,16 @@ +/* + * arch/i386/libgcc/__umoddi3.c + */ + +#include <stdint.h> +#include <stddef.h> + +extern uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t *rem); + +uint64_t __umoddi3(uint64_t num, uint64_t den) +{ + uint64_t v; + + (void) __udivmoddi4(num, den, &v); + return v; +} diff --git a/syslinux/com32/lib/libpng/ANNOUNCE b/syslinux/com32/lib/libpng/ANNOUNCE new file mode 100644 index 0000000..e40b94a --- /dev/null +++ b/syslinux/com32/lib/libpng/ANNOUNCE @@ -0,0 +1,32 @@ + +Libpng 1.2.8 - December 3, 2004 + +This is a public release of libpng, intended for use in production codes. + +Changes since the last public release (1.2.7): + + Fixed bug in png_text_compress() that would fail to complete a large block. + Fixed bug, introduced in libpng-1.2.7, that overruns a buffer during + strip alpha operation in png_do_strip_filler(). + Added PNG_1_2_X definition in pngconf.h + #ifdef out png_info_init in png.c and png_read_init in pngread.c (as of 1.3.0) + Reduce color_type to a nonalpha type after strip alpha operation in + png_do_strip_filler(). + Revised definitions of PNG_MAX_UINT_32, PNG_MAX_SIZE, and PNG_MAXSUM + Fixed (again) definition of PNG_LIBPNG_VER_DLLNUM in png.h (Cosmin). + Added PNG_LIBPNG_BUILD_PRIVATE in png.h (Cosmin). + Set png_ptr->zstream.data_type to Z_BINARY, to avoid unnecessary detection + of data type in deflate (Cosmin). + Deprecated but continue to support SPECIALBUILD and PRIVATEBUILD in favor of + PNG_LIBPNG_BUILD_SPECIAL_STRING and PNG_LIBPNG_BUILD_PRIVATE_STRING. + Despammed mailing addresses by masking "@" with "at". + Added scripts/makefile.elf with supporting code in pngconf.h for symbol + versioning (John Bowler). + Added projects/visualc71 (Simon-pierre). + +Send comments/corrections/commendations to +png-implement at ccrc.wustl.edu (subscription required; write to +majordomo at ccrc.wustl.edu with "subscribe png-implement" in the message) +or to glennrp at users.sourceforge.net + +Glenn R-P diff --git a/syslinux/com32/lib/libpng/CHANGES b/syslinux/com32/lib/libpng/CHANGES new file mode 100644 index 0000000..90c816e --- /dev/null +++ b/syslinux/com32/lib/libpng/CHANGES @@ -0,0 +1,1419 @@ + +CHANGES - changes for libpng + +version 0.2 + added reader into png.h + fixed small problems in stub file + +version 0.3 + added pull reader + split up pngwrite.c to several files + added pnglib.txt + added example.c + cleaned up writer, adding a few new tranformations + fixed some bugs in writer + interfaced with zlib 0.5 + added K&R support + added check for 64 KB blocks for 16 bit machines + +version 0.4 + cleaned up code and commented code + simplified time handling into png_time + created png_color_16 and png_color_8 to handle color needs + cleaned up color type defines + fixed various bugs + made various names more consistant + interfaced with zlib 0.71 + cleaned up zTXt reader and writer (using zlib's Reset functions) + split transformations into pngrtran.c and pngwtran.c + +version 0.5 + interfaced with zlib 0.8 + fixed many reading and writing bugs + saved using 3 spaces instead of tabs + +version 0.6 + added png_large_malloc() and png_large_free() + added png_size_t + cleaned up some compiler warnings + added png_start_read_image() + +version 0.7 + cleaned up lots of bugs + finished dithering and other stuff + added test program + changed name from pnglib to libpng + +version 0.71 [June, 1995] + changed pngtest.png for zlib 0.93 + fixed error in libpng.txt and example.c + +version 0.8 + cleaned up some bugs + added png_set_filler() + split up pngstub.c into pngmem.c, pngio.c, and pngerror.c + added #define's to remove unwanted code + moved png_info_init() to png.c + added old_size into png_realloc() + added functions to manually set filtering and compression info + changed compression parameters based on image type + optimized filter selection code + added version info + changed external functions passing floats to doubles (k&r problems?) + put all the configurable stuff in pngconf.h + enabled png_set_shift to work with paletted images on read + added png_read_update_info() - updates info structure with + transformations + +version 0.81 [August, 1995] + incorporated Tim Wegner's medium model code (thanks, Tim) + +version 0.82 [September, 1995] + [unspecified changes] + +version 0.85 [December, 1995] + added more medium model code (almost everything's a far) + added i/o, error, and memory callback functions + fixed some bugs (16 bit, 4 bit interlaced, etc.) + added first run progressive reader (barely tested) + +version 0.86 [January, 1996] + fixed bugs + improved documentation + +version 0.87 [January, 1996] + fixed medium model bugs + fixed other bugs introduced in 0.85 and 0.86 + added some minor documentation + +version 0.88 [January, 1996] + fixed progressive bugs + replaced tabs with spaces + cleaned up documentation + added callbacks for read/write and warning/error functions + +version 0.89 [July, 1996] + added new initialization API to make libpng work better with shared libs + we now have png_create_read_struct(), png_create_write_struct(), + png_create_info_struct(), png_destroy_read_struct(), and + png_destroy_write_struct() instead of the separate calls to + malloc and png_read_init(), png_info_init(), and png_write_init() + changed warning/error callback functions to fix bug - this means you + should use the new initialization API if you were using the old + png_set_message_fn() calls, and that the old API no longer exists + so that people are aware that they need to change their code + changed filter selection API to allow selection of multiple filters + since it didn't work in previous versions of libpng anyways + optimized filter selection code + fixed png_set_background() to allow using an arbitrary RGB color for + paletted images + fixed gamma and background correction for paletted images, so + png_correct_palette is not needed unless you are correcting an + external palette (you will need to #define PNG_CORRECT_PALETTE_SUPPORTED + in pngconf.h) - if nobody uses this, it may disappear in the future. + fixed bug with Borland 64K memory allocation (Alexander Lehmann) + fixed bug in interlace handling (Smarasderagd, I think) + added more error checking for writing and image to reduce invalid files + separated read and write functions so that they won't both be linked + into a binary when only reading or writing functionality is used + new pngtest image also has interlacing and zTXt + updated documentation to reflect new API + +version 0.90 [January, 1997] + made CRC errors/warnings on critical and ancillary chunks configurable + libpng will use the zlib CRC routines by (compile-time) default + changed DOS small/medium model memory support - needs zlib 1.04 (Tim Wegner) + added external C++ wrapper statements to png.h (Gilles Dauphin) + allow PNG file to be read when some or all of file signature has already + been read from the beginning of the stream. ****This affects the size + of info_struct and invalidates all programs that use a shared libpng**** + fixed png_filler() declarations + fixed? background color conversions + fixed order of error function pointers to match documentation + current chunk name is now available in png_struct to reduce the number + of nearly identical error messages (will simplify multi-lingual + support when available) + try to get ready for unknown-chunk callback functions: + - previously read critical chunks are flagged, so the chunk handling + routines can determine if the chunk is in the right place + - all chunk handling routines have the same prototypes, so we will + be able to handle all chunks via a callback mechanism + try to fix Linux "setjmp" buffer size problems + removed png_large_malloc, png_large_free, and png_realloc functions. + +version 0.95 [March, 1997] + fixed bug in pngwutil.c allocating "up_row" twice and "avg_row" never + fixed bug in PNG file signature compares when start != 0 + changed parameter type of png_set_filler(...filler...) from png_byte + to png_uint_32 + added test for MACOS to ensure that both math.h and fp.h are not #included + added macros for libpng to be compiled as a Windows DLL (Andreas Kupries) + added "packswap" transformation, which changes the endianness of + packed-pixel bytes (Kevin Bracey) + added "strip_alpha" transformation, which removes the alpha channel of + input images without using it (not neccesarily a good idea) + added "swap_alpha" transformation, which puts the alpha channel in front + of the color bytes instead of after + removed all implicit variable tests which assume NULL == 0 (I think) + changed several variables to "png_size_t" to show 16/32-bit limitations + added new pCAL chunk read/write support + added experimental filter selection weighting (Greg Roelofs) + removed old png_set_rgbx() and png_set_xrgb() functions that have been + obsolete for about 2 years now (use png_set_filler() instead) + added macros to read 16- and 32-bit ints directly from buffer, to be + used only on those systems that support it (namely PowerPC and 680x0) + With some testing, this may become the default for MACOS/PPC systems. + only calculate CRC on data if we are going to use it + added macros for zTXt compression type PNG_zTXt_COMPRESSION_??? + added macros for simple libpng debugging output selectable at compile time + removed PNG_READ_END_MODE in progressive reader (Smarasderagd) + more description of info_struct in libpng.txt and png.h + more instructions in example.c + more chunk types tested in pngtest.c + renamed pngrcb.c to pngset.c, and all png_read_<chunk> functions to be + png_set_<chunk>. We now have corresponding png_get_<chunk> + functions in pngget.c to get infomation in info_ptr. This isolates + the application from the internal organization of png_info_struct + (good for shared library implementations). + +version 0.96 [May, 1997] + fixed serious bug with < 8bpp images introduced in 0.95 + fixed 256-color transparency bug (Greg Roelofs) + fixed up documentation (Greg Roelofs, Laszlo Nyul) + fixed "error" in pngconf.h for Linux setjmp() behaviour + fixed DOS medium model support (Tim Wegner) + fixed png_check_keyword() for case with error in static string text + added read of CRC after IEND chunk for embedded PNGs (Laszlo Nyul) + added typecasts to quiet compiler errors + added more debugging info + +version 0.97 [January, 1998] + removed PNG_USE_OWN_CRC capability + relocated png_set_crc_action from pngrutil.c to pngrtran.c + fixed typecasts of "new_key", etc. (Andreas Dilger) + added RFC 1152 [sic] date support + fixed bug in gamma handling of 4-bit grayscale + added 2-bit grayscale gamma handling (Glenn R-P) + added more typecasts. 65536L becomes (png_uint_32)65536L, etc. (Glenn R-P) + minor corrections in libpng.txt + added simple sRGB support (Glenn R-P) + easier conditional compiling, e.g. define PNG_READ/WRITE_NOT_FULLY_SUPPORTED; + all configurable options can be selected from command-line instead + of having to edit pngconf.h (Glenn R-P) + fixed memory leak in pngwrite.c (free info_ptr->text) (Glenn R-P) + added more conditions for png_do_background, to avoid changing + black pixels to background when a background is supplied and + no pixels are transparent + repaired PNG_NO_STDIO behaviour + tested NODIV support and made it default behaviour (Greg Roelofs) + added "-m" option and PNGTEST_DEBUG_MEMORY to pngtest (John Bowler) + regularized version numbering scheme and bumped shared-library major + version number to 2 to avoid problems with libpng 0.89 apps (Greg Roelofs) + +version 0.98 [January, 1998] + cleaned up some typos in libpng.txt and in code documentation + fixed memory leaks in pCAL chunk processing (Glenn R-P and John Bowler) + cosmetic change "display_gamma" to "screen_gamma" in pngrtran.c + changed recommendation about file_gamma for PC images to .51 from .45, + in example.c and libpng.txt, added comments to distinguish between + screen_gamma, viewing_gamma, and display_gamma. + changed all references to RFC1152 to read RFC1123 and changed the + PNG_TIME_RFC1152_SUPPORTED macro to PNG_TIME_RFC1123_SUPPORTED + added png_invert_alpha capability (Glenn R-P -- suggestion by Jon Vincent) + changed srgb_intent from png_byte to int to avoid compiler bugs + +version 0.99 [January 30, 1998] + free info_ptr->text instead of end_info_ptr->text in pngread.c (John Bowler) + fixed a longstanding "packswap" bug in pngtrans.c + fixed some inconsistencies in pngconf.h that prevented compiling with + PNG_READ_GAMMA_SUPPORTED and PNG_READ_hIST_SUPPORTED undefined + fixed some typos and made other minor rearrangement of libpng.txt (Andreas) + changed recommendation about file_gamma for PC images to .50 from .51 in + example.c and libpng.txt, and changed file_gamma for sRGB images to .45 + added a number of functions to access information from the png structure + png_get_image_height(), etc. (Glenn R-P, suggestion by Brad Pettit) + added TARGET_MACOS similar to zlib-1.0.8 + define PNG_ALWAYS_EXTERN when __MWERKS__ && WIN32 are defined + added type casting to all png_malloc() function calls +version 0.99a [January 31, 1998] + Added type casts and parentheses to all returns that return a value.(Tim W.) +version 0.99b [February 4, 1998] + Added type cast png_uint_32 on malloc function calls where needed. + Changed type of num_hist from png_uint_32 to int (same as num_palette). + Added checks for rowbytes overflow, in case png_size_t is less than 32 bits. + Renamed makefile.elf to makefile.lnx. +version 0.99c [February 7, 1998] + More type casting. Removed erroneous overflow test in pngmem.c. + Added png_buffered_memcpy() and png_buffered_memset(), apply them to rowbytes. + Added UNIX manual pages libpng.3 (incorporating libpng.txt) and png.5. +version 0.99d [February 11, 1998] + Renamed "far_to_near()" "png_far_to_near()" + Revised libpng.3 + Version 99c "buffered" operations didn't work as intended. Replaced them + with png_memcpy_check() and png_memset_check(). + Added many "if (png_ptr == NULL) return" to quell compiler warnings about + unused png_ptr, mostly in pngget.c and pngset.c. + Check for overlength tRNS chunk present when indexed-color PLTE is read. + Cleaned up spelling errors in libpng.3/libpng.txt + Corrected a problem with png_get_tRNS() which returned undefined trans array +version 0.99e [February 28, 1998] + Corrected png_get_tRNS() again. + Add parentheses for easier reading of pngget.c, fixed "||" should be "&&". + Touched up example.c to make more of it compileable, although the entire + file still can't be compiled (Willem van Schaik) + Fixed a bug in png_do_shift() (Bryan Tsai) + Added a space in png.h prototype for png_write_chunk_start() + Replaced pngtest.png with one created with zlib 1.1.1 + Changed pngtest to report PASS even when file size is different (Jean-loup G.) + Corrected some logic errors in png_do_invert_alpha() (Chris Patterson) +version 0.99f [March 5, 1998] + Corrected a bug in pngpread() introduced in version 99c (Kevin Bracey) + Moved makefiles into a "scripts" directory, and added INSTALL instruction file + Added makefile.os2 and pngos2.def (A. Zabolotny) and makefile.s2x (W. Sebok) + Added pointers to "note on libpng versions" in makefile.lnx and README + Added row callback feature when reading and writing nonprogressive rows + and added a test of this feature in pngtest.c + Added user transform callbacks, with test of the feature in pngtest.c +version 0.99g [March 6, 1998, morning] + Minor changes to pngtest.c to suppress compiler warnings. + Removed "beta" language from documentation. +version 0.99h [March 6, 1998, evening] + Minor changes to previous minor changes to pngtest.c + Changed PNG_READ_NOT_FULLY_SUPPORTED to PNG_READ_TRANSFORMS_NOT_SUPPORTED + and added PNG_PROGRESSIVE_READ_NOT_SUPPORTED macro + Added user transform capability + +version 1.00 [March 7, 1998] + Changed several typedefs in pngrutil.c + Added makefile.wat (Pawel Mrochen), updated makefile.tc3 (Willem van Schaik) + replaced "while(1)" with "for(;;)" + added PNGARG() to prototypes in pngtest.c and removed some prototypes + updated some of the makefiles (Tom Lane) + changed some typedefs (s_start, etc.) in pngrutil.c + fixed dimensions of "short_months" array in pngwrite.c + Replaced ansi2knr.c with the one from jpeg-v6 + +version 1.0.0 [March 8, 1998] + Changed name from 1.00 to 1.0.0 (Adam Costello) + Added smakefile.ppc (with SCOPTIONS.ppc) for Amiga PPC (Andreas Kleinert) +version 1.0.0a [March 9, 1998] + Fixed three bugs in pngrtran.c to make gamma+background handling consistent + (Greg Roelofs) + Changed format of the PNG_LIBPNG_VER integer to xyyzz instead of xyz + for major, minor, and bugfix releases. This is 10001. (Adam Costello, + Tom Lane) + Make months range from 1-12 in png_convert_to_rfc1123 +version 1.0.0b [March 13, 1998] + Quieted compiler complaints about two empty "for" loops in pngrutil.c + Minor changes to makefile.s2x + Removed #ifdef/#endif around a png_free() in pngread.c + +version 1.0.1 [March 14, 1998] + Changed makefile.s2x to reduce security risk of using a relative pathname + Fixed some typos in the documentation (Greg). + Fixed a problem with value of "channels" returned by png_read_update_info() +version 1.0.1a [April 21, 1998] + Optimized Paeth calculations by replacing abs() function calls with intrinsics + plus other loop optimizations. Improves avg decoding speed by about 20%. + Commented out i386istic "align" compiler flags in makefile.lnx. + Reduced the default warning level in some makefiles, to make them consistent. + Removed references to IJG and JPEG in the ansi2knr.c copyright statement. + Fixed a bug in png_do_strip_filler with XXRRGGBB => RRGGBB transformation. + Added grayscale and 16-bit capability to png_do_read_filler(). + Fixed a bug in pngset.c, introduced in version 0.99c, that sets rowbytes + too large when writing an image with bit_depth < 8 (Bob Dellaca). + Corrected some bugs in the experimental weighted filtering heuristics. + Moved a misplaced pngrutil code block that truncates tRNS if it has more + than num_palette entries -- test was done before num_palette was defined. + Fixed a png_convert_to_rfc1123() bug that converts day 31 to 0 (Steve Eddins). + Changed compiler flags in makefile.wat for better optimization (Pawel Mrochen). +version 1.0.1b [May 2, 1998] + Relocated png_do_gray_to_rgb() within png_do_read_transformations() (Greg). + Relocated the png_composite macros from pngrtran.c to png.h (Greg). + Added makefile.sco (contributed by Mike Hopkirk). + Fixed two bugs (missing definitions of "istop") introduced in libpng-1.0.1a. + Fixed a bug in pngrtran.c that would set channels=5 under some circumstances. + More work on the Paeth-filtering, achieving imperceptible speedup (A Kleinert). + More work on loop optimization which may help when compiled with C++ compilers. + Added warnings when people try to use transforms they've defined out. + Collapsed 4 "i" and "c" loops into single "i" loops in pngrtran and pngwtran. + Revised paragraph about png_set_expand() in libpng.txt and libpng.3 (Greg) +version 1.0.1c [May 11, 1998] + Fixed a bug in pngrtran.c (introduced in libpng-1.0.1a) where the masks for + filler bytes should have been 0xff instead of 0xf. + Added max_pixel_depth=32 in pngrutil.c when using FILLER with palette images. + Moved PNG_WRITE_WEIGHTED_FILTER_SUPPORTED and PNG_WRITE_FLUSH_SUPPORTED + out of the PNG_WRITE_TRANSFORMS_NOT_SUPPORTED block of pngconf.h + Added "PNG_NO_WRITE_TRANSFORMS" etc., as alternatives for *_NOT_SUPPORTED, + for consistency, in pngconf.h + Added individual "ifndef PNG_NO_[CAPABILITY]" in pngconf.h to make it easier + to remove unwanted capabilities via the compile line + Made some corrections to grammar (which, it's) in documentation (Greg). + Corrected example.c, use of row_pointers in png_write_image(). +version 1.0.1d [May 24, 1998] + Corrected several statements that used side effects illegally in pngrutil.c + and pngtrans.c, that were introduced in version 1.0.1b + Revised png_read_rows() to avoid repeated if-testing for NULL (A Kleinert) + More corrections to example.c, use of row_pointers in png_write_image() + and png_read_rows(). + Added pngdll.mak and pngdef.pas to scripts directory, contributed by + Bob Dellaca, to make a png32bd.dll with Borland C++ 4.5 + Fixed error in example.c with png_set_text: num_text is 3, not 2 (Guido V.) + Changed several loops from count-down to count-up, for consistency. +version 1.0.1e [June 6, 1998] + Revised libpng.txt and libpng.3 description of png_set_read|write_fn(), and + added warnings when people try to set png_read_fn and png_write_fn in + the same structure. + Added a test such that png_do_gamma will be done when num_trans==0 + for truecolor images that have defined a background. This corrects an + error that was introduced in libpng-0.90 that can cause gamma processing + to be skipped. + Added tests in png.h to include "trans" and "trans_values" in structures + when PNG_READ_BACKGROUND_SUPPORTED or PNG_READ_EXPAND_SUPPORTED is defined. + Add png_free(png_ptr->time_buffer) in png_destroy_read_struct() + Moved png_convert_to_rfc_1123() from pngwrite.c to png.c + Added capability for user-provided malloc_fn() and free_fn() functions, + and revised pngtest.c to demonstrate their use, replacing the + PNGTEST_DEBUG_MEM feature. + Added makefile.w32, for Microsoft C++ 4.0 and later (Tim Wegner). + +version 1.0.2 [June 14, 1998] + Fixed two bugs in makefile.bor . +version 1.0.2a [December 30, 1998] + Replaced and extended code that was removed from png_set_filler() in 1.0.1a. + Fixed a bug in png_do_filler() that made it fail to write filler bytes in + the left-most pixel of each row (Kevin Bracey). + Changed "static pngcharp tIME_string" to "static char tIME_string[30]" + in pngtest.c (Duncan Simpson). + Fixed a bug in pngtest.c that caused pngtest to try to write a tIME chunk + even when no tIME chunk was present in the source file. + Fixed a problem in pngrutil.c: gray_to_rgb didn't always work with 16-bit. + Fixed a problem in png_read_push_finish_row(), which would not skip some + passes that it should skip, for images that are less than 3 pixels high. + Interchanged the order of calls to png_do_swap() and png_do_shift() + in pngwtran.c (John Cromer). + Added #ifdef PNG_DEBUG/#endif surrounding use of PNG_DEBUG in png.h . + Changed "bad adaptive filter type" from error to warning in pngrutil.c . + Fixed a documentation error about default filtering with 8-bit indexed-color. + Separated the PNG_NO_STDIO macro into PNG_NO_STDIO and PNG_NO_CONSOLE_IO + (L. Peter Deutsch). + Added png_set_rgb_to_gray() and png_get_rgb_to_gray_status() functions. + Added png_get_copyright() and png_get_header_version() functions. + Revised comments on png_set_progressive_read_fn() in libpng.txt and example.c + Added information about debugging in libpng.txt and libpng.3 . + Changed "ln -sf" to "ln -s -f" in makefile.s2x, makefile.lnx, and makefile.sco. + Removed lines after Dynamic Dependencies" in makefile.aco . + Revised makefile.dec to make a shared library (Jeremie Petit). + Removed trailing blanks from all files. +version 1.0.2a [January 6, 1999] + Removed misplaced #endif and #ifdef PNG_NO_EXTERN near the end of png.h + Added "if" tests to silence complaints about unused png_ptr in png.h and png.c + Changed "check_if_png" function in example.c to return true (nonzero) if PNG. + Changed libpng.txt to demonstrate png_sig_cmp() instead of png_check_sig() + which is obsolete. + +version 1.0.3 [January 14, 1999] + Added makefile.hux, for Hewlett Packard HPUX 10.20 and 11.00 (Jim Rice) + Added a statement of Y2K compliance in png.h, libpng.3, and Y2KINFO. +version 1.0.3a [August 12, 1999] + Added check for PNG_READ_INTERLACE_SUPPORTED in pngread.c; issue a warning + if an attempt is made to read an interlaced image when it's not supported. + Added check if png_ptr->trans is defined before freeing it in pngread.c + Modified the Y2K statement to include versions back to version 0.71 + Fixed a bug in the check for valid IHDR bit_depth/color_types in pngrutil.c + Modified makefile.wat (added -zp8 flag, ".symbolic", changed some comments) + Replaced leading blanks with tab characters in makefile.hux + Changed "dworkin.wustl.edu" to "ccrc.wustl.edu" in various documents. + Changed (float)red and (float)green to (double)red, (double)green + in png_set_rgb_to_gray() to avoid "promotion" problems in AIX. + Fixed a bug in pngconf.h that omitted <stdio.h> when PNG_DEBUG==0 (K Bracey). + Reformatted libpng.3 and libpngpf.3 with proper fonts (script by J. vanZandt). + Updated documentation to refer to the PNG-1.2 specification. + Removed ansi2knr.c and left pointers to the latest source for ansi2knr.c + in makefile.knr, INSTALL, and README (L. Peter Deutsch) + Fixed bugs in calculation of the length of rowbytes when adding alpha + channels to 16-bit images, in pngrtran.c (Chris Nokleberg) + Added function png_set_user_transform_info() to store user_transform_ptr, + user_depth, and user_channels into the png_struct, and a function + png_get_user_transform_ptr() to retrieve the pointer (Chris Nokleberg) + Added function png_set_empty_plte_permitted() to make libpng useable + in MNG applications. + Corrected the typedef for png_free_ptr in png.h (Jesse Jones). + Correct gamma with srgb is 45455 instead of 45000 in pngrutil.c, to be + consistent with PNG-1.2, and allow variance of 500 before complaining. + Added assembler code contributed by Intel in file pngvcrd.c and modified + makefile.w32 to use it (Nirav Chhatrapati, INTEL Corporation, Gilles Vollant) + Changed "ln -s -f" to "ln -f -s" in the makefiles to make Solaris happy. + Added some aliases for png_set_expand() in pngrtran.c, namely + png_set_expand_PLTE(), png_set_expand_depth(), and png_set_expand_tRNS() + (Greg Roelofs, in "PNG: The Definitive Guide"). + Added makefile.beo for BEOS on X86, contributed by Sander Stok. +version 1.0.3b [August 26, 1999] + Replaced 2147483647L several places with PNG_MAX_UINT macro, defined in png.h + Changed leading blanks to tabs in all makefiles. + Define PNG_USE_PNGVCRD in makefile.w32, to get MMX assembler code. + Made alternate versions of png_set_expand() in pngrtran.c, namely + png_set_gray_1_2_4_to_8, png_set_palette_to_rgb, and png_set_tRNS_to_alpha + (Greg Roelofs, in "PNG: The Definitive Guide"). Deleted the 1.0.3a aliases. + Relocated start of 'extern "C"' block in png.h so it doesn't include pngconf.h + Revised calculation of num_blocks in pngmem.c to avoid a potentially + negative shift distance, whose results are undefined in the C language. + Added a check in pngset.c to prevent writing multiple tIME chunks. + Added a check in pngwrite.c to detect invalid small window_bits sizes. +version 1.0.3d [September 4, 1999] + Fixed type casting of igamma in pngrutil.c + Added new png_expand functions to scripts/pngdef.pas and pngos2.def + Added a demo read_user_transform_fn that examines the row filters in pngtest.c + +version 1.0.4 [September 24, 1999] + Define PNG_ALWAYS_EXTERN in pngconf.h if __STDC__ is defined + Delete #define PNG_INTERNAL and include "png.h" from pngasmrd.h + Made several minor corrections to pngtest.c + Renamed the makefiles with longer but more user friendly extensions. + Copied the PNG copyright and license to a separate LICENSE file. + Revised documentation, png.h, and example.c to remove reference to + "viewing_gamma" which no longer appears in the PNG specification. + Revised pngvcrd.c to use MMX code for interlacing only on the final pass. + Updated pngvcrd.c to use the faster C filter algorithms from libpng-1.0.1a + Split makefile.win32vc into two versions, makefile.vcawin32 (uses MMX + assembler code) and makefile.vcwin32 (doesn't). + Added a CPU timing report to pngtest.c (enabled by defining PNGTEST_TIMING) + Added a copy of pngnow.png to the distribution. +version 1.0.4a [September 25, 1999] + Increase max_pixel_depth in pngrutil.c if a user transform needs it. + Changed several division operations to right-shifts in pngvcrd.c +version 1.0.4b [September 30, 1999] + Added parentheses in line 3732 of pngvcrd.c + Added a comment in makefile.linux warning about buggy -O3 in pgcc 2.95.1 +version 1.0.4c [October 1, 1999] + Added a "png_check_version" function in png.c and pngtest.c that will generate + a helpful compiler error if an old png.h is found in the search path. + Changed type of png_user_transform_depth|channels from int to png_byte. +version 1.0.4d [October 6, 1999] + Changed 0.45 to 0.45455 in png_set_sRGB() + Removed unused PLTE entries from pngnow.png + Re-enabled some parts of pngvcrd.c (png_combine_row) that work properly. +version 1.0.4e [October 10, 1999] + Fixed sign error in pngvcrd.c (Greg Roelofs) + Replaced some instances of memcpy with simple assignments in pngvcrd (GR-P) +version 1.0.4f [October 15, 1999] + Surrounded example.c code with #if 0 .. #endif to prevent people from + inadvertently trying to compile it. + Changed png_get_header_version() from a function to a macro in png.h + Added type casting mostly in pngrtran.c and pngwtran.c + Removed some pointless "ptr = NULL" in pngmem.c + Added a "contrib" directory containing the source code from Greg's book. + +version 1.0.5 [October 15, 1999] + Minor editing of the INSTALL and README files. +version 1.0.5a [October 23, 1999] + Added contrib/pngsuite and contrib/pngminus (Willem van Schaik) + Fixed a typo in the png_set_sRGB() function call in example.c (Jan Nijtmans) + Further optimization and bugfix of pngvcrd.c + Revised pngset.c so that it does not allocate or free memory in the user's + text_ptr structure. Instead, it makes its own copy. + Created separate write_end_info_struct in pngtest.c for a more severe test. + Added code in pngwrite.c to free info_ptr->text[i].key to stop a memory leak. +version 1.0.5b [November 23, 1999] + Moved PNG_FLAG_HAVE_CHUNK_HEADER, PNG_FLAG_BACKGROUND_IS_GRAY and + PNG_FLAG_WROTE_tIME from flags to mode. + Added png_write_info_before_PLTE() function. + Fixed some typecasting in contrib/gregbook/*.c + Updated scripts/makevms.com and added makevms.com to contrib/gregbook + and contrib/pngminus (Martin Zinser) +version 1.0.5c [November 26, 1999] + Moved png_get_header_version from png.h to png.c, to accomodate ansi2knr. + Removed all global arrays (according to PNG_NO_GLOBAL_ARRAYS macro), to + accomodate making DLL's: Moved usr_png_ver from global variable to function + png_get_header_ver() in png.c. Moved png_sig to png_sig_bytes in png.c and + eliminated use of png_sig in pngwutil.c. Moved the various png_CHNK arrays + into pngtypes.h. Eliminated use of global png_pass arrays. Declared the + png_CHNK and png_pass arrays to be "const". Made the global arrays + available to applications (although none are used in libpng itself) when + PNG_NO_GLOBAL_ARRAYS is not defined or when PNG_GLOBAL_ARRAYS is defined. + Removed some extraneous "-I" from contrib/pngminus/makefile.std + Changed the PNG_sRGB_INTENT macros in png.h to be consistent with PNG-1.2. + Change PNG_SRGB_INTENT to PNG_sRGB_INTENT in libpng.txt and libpng.3 +version 1.0.5d [November 29, 1999] + Add type cast (png_const_charp) two places in png.c + Eliminated pngtypes.h; use macros instead to declare PNG_CHNK arrays. + Renamed "PNG_GLOBAL_ARRAYS" to "PNG_USE_GLOBAL_ARRAYS" and made available + to applications a macro "PNG_USE_LOCAL_ARRAYS". + #ifdef out all the new declarations when PNG_USE_GLOBAL_ARRAYS is defined. + Added PNG_EXPORT_VAR macro to accommodate making DLL's. +version 1.0.5e [November 30, 1999] + Added iCCP, iTXt, and sPLT support; added "lang" member to the png_text + structure; refactored the inflate/deflate support to make adding new chunks + with trailing compressed parts easier in the future, and added new functions + png_free_iCCP, png_free_pCAL, png_free_sPLT, png_free_text, png_get_iCCP, + png_get_spalettes, png_set_iCCP, png_set_spalettes (Eric S. Raymond). + NOTE: Applications that write text chunks MUST define png_text->lang + before calling png_set_text(). It must be set to NULL if you want to + write tEXt or zTXt chunks. If you want your application to be able to + run with older versions of libpng, use + + #ifdef PNG_iTXt_SUPPORTED + png_text[i].lang = NULL; + #endif + + Changed png_get_oFFs() and png_set_oFFs() to use signed rather than unsigned + offsets (Eric S. Raymond). + Combined PNG_READ_cHNK_SUPPORTED and PNG_WRITE_cHNK_SUPPORTED macros into + PNG_cHNK_SUPPORTED and combined the three types of PNG_text_SUPPORTED + macros, leaving the separate macros also available. + Removed comments on #endifs at the end of many short, non-nested #if-blocks. +version 1.0.5f [December 6, 1999] + Changed makefile.solaris to issue a warning about potential problems when + the ucb "ld" is in the path ahead of the ccs "ld". + Removed "- [date]" from the "synopsis" line in libpng.3 and libpngpf.3. + Added sCAL chunk support (Eric S. Raymond). +version 1.0.5g [December 7, 1999] + Fixed "png_free_spallettes" typo in png.h + Added code to handle new chunks in pngpread.c + Moved PNG_CHNK string macro definitions outside of PNG_NO_EXTERN block + Added "translated_key" to png_text structure and png_write_iTXt(). + Added code in pngwrite.c to work around a newly discovered zlib bug. +version 1.0.5h [December 10, 1999] + NOTE: regarding the note for version 1.0.5e, the following must also + be included in your code: + png_text[i].translated_key = NULL; + Unknown chunk handling is now supported. + Option to eliminate all floating point support was added. Some new + fixed-point functions such as png_set_gAMA_fixed() were added. + Expanded tabs and removed trailing blanks in source files. +version 1.0.5i [December 13, 1999] + Added some type casts to silence compiler warnings. + Renamed "png_free_spalette" to "png_free_spalettes" for consistency. + Removed leading blanks from a #define in pngvcrd.c + Added some parameters to the new png_set_keep_unknown_chunks() function. + Added a test for up->location != 0 in the first instance of writing + unknown chunks in pngwrite.c + Changed "num" to "i" in png_free_spalettes() and png_free_unknowns() to + prevent recursion. + Added png_free_hIST() function. + Various patches to fix bugs in the sCAL and integer cHRM processing, + and to add some convenience macros for use with sCAL. +version 1.0.5j [December 21, 1999] + Changed "unit" parameter of png_write_sCAL from png_byte to int, to work + around buggy compilers. + Added new type "png_fixed_point" for integers that hold float*100000 values + Restored backward compatibility of tEXt/zTXt chunk processing: + Restored the first four members of png_text to the same order as v.1.0.5d. + Added members "lang_key" and "itxt_length" to png_text struct. Set + text_length=0 when "text" contains iTXt data. Use the "compression" + member to distinguish among tEXt/zTXt/iTXt types. Added + PNG_ITXT_COMPRESSION_NONE (1) and PNG_ITXT_COMPRESSION_zTXt(2) macros. + The "Note" above, about backward incompatibility of libpng-1.0.5e, no + longer applies. + Fixed png_read|write_iTXt() to read|write parameters in the right order, + and to write the iTXt chunk after IDAT if it appears in the end_ptr. + Added pnggccrd.c, version of pngvcrd.c Intel assembler for gcc (Greg Roelofs) + Reversed the order of trying to write floating-point and fixed-point gAMA. +version 1.0.5k [December 27, 1999] + Added many parentheses, e.g., "if (a && b & c)" becomes "if (a && (b & c))" + Added png_handle_as_unknown() function (Glenn) + Added png_free_chunk_list() function and chunk_list and num_chunk_list members + of png_ptr. + Eliminated erroneous warnings about multiple sPLT chunks and sPLT-after-PLTE. + Fixed a libpng-1.0.5h bug in pngrutil.c that was issuing erroneous warnings + about ignoring incorrect gAMA with sRGB (gAMA was in fact not ignored) + Added png_free_tRNS(); png_set_tRNS() now malloc's its own trans array (ESR). + Define png_get_int_32 when oFFs chunk is supported as well as when pCAL is. + Changed type of proflen from png_int_32 to png_uint_32 in png_get_iCCP(). +version 1.0.5l [January 1, 2000] + Added functions png_set_read_user_chunk_fn() and png_get_user_chunk_ptr() + for setting a callback function to handle unknown chunks and for + retrieving the associated user pointer (Glenn). +version 1.0.5m [January 7, 2000] + Added high-level functions png_read_png(), png_write_png(), png_free_pixels(). +version 1.0.5n [January 9, 2000] + Added png_free_PLTE() function, and modified png_set_PLTE() to malloc its + own memory for info_ptr->palette. This makes it safe for the calling + application to free its copy of the palette any time after it calls + png_set_PLTE(). +version 1.0.5o [January 20, 2000] + Cosmetic changes only (removed some trailing blanks and TABs) +version 1.0.5p [January 31, 2000] + Renamed pngdll.mak to makefile.bd32 + Cosmetic changes in pngtest.c +version 1.0.5q [February 5, 2000] + Relocated the makefile.solaris warning about PATH problems. + Fixed pngvcrd.c bug by pushing/popping registers in mmxsupport (Bruce Oberg) + Revised makefile.gcmmx + Added PNG_SETJMP_SUPPORTED, PNG_SETJMP_NOT_SUPPORTED, and PNG_ABORT() macros +version 1.0.5r [February 7, 2000] + Removed superfluous prototype for png_get_itxt from png.h + Fixed a bug in pngrtran.c that improperly expanded the background color. + Return *num_text=0 from png_get_text() when appropriate, and fix documentation + of png_get_text() in libpng.txt/libpng.3. +version 1.0.5s [February 18, 2000] + Added "png_jmp_env()" macro to pngconf.h, to help people migrate to the + new error handler that's planned for the next libpng release, and changed + example.c, pngtest.c, and contrib programs to use this macro. + Revised some of the DLL-export macros in pngconf.h (Greg Roelofs) + Fixed a bug in png_read_png() that caused it to fail to expand some images + that it should have expanded. + Fixed some mistakes in the unused and undocumented INCH_CONVERSIONS functions + in pngget.c + Changed the allocation of palette, history, and trans arrays back to + the version 1.0.5 method (linking instead of copying) which restores + backward compatibility with version 1.0.5. Added some remarks about + that in example.c. Added "free_me" member to info_ptr and png_ptr + and added png_free_data() function. + Updated makefile.linux and makefile.gccmmx to make directories conditionally. + Made cosmetic changes to pngasmrd.h + Added png_set_rows() and png_get_rows(), for use with png_read|write_png(). + Modified png_read_png() to allocate info_ptr->row_pointers only if it + hasn't already been allocated. +version 1.0.5t [March 4, 2000] + Changed png_jmp_env() migration aiding macro to png_jmpbuf(). + Fixed "interlace" typo (should be "interlaced") in contrib/gregbook/read2-x.c + Fixed bug with use of PNG_BEFORE_IHDR bit in png_ptr->mode, introduced when + PNG_FLAG_HAVE_CHUNK_HEADER was moved into png_ptr->mode in version 1.0.5b + Files in contrib/gregbook were revised to use png_jmpbuf() and to select + a 24-bit visual if one is available, and to allow abbreviated options. + Files in contrib/pngminus were revised to use the png_jmpbuf() macro. + Removed spaces in makefile.linux and makefile.gcmmx, introduced in 1.0.5s +version 1.0.5u [March 5, 2000] + Simplified the code that detects old png.h in png.c and pngtest.c + Renamed png_spalette (_p, _pp) to png_sPLT_t (_tp, _tpp) + Increased precision of rgb_to_gray calculations from 8 to 15 bits and + added png_set_rgb_to_gray_fixed() function. + Added makefile.bc32 (32-bit Borland C++, C mode) +version 1.0.5v [March 11, 2000] + Added some parentheses to the png_jmpbuf macro definition. + Updated references to the zlib home page, which has moved to freesoftware.com. + Corrected bugs in documentation regarding png_read_row() and png_write_row(). + Updated documentation of png_rgb_to_gray calculations in libpng.3/libpng.txt. + Renamed makefile.borland,turboc3 back to makefile.bor,tc3 as in version 1.0.3, + revised borland makefiles; added makefile.ibmvac3 and makefile.gcc (Cosmin) + +version 1.0.6 [March 20, 2000] + Minor revisions of makefile.bor, libpng.txt, and gregbook/rpng2-win.c + Added makefile.sggcc (SGI IRIX with gcc) +version 1.0.6d [April 7, 2000] + Changed sprintf() to strcpy() in png_write_sCAL_s() to work without STDIO + Added data_length parameter to png_decompress_chunk() function + Revised documentation to remove reference to abandoned png_free_chnk functions + Fixed an error in png_rgb_to_gray_fixed() + Revised example.c, usage of png_destroy_write_struct(). + Renamed makefile.ibmvac3 to makefile.ibmc, added libpng.icc IBM project file + Added a check for info_ptr->free_me&PNG_FREE_TEXT when freeing text in png.c + Simplify png_sig_bytes() function to remove use of non-ISO-C strdup(). +version 1.0.6e [April 9, 2000] + Added png_data_freer() function. + In the code that checks for over-length tRNS chunks, added check of + info_ptr->num_trans as well as png_ptr->num_trans (Matthias Benckmann) + Minor revisions of libpng.txt/libpng.3. + Check for existing data and free it if the free_me flag is set, in png_set_*() + and png_handle_*(). + Only define PNG_WEIGHTED_FILTERS_SUPPORTED when PNG_FLOATING_POINT_SUPPORTED + is defined. + Changed several instances of PNG_NO_CONSOLE_ID to PNG_NO_STDIO in pngrutil.c + and mentioned the purposes of the two macros in libpng.txt/libpng.3. +version 1.0.6f [April 14, 2000] + Revised png_set_iCCP() and png_set_rows() to avoid prematurely freeing data. + Add checks in png_set_text() for NULL members of the input text structure. + Revised libpng.txt/libpng.3. + Removed superfluous prototype for png_set_itxt from png.h + Removed "else" from pngread.c, after png_error(), and changed "0" to "length". + Changed several png_errors about malformed ancillary chunks to png_warnings. +version 1.0.6g [April 24, 2000] + Added png_pass-* arrays to pnggccrd.c when PNG_USE_LOCAL_ARRAYS is defined. + Relocated paragraph about png_set_background() in libpng.3/libpng.txt + and other revisions (Matthias Benckmann) + Relocated info_ptr->free_me, png_ptr->free_me, and other info_ptr and + png_ptr members to restore binary compatibility with libpng-1.0.5 + (breaks compatibility with libpng-1.0.6). +version 1.0.6h [April 24, 2000] + Changed shared library so-number pattern from 2.x.y.z to xy.z (this builds + libpng.so.10 & libpng.so.10.6h instead of libpng.so.2 & libpng.so.2.1.0.6h) + This is a temporary change for test purposes. +version 1.0.6i [May 2, 2000] + Rearranged some members at the end of png_info and png_struct, to put + unknown_chunks_num and free_me within the original size of the png_structs + and free_me, png_read_user_fn, and png_free_fn within the original png_info, + because some old applications allocate the structs directly instead of + using png_create_*(). + Added documentation of user memory functions in libpng.txt/libpng.3 + Modified png_read_png so that it will use user_allocated row_pointers + if present, unless free_me directs that it be freed, and added description + of the use of png_set_rows() and png_get_rows() in libpng.txt/libpng.3. + Added PNG_LEGACY_SUPPORTED macro, and #ifdef out all new (since version + 1.00) members of png_struct and png_info, to regain binary compatibility + when you define this macro. Capabilities lost in this event + are user transforms (new in version 1.0.0),the user transform pointer + (new in version 1.0.2), rgb_to_gray (new in 1.0.5), iCCP, sCAL, sPLT, + the high-level interface, and unknown chunks support (all new in 1.0.6). + This was necessary because of old applications that allocate the structs + directly as authors were instructed to do in libpng-0.88 and earlier, + instead of using png_create_*(). + Added modes PNG_CREATED_READ_STRUCT and PNG_CREATED_WRITE_STRUCT which + can be used to detect codes that directly allocate the structs, and + code to check these modes in png_read_init() and png_write_init() and + generate a libpng error if the modes aren't set and PNG_LEGACY_SUPPORTED + was not defined. + Added makefile.intel and updated makefile.watcom (Pawel Mrochen) +version 1.0.6j [May 3, 2000] + Overloaded png_read_init() and png_write_init() with macros that convert + calls to png_read_init_2() or png_write_init_2() that check the version + and structure sizes. +version 1.0.7beta11 [May 7, 2000] + Removed the new PNG_CREATED_READ_STRUCT and PNG_CREATED_WRITE_STRUCT modes + which are no longer used. + Eliminated the three new members of png_text when PNG_LEGACY_SUPPORTED is + defined or when neither PNG_READ_iTXt_SUPPORTED nor PNG_WRITE_iTXT_SUPPORTED + is defined. + Made PNG_NO_READ|WRITE_iTXt the default setting, to avoid memory + overrun when old applications fill the info_ptr->text structure directly. + Added PNGAPI macro, and added it to the definitions of all exported functions. + Relocated version macro definitions ahead of the includes of zlib.h and + pngconf.h in png.h. +version 1.0.7beta12 [May 12, 2000] + Revised pngset.c to avoid a problem with expanding the png_debug macro. + Deleted some extraneous defines from pngconf.h + Made PNG_NO_CONSOLE_IO the default condition when PNG_BUILD_DLL is defined. + Use MSC _RPTn debugging instead of fprintf if _MSC_VER is defined. + Added png_access_version_number() function. + Check for mask&PNG_FREE_CHNK (for TEXT, SCAL, PCAL) in png_free_data(). + Expanded libpng.3/libpng.txt information about png_data_freer(). +version 1.0.7beta14 [May 17, 2000] (beta13 was not published) + Changed pnggccrd.c and pngvcrd.c to handle bad adaptive filter types as + warnings instead of errors, as pngrutil.c does. + Set the PNG_INFO_IDAT valid flag in png_set_rows() so png_write_png() + will actually write IDATs. + Made the default PNG_USE_LOCAL_ARRAYS depend on PNG_DLL instead of WIN32. + Make png_free_data() ignore its final parameter except when freeing data + that can have multiple instances (text, sPLT, unknowns). + Fixed a new bug in png_set_rows(). + Removed info_ptr->valid tests from png_free_data(), as in version 1.0.5. + Added png_set_invalid() function. + Fixed incorrect illustrations of png_destroy_write_struct() in example.c. +version 1.0.7beta15 [May 30, 2000] + Revised the deliberately erroneous Linux setjmp code in pngconf.h to produce + fewer error messages. + Rearranged checks for Z_OK to check the most likely path first in pngpread.c + and pngwutil.c. + Added checks in pngtest.c for png_create_*() returning NULL, and mentioned + in libpng.txt/libpng.3 the need for applications to check this. + Changed names of png_default_*() functions in pngtest to pngtest_*(). + Changed return type of png_get_x|y_offset_*() from png_uint_32 to png_int_32. + Fixed some bugs in the unused PNG_INCH_CONVERSIONS functions in pngget.c + Set each pointer to NULL after freeing it in png_free_data(). + Worked around a problem in pngconf.h; AIX's strings.h defines an "index" + macro that conflicts with libpng's png_color_16.index. (Dimitri Papadapoulos) + Added "msvc" directory with MSVC++ project files (Simon-Pierre Cadieux). +version 1.0.7beta16 [June 4, 2000] + Revised the workaround of AIX string.h "index" bug. + Added a check for overlength PLTE chunk in pngrutil.c. + Added PNG_NO_POINTER_INDEXING macro to use array-indexing instead of pointer + indexing in pngrutil.c and pngwutil.c to accommodate a buggy compiler. + Added a warning in png_decompress_chunk() when it runs out of data, e.g. + when it tries to read an erroneous PhotoShop iCCP chunk. + Added PNG_USE_DLL macro. + Revised the copyright/disclaimer/license notice. + Added contrib/msvctest directory +version 1.0.7rc1 [June 9, 2000] + Corrected the definition of PNG_TRANSFORM_INVERT_ALPHA (0x0400 not 0x0200) + Added contrib/visupng directory (Willem van Schaik) +version 1.0.7beta18 [June 23, 2000] + Revised PNGAPI definition, and pngvcrd.c to work with __GCC__ + and do not redefine PNGAPI if it is passed in via a compiler directive. + Revised visupng/PngFile.c to remove returns from within the Try block. + Removed leading underscores from "_PNG_H" and "_PNG_SAVE_BSD_SOURCE" macros. + Updated contrib/visupng/cexcept.h to version 1.0.0. + Fixed bugs in pngwrite.c and pngwutil.c that prevented writing iCCP chunks. +version 1.0.7rc2 [June 28, 2000] + Updated license to include disclaimers required by UCITA. + Fixed "DJBPP" typo in pnggccrd.c introduced in beta18. + +version 1.0.7 [July 1, 2000] + Revised the definition of "trans_values" in libpng.3/libpng.txt +version 1.0.8beta1 [July 8, 2000] + Added png_free(png_ptr, key) two places in pngpread.c to stop memory leaks. + Changed PNG_NO_STDIO to PNG_NO_CONSOLE_IO, several places in pngrutil.c and + pngwutil.c. + Changed PNG_EXPORT_VAR to use PNG_IMPEXP, in pngconf.h. + Removed unused "#include <assert.h>" from png.c + Added WindowsCE support. + Revised pnggccrd.c to work with gcc-2.95.2 and in the Cygwin environment. +version 1.0.8beta2 [July 10, 2000] + Added project files to the wince directory and made further revisions + of pngtest.c, pngrio.c, and pngwio.c in support of WindowsCE. +version 1.0.8beta3 [July 11, 2000] + Only set the PNG_FLAG_FREE_TRNS or PNG_FREE_TRNS flag in png_handle_tRNS() + for indexed-color input files to avoid potential double-freeing trans array + under some unusual conditions; problem was introduced in version 1.0.6f. + Further revisions to pngtest.c and files in the wince subdirectory. +version 1.0.8beta4 [July 14, 2000] + Added the files pngbar.png and pngbar.jpg to the distribution. + Added makefile.cygwin, and cygwin support in pngconf.h + Added PNG_NO_ZALLOC_ZERO macro (makes png_zalloc skip zeroing memory) +version 1.0.8rc1 [July 16, 2000] + Revised png_debug() macros and statements to eliminate compiler warnings. + +version 1.0.8 [July 24, 2000] + Added png_flush() in pngwrite.c, after png_write_IEND(). + Updated makefile.hpux to build a shared library. +version 1.0.9beta1 [November 10, 2000] + Fixed typo in scripts/makefile.hpux + Updated makevms.com in scripts and contrib/* and contrib/* (Martin Zinser) + Fixed seqence-point bug in contrib/pngminus/png2pnm (Martin Zinser) + Changed "cdrom.com" in documentation to "libpng.org" + Revised pnggccrd.c to get it all working, and updated makefile.gcmmx (Greg). + Changed type of "params" from voidp to png_voidp in png_read|write_png(). + Make sure PNGAPI and PNG_IMPEXP are defined in pngconf.h. + Revised the 3 instances of WRITEFILE in pngtest.c. + Relocated "msvc" and "wince" project subdirectories into "dll" subdirectory. + Updated png.rc in dll/msvc project + Revised makefile.dec to define and use LIBPATH and INCPATH + Increased size of global png_libpng_ver[] array from 12 to 18 chars. + Made global png_libpng_ver[], png_sig[] and png_pass_*[] arrays const. + Removed duplicate png_crc_finish() from png_handle_bKGD() function. + Added a warning when application calls png_read_update_info() multiple times. + Revised makefile.cygwin + Fixed bugs in iCCP support in pngrutil.c and pngwutil.c. + Replaced png_set_empty_plte_permitted() with png_permit_mng_features(). +version 1.0.9beta2 [November 19, 2000] + Renamed the "dll" subdirectory "projects". + Added borland project files to "projects" subdirectory. + Set VS_FF_PRERELEASE and VS_FF_PATCHED flags in msvc/png.rc when appropriate. + Add error message in png_set_compression_buffer_size() when malloc fails. +version 1.0.9beta3 [November 23, 2000] + Revised PNG_LIBPNG_BUILD_TYPE macro in png.h, used in the msvc project. + Removed the png_flush() in pngwrite.c that crashes some applications + that don't set png_output_flush_fn. + Added makefile.macosx and makefile.aix to scripts directory. +version 1.0.9beta4 [December 1, 2000] + Change png_chunk_warning to png_warning in png_check_keyword(). + Increased the first part of msg buffer from 16 to 18 in png_chunk_error(). +version 1.0.9beta5 [December 15, 2000] + Added support for filter method 64 (for PNG datastreams embedded in MNG). +version 1.0.9beta6 [December 18, 2000] + Revised png_set_filter() to accept filter method 64 when appropriate. + Added new PNG_HAVE_PNG_SIGNATURE bit to png_ptr->mode and use it to + help prevent applications from using MNG features in PNG datastreams. + Added png_permit_mng_features() function. + Revised libpng.3/libpng.txt. Changed "filter type" to "filter method". +version 1.0.9rc1 [December 23, 2000] + Revised test for PNG_HAVE_PNG_SIGNATURE in pngrutil.c + Fixed error handling of unknown compression type in png_decompress_chunk(). + In pngconf.h, define __cdecl when _MSC_VER is defined. +version 1.0.9beta7 [December 28, 2000] + Changed PNG_TEXT_COMPRESSION_zTXt to PNG_COMPRESSION_TYPE_BASE several places. + Revised memory management in png_set_hIST and png_handle_hIST in a backward + compatible manner. PLTE and tRNS were revised similarly. + Revised the iCCP chunk reader to ignore trailing garbage. +version 1.0.9beta8 [January 12, 2001] + Moved pngasmrd.h into pngconf.h. + Improved handling of out-of-spec garbage iCCP chunks generated by PhotoShop. +version 1.0.9beta9 [January 15, 2001] + Added png_set_invalid, png_permit_mng_features, and png_mmx_supported to + wince and msvc project module definition files. + Minor revision of makefile.cygwin. + Fixed bug with progressive reading of narrow interlaced images in pngpread.c +version 1.0.9beta10 [January 16, 2001] + Do not typedef png_FILE_p in pngconf.h when PNG_NO_STDIO is defined. + Fixed "png_mmx_supported" typo in project definition files. +version 1.0.9beta11 [January 19, 2001] + Updated makefile.sgi to make shared library. + Removed png_mmx_support() function and disabled PNG_MNG_FEATURES_SUPPORTED + by default, for the benefit of DLL forward compatibility. These will + be re-enabled in version 1.2.0. +version 1.0.9rc2 [January 22, 2001] + Revised cygwin support. + +version 1.0.9 [January 31, 2001] + Added check of cygwin's ALL_STATIC in pngconf.h + Added "-nommx" parameter to contrib/gregbook/rpng2-win and rpng2-x demos. +version 1.0.10beta1 [March 14, 2001] + Revised makefile.dec, makefile.sgi, and makefile.sggcc; added makefile.hpgcc. + Reformatted libpng.3 to eliminate bad line breaks. + Added checks for _mmx_supported in the read_filter_row function of pnggccrd.c + Added prototype for png_mmx_support() near the top of pnggccrd.c + Moved some error checking from png_handle_IHDR to png_set_IHDR. + Added PNG_NO_READ_SUPPORTED and PNG_NO_WRITE_SUPPORTED macros. + Revised png_mmx_support() function in pnggccrd.c + Restored version 1.0.8 PNG_WRITE_EMPTY_PLTE_SUPPORTED behavior in pngwutil.c + Fixed memory leak in contrib/visupng/PngFile.c + Fixed bugs in png_combine_row() in pnggccrd.c and pngvcrd.c (C version) + Added warnings when retrieving or setting gamma=0. + Increased the first part of msg buffer from 16 to 18 in png_chunk_warning(). +version 1.0.10rc1 [March 23, 2001] + Changed all instances of memcpy, strcpy, and strlen to png_memcpy, png_strcpy, + and png_strlen. + Revised png_mmx_supported() function in pnggccrd.c to return proper value. + Fixed bug in progressive reading (pngpread.c) with small images (height < 8). + +version 1.0.10 [March 30, 2001] + Deleted extraneous space (introduced in 1.0.9) from line 42 of makefile.cygwin + Added beos project files (Chris Herborth) +version 1.0.11beta1 [April 3, 2001] + Added type casts on several png_malloc() calls (Dimitri Papadapoulos). + Removed a no-longer needed AIX work-around from pngconf.h + Changed several "//" single-line comments to C-style in pnggccrd.c +version 1.0.11beta2 [April 11, 2001] + Removed PNGAPI from several functions whose prototypes did not have PNGAPI. + Updated scripts/pngos2.def +version 1.0.11beta3 [April 14, 2001] + Added checking the results of many instances of png_malloc() for NULL +version 1.0.11beta4 [April 20, 2001] + Undid the changes from version 1.0.11beta3. Added a check for NULL return + from user's malloc_fn(). + Removed some useless type casts of the NULL pointer. + Added makefile.netbsd + +version 1.0.11 [April 27, 2001] + Revised makefile.netbsd +version 1.0.12beta1 [May 14, 2001] + Test for Windows platform in pngconf.h when including malloc.h (Emmanuel Blot) + Updated makefile.cygwin and handling of Cygwin's ALL_STATIC in pngconf.h + Added some never-to-be-executed code in pnggccrd.c to quiet compiler warnings. + Eliminated the png_error about apps using png_read|write_init(). Instead, + libpng will reallocate the png_struct and info_struct if they are too small. + This retains future binary compatibility for old applications written for + libpng-0.88 and earlier. +version 1.2.0beta1 [May 6, 2001] + Bumped DLLNUM to 2. + Re-enabled PNG_MNG_FEATURES_SUPPORTED and enabled PNG_ASSEMBLER_CODE_SUPPORTED + by default. + Added runtime selection of MMX features. + Added png_set_strip_error_numbers function and related macros. +version 1.2.0beta2 [May 7, 2001] + Finished merging 1.2.0beta1 with version 1.0.11 + Added a check for attempts to read or write PLTE in grayscale PNG datastreams. +version 1.2.0beta3 [May 17, 2001] + Enabled user memory function by default. + Modified png_create_struct so it passes user mem_ptr to user memory allocator. + Increased png_mng_features flag from png_byte to png_uint_32. + Bumped shared-library (so-number) and dll-number to 3. +version 1.2.0beta4 [June 23, 2001] + Check for missing profile length field in iCCP chunk and free chunk_data + in case of truncated iCCP chunk. + Bumped shared-library number to 3 in makefile.sgi and makefile.sggcc + Bumped dll-number from 2 to 3 in makefile.cygwin + Revised contrib/gregbook/rpng*-x.c to avoid a memory leak and to exit cleanly + if user attempts to run it on an 8-bit display. + Updated contrib/gregbook + Use png_malloc instead of png_zalloc to allocate palette in pngset.c + Updated makefile.ibmc + Added some typecasts to eliminate gcc 3.0 warnings. Changed prototypes + of png_write_oFFS width and height from png_uint_32 to png_int_32. + Updated example.c + Revised prototypes for png_debug_malloc and png_debug_free in pngtest.c +version 1.2.0beta5 [August 8, 2001] + Revised contrib/gregbook + Revised makefile.gcmmx + Revised pnggccrd.c to conditionally compile some thread-unsafe code only + when PNG_THREAD_UNSAFE_OK is defined. + Added tests to prevent pngwutil.c from writing a bKGD or tRNS chunk with + value exceeding 2^bit_depth-1 + Revised makefile.sgi and makefile.sggcc + Replaced calls to fprintf(stderr,...) with png_warning() in pnggccrd.c + Removed restriction that do_invert_mono only operate on 1-bit opaque files + +version 1.2.0 [September 1, 2001] + Changed a png_warning() to png_debug() in pnggccrd.c + Fixed contrib/gregbook/rpng-x.c, rpng2-x.c to avoid crash with XFreeGC(). +version 1.2.1beta1 [October 19, 2001] + Revised makefile.std in contrib/pngminus + Include background_1 in png_struct regardless of gamma support. + Revised makefile.netbsd and makefile.macosx, added makefile.darwin. + Revised example.c to provide more details about using row_callback(). +version 1.2.1beta2 [October 25, 2001] + Added type cast to each NULL appearing in a function call, except for + WINCE functions. + Added makefile.so9. +version 1.2.1beta3 [October 27, 2001] + Removed type casts from all NULLs. + Simplified png_create_struct_2(). +version 1.2.1beta4 [November 7, 2001] + Revised png_create_info_struct() and png_creat_struct_2(). + Added error message if png_write_info() was omitted. + Type cast NULLs appearing in function calls when _NO_PROTO or + PNG_TYPECAST_NULL is defined. +version 1.2.1rc1 [November 24, 2001] + Type cast NULLs appearing in function calls except when PNG_NO_TYPECAST_NULL + is defined. + Changed typecast of "size" argument to png_size_t in pngmem.c calls to + the user malloc_fn, to agree with the prototype in png.h + Added a pop/push operation to pnggccrd.c, to preserve Eflag (Maxim Sobolev) + Updated makefile.sgi to recognize LIBPATH and INCPATH. + Updated various makefiles so "make clean" does not remove previous major + version of the shared library. +version 1.2.1rc2 [December 4, 2001] + Always allocate 256-entry internal palette, hist, and trans arrays, to + avoid out-of-bounds memory reference caused by invalid PNG datastreams. + Added a check for prefix_length > data_length in iCCP chunk handler. + +version 1.2.1 [December 7, 2001] + None. +version 1.2.2beta1 [February 22, 2002] + Fixed a bug with reading the length of iCCP profiles (Larry Reeves). + Revised makefile.linux, makefile.gcmmx, and makefile.sgi to generate + libpng.a, libpng12.so (not libpng.so.3), and libpng12/png.h + Revised makefile.darwin to remove "-undefined suppress" option. + Added checks for gamma and chromaticity values over 21474.83, which exceed + the limit for PNG unsigned 32-bit integers when encoded. + Revised calls to png_create_read_struct() and png_create_write_struct() + for simpler debugging. + Revised png_zalloc() so zlib handles errors (uses PNG_FLAG_MALLOC_NULL_MEM_OK) +version 1.2.2beta2 [February 23, 2002] + Check chunk_length and idat_size for invalid (over PNG_MAX_UINT) lengths. + Check for invalid image dimensions in png_get_IHDR. + Added missing "fi;" in the install target of the SGI makefiles. + Added install-static to all makefiles that make shared libraries. + Always do gamma compensation when image is partially transparent. +version 1.2.2beta3 [March 7, 2002] + Compute background.gray and background_1.gray even when color_type is RGB + in case image gets reduced to gray later. + Modified shared-library makefiles to install pkgconfig/libpngNN.pc. + Export (with PNGAPI) png_zalloc, png_zfree, and png_handle_as_unknown + Removed unused png_write_destroy_info prototype from png.h + Eliminated incorrect use of width_mmx from pnggccrd.c in pixel_bytes == 8 case + Added install-shared target to all makefiles that make shared libraries. + Stopped a double free of palette, hist, and trans when not using free_me. + Added makefile.32sunu for Sun Ultra 32 and makefile.64sunu for Sun Ultra 64. +version 1.2.2beta4 [March 8, 2002] + Compute background.gray and background_1.gray even when color_type is RGB + in case image gets reduced to gray later (Jason Summers). + Relocated a misplaced /bin/rm in the "install-shared" makefile targets + Added PNG_1_0_X macro which can be used to build a 1.0.x-compatible library. +version 1.2.2beta5 [March 26, 2002] + Added missing PNGAPI to several function definitions. + Check for invalid bit_depth or color_type in png_get_IHDR(), and + check for missing PLTE or IHDR in png_push_read_chunk() (Matthias Clasen). + Revised iTXt support to accept NULL for lang and lang_key. + Compute gamma for color components of background even when color_type is gray. + Changed "()" to "{}" in scripts/libpng.pc.in. + Revised makefiles to put png.h and pngconf.h only in $prefix/include/libpngNN + Revised makefiles to make symlink to libpng.so.NN in addition to libpngNN.so +version 1.2.2beta6 [March 31, 2002] +version 1.0.13beta1 [March 31, 2002] + Prevent png_zalloc() from trying to memset memory that it failed to acquire. + Add typecasts of PNG_MAX_UINT in pngset_cHRM_fixed() (Matt Holgate). + Ensure that the right function (user or default) is used to free the + png_struct after an error in png_create_read_struct_2(). +version 1.2.2rc1 [April 7, 2002] +version 1.0.13rc1 [April 7, 2002] + Save the ebx register in pnggccrd.c (Sami Farin) + Add "mem_ptr = png_ptr->mem_ptr" in png_destroy_write_struct() (Paul Gardner). + Updated makefiles to put headers in include/libpng and remove old include/*.h. + +version 1.2.2 [April 15, 2002] +version 1.0.13 [April 15, 2002] + Revised description of png_set_filter() in libpng.3/libpng.txt. + Revised makefile.netbsd and added makefile.neNNbsd and makefile.freebsd +version 1.0.13patch01 [April 17, 2002] +version 1.2.2patch01 [April 17, 2002] + Changed ${PNGMAJ}.${PNGVER} bug to ${PNGVER} in makefile.sgi and makefile.sggcc + Fixed VER -> PNGVER typo in makefile.macosx and added install-static to install + Added install: target to makefile.32sunu and makefile.64sunu +version 1.0.13patch03 [April 18, 2002] +version 1.2.2patch03 [April 18, 2002] + Revised 15 makefiles to link libpng.a to libpngNN.a and the include libpng + subdirectory to libpngNN subdirectory without the full pathname. + Moved generation of libpng.pc from "install" to "all" in 15 makefiles. +version 1.2.3rc1 [April 28, 2002] + Added install-man target to 15 makefiles (Dimitri Papadopolous-Orfanos). + Added $(DESTDIR) feature to 24 makefiles (Tim Mooney) + Fixed bug with $prefix, should be $(prefix) in makefile.hpux. + Updated cygwin-specific portion of pngconf.h and revised makefile.cygwin + Added a link from libpngNN.pc to libpng.pc in 15 makefiles. + Added links from include/libpngNN/*.h to include/*.h in 24 makefiles. + Revised makefile.darwin to make relative links without full pathname. + Added setjmp() at the end of png_create_*_struct_2() in case user forgets + to put one in their application. + Restored png_zalloc() and png_zfree() prototypes to version 1.2.1 and + removed them from module definition files. +version 1.2.3rc2 [May 1, 2002] + Fixed bug in reporting number of channels in pngget.c and pngset.c, + that was introduced in version 1.2.2beta5. + Exported png_zalloc(), png_zfree(), png_default_read(), png_default_write(), + png_default_flush(), and png_push_fill_buffer() and included them in + module definition files. + Added "libpng.pc" dependency to the "install-shared" target in 15 makefiles. +version 1.2.3rc3 [May 1, 2002] + Revised prototype for png_default_flush() + Remove old libpng.pc and libpngNN.pc before installing new ones. +version 1.2.3rc4 [May 2, 2002] + Typos in *.def files (png_default_read|write -> png_default_read|write_data) + In makefiles, changed rm libpng.NN.pc to rm libpngNN.pc + Added libpng-config and libpngNN-config and modified makefiles to install them. + Changed $(MANPATH) to $(DESTDIR)$(MANPATH) in makefiles + Added "Win32 DLL VB" configuration to projects/msvc/libpng.dsp +version 1.2.3rc5 [May 11, 2002] + Changed "error" and "message" in prototypes to "error_message" and + "warning_message" to avoid namespace conflict. + Revised 15 makefiles to build libpng-config from libpng-config-*.in + Once more restored png_zalloc and png_zfree to regular nonexported form. + Restored png_default_read|write_data, png_default_flush, png_read_fill_buffer + to nonexported form, but with PNGAPI, and removed them from module def files. +version 1.2.3rc6 [May 14, 2002] + Removed "PNGAPI" from png_zalloc() and png_zfree() in png.c + Changed "Gz" to "Gd" in projects/msvc/libpng.dsp and zlib.dsp. + Removed leftover libpng-config "sed" script from four makefiles. + Revised libpng-config creating script in 16 makefiles. + +version 1.2.3 [May 22, 2002] + Revised libpng-config target in makefile.cygwin. + Removed description of png_set_mem_fn() from documentation. + Revised makefile.freebsd. + Minor cosmetic changes to 15 makefiles, e.g., $(DI) = $(DESTDIR)/$(INCDIR). + Revised projects/msvc/README.txt + Changed -lpng to -lpngNN in LDFLAGS in several makefiles. +version 1.2.4beta1 [May 24, 2002] + Added libpng.pc and libpng-config to "all:" target in 16 makefiles. + Fixed bug in 16 makefiles: $(DESTDIR)/$(LIBPATH) to $(DESTDIR)$(LIBPATH) + Added missing "\" before closing double quote in makefile.gcmmx. + Plugged various memory leaks; added png_malloc_warn() and png_set_text_2() + functions. +version 1.2.4beta2 [June 25, 2002] + Plugged memory leak of png_ptr->current_text (Matt Holgate). + Check for buffer overflow before reading CRC in pngpread.c (Warwick Allison) + Added -soname to the loader flags in makefile.dec, makefile.sgi, and + makefile.sggcc. + Added "test-installed" target to makefile.linux, makefile.gcmmx, + makefile.sgi, and makefile.sggcc. +version 1.2.4beta3 [June 28, 2002] + Plugged memory leak of row_buf in pngtest.c when there is a png_error(). + Detect buffer overflow in pngpread.c when IDAT is corrupted with extra data. + Added "test-installed" target to makefile.32sunu, makefile.64sunu, + makefile.beos, makefile.darwin, makefile.dec, makefile.macosx, + makefile.solaris, makefile.hpux, makefile.hpgcc, and makefile.so9. +version 1.2.4rc1 and 1.0.14rc1 [July 2, 2002] + Added "test-installed" target to makefile.cygwin and makefile.sco. + Revised pnggccrd.c to be able to back out version 1.0.x via PNG_1_0_X macro. + +version 1.2.4 and 1.0.14 [July 8, 2002] + Changed png_warning() to png_error() when width is too large to process. +version 1.2.4patch01 [July 20, 2002] + Revised makefile.cygwin to use DLL number 12 instead of 13. +version 1.2.5beta1 [August 6, 2002] + Added code to contrib/gregbook/readpng2.c to ignore unused chunks. + Replaced toucan.png in contrib/gregbook (it has been corrupt since 1.0.11) + Removed some stray *.o files from contrib/gregbook. + Changed png_error() to png_warning() about "Too much data" in pngpread.c + and about "Extra compressed data" in pngrutil.c. + Prevent png_ptr->pass from exceeding 7 in png_push_finish_row(). + Updated makefile.hpgcc + Updated png.c and pnggccrd.c handling of return from png_mmx_support() +version 1.2.5beta2 [August 15, 2002] + Only issue png_warning() about "Too much data" in pngpread.c when avail_in + is nonzero. + Updated makefiles to install a separate libpng.so.3 with its own rpath. +version 1.2.5rc1 and 1.0.15rc1 [August 24, 2002] + Revised makefiles to not remove previous minor versions of shared libraries. +version 1.2.5rc2 and 1.0.15rc2 [September 16, 2002] + Revised 13 makefiles to remove "-lz" and "-L$(ZLIBLIB)", etc., from shared + library loader directive. + Added missing "$OBJSDLL" line to makefile.gcmmx. + Added missing "; fi" to makefile.32sunu. +version 1.2.5rc3 and 1.0.15rc3 [September 18, 2002] + Revised libpng-config script. + +version 1.2.5 and 1.0.15 [October 3, 2002] + Revised makefile.macosx, makefile.darwin, makefile.hpgcc, and makefile.hpux, + and makefile.aix. + Relocated two misplaced PNGAPI lines in pngtest.c +version 1.2.6beta1 [October 22, 2002] + Commented out warning about uninitialized mmx_support in pnggccrd.c. + Changed "IBMCPP__" flag to "__IBMCPP__" in pngconf.h. + Relocated two more misplaced PNGAPI lines in pngtest.c + Fixed memory overrun bug in png_do_read_filler() with 16-bit datastreams, + introduced in version 1.0.2. + Revised makefile.macosx, makefile.dec, makefile.aix, and makefile.32sunu. +version 1.2.6beta2 [November 1, 2002] + Added libpng-config "--ldopts" output. + Added "AR=ar" and "ARFLAGS=rc" and changed "ar rc" to "$(AR) $(ARFLAGS)" + in makefiles. +version 1.2.6beta3 [July 18, 2004] + Reverted makefile changes from version 1.2.6beta2 and some of the changes + from version 1.2.6beta1; these will be postponed until version 1.2.7. + Version 1.2.6 is going to be a simple bugfix release. + Changed the one instance of "ln -sf" to "ln -f -s" in each Sun makefile. + Fixed potential overrun in pngerror.c by using strncpy instead of memcpy. + Added "#!/bin/sh" at the top of configure, for recognition of the + 'x' flag under Cygwin (Cosmin). + Optimized vacuous tests that silence compiler warnings, in png.c (Cosmin). + Added support for PNG_USER_CONFIG, in pngconf.h (Cosmin). + Fixed the special memory handler for Borland C under DOS, in pngmem.c + (Cosmin). + Removed some spurious assignments in pngrutil.c (Cosmin). + Replaced 65536 with 65536L, and 0xffff with 0xffffL, to silence warnings + on 16-bit platforms (Cosmin). + Enclosed shift op expressions in parentheses, to silence warnings (Cosmin). + Used proper type png_fixed_point, to avoid problems on 16-bit platforms, + in png_handle_sRGB() (Cosmin). + Added compression_type to png_struct, and optimized the window size + inside the deflate stream (Cosmin). + Fixed definition of isnonalpha(), in pngerror.c and pngrutil.c (Cosmin). + Fixed handling of unknown chunks that come after IDAT (Cosmin). + Allowed png_error() and png_warning() to work even if png_ptr == NULL + (Cosmin). + Replaced row_info->rowbytes with row_bytes in png_write_find_filter() + (Cosmin). + Fixed definition of PNG_LIBPNG_VER_DLLNUM (Simon-Pierre). + Used PNG_LIBPNG_VER and PNG_LIBPNG_VER_STRING instead of the hardcoded + values in png.c (Simon-Pierre, Cosmin). + Initialized png_libpng_ver[] with PNG_LIBPNG_VER_STRING (Simon-Pierre). + Replaced PNG_LIBPNG_VER_MAJOR with PNG_LIBPNG_VER_DLLNUM in png.rc + (Simon-Pierre). + Moved the definition of PNG_HEADER_VERSION_STRING near the definitions + of the other PNG_LIBPNG_VER_... symbols in png.h (Cosmin). + Relocated #ifndef PNGAPI guards in pngconf.h (Simon-Pierre, Cosmin). + Updated scripts/makefile.vc(a)win32 (Cosmin). + Updated the MSVC project (Simon-Pierre, Cosmin). + Updated the Borland C++ Builder project (Cosmin). + Avoided access to asm_flags in pngvcrd.c, if PNG_1_0_X is defined (Cosmin). + Commented out warning about uninitialized mmx_support in pngvcrd.c (Cosmin). + Removed scripts/makefile.bd32 and scripts/pngdef.pas (Cosmin). + Added extra guard around inclusion of Turbo C memory headers, in pngconf.h + (Cosmin). + Renamed projects/msvc/ to projects/visualc6/, and projects/borland/ to + projects/cbuilder5/ (Cosmin). + Moved projects/visualc6/png32ms.def to scripts/pngw32.def, + and projects/visualc6/png.rc to scripts/pngw32.rc (Cosmin). + Added projects/visualc6/pngtest.dsp; removed contrib/msvctest/ (Cosmin). + Changed line endings to DOS style in cbuilder5 and visualc6 files, even + in the tar.* distributions (Cosmin). + Updated contrib/visupng/VisualPng.dsp (Cosmin). + Updated contrib/visupng/cexcept.h to version 2.0.0 (Cosmin). + Added a separate distribution with "configure" and supporting files (Junichi). +version 1.2.6beta4 [July 28, 2004] + Added user ability to change png_size_t via a PNG_SIZE_T macro. + Added png_sizeof() and png_convert_size() functions. + Added PNG_SIZE_MAX (maximum value of a png_size_t variable. + Added check in png_malloc_default() for (size_t)size != (png_uint_32)size + which would indicate an overflow. + Changed sPLT failure action from png_error to png_warning and abandon chunk. + Changed sCAL and iCCP failures from png_error to png_warning and abandon. + Added png_get_uint_31(png_ptr, buf) function. + Added PNG_UINT_32_MAX macro. + Renamed PNG_MAX_UINT to PNG_UINT_31_MAX. + Made png_zalloc() issue a png_warning and return NULL on potential + overflow. + Turn on PNG_NO_ZALLOC_ZERO by default in version 1.2.x + Revised "clobber list" in pnggccrd.c so it will compile under gcc-3.4. + Revised Borland portion of png_malloc() to return NULL or issue + png_error() according to setting of PNG_FLAG_MALLOC_NULL_MEM_OK. + Added PNG_NO_SEQUENTIAL_READ_SUPPORTED macro to conditionally remove + sequential read support. + Added some "#if PNG_WRITE_SUPPORTED" blocks. + #ifdef'ed out some redundancy in png_malloc_default(). + Use png_malloc instead of png_zalloc to allocate the pallete. +version 1.0.16rc1 and 1.2.6rc1 [August 4, 2004] + Fixed buffer overflow vulnerability in png_handle_tRNS() + Fixed integer arithmetic overflow vulnerability in png_read_png(). + Fixed some harmless bugs in png_handle_sBIT, etc, that would cause + duplicate chunk types to go undetected. + Fixed some timestamps in the -config version + Rearranged order of processing of color types in png_handle_tRNS(). + Added ROWBYTES macro to calculate rowbytes without integer overflow. + Updated makefile.darwin and removed makefile.macosx from scripts directory. + Imposed default one million column, one-million row limits on the image + dimensions, and added png_set_user_limits() function to override them. + Revised use of PNG_SET_USER_LIMITS_SUPPORTED macro. + Fixed wrong cast of returns from png_get_user_width|height_max(). + Changed some "keep the compiler happy" from empty statements to returns, + Revised libpng.txt to remove 1.2.x stuff from the 1.0.x distribution +version 1.0.16rc2 and 1.2.6rc2 [August 7, 2004] + Revised makefile.darwin and makefile.solaris. Removed makefile.macosx. + Revised pngtest's png_debug_malloc() to use png_malloc() instead of + png_malloc_default() which is not supposed to be exported. + Fixed off-by-one error in one of the conversions to PNG_ROWBYTES() in + pngpread.c. Bug was introduced in 1.2.6rc1. + Fixed bug in RGB to RGBX transformation introduced in 1.2.6rc1. + Fixed old bug in RGB to Gray transformation. + Fixed problem with 64-bit compilers by casting arguments to abs() + to png_int_32. + Changed "ln -sf" to "ln -f -s" in three makefiles (solaris, sco, so9). + Changed "HANDLE_CHUNK_*" to "PNG_HANDLE_CHUNK_*" (Cosmin) + Added "-@/bin/rm -f $(DL)/$(LIBNAME).so.$(PNGMAJ)" to 15 *NIX makefiles. + Added code to update the row_info->colortype in png_do_read_filler() (MSB). +version 1.0.16rc3 and 1.2.6rc3 [August 9, 2004] + Eliminated use of "abs()" in testing cHRM and gAMA values, to avoid + trouble with some 64-bit compilers. Created PNG_OUT_OF_RANGE() macro. + Revised documentation of png_set_keep_unknown_chunks(). + Check handle_as_unknown status in pngpread.c, as in pngread.c previously. + Moved "PNG_HANDLE_CHUNK_*" macros out of PNG_INTERNAL section of png.h + Added "rim" definitions for CONST4 and CONST6 in pnggccrd.c +version 1.0.16rc4 and 1.2.6rc4 [August 10, 2004] + Fixed mistake in pngtest.c introduced in 1.2.6rc2 (declaration of + "pinfo" was out of place). +version 1.0.16rc5 and 1.2.6rc5 [August 10, 2004] + Moved "PNG_HANDLE_CHUNK_*" macros out of PNG_ASSEMBLER_CODE_SUPPORTED + section of png.h where they were inadvertently placed in version rc3. + +version 1.0.16 and 1.2.6 [August 15, 2004] + Revised pngtest so memory allocation testing is only done when PNG_DEBUG==1. +version 1.2.7beta1 [August 26, 2004] + Removed unused pngasmrd.h file. + Removed references to uu.net for archived files. Added references to + PNG Spec (second edition) and the PNG ISO/IEC Standard. + Added "test-dd" target in 15 makefiles, to run pngtest in DESTDIR. + Fixed bug with "optimized window size" in the IDAT datastream, that + causes libpng to write PNG files with incorrect zlib header bytes. +version 1.2.7beta2 [August 28, 2004] + Fixed bug with sCAL chunk and big-endian machines (David Munro). + Undid new code added in 1.2.6rc2 to update the color_type in + png_set_filler(). + Added png_set_add_alpha() that updates color type. +version 1.0.17rc1 and 1.2.7rc1 [September 4, 2004] + Revised png_set_strip_filler() to not remove alpha if color_type has alpha. +version 1.0.17 and 1.2.7 [September 12, 2004] + Added makefile.hp64 + Changed projects/msvc/png32ms.def to scripts/png32ms.def in makefile.cygwin +version 1.2.8beta1 [November 1, 2004] + Fixed bug in png_text_compress() that would fail to complete a large block. + Fixed bug, introduced in libpng-1.2.7, that overruns a buffer during + strip alpha operation in png_do_strip_filler(). + Added PNG_1_2_X definition in pngconf.h + #ifdef out png_info_init in png.c and png_read_init in pngread.c (as of 1.3.0) +version 1.2.8beta2 [November 2, 2004] + Reduce color_type to a nonalpha type after strip alpha operation in + png_do_strip_filler(). +version 1.2.8beta3 [November 3, 2004] + Revised definitions of PNG_MAX_UINT_32, PNG_MAX_SIZE, and PNG_MAXSUM +version 1.2.8beta4 [November 12, 2004] + Fixed (again) definition of PNG_LIBPNG_VER_DLLNUM in png.h (Cosmin). + Added PNG_LIBPNG_BUILD_PRIVATE in png.h (Cosmin). + Set png_ptr->zstream.data_type to Z_BINARY, to avoid unnecessary detection + of data type in deflate (Cosmin). + Deprecated but continue to support SPECIALBUILD and PRIVATEBUILD in favor of + PNG_LIBPNG_BUILD_SPECIAL_STRING and PNG_LIBPNG_BUILD_PRIVATE_STRING. +version 1.2.8beta5 [November 20, 2004] + Use png_ptr->flags instead of png_ptr->transformations to pass + PNG_STRIP_ALPHA info to png_do_strip_filler(), to preserve ABI + compatibility. + Revised handling of SPECIALBUILD, PRIVATEBUILD, + PNG_LIBPNG_BUILD_SPECIAL_STRING and PNG_LIBPNG_BUILD_PRIVATE_STRING. +version 1.2.8rc1 [November 24, 2004] + Moved handling of BUILD macros from pngconf.h to png.h + Added definition of PNG_LIBPNG_BASE_TYPE in png.h, inadvertently + omitted from beta5. + Revised scripts/pngw32.rc + Despammed mailing addresses by masking "@" with "at". + Inadvertently installed a supposedly faster test version of pngrutil.c +version 1.2.8rc2 [November 26, 2004] + Added two missing "\" in png.h + Change tests in pngread.c and pngpread.c to + if (png_ptr->transformations || (png_ptr->flags&PNG_FLAG_STRIP_ALPHA)) + png_do_read_transformations(png_ptr); +version 1.2.8rc3 [November 28, 2004] + Reverted pngrutil.c to version libpng-1.2.8beta5. + Added scripts/makefile.elf with supporting code in pngconf.h for symbol + versioning (John Bowler). +version 1.2.8rc4 [November 29, 2004] + Added projects/visualc7 (Simon-pierre). +version 1.2.8rc5 [November 29, 2004] + Fixed new typo in scripts/pngw32.rc +version 1.2.8 [December 3, 2004] + Removed projects/visualc7, added projects/visualc71. + +Send comments/corrections/commendations to +png-implement at ccrc.wustl.edu (subscription required; write to +majordomo at ccrc.wustl.edu with "subscribe png-implement" in the message) +or to glennrp at users.sourceforge.net + +Glenn R-P diff --git a/syslinux/com32/lib/libpng/KNOWNBUG b/syslinux/com32/lib/libpng/KNOWNBUG new file mode 100644 index 0000000..620296f --- /dev/null +++ b/syslinux/com32/lib/libpng/KNOWNBUG @@ -0,0 +1,11 @@ + +Known bugs in libpng version 1.2.8 + +1. April 22, 2001: pnggccrd.c has been reported to crash on NetBSD when + reading interlaced PNG files, when assembler code is enabled but running + on a non-MMX i386 platform. + + STATUS: Under investigation. The change to pnggccrd.c in libpng-1.2.1 + fixed a problem under FreeBSD but not the problem with NetBSD, which + still fails as of libpng-1.2.2rc1. + diff --git a/syslinux/com32/lib/libpng/LICENSE b/syslinux/com32/lib/libpng/LICENSE new file mode 100644 index 0000000..7ef3667 --- /dev/null +++ b/syslinux/com32/lib/libpng/LICENSE @@ -0,0 +1,113 @@ + +This copy of the libpng notices is provided for your convenience. In case of +any discrepancy between this copy and the notices in the file png.h that is +included in the libpng distribution, the latter shall prevail. + +COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: + +If you modify libpng you may insert additional notices immediately following +this sentence. + +*** This version of libpng has been slightly modified to fit into the + libcom32 framework. In particular, it uses the libcom32 Makefile + system instead of its own. + +libpng version 1.2.6, December 3, 2004, is +Copyright (c) 2004 Glenn Randers-Pehrson, and is +distributed according to the same disclaimer and license as libpng-1.2.5 +with the following individual added to the list of Contributing Authors + + Cosmin Truta + +libpng versions 1.0.7, July 1, 2000, through 1.2.5 - October 3, 2002, are +Copyright (c) 2000-2002 Glenn Randers-Pehrson, and are +distributed according to the same disclaimer and license as libpng-1.0.6 +with the following individuals added to the list of Contributing Authors + + Simon-Pierre Cadieux + Eric S. Raymond + Gilles Vollant + +and with the following additions to the disclaimer: + + There is no warranty against interference with your enjoyment of the + library or against infringement. There is no warranty that our + efforts or the library will fulfill any of your particular purposes + or needs. This library is provided with all faults, and the entire + risk of satisfactory quality, performance, accuracy, and effort is with + the user. + +libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are +Copyright (c) 1998, 1999 Glenn Randers-Pehrson, and are +distributed according to the same disclaimer and license as libpng-0.96, +with the following individuals added to the list of Contributing Authors: + + Tom Lane + Glenn Randers-Pehrson + Willem van Schaik + +libpng versions 0.89, June 1996, through 0.96, May 1997, are +Copyright (c) 1996, 1997 Andreas Dilger +Distributed according to the same disclaimer and license as libpng-0.88, +with the following individuals added to the list of Contributing Authors: + + John Bowler + Kevin Bracey + Sam Bushell + Magnus Holmgren + Greg Roelofs + Tom Tanner + +libpng versions 0.5, May 1995, through 0.88, January 1996, are +Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. + +For the purposes of this copyright and license, "Contributing Authors" +is defined as the following set of individuals: + + Andreas Dilger + Dave Martindale + Guy Eric Schalnat + Paul Schmidt + Tim Wegner + +The PNG Reference Library is supplied "AS IS". The Contributing Authors +and Group 42, Inc. disclaim all warranties, expressed or implied, +including, without limitation, the warranties of merchantability and of +fitness for any purpose. The Contributing Authors and Group 42, Inc. +assume no liability for direct, indirect, incidental, special, exemplary, +or consequential damages, which may result from the use of the PNG +Reference Library, even if advised of the possibility of such damage. + +Permission is hereby granted to use, copy, modify, and distribute this +source code, or portions hereof, for any purpose, without fee, subject +to the following restrictions: + +1. The origin of this source code must not be misrepresented. + +2. Altered versions must be plainly marked as such and must not + be misrepresented as being the original source. + +3. This Copyright notice may not be removed or altered from any + source or altered source distribution. + +The Contributing Authors and Group 42, Inc. specifically permit, without +fee, and encourage the use of this source code as a component to +supporting the PNG file format in commercial products. If you use this +source code in a product, acknowledgment is not required but would be +appreciated. + + +A "png_get_copyright" function is available, for convenient use in "about" +boxes and the like: + + printf("%s",png_get_copyright(NULL)); + +Also, the PNG logo (in PNG format, of course) is supplied in the +files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31). + +Libpng is OSI Certified Open Source Software. OSI Certified Open Source is a +certification mark of the Open Source Initiative. + +Glenn Randers-Pehrson +glennrp at users.sourceforge.net +December 3, 2004 diff --git a/syslinux/com32/lib/libpng/README b/syslinux/com32/lib/libpng/README new file mode 100644 index 0000000..06f9fe4 --- /dev/null +++ b/syslinux/com32/lib/libpng/README @@ -0,0 +1,262 @@ +README for libpng version 1.2.8 - December 3, 2004 (shared library 12.0) +See the note about version numbers near the top of png.h + +See INSTALL for instructions on how to install libpng. + +Libpng comes in several distribution formats. Get libpng-*.tar.gz +or libpng-*.tar.bz2 if you want UNIX-style line endings in the text +files, or lpng*.zip if you want DOS-style line endings. + +Version 0.89 was the first official release of libpng. Don't let the +fact that it's the first release fool you. The libpng library has been in +extensive use and testing since mid-1995. By late 1997 it had +finally gotten to the stage where there hadn't been significant +changes to the API in some time, and people have a bad feeling about +libraries with versions < 1.0. Version 1.0.0 was released in +March 1998. + +**** +Note that some of the changes to the png_info structure render this +version of the library binary incompatible with libpng-0.89 or +earlier versions if you are using a shared library. The type of the +"filler" parameter for png_set_filler() has changed from png_byte to +png_uint_32, which will affect shared-library applications that use +this function. + +To avoid problems with changes to the internals of png_info_struct, +new APIs have been made available in 0.95 to avoid direct application +access to info_ptr. These functions are the png_set_<chunk> and +png_get_<chunk> functions. These functions should be used when +accessing/storing the info_struct data, rather than manipulating it +directly, to avoid such problems in the future. + +It is important to note that the APIs do not make current programs +that access the info struct directly incompatible with the new +library. However, it is strongly suggested that new programs use +the new APIs (as shown in example.c and pngtest.c), and older programs +be converted to the new format, to facilitate upgrades in the future. +**** + +Additions since 0.90 include the ability to compile libpng as a +Windows DLL, and new APIs for accessing data in the info struct. +Experimental functions include the ability to set weighting and cost +factors for row filter selection, direct reads of integers from buffers +on big-endian processors that support misaligned data access, faster +methods of doing alpha composition, and more accurate 16->8 bit color +conversion. + +The additions since 0.89 include the ability to read from a PNG stream +which has had some (or all) of the signature bytes read by the calling +application. This also allows the reading of embedded PNG streams that +do not have the PNG file signature. As well, it is now possible to set +the library action on the detection of chunk CRC errors. It is possible +to set different actions based on whether the CRC error occurred in a +critical or an ancillary chunk. + +The changes made to the library, and bugs fixed are based on discussions +on the PNG-implement mailing list +and not on material submitted privately to Guy, Andreas, or Glenn. They will +forward any good suggestions to the list. + +For a detailed description on using libpng, read libpng.txt. For +examples of libpng in a program, see example.c and pngtest.c. For usage +information and restrictions (what little they are) on libpng, see +png.h. For a description on using zlib (the compression library used by +libpng) and zlib's restrictions, see zlib.h + +I have included a general makefile, as well as several machine and +compiler specific ones, but you may have to modify one for your own needs. + +You should use zlib 1.0.4 or later to run this, but it MAY work with +versions as old as zlib 0.95. Even so, there are bugs in older zlib +versions which can cause the output of invalid compression streams for +some images. You will definitely need zlib 1.0.4 or later if you are +taking advantage of the MS-DOS "far" structure allocation for the small +and medium memory models. You should also note that zlib is a +compression library that is useful for more things than just PNG files. +You can use zlib as a drop-in replacement for fread() and fwrite() if +you are so inclined. + +zlib should be available at the same place that libpng is, or at. +ftp://ftp.info-zip.org/pub/infozip/zlib + +You may also want a copy of the PNG specification. It is available +as an RFC, a W3C Recommendation, and an ISO/IEC Standard. You can find +these at http://www.libpng.org/pub/png/documents/ + +This code is currently being archived at libpng.sf.net in the +[DOWNLOAD] area, and on CompuServe, Lib 20 (PNG SUPPORT) +at GO GRAPHSUP. If you can't find it in any of those places, +e-mail me, and I'll help you find it. + +If you have any code changes, requests, problems, etc., please e-mail +them to me. Also, I'd appreciate any make files or project files, +and any modifications you needed to make to get libpng to compile, +along with a #define variable to tell what compiler/system you are on. +If you needed to add transformations to libpng, or wish libpng would +provide the image in a different way, drop me a note (and code, if +possible), so I can consider supporting the transformation. +Finally, if you get any warning messages when compiling libpng +(note: not zlib), and they are easy to fix, I'd appreciate the +fix. Please mention "libpng" somewhere in the subject line. Thanks. + +This release was created and will be supported by myself (of course +based in a large way on Guy's and Andreas' earlier work), and the PNG group. + +glennrp at users.sourceforge.net +png-implement at ccrc.wustl.edu (subscription required; write to +majordomo at ccrc.wustl.edu with "subscribe png-implement" in the message). + +You can't reach Guy, the original libpng author, at the addresses +given in previous versions of this document. He and Andreas will read mail +addressed to the png-implement list, however. + +Please do not send general questions about PNG. Send them to +the (png-list at ccrc.wustl.edu, subscription required, write to +majordomo at ccrc.wustl.edu with "subscribe png-list" in your message). +On the other hand, +please do not send libpng questions to that address, send them to me +or to the png-implement list. I'll +get them in the end anyway. If you have a question about something +in the PNG specification that is related to using libpng, send it +to me. Send me any questions that start with "I was using libpng, +and ...". If in doubt, send questions to me. I'll bounce them +to others, if necessary. + +Please do not send suggestions on how to change PNG. We have +been discussing PNG for nine years now, and it is official and +finished. If you have suggestions for libpng, however, I'll +gladly listen. Even if your suggestion is not used immediately, +it may be used later. + +Files in this distribution: + + ANNOUNCE => Announcement of this version, with recent changes + CHANGES => Description of changes between libpng versions + KNOWNBUG => List of known bugs and deficiencies + LICENSE => License to use and redistribute libpng + README => This file + TODO => Things not implemented in the current library + Y2KINFO => Statement of Y2K compliance + example.c => Example code for using libpng functions + libpng.3 => manual page for libpng (includes libpng.txt) + libpng.txt => Description of libpng and its functions + libpngpf.3 => manual page for libpng's private functions + png.5 => manual page for the PNG format + png.c => Basic interface functions common to library + png.h => Library function and interface declarations + pngconf.h => System specific library configuration + pngasmrd.h => Header file for assembler-coded functions + pngerror.c => Error/warning message I/O functions + pngget.c => Functions for retrieving info from struct + pngmem.c => Memory handling functions + pngbar.png => PNG logo, 88x31 + pngnow.png => PNG logo, 98x31 + pngpread.c => Progressive reading functions + pngread.c => Read data/helper high-level functions + pngrio.c => Lowest-level data read I/O functions + pngrtran.c => Read data transformation functions + pngrutil.c => Read data utility functions + pngset.c => Functions for storing data into the info_struct + pngtest.c => Library test program + pngtest.png => Library test sample image + pngtrans.c => Common data transformation functions + pngwio.c => Lowest-level write I/O functions + pngwrite.c => High-level write functions + pngwtran.c => Write data transformations + pngwutil.c => Write utility functions + contrib => Contributions + gregbook => source code for PNG reading and writing, from + Greg Roelofs' "PNG: The Definitive Guide", + O'Reilly, 1999 + msvctest => Builds and runs pngtest using a MSVC workspace + pngminus => Simple pnm2png and png2pnm programs + pngsuite => Test images + visupng => Contains a MSVC workspace for VisualPng + projects => Contains project files and workspaces for building DLL + beos => Contains a Beos workspace for building libpng + c5builder => Contains a Borland workspace for building libpng + and zlib + visualc6 => Contains a Microsoft Visual C++ (MSVC) workspace + for building libpng and zlib + netware.txt => Contains instructions for downloading a set of + project files for building libpng and zlib on + Netware. + wince.txt => Contains instructions for downloading a Microsoft + Visual C++ (Windows CD Toolkit) workspace for + building libpng and zlib on WindowsCE + scripts => Directory containing scripts for building libpng: + descrip.mms => VMS makefile for MMS or MMK + makefile.std => Generic UNIX makefile (cc, creates static libpng.a) + makefile.elf => Linux/ELF makefile symbol versioning, + gcc, creates libpng12.so.0.1.2.8) + makefile.linux => Linux/ELF makefile + (gcc, creates libpng12.so.0.1.2.8) + makefile.gcmmx => Linux/ELF makefile + (gcc, creates libpng12.so.0.1.2.8, + uses assembler code tuned for Intel MMX platform) + makefile.gcc => Generic makefile (gcc, creates static libpng.a) + makefile.knr => Archaic UNIX Makefile that converts files with + ansi2knr (Requires ansi2knr.c from + ftp://ftp.cs.wisc.edu/ghost) + makefile.aix => AIX makefile + makefile.cygwin => Cygwin/gcc makefile + makefile.darwin => Darwin makefile + makefile.dec => DEC Alpha UNIX makefile + makefile.freebsd => FreeBSD makefile + makefile.hpgcc => HPUX makefile using gcc + makefile.hpux => HPUX (10.20 and 11.00) makefile + makefile.hp64 => HPUX (10.20 and 11.00) makefile, 64 bit + makefile.ibmc => IBM C/C++ version 3.x for Win32 and OS/2 (static) + makefile.intel => Intel C/C++ version 4.0 and later + libpng.icc => Project file, IBM VisualAge/C++ 4.0 or later + makefile.netbsd => NetBSD/cc makefile, PNGGCCRD, makes libpng.so. + makefile.ne12bsd => NetBSD/cc makefile, PNGGCCRD, makes libpng12.so + makefile.openbsd => OpenBSD makefile + makefile.sgi => Silicon Graphics IRIX (cc, creates static lib) + makefile.sggcc => Silicon Graphics + (gcc, creates libpng12.so.0.1.2.8) + makefile.sunos => Sun makefile + makefile.solaris => Solaris 2.X makefile + (gcc, creates libpng12.so.0.1.2.8) + makefile.so9 => Solaris 9 makefile + (gcc, creates libpng12.so.0.1.2.8) + makefile.32sunu => Sun Ultra 32-bit makefile + makefile.64sunu => Sun Ultra 64-bit makefile + makefile.sco => For SCO OSr5 ELF and Unixware 7 with Native cc + makefile.mips => MIPS makefile + makefile.acorn => Acorn makefile + makefile.amiga => Amiga makefile + smakefile.ppc => AMIGA smakefile for SAS C V6.58/7.00 PPC + compiler (Requires SCOPTIONS, copied from + scripts/SCOPTIONS.ppc) + makefile.atari => Atari makefile + makefile.beos => BEOS makefile for X86 + makefile.bor => Borland makefile (uses bcc) + makefile.bc32 => 32-bit Borland C++ (all modules compiled in C mode) + makefile.tc3 => Turbo C 3.0 makefile + makefile.dj2 => DJGPP 2 makefile + makefile.msc => Microsoft C makefile + makefile.vcawin32=> makefile for Microsoft Visual C++ 5.0 and + later (uses assembler code tuned for Intel MMX + platform) + makefile.vcwin32 => makefile for Microsoft Visual C++ 4.0 and + later (does not use assembler code) + makefile.os2 => OS/2 Makefile (gcc and emx, requires pngos2.def) + pngos2.def => OS/2 module definition file used by makefile.os2 + makefile.watcom => Watcom 10a+ Makefile, 32-bit flat memory model + makevms.com => VMS build script + SCOPTIONS.ppc => Used with smakefile.ppc + +Good luck, and happy coding. + +-Glenn Randers-Pehrson (current maintainer) + Internet: glennrp at users.sourceforge.net + +-Andreas Eric Dilger (former maintainer, 1996-1997) + Internet: adilger at enel.ucalgary.ca + Web: http://www-mddsp.enel.ucalgary.ca/People/adilger/ + +-Guy Eric Schalnat (original author and former maintainer, 1995-1996) + (formerly of Group 42, Inc) + Internet: gschal at infinet.com diff --git a/syslinux/com32/lib/libpng/TODO b/syslinux/com32/lib/libpng/TODO new file mode 100644 index 0000000..a5f6395 --- /dev/null +++ b/syslinux/com32/lib/libpng/TODO @@ -0,0 +1,24 @@ +TODO - list of things to do for libpng: + +Final bug fixes. +Improve API by hiding the png_struct and png_info structs. +Finish work on the no-floating-point version (including gamma compensation) +Better C++ wrapper/full C++ implementation? +Fix problem with C++ and EXTERN "C". +cHRM transformation. +Improve setjmp/longjmp usage or remove it in favor of returning error codes. +Add "grayscale->palette" transformation and "palette->grayscale" detection. +Improved dithering. +Multi-lingual error and warning message support. +Complete sRGB transformation (presently it simply uses gamma=0.45455). +Man pages for function calls. +Better documentation. +Better filter selection + (counting huffman bits/precompression? filter inertia? filter costs?). +Histogram creation. +Text conversion between different code pages (Latin-1 -> Mac and DOS). +Should we always malloc 2^bit_depth PLTE/tRNS/hIST entries for safety? +Build gamma tables using fixed point (and do away with floating point entirely). +Use greater precision when changing to linear gamma for compositing against + background and doing rgb-to-gray transformation. +Investigate pre-incremented loop counters and other loop constructions. diff --git a/syslinux/com32/lib/libpng/Y2KINFO b/syslinux/com32/lib/libpng/Y2KINFO new file mode 100644 index 0000000..4db294f --- /dev/null +++ b/syslinux/com32/lib/libpng/Y2KINFO @@ -0,0 +1,55 @@ + Y2K compliance in libpng: + ========================= + + December 3, 2004 + + Since the PNG Development group is an ad-hoc body, we can't make + an official declaration. + + This is your unofficial assurance that libpng from version 0.71 and + upward through 1.2.8 are Y2K compliant. It is my belief that earlier + versions were also Y2K compliant. + + Libpng only has three year fields. One is a 2-byte unsigned integer + that will hold years up to 65535. The other two hold the date in text + format, and will hold years up to 9999. + + The integer is + "png_uint_16 year" in png_time_struct. + + The strings are + "png_charp time_buffer" in png_struct and + "near_time_buffer", which is a local character string in png.c. + + There are seven time-related functions: + + png_convert_to_rfc_1123() in png.c + (formerly png_convert_to_rfc_1152() in error) + png_convert_from_struct_tm() in pngwrite.c, called in pngwrite.c + png_convert_from_time_t() in pngwrite.c + png_get_tIME() in pngget.c + png_handle_tIME() in pngrutil.c, called in pngread.c + png_set_tIME() in pngset.c + png_write_tIME() in pngwutil.c, called in pngwrite.c + + All appear to handle dates properly in a Y2K environment. The + png_convert_from_time_t() function calls gmtime() to convert from system + clock time, which returns (year - 1900), which we properly convert to + the full 4-digit year. There is a possibility that applications using + libpng are not passing 4-digit years into the png_convert_to_rfc_1123() + function, or that they are incorrectly passing only a 2-digit year + instead of "year - 1900" into the png_convert_from_struct_tm() function, + but this is not under our control. The libpng documentation has always + stated that it works with 4-digit years, and the APIs have been + documented as such. + + The tIME chunk itself is also Y2K compliant. It uses a 2-byte unsigned + integer to hold the year, and can hold years as large as 65535. + + zlib, upon which libpng depends, is also Y2K compliant. It contains + no date-related code. + + + Glenn Randers-Pehrson + libpng maintainer + PNG Development Group diff --git a/syslinux/com32/lib/libpng/example.c b/syslinux/com32/lib/libpng/example.c new file mode 100644 index 0000000..ba0ecc5 --- /dev/null +++ b/syslinux/com32/lib/libpng/example.c @@ -0,0 +1,808 @@ + +#if 0 /* in case someone actually tries to compile this */ + +/* example.c - an example of using libpng */ + +/* This is an example of how to use libpng to read and write PNG files. + * The file libpng.txt is much more verbose then this. If you have not + * read it, do so first. This was designed to be a starting point of an + * implementation. This is not officially part of libpng, is hereby placed + * in the public domain, and therefore does not require a copyright notice. + * + * This file does not currently compile, because it is missing certain + * parts, like allocating memory to hold an image. You will have to + * supply these parts to get it to compile. For an example of a minimal + * working PNG reader/writer, see pngtest.c, included in this distribution; + * see also the programs in the contrib directory. + */ + +#include "png.h" + + /* The png_jmpbuf() macro, used in error handling, became available in + * libpng version 1.0.6. If you want to be able to run your code with older + * versions of libpng, you must define the macro yourself (but only if it + * is not already defined by libpng!). + */ + +#ifndef png_jmpbuf +# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) +#endif + +/* Check to see if a file is a PNG file using png_sig_cmp(). png_sig_cmp() + * returns zero if the image is a PNG and nonzero if it isn't a PNG. + * + * The function check_if_png() shown here, but not used, returns nonzero (true) + * if the file can be opened and is a PNG, 0 (false) otherwise. + * + * If this call is successful, and you are going to keep the file open, + * you should call png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); once + * you have created the png_ptr, so that libpng knows your application + * has read that many bytes from the start of the file. Make sure you + * don't call png_set_sig_bytes() with more than 8 bytes read or give it + * an incorrect number of bytes read, or you will either have read too + * many bytes (your fault), or you are telling libpng to read the wrong + * number of magic bytes (also your fault). + * + * Many applications already read the first 2 or 4 bytes from the start + * of the image to determine the file type, so it would be easiest just + * to pass the bytes to png_sig_cmp() or even skip that if you know + * you have a PNG file, and call png_set_sig_bytes(). + */ +#define PNG_BYTES_TO_CHECK 4 +int check_if_png(char *file_name, FILE **fp) +{ + char buf[PNG_BYTES_TO_CHECK]; + + /* Open the prospective PNG file. */ + if ((*fp = fopen(file_name, "rb")) == NULL) + return 0; + + /* Read in some of the signature bytes */ + if (fread(buf, 1, PNG_BYTES_TO_CHECK, *fp) != PNG_BYTES_TO_CHECK) + return 0; + + /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature. + Return nonzero (true) if they match */ + + return(!png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK)); +} + +/* Read a PNG file. You may want to return an error code if the read + * fails (depending upon the failure). There are two "prototypes" given + * here - one where we are given the filename, and we need to open the + * file, and the other where we are given an open file (possibly with + * some or all of the magic bytes read - see comments above). + */ +#ifdef open_file /* prototype 1 */ +void read_png(char *file_name) /* We need to open the file */ +{ + png_structp png_ptr; + png_infop info_ptr; + unsigned int sig_read = 0; + png_uint_32 width, height; + int bit_depth, color_type, interlace_type; + FILE *fp; + + if ((fp = fopen(file_name, "rb")) == NULL) + return (ERROR); +#else no_open_file /* prototype 2 */ +void read_png(FILE *fp, unsigned int sig_read) /* file is already open */ +{ + png_structp png_ptr; + png_infop info_ptr; + png_uint_32 width, height; + int bit_depth, color_type, interlace_type; +#endif no_open_file /* only use one prototype! */ + + /* Create and initialize the png_struct with the desired error handler + * functions. If you want to use the default stderr and longjump method, + * you can supply NULL for the last three parameters. We also supply the + * the compiler header file version, so that we know if the application + * was compiled with a compatible version of the library. REQUIRED + */ + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, + png_voidp user_error_ptr, user_error_fn, user_warning_fn); + + if (png_ptr == NULL) + { + fclose(fp); + return (ERROR); + } + + /* Allocate/initialize the memory for image information. REQUIRED. */ + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) + { + fclose(fp); + png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); + return (ERROR); + } + + /* Set error handling if you are using the setjmp/longjmp method (this is + * the normal method of doing things with libpng). REQUIRED unless you + * set up your own error handlers in the png_create_read_struct() earlier. + */ + + if (setjmp(png_jmpbuf(png_ptr))) + { + /* Free all of the memory associated with the png_ptr and info_ptr */ + png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); + fclose(fp); + /* If we get here, we had a problem reading the file */ + return (ERROR); + } + + /* One of the following I/O initialization methods is REQUIRED */ +#ifdef streams /* PNG file I/O method 1 */ + /* Set up the input control if you are using standard C streams */ + png_init_io(png_ptr, fp); + +#else no_streams /* PNG file I/O method 2 */ + /* If you are using replacement read functions, instead of calling + * png_init_io() here you would call: + */ + png_set_read_fn(png_ptr, (void *)user_io_ptr, user_read_fn); + /* where user_io_ptr is a structure you want available to the callbacks */ +#endif no_streams /* Use only one I/O method! */ + + /* If we have already read some of the signature */ + png_set_sig_bytes(png_ptr, sig_read); + +#ifdef hilevel + /* + * If you have enough memory to read in the entire image at once, + * and you need to specify only transforms that can be controlled + * with one of the PNG_TRANSFORM_* bits (this presently excludes + * dithering, filling, setting background, and doing gamma + * adjustment), then you can read the entire image (including + * pixels) into the info structure with this call: + */ + png_read_png(png_ptr, info_ptr, png_transforms, png_voidp_NULL); +#else + /* OK, you're doing it the hard way, with the lower-level functions */ + + /* The call to png_read_info() gives us all of the information from the + * PNG file before the first IDAT (image data chunk). REQUIRED + */ + png_read_info(png_ptr, info_ptr); + + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, + &interlace_type, int_p_NULL, int_p_NULL); + +/* Set up the data transformations you want. Note that these are all + * optional. Only call them if you want/need them. Many of the + * transformations only work on specific types of images, and many + * are mutually exclusive. + */ + + /* tell libpng to strip 16 bit/color files down to 8 bits/color */ + png_set_strip_16(png_ptr); + + /* Strip alpha bytes from the input data without combining with the + * background (not recommended). + */ + png_set_strip_alpha(png_ptr); + + /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single + * byte into separate bytes (useful for paletted and grayscale images). + */ + png_set_packing(png_ptr); + + /* Change the order of packed pixels to least significant bit first + * (not useful if you are using png_set_packing). */ + png_set_packswap(png_ptr); + + /* Expand paletted colors into true RGB triplets */ + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_rgb(png_ptr); + + /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ + if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) + png_set_gray_1_2_4_to_8(png_ptr); + + /* Expand paletted or RGB images with transparency to full alpha channels + * so the data will be available as RGBA quartets. + */ + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) + png_set_tRNS_to_alpha(png_ptr); + + /* Set the background color to draw transparent and alpha images over. + * It is possible to set the red, green, and blue components directly + * for paletted images instead of supplying a palette index. Note that + * even if the PNG file supplies a background, you are not required to + * use it - you should use the (solid) application background if it has one. + */ + + png_color_16 my_background, *image_background; + + if (png_get_bKGD(png_ptr, info_ptr, &image_background)) + png_set_background(png_ptr, image_background, + PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); + else + png_set_background(png_ptr, &my_background, + PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); + + /* Some suggestions as to how to get a screen gamma value */ + + /* Note that screen gamma is the display_exponent, which includes + * the CRT_exponent and any correction for viewing conditions */ + if (/* We have a user-defined screen gamma value */) + { + screen_gamma = user-defined screen_gamma; + } + /* This is one way that applications share the same screen gamma value */ + else if ((gamma_str = getenv("SCREEN_GAMMA")) != NULL) + { + screen_gamma = atof(gamma_str); + } + /* If we don't have another value */ + else + { + screen_gamma = 2.2; /* A good guess for a PC monitors in a dimly + lit room */ + screen_gamma = 1.7 or 1.0; /* A good guess for Mac systems */ + } + + /* Tell libpng to handle the gamma conversion for you. The final call + * is a good guess for PC generated images, but it should be configurable + * by the user at run time by the user. It is strongly suggested that + * your application support gamma correction. + */ + + int intent; + + if (png_get_sRGB(png_ptr, info_ptr, &intent)) + png_set_gamma(png_ptr, screen_gamma, 0.45455); + else + { + double image_gamma; + if (png_get_gAMA(png_ptr, info_ptr, &image_gamma)) + png_set_gamma(png_ptr, screen_gamma, image_gamma); + else + png_set_gamma(png_ptr, screen_gamma, 0.45455); + } + + /* Dither RGB files down to 8 bit palette or reduce palettes + * to the number of colors available on your screen. + */ + if (color_type & PNG_COLOR_MASK_COLOR) + { + int num_palette; + png_colorp palette; + + /* This reduces the image to the application supplied palette */ + if (/* we have our own palette */) + { + /* An array of colors to which the image should be dithered */ + png_color std_color_cube[MAX_SCREEN_COLORS]; + + png_set_dither(png_ptr, std_color_cube, MAX_SCREEN_COLORS, + MAX_SCREEN_COLORS, png_uint_16p_NULL, 0); + } + /* This reduces the image to the palette supplied in the file */ + else if (png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)) + { + png_uint_16p histogram = NULL; + + png_get_hIST(png_ptr, info_ptr, &histogram); + + png_set_dither(png_ptr, palette, num_palette, + max_screen_colors, histogram, 0); + } + } + + /* invert monochrome files to have 0 as white and 1 as black */ + png_set_invert_mono(png_ptr); + + /* If you want to shift the pixel values from the range [0,255] or + * [0,65535] to the original [0,7] or [0,31], or whatever range the + * colors were originally in: + */ + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT)) + { + png_color_8p sig_bit; + + png_get_sBIT(png_ptr, info_ptr, &sig_bit); + png_set_shift(png_ptr, sig_bit); + } + + /* flip the RGB pixels to BGR (or RGBA to BGRA) */ + if (color_type & PNG_COLOR_MASK_COLOR) + png_set_bgr(png_ptr); + + /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ + png_set_swap_alpha(png_ptr); + + /* swap bytes of 16 bit files to least significant byte first */ + png_set_swap(png_ptr); + + /* Add filler (or alpha) byte (before/after each RGB triplet) */ + png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); + + /* Turn on interlace handling. REQUIRED if you are not using + * png_read_image(). To see how to handle interlacing passes, + * see the png_read_row() method below: + */ + number_passes = png_set_interlace_handling(png_ptr); + + /* Optional call to gamma correct and add the background to the palette + * and update info structure. REQUIRED if you are expecting libpng to + * update the palette for you (ie you selected such a transform above). + */ + png_read_update_info(png_ptr, info_ptr); + + /* Allocate the memory to hold the image using the fields of info_ptr. */ + + /* The easiest way to read the image: */ + png_bytep row_pointers[height]; + + for (row = 0; row < height; row++) + { + row_pointers[row] = png_malloc(png_ptr, png_get_rowbytes(png_ptr, + info_ptr)); + } + + /* Now it's time to read the image. One of these methods is REQUIRED */ +#ifdef entire /* Read the entire image in one go */ + png_read_image(png_ptr, row_pointers); + +#else no_entire /* Read the image one or more scanlines at a time */ + /* The other way to read images - deal with interlacing: */ + + for (pass = 0; pass < number_passes; pass++) + { +#ifdef single /* Read the image a single row at a time */ + for (y = 0; y < height; y++) + { + png_read_rows(png_ptr, &row_pointers[y], png_bytepp_NULL, 1); + } + +#else no_single /* Read the image several rows at a time */ + for (y = 0; y < height; y += number_of_rows) + { +#ifdef sparkle /* Read the image using the "sparkle" effect. */ + png_read_rows(png_ptr, &row_pointers[y], png_bytepp_NULL, + number_of_rows); +#else no_sparkle /* Read the image using the "rectangle" effect */ + png_read_rows(png_ptr, png_bytepp_NULL, &row_pointers[y], + number_of_rows); +#endif no_sparkle /* use only one of these two methods */ + } + + /* if you want to display the image after every pass, do + so here */ +#endif no_single /* use only one of these two methods */ + } +#endif no_entire /* use only one of these two methods */ + + /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ + png_read_end(png_ptr, info_ptr); +#endif hilevel + + /* At this point you have read the entire image */ + + /* clean up after the read, and free any memory allocated - REQUIRED */ + png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); + + /* close the file */ + fclose(fp); + + /* that's it */ + return (OK); +} + +/* progressively read a file */ + +int +initialize_png_reader(png_structp *png_ptr, png_infop *info_ptr) +{ + /* Create and initialize the png_struct with the desired error handler + * functions. If you want to use the default stderr and longjump method, + * you can supply NULL for the last three parameters. We also check that + * the library version is compatible in case we are using dynamically + * linked libraries. + */ + *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, + png_voidp user_error_ptr, user_error_fn, user_warning_fn); + + if (*png_ptr == NULL) + { + *info_ptr = NULL; + return (ERROR); + } + + *info_ptr = png_create_info_struct(png_ptr); + + if (*info_ptr == NULL) + { + png_destroy_read_struct(png_ptr, info_ptr, png_infopp_NULL); + return (ERROR); + } + + if (setjmp(png_jmpbuf((*png_ptr)))) + { + png_destroy_read_struct(png_ptr, info_ptr, png_infopp_NULL); + return (ERROR); + } + + /* This one's new. You will need to provide all three + * function callbacks, even if you aren't using them all. + * If you aren't using all functions, you can specify NULL + * parameters. Even when all three functions are NULL, + * you need to call png_set_progressive_read_fn(). + * These functions shouldn't be dependent on global or + * static variables if you are decoding several images + * simultaneously. You should store stream specific data + * in a separate struct, given as the second parameter, + * and retrieve the pointer from inside the callbacks using + * the function png_get_progressive_ptr(png_ptr). + */ + png_set_progressive_read_fn(*png_ptr, (void *)stream_data, + info_callback, row_callback, end_callback); + + return (OK); +} + +int +process_data(png_structp *png_ptr, png_infop *info_ptr, + png_bytep buffer, png_uint_32 length) +{ + if (setjmp(png_jmpbuf((*png_ptr)))) + { + /* Free the png_ptr and info_ptr memory on error */ + png_destroy_read_struct(png_ptr, info_ptr, png_infopp_NULL); + return (ERROR); + } + + /* This one's new also. Simply give it chunks of data as + * they arrive from the data stream (in order, of course). + * On Segmented machines, don't give it any more than 64K. + * The library seems to run fine with sizes of 4K, although + * you can give it much less if necessary (I assume you can + * give it chunks of 1 byte, but I haven't tried with less + * than 256 bytes yet). When this function returns, you may + * want to display any rows that were generated in the row + * callback, if you aren't already displaying them there. + */ + png_process_data(*png_ptr, *info_ptr, buffer, length); + return (OK); +} + +info_callback(png_structp png_ptr, png_infop info) +{ +/* do any setup here, including setting any of the transformations + * mentioned in the Reading PNG files section. For now, you _must_ + * call either png_start_read_image() or png_read_update_info() + * after all the transformations are set (even if you don't set + * any). You may start getting rows before png_process_data() + * returns, so this is your last chance to prepare for that. + */ +} + +row_callback(png_structp png_ptr, png_bytep new_row, + png_uint_32 row_num, int pass) +{ +/* + * This function is called for every row in the image. If the + * image is interlaced, and you turned on the interlace handler, + * this function will be called for every row in every pass. + * + * In this function you will receive a pointer to new row data from + * libpng called new_row that is to replace a corresponding row (of + * the same data format) in a buffer allocated by your application. + * + * The new row data pointer new_row may be NULL, indicating there is + * no new data to be replaced (in cases of interlace loading). + * + * If new_row is not NULL then you need to call + * png_progressive_combine_row() to replace the corresponding row as + * shown below: + */ + /* Check if row_num is in bounds. */ + if((row_num >= 0) && (row_num < height)) + { + /* Get pointer to corresponding row in our + * PNG read buffer. + */ + png_bytep old_row = ((png_bytep *)our_data)[row_num]; + + /* If both rows are allocated then copy the new row + * data to the corresponding row data. + */ + if((old_row != NULL) && (new_row != NULL)) + png_progressive_combine_row(png_ptr, old_row, new_row); + } +/* + * The rows and passes are called in order, so you don't really + * need the row_num and pass, but I'm supplying them because it + * may make your life easier. + * + * For the non-NULL rows of interlaced images, you must call + * png_progressive_combine_row() passing in the new row and the + * old row, as demonstrated above. You can call this function for + * NULL rows (it will just return) and for non-interlaced images + * (it just does the png_memcpy for you) if it will make the code + * easier. Thus, you can just do this for all cases: + */ + + png_progressive_combine_row(png_ptr, old_row, new_row); + +/* where old_row is what was displayed for previous rows. Note + * that the first pass (pass == 0 really) will completely cover + * the old row, so the rows do not have to be initialized. After + * the first pass (and only for interlaced images), you will have + * to pass the current row as new_row, and the function will combine + * the old row and the new row. + */ +} + +end_callback(png_structp png_ptr, png_infop info) +{ +/* this function is called when the whole image has been read, + * including any chunks after the image (up to and including + * the IEND). You will usually have the same info chunk as you + * had in the header, although some data may have been added + * to the comments and time fields. + * + * Most people won't do much here, perhaps setting a flag that + * marks the image as finished. + */ +} + +/* write a png file */ +void write_png(char *file_name /* , ... other image information ... */) +{ + FILE *fp; + png_structp png_ptr; + png_infop info_ptr; + png_colorp palette; + + /* open the file */ + fp = fopen(file_name, "wb"); + if (fp == NULL) + return (ERROR); + + /* Create and initialize the png_struct with the desired error handler + * functions. If you want to use the default stderr and longjump method, + * you can supply NULL for the last three parameters. We also check that + * the library version is compatible with the one used at compile time, + * in case we are using dynamically linked libraries. REQUIRED. + */ + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, + png_voidp user_error_ptr, user_error_fn, user_warning_fn); + + if (png_ptr == NULL) + { + fclose(fp); + return (ERROR); + } + + /* Allocate/initialize the image information data. REQUIRED */ + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) + { + fclose(fp); + png_destroy_write_struct(&png_ptr, png_infopp_NULL); + return (ERROR); + } + + /* Set error handling. REQUIRED if you aren't supplying your own + * error handling functions in the png_create_write_struct() call. + */ + if (setjmp(png_jmpbuf(png_ptr))) + { + /* If we get here, we had a problem reading the file */ + fclose(fp); + png_destroy_write_struct(&png_ptr, &info_ptr); + return (ERROR); + } + + /* One of the following I/O initialization functions is REQUIRED */ +#ifdef streams /* I/O initialization method 1 */ + /* set up the output control if you are using standard C streams */ + png_init_io(png_ptr, fp); +#else no_streams /* I/O initialization method 2 */ + /* If you are using replacement read functions, instead of calling + * png_init_io() here you would call */ + png_set_write_fn(png_ptr, (void *)user_io_ptr, user_write_fn, + user_IO_flush_function); + /* where user_io_ptr is a structure you want available to the callbacks */ +#endif no_streams /* only use one initialization method */ + +#ifdef hilevel + /* This is the easy way. Use it if you already have all the + * image info living info in the structure. You could "|" many + * PNG_TRANSFORM flags into the png_transforms integer here. + */ + png_write_png(png_ptr, info_ptr, png_transforms, png_voidp_NULL); +#else + /* This is the hard way */ + + /* Set the image information here. Width and height are up to 2^31, + * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on + * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, + * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, + * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or + * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST + * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED + */ + png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_???, + PNG_INTERLACE_????, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + /* set the palette if there is one. REQUIRED for indexed-color images */ + palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH + * png_sizeof (png_color)); + /* ... set palette colors ... */ + png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH); + /* You must not free palette here, because png_set_PLTE only makes a link to + the palette that you malloced. Wait until you are about to destroy + the png structure. */ + + /* optional significant bit chunk */ + /* if we are dealing with a grayscale image then */ + sig_bit.gray = true_bit_depth; + /* otherwise, if we are dealing with a color image then */ + sig_bit.red = true_red_bit_depth; + sig_bit.green = true_green_bit_depth; + sig_bit.blue = true_blue_bit_depth; + /* if the image has an alpha channel then */ + sig_bit.alpha = true_alpha_bit_depth; + png_set_sBIT(png_ptr, info_ptr, sig_bit); + + + /* Optional gamma chunk is strongly suggested if you have any guess + * as to the correct gamma of the image. + */ + png_set_gAMA(png_ptr, info_ptr, gamma); + + /* Optionally write comments into the image */ + text_ptr[0].key = "Title"; + text_ptr[0].text = "Mona Lisa"; + text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE; + text_ptr[1].key = "Author"; + text_ptr[1].text = "Leonardo DaVinci"; + text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE; + text_ptr[2].key = "Description"; + text_ptr[2].text = "<long text>"; + text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt; +#ifdef PNG_iTXt_SUPPORTED + text_ptr[0].lang = NULL; + text_ptr[1].lang = NULL; + text_ptr[2].lang = NULL; +#endif + png_set_text(png_ptr, info_ptr, text_ptr, 3); + + /* other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs, */ + /* note that if sRGB is present the gAMA and cHRM chunks must be ignored + * on read and must be written in accordance with the sRGB profile */ + + /* Write the file header information. REQUIRED */ + png_write_info(png_ptr, info_ptr); + + /* If you want, you can write the info in two steps, in case you need to + * write your private chunk ahead of PLTE: + * + * png_write_info_before_PLTE(write_ptr, write_info_ptr); + * write_my_chunk(); + * png_write_info(png_ptr, info_ptr); + * + * However, given the level of known- and unknown-chunk support in 1.1.0 + * and up, this should no longer be necessary. + */ + + /* Once we write out the header, the compression type on the text + * chunks gets changed to PNG_TEXT_COMPRESSION_NONE_WR or + * PNG_TEXT_COMPRESSION_zTXt_WR, so it doesn't get written out again + * at the end. + */ + + /* set up the transformations you want. Note that these are + * all optional. Only call them if you want them. + */ + + /* invert monochrome pixels */ + png_set_invert_mono(png_ptr); + + /* Shift the pixels up to a legal bit depth and fill in + * as appropriate to correctly scale the image. + */ + png_set_shift(png_ptr, &sig_bit); + + /* pack pixels into bytes */ + png_set_packing(png_ptr); + + /* swap location of alpha bytes from ARGB to RGBA */ + png_set_swap_alpha(png_ptr); + + /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into + * RGB (4 channels -> 3 channels). The second parameter is not used. + */ + png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); + + /* flip BGR pixels to RGB */ + png_set_bgr(png_ptr); + + /* swap bytes of 16-bit files to most significant byte first */ + png_set_swap(png_ptr); + + /* swap bits of 1, 2, 4 bit packed pixel formats */ + png_set_packswap(png_ptr); + + /* turn on interlace handling if you are not using png_write_image() */ + if (interlacing) + number_passes = png_set_interlace_handling(png_ptr); + else + number_passes = 1; + + /* The easiest way to write the image (you may have a different memory + * layout, however, so choose what fits your needs best). You need to + * use the first method if you aren't handling interlacing yourself. + */ + png_uint_32 k, height, width; + png_byte image[height][width*bytes_per_pixel]; + png_bytep row_pointers[height]; + + if (height > PNG_UINT_32_MAX/png_sizeof(png_bytep)) + png_error (png_ptr, "Image is too tall to process in memory"); + + for (k = 0; k < height; k++) + row_pointers[k] = image + k*width*bytes_per_pixel; + + /* One of the following output methods is REQUIRED */ +#ifdef entire /* write out the entire image data in one call */ + png_write_image(png_ptr, row_pointers); + + /* the other way to write the image - deal with interlacing */ + +#else no_entire /* write out the image data by one or more scanlines */ + /* The number of passes is either 1 for non-interlaced images, + * or 7 for interlaced images. + */ + for (pass = 0; pass < number_passes; pass++) + { + /* Write a few rows at a time. */ + png_write_rows(png_ptr, &row_pointers[first_row], number_of_rows); + + /* If you are only writing one row at a time, this works */ + for (y = 0; y < height; y++) + { + png_write_rows(png_ptr, &row_pointers[y], 1); + } + } +#endif no_entire /* use only one output method */ + + /* You can write optional chunks like tEXt, zTXt, and tIME at the end + * as well. Shouldn't be necessary in 1.1.0 and up as all the public + * chunks are supported and you can use png_set_unknown_chunks() to + * register unknown chunks into the info structure to be written out. + */ + + /* It is REQUIRED to call this to finish writing the rest of the file */ + png_write_end(png_ptr, info_ptr); +#endif hilevel + + /* If you png_malloced a palette, free it here (don't free info_ptr->palette, + as recommended in versions 1.0.5m and earlier of this example; if + libpng mallocs info_ptr->palette, libpng will free it). If you + allocated it with malloc() instead of png_malloc(), use free() instead + of png_free(). */ + png_free(png_ptr, palette); + palette=NULL; + + /* Similarly, if you png_malloced any data that you passed in with + png_set_something(), such as a hist or trans array, free it here, + when you can be sure that libpng is through with it. */ + png_free(png_ptr, trans); + trans=NULL; + + /* clean up after the write, and free any memory allocated */ + png_destroy_write_struct(&png_ptr, &info_ptr); + + /* close the file */ + fclose(fp); + + /* that's it */ + return (OK); +} + +#endif /* if 0 */ diff --git a/syslinux/com32/lib/libpng/libpng.3 b/syslinux/com32/lib/libpng/libpng.3 new file mode 100644 index 0000000..1feceee --- /dev/null +++ b/syslinux/com32/lib/libpng/libpng.3 @@ -0,0 +1,4022 @@ +.TH LIBPNG 3 "December 3, 2004" +.SH NAME +libpng \- Portable Network Graphics (PNG) Reference Library 1.2.8 +.SH SYNOPSIS +\fI\fB + +\fB#include <png.h>\fP + +\fI\fB + +\fBpng_uint_32 png_access_version_number \fI(void\fP\fB);\fP + +\fI\fB + +\fBint png_check_sig (png_bytep \fP\fIsig\fP\fB, int \fInum\fP\fB);\fP + +\fI\fB + +\fBvoid png_chunk_error (png_structp \fP\fIpng_ptr\fP\fB, png_const_charp \fIerror\fP\fB);\fP + +\fI\fB + +\fBvoid png_chunk_warning (png_structp \fP\fIpng_ptr\fP\fB, png_const_charp \fImessage\fP\fB);\fP + +\fI\fB + +\fBvoid png_convert_from_struct_tm (png_timep \fP\fIptime\fP\fB, struct tm FAR * \fIttime\fP\fB);\fP + +\fI\fB + +\fBvoid png_convert_from_time_t (png_timep \fP\fIptime\fP\fB, time_t \fIttime\fP\fB);\fP + +\fI\fB + +\fBpng_charp png_convert_to_rfc1123 (png_structp \fP\fIpng_ptr\fP\fB, png_timep \fIptime\fP\fB);\fP + +\fI\fB + +\fBpng_infop png_create_info_struct (png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_structp png_create_read_struct (png_const_charp \fP\fIuser_png_ver\fP\fB, png_voidp \fP\fIerror_ptr\fP\fB, png_error_ptr \fP\fIerror_fn\fP\fB, png_error_ptr \fIwarn_fn\fP\fB);\fP + +\fI\fB + +\fBpng_structp png_create_read_struct_2(png_const_charp \fP\fIuser_png_ver\fP\fB, png_voidp \fP\fIerror_ptr\fP\fB, png_error_ptr \fP\fIerror_fn\fP\fB, png_error_ptr \fP\fIwarn_fn\fP\fB, png_voidp \fP\fImem_ptr\fP\fB, png_malloc_ptr \fP\fImalloc_fn\fP\fB, png_free_ptr \fIfree_fn\fP\fB);\fP + +\fI\fB + +\fBpng_structp png_create_write_struct (png_const_charp \fP\fIuser_png_ver\fP\fB, png_voidp \fP\fIerror_ptr\fP\fB, png_error_ptr \fP\fIerror_fn\fP\fB, png_error_ptr \fIwarn_fn\fP\fB);\fP + +\fI\fB + +\fBpng_structp png_create_write_struct_2(png_const_charp \fP\fIuser_png_ver\fP\fB, png_voidp \fP\fIerror_ptr\fP\fB, png_error_ptr \fP\fIerror_fn\fP\fB, png_error_ptr \fP\fIwarn_fn\fP\fB, png_voidp \fP\fImem_ptr\fP\fB, png_malloc_ptr \fP\fImalloc_fn\fP\fB, png_free_ptr \fIfree_fn\fP\fB);\fP + +\fI\fB + +\fBint png_debug(int \fP\fIlevel\fP\fB, png_const_charp \fImessage\fP\fB);\fP + +\fI\fB + +\fBint png_debug1(int \fP\fIlevel\fP\fB, png_const_charp \fP\fImessage\fP\fB, \fIp1\fP\fB);\fP + +\fI\fB + +\fBint png_debug2(int \fP\fIlevel\fP\fB, png_const_charp \fP\fImessage\fP\fB, \fP\fIp1\fP\fB, \fIp2\fP\fB);\fP + +\fI\fB + +\fBvoid png_destroy_info_struct (png_structp \fP\fIpng_ptr\fP\fB, png_infopp \fIinfo_ptr_ptr\fP\fB);\fP + +\fI\fB + +\fBvoid png_destroy_read_struct (png_structpp \fP\fIpng_ptr_ptr\fP\fB, png_infopp \fP\fIinfo_ptr_ptr\fP\fB, png_infopp \fIend_info_ptr_ptr\fP\fB);\fP + +\fI\fB + +\fBvoid png_destroy_write_struct (png_structpp \fP\fIpng_ptr_ptr\fP\fB, png_infopp \fIinfo_ptr_ptr\fP\fB);\fP + +\fI\fB + +\fBvoid png_error (png_structp \fP\fIpng_ptr\fP\fB, png_const_charp \fIerror\fP\fB);\fP + +\fI\fB + +\fBvoid png_free (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fIptr\fP\fB);\fP + +\fI\fB + +\fBvoid png_free_chunk_list (png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBvoid png_free_default(png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fIptr\fP\fB);\fP + +\fI\fB + +\fBvoid png_free_data (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fInum\fP\fB);\fP + +\fI\fB + +\fBpng_byte png_get_bit_depth (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_uint_32 png_get_bKGD (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_color_16p \fI*background\fP\fB);\fP + +\fI\fB + +\fBpng_byte png_get_channels (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_uint_32 png_get_cHRM (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, double \fP\fI*white_x\fP\fB, double \fP\fI*white_y\fP\fB, double \fP\fI*red_x\fP\fB, double \fP\fI*red_y\fP\fB, double \fP\fI*green_x\fP\fB, double \fP\fI*green_y\fP\fB, double \fP\fI*blue_x\fP\fB, double \fI*blue_y\fP\fB);\fP + +\fI\fB + +\fBpng_uint_32 png_get_cHRM_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fI*white_x\fP\fB, png_uint_32 \fP\fI*white_y\fP\fB, png_uint_32 \fP\fI*red_x\fP\fB, png_uint_32 \fP\fI*red_y\fP\fB, png_uint_32 \fP\fI*green_x\fP\fB, png_uint_32 \fP\fI*green_y\fP\fB, png_uint_32 \fP\fI*blue_x\fP\fB, png_uint_32 \fI*blue_y\fP\fB);\fP + +\fI\fB + +\fBpng_byte png_get_color_type (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_byte png_get_compression_type (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_byte png_get_copyright (png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_voidp png_get_error_ptr (png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_byte png_get_filter_type (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_uint_32 png_get_gAMA (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, double \fI*file_gamma\fP\fB);\fP + +\fI\fB + +\fBpng_uint_32 png_get_gAMA_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fI*int_file_gamma\fP\fB);\fP + +\fI\fB + +\fBpng_byte png_get_header_ver (png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_byte png_get_header_version (png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_uint_32 png_get_hIST (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_16p \fI*hist\fP\fB);\fP + +\fI\fB + +\fBpng_uint_32 png_get_iCCP (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_charpp \fP\fIname\fP\fB, int \fP\fI*compression_type\fP\fB, png_charpp \fP\fIprofile\fP\fB, png_uint_32 \fI*proflen\fP\fB);\fP + +\fI\fB + +\fBpng_uint_32 png_get_IHDR (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fI*width\fP\fB, png_uint_32 \fP\fI*height\fP\fB, int \fP\fI*bit_depth\fP\fB, int \fP\fI*color_type\fP\fB, int \fP\fI*interlace_type\fP\fB, int \fP\fI*compression_type\fP\fB, int \fI*filter_type\fP\fB);\fP + +\fI\fB + +\fBpng_uint_32 png_get_image_height (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_uint_32 png_get_image_width (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_byte png_get_interlace_type (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_voidp png_get_io_ptr (png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_byte png_get_libpng_ver (png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_voidp png_get_mem_ptr(png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_uint_32 png_get_oFFs (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fI*offset_x\fP\fB, png_uint_32 \fP\fI*offset_y\fP\fB, int \fI*unit_type\fP\fB);\fP + +\fI\fB + +\fBpng_uint_32 png_get_pCAL (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_charp \fP\fI*purpose\fP\fB, png_int_32 \fP\fI*X0\fP\fB, png_int_32 \fP\fI*X1\fP\fB, int \fP\fI*type\fP\fB, int \fP\fI*nparams\fP\fB, png_charp \fP\fI*units\fP\fB, png_charpp \fI*params\fP\fB);\fP + +\fI\fB + +\fBpng_uint_32 png_get_pHYs (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fI*res_x\fP\fB, png_uint_32 \fP\fI*res_y\fP\fB, int \fI*unit_type\fP\fB);\fP + +\fI\fB + +\fBfloat png_get_pixel_aspect_ratio (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_uint_32 png_get_pixels_per_meter (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_voidp png_get_progressive_ptr (png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_uint_32 png_get_PLTE (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_colorp \fP\fI*palette\fP\fB, int \fI*num_palette\fP\fB);\fP + +\fI\fB + +\fBpng_byte png_get_rgb_to_gray_status (png_structp \fIpng_ptr) + +\fBpng_uint_32 png_get_rowbytes (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_bytepp png_get_rows (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_uint_32 png_get_sBIT (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_color_8p \fI*sig_bit\fP\fB);\fP + +\fI\fB + +\fBpng_bytep png_get_signature (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_uint_32 png_get_sPLT (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_spalette_p \fI*splt_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_uint_32 png_get_sRGB (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fI*intent\fP\fB);\fP + +\fI\fB + +\fBpng_uint_32 png_get_text (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_textp \fP\fI*text_ptr\fP\fB, int \fI*num_text\fP\fB);\fP + +\fI\fB + +\fBpng_uint_32 png_get_tIME (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_timep \fI*mod_time\fP\fB);\fP + +\fI\fB + +\fBpng_uint_32 png_get_tRNS (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_bytep \fP\fI*trans\fP\fB, int \fP\fI*num_trans\fP\fB, png_color_16p \fI*trans_values\fP\fB);\fP + +\fI\fB + +\fBpng_uint_32 png_get_unknown_chunks (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_unknown_chunkpp \fIunknowns\fP\fB);\fP + +\fI\fB + +\fBpng_voidp png_get_user_chunk_ptr (png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_uint_32 png_get_user_height_max( png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_voidp png_get_user_transform_ptr (png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_uint_32 png_get_user_width_max (png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_uint_32 png_get_valid (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIflag\fP\fB);\fP + +\fI\fB + +\fBpng_int_32 png_get_x_offset_microns (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_int_32 png_get_x_offset_pixels (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_uint_32 png_get_x_pixels_per_meter (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_int_32 png_get_y_offset_microns (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_int_32 png_get_y_offset_pixels (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_uint_32 png_get_y_pixels_per_meter (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_uint_32 png_get_compression_buffer_size (png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBint png_handle_as_unknown (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fIchunk_name\fP\fB);\fP + +\fI\fB + +\fBvoid png_init_io (png_structp \fP\fIpng_ptr\fP\fB, FILE \fI*fp\fP\fB);\fP + +\fI\fB + +\fBDEPRECATED: void png_info_init (png_infop \fIinfo_ptr\fP\fB);\fP + +\fI\fB + +\fBDEPRECATED: void png_info_init_2 (png_infopp \fP\fIptr_ptr\fP\fB, png_size_t \fIpng_info_struct_size\fP\fB);\fP + +\fI\fB + +\fBpng_voidp png_malloc (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fIsize\fP\fB);\fP + +\fI\fB + +\fBpng_voidp png_malloc_default(png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fIsize\fP\fB);\fP + +\fI\fB + +\fBvoidp png_memcpy (png_voidp \fP\fIs1\fP\fB, png_voidp \fP\fIs2\fP\fB, png_size_t \fIsize\fP\fB);\fP + +\fI\fB + +\fBpng_voidp png_memcpy_check (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIs1\fP\fB, png_voidp \fP\fIs2\fP\fB, png_uint_32 \fIsize\fP\fB);\fP + +\fI\fB + +\fBvoidp png_memset (png_voidp \fP\fIs1\fP\fB, int \fP\fIvalue\fP\fB, png_size_t \fIsize\fP\fB);\fP + +\fI\fB + +\fBpng_voidp png_memset_check (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIs1\fP\fB, int \fP\fIvalue\fP\fB, png_uint_32 \fIsize\fP\fB);\fP + +\fI\fB + +\fBDEPRECATED: void png_permit_empty_plte (png_structp \fP\fIpng_ptr\fP\fB, int \fIempty_plte_permitted\fP\fB);\fP + +\fI\fB + +\fBvoid png_process_data (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_bytep \fP\fIbuffer\fP\fB, png_size_t \fIbuffer_size\fP\fB);\fP + +\fI\fB + +\fBvoid png_progressive_combine_row (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIold_row\fP\fB, png_bytep \fInew_row\fP\fB);\fP + +\fI\fB + +\fBvoid png_read_destroy (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_infop \fIend_info_ptr\fP\fB);\fP + +\fI\fB + +\fBvoid png_read_end (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fI\fB + +\fBvoid png_read_image (png_structp \fP\fIpng_ptr\fP\fB, png_bytepp \fIimage\fP\fB);\fP + +\fI\fB + +\fBDEPRECATED: void png_read_init (png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBDEPRECATED: void png_read_init_2 (png_structpp \fP\fIptr_ptr\fP\fB, png_const_charp \fP\fIuser_png_ver\fP\fB, png_size_t \fP\fIpng_struct_size\fP\fB, png_size_t \fIpng_info_size\fP\fB);\fP + +\fI\fB + +\fBvoid png_read_info (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fI\fB + +\fBvoid png_read_png (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fP\fItransforms\fP\fB, png_voidp \fIparams\fP\fB);\fP + +\fI\fB + +\fBvoid png_read_row (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIrow\fP\fB, png_bytep \fIdisplay_row\fP\fB);\fP + +\fI\fB + +\fBvoid png_read_rows (png_structp \fP\fIpng_ptr\fP\fB, png_bytepp \fP\fIrow\fP\fB, png_bytepp \fP\fIdisplay_row\fP\fB, png_uint_32 \fInum_rows\fP\fB);\fP + +\fI\fB + +\fBvoid png_read_update_info (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fI\fB + +\fB#if \fI!defined(PNG_1_0_X) + +\fBvoid png_set_add_alpha (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIfiller\fP\fB, int \fIflags\fP\fB);\fP + +\fI\fB#endif + +\fI\fB + +\fBvoid png_set_background (png_structp \fP\fIpng_ptr\fP\fB, png_color_16p \fP\fIbackground_color\fP\fB, int \fP\fIbackground_gamma_code\fP\fB, int \fP\fIneed_expand\fP\fB, double \fIbackground_gamma\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_bgr (png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_bKGD (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_color_16p \fIbackground\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_cHRM (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, double \fP\fIwhite_x\fP\fB, double \fP\fIwhite_y\fP\fB, double \fP\fIred_x\fP\fB, double \fP\fIred_y\fP\fB, double \fP\fIgreen_x\fP\fB, double \fP\fIgreen_y\fP\fB, double \fP\fIblue_x\fP\fB, double \fIblue_y\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_cHRM_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fIwhite_x\fP\fB, png_uint_32 \fP\fIwhite_y\fP\fB, png_uint_32 \fP\fIred_x\fP\fB, png_uint_32 \fP\fIred_y\fP\fB, png_uint_32 \fP\fIgreen_x\fP\fB, png_uint_32 \fP\fIgreen_y\fP\fB, png_uint_32 \fP\fIblue_x\fP\fB, png_uint_32 \fIblue_y\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_compression_level (png_structp \fP\fIpng_ptr\fP\fB, int \fIlevel\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_compression_mem_level (png_structp \fP\fIpng_ptr\fP\fB, int \fImem_level\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_compression_method (png_structp \fP\fIpng_ptr\fP\fB, int \fImethod\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_compression_strategy (png_structp \fP\fIpng_ptr\fP\fB, int \fIstrategy\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_compression_window_bits (png_structp \fP\fIpng_ptr\fP\fB, int \fIwindow_bits\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_crc_action (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIcrit_action\fP\fB, int \fIancil_action\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_dither (png_structp \fP\fIpng_ptr\fP\fB, png_colorp \fP\fIpalette\fP\fB, int \fP\fInum_palette\fP\fB, int \fP\fImaximum_colors\fP\fB, png_uint_16p \fP\fIhistogram\fP\fB, int \fIfull_dither\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_error_fn (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIerror_ptr\fP\fB, png_error_ptr \fP\fIerror_fn\fP\fB, png_error_ptr \fIwarning_fn\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_expand (png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_filler (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIfiller\fP\fB, int \fIflags\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_filter (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fImethod\fP\fB, int \fIfilters\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_filter_heuristics (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIheuristic_method\fP\fB, int \fP\fInum_weights\fP\fB, png_doublep \fP\fIfilter_weights\fP\fB, png_doublep \fIfilter_costs\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_flush (png_structp \fP\fIpng_ptr\fP\fB, int \fInrows\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_gamma (png_structp \fP\fIpng_ptr\fP\fB, double \fP\fIscreen_gamma\fP\fB, double \fIdefault_file_gamma\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_gAMA (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, double \fIfile_gamma\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_gAMA_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIfile_gamma\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_gray_1_2_4_to_8(png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_gray_to_rgb (png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_hIST (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_16p \fIhist\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_iCCP (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_charp \fP\fIname\fP\fB, int \fP\fIcompression_type\fP\fB, png_charp \fP\fIprofile\fP\fB, png_uint_32 \fIproflen\fP\fB);\fP + +\fI\fB + +\fBint png_set_interlace_handling (png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_invalid (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fImask\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_invert_alpha (png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_invert_mono (png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_IHDR (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fIwidth\fP\fB, png_uint_32 \fP\fIheight\fP\fB, int \fP\fIbit_depth\fP\fB, int \fP\fIcolor_type\fP\fB, int \fP\fIinterlace_type\fP\fB, int \fP\fIcompression_type\fP\fB, int \fIfilter_type\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_keep_unknown_chunks (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIkeep\fP\fB, png_bytep \fP\fIchunk_list\fP\fB, int \fInum_chunks\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_mem_fn(png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fImem_ptr\fP\fB, png_malloc_ptr \fP\fImalloc_fn\fP\fB, png_free_ptr \fIfree_fn\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_oFFs (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fIoffset_x\fP\fB, png_uint_32 \fP\fIoffset_y\fP\fB, int \fIunit_type\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_packing (png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_packswap (png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_palette_to_rgb(png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_pCAL (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_charp \fP\fIpurpose\fP\fB, png_int_32 \fP\fIX0\fP\fB, png_int_32 \fP\fIX1\fP\fB, int \fP\fItype\fP\fB, int \fP\fInparams\fP\fB, png_charp \fP\fIunits\fP\fB, png_charpp \fIparams\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_pHYs (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fIres_x\fP\fB, png_uint_32 \fP\fIres_y\fP\fB, int \fIunit_type\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_progressive_read_fn (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIprogressive_ptr\fP\fB, png_progressive_info_ptr \fP\fIinfo_fn\fP\fB, png_progressive_row_ptr \fP\fIrow_fn\fP\fB, png_progressive_end_ptr \fIend_fn\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_PLTE (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_colorp \fP\fIpalette\fP\fB, int \fInum_palette\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_read_fn (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIio_ptr\fP\fB, png_rw_ptr \fIread_data_fn\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_read_status_fn (png_structp \fP\fIpng_ptr\fP\fB, png_read_status_ptr \fIread_row_fn\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_read_user_transform_fn (png_structp \fP\fIpng_ptr\fP\fB, png_user_transform_ptr \fIread_user_transform_fn\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_rgb_to_gray (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIerror_action\fP\fB, double \fP\fIred\fP\fB, double \fIgreen\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_rgb_to_gray_fixed (png_structp \fP\fIpng_ptr\fP\fB, int error_action png_fixed_point \fP\fIred\fP\fB, png_fixed_point \fIgreen\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_rows (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_bytepp \fIrow_pointers\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_sBIT (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_color_8p \fIsig_bit\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_sCAL (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_charp \fP\fIunit\fP\fB, double \fP\fIwidth\fP\fB, double \fIheight\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_shift (png_structp \fP\fIpng_ptr\fP\fB, png_color_8p \fItrue_bits\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_sig_bytes (png_structp \fP\fIpng_ptr\fP\fB, int \fInum_bytes\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_sPLT (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_spalette_p \fP\fIsplt_ptr\fP\fB, int \fInum_spalettes\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_sRGB (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fIintent\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_sRGB_gAMA_and_cHRM (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fIintent\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_strip_16 (png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_strip_alpha (png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_swap (png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_swap_alpha (png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_text (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_textp \fP\fItext_ptr\fP\fB, int \fInum_text\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_tIME (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_timep \fImod_time\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_tRNS (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_bytep \fP\fItrans\fP\fB, int \fP\fInum_trans\fP\fB, png_color_16p \fItrans_values\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_tRNS_to_alpha(png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBpng_uint_32 png_set_unknown_chunks (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_unknown_chunkp \fP\fIunknowns\fP\fB, int \fP\fInum\fP\fB, int \fIlocation\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_unknown_chunk_location(png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fP\fIchunk\fP\fB, int \fIlocation\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_read_user_chunk_fn (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIuser_chunk_ptr\fP\fB, png_user_chunk_ptr \fIread_user_chunk_fn\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_user_limits (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIuser_width_max\fP\fB, png_uint_32 \fIuser_height_max\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_user_transform_info (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIuser_transform_ptr\fP\fB, int \fP\fIuser_transform_depth\fP\fB, int \fIuser_transform_channels\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_write_fn (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIio_ptr\fP\fB, png_rw_ptr \fP\fIwrite_data_fn\fP\fB, png_flush_ptr \fIoutput_flush_fn\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_write_status_fn (png_structp \fP\fIpng_ptr\fP\fB, png_write_status_ptr \fIwrite_row_fn\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_write_user_transform_fn (png_structp \fP\fIpng_ptr\fP\fB, png_user_transform_ptr \fIwrite_user_transform_fn\fP\fB);\fP + +\fI\fB + +\fBvoid png_set_compression_buffer_size(png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fIsize\fP\fB);\fP + +\fI\fB + +\fBint png_sig_cmp (png_bytep \fP\fIsig\fP\fB, png_size_t \fP\fIstart\fP\fB, png_size_t \fInum_to_check\fP\fB);\fP + +\fI\fB + +\fBvoid png_start_read_image (png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBvoid png_warning (png_structp \fP\fIpng_ptr\fP\fB, png_const_charp \fImessage\fP\fB);\fP + +\fI\fB + +\fBvoid png_write_chunk (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIchunk_name\fP\fB, png_bytep \fP\fIdata\fP\fB, png_size_t \fIlength\fP\fB);\fP + +\fI\fB + +\fBvoid png_write_chunk_data (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIdata\fP\fB, png_size_t \fIlength\fP\fB);\fP + +\fI\fB + +\fBvoid png_write_chunk_end (png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBvoid png_write_chunk_start (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIchunk_name\fP\fB, png_uint_32 \fIlength\fP\fB);\fP + +\fI\fB + +\fBvoid png_write_destroy (png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBvoid png_write_end (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fI\fB + +\fBvoid png_write_flush (png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBvoid png_write_image (png_structp \fP\fIpng_ptr\fP\fB, png_bytepp \fIimage\fP\fB);\fP + +\fI\fB + +\fBDEPRECATED: void png_write_init (png_structp \fIpng_ptr\fP\fB);\fP + +\fI\fB + +\fBDEPRECATED: void png_write_init_2 (png_structpp \fP\fIptr_ptr\fP\fB, png_const_charp \fP\fIuser_png_ver\fP\fB, png_size_t \fP\fIpng_struct_size\fP\fB, png_size_t \fIpng_info_size\fP\fB);\fP + +\fI\fB + +\fBvoid png_write_info (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fI\fB + +\fBvoid png_write_info_before_PLTE (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fI\fB + +\fBvoid png_write_png (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fP\fItransforms\fP\fB, png_voidp \fIparams\fP\fB);\fP + +\fI\fB + +\fBvoid png_write_row (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fIrow\fP\fB);\fP + +\fI\fB + +\fBvoid png_write_rows (png_structp \fP\fIpng_ptr\fP\fB, png_bytepp \fP\fIrow\fP\fB, png_uint_32 \fInum_rows\fP\fB);\fP + +\fI\fB + +\fBvoidpf png_zalloc (voidpf \fP\fIpng_ptr\fP\fB, uInt \fP\fIitems\fP\fB, uInt \fIsize\fP\fB);\fP + +\fI\fB + +\fBvoid png_zfree (voidpf \fP\fIpng_ptr\fP\fB, voidpf \fIptr\fP\fB);\fP + +\fI\fB + +.SH DESCRIPTION +The +.I libpng +library supports encoding, decoding, and various manipulations of +the Portable Network Graphics (PNG) format image files. It uses the +.IR zlib(3) +compression library. +Following is a copy of the libpng.txt file that accompanies libpng. +.SH LIBPNG.TXT +libpng.txt - A description on how to use and modify libpng + + libpng version 1.2.8 - December 3, 2004 + Updated and distributed by Glenn Randers-Pehrson + <glennrp at users.sourceforge.net> + Copyright (c) 1998-2004 Glenn Randers-Pehrson + For conditions of distribution and use, see copyright + notice in png.h. + + based on: + + libpng 1.0 beta 6 version 0.96 May 28, 1997 + Updated and distributed by Andreas Dilger + Copyright (c) 1996, 1997 Andreas Dilger + + libpng 1.0 beta 2 - version 0.88 January 26, 1996 + For conditions of distribution and use, see copyright + notice in png.h. Copyright (c) 1995, 1996 Guy Eric + Schalnat, Group 42, Inc. + + Updated/rewritten per request in the libpng FAQ + Copyright (c) 1995, 1996 Frank J. T. Wojcik + December 18, 1995 & January 20, 1996 + +.SH I. Introduction + +This file describes how to use and modify the PNG reference library +(known as libpng) for your own use. There are five sections to this +file: introduction, structures, reading, writing, and modification and +configuration notes for various special platforms. In addition to this +file, example.c is a good starting point for using the library, as +it is heavily commented and should include everything most people +will need. We assume that libpng is already installed; see the +INSTALL file for instructions on how to install libpng. + +Libpng was written as a companion to the PNG specification, as a way +of reducing the amount of time and effort it takes to support the PNG +file format in application programs. + +The PNG specification (second edition), November 2003, is available as +a W3C Recommendation and as an ISO Standard (ISO/IEC 15948:2003 (E)) at +<http://www.w3.org/TR/2003/REC-PNG-20031110/ +The W3C and ISO documents have identical technical content. + +The PNG-1.2 specification is available at +<http://www.libpng.org/pub/png/documents/> + +The PNG-1.0 specification is available +as RFC 2083 <http://www.libpng.org/pub/png/documents/> and as a +W3C Recommendation <http://www.w3.org/TR/REC.png.html>. Some +additional chunks are described in the special-purpose public chunks +documents at <http://www.libpng.org/pub/png/documents/>. + +Other information +about PNG, and the latest version of libpng, can be found at the PNG home +page, <http://www.libpng.org/pub/png/>. + +Most users will not have to modify the library significantly; advanced +users may want to modify it more. All attempts were made to make it as +complete as possible, while keeping the code easy to understand. +Currently, this library only supports C. Support for other languages +is being considered. + +Libpng has been designed to handle multiple sessions at one time, +to be easily modifiable, to be portable to the vast majority of +machines (ANSI, K&R, 16-, 32-, and 64-bit) available, and to be easy +to use. The ultimate goal of libpng is to promote the acceptance of +the PNG file format in whatever way possible. While there is still +work to be done (see the TODO file), libpng should cover the +majority of the needs of its users. + +Libpng uses zlib for its compression and decompression of PNG files. +Further information about zlib, and the latest version of zlib, can +be found at the zlib home page, <http://www.info-zip.org/pub/infozip/zlib/>. +The zlib compression utility is a general purpose utility that is +useful for more than PNG files, and can be used without libpng. +See the documentation delivered with zlib for more details. +You can usually find the source files for the zlib utility wherever you +find the libpng source files. + +Libpng is thread safe, provided the threads are using different +instances of the structures. Each thread should have its own +png_struct and png_info instances, and thus its own image. +Libpng does not protect itself against two threads using the +same instance of a structure. Note: thread safety may be defeated +by use of some of the MMX assembler code in pnggccrd.c, which is only +compiled when the user defines PNG_THREAD_UNSAFE_OK. + +.SH II. Structures + +There are two main structures that are important to libpng, png_struct +and png_info. The first, png_struct, is an internal structure that +will not, for the most part, be used by a user except as the first +variable passed to every libpng function call. + +The png_info structure is designed to provide information about the +PNG file. At one time, the fields of png_info were intended to be +directly accessible to the user. However, this tended to cause problems +with applications using dynamically loaded libraries, and as a result +a set of interface functions for png_info (the png_get_*() and png_set_*() +functions) was developed. The fields of png_info are still available for +older applications, but it is suggested that applications use the new +interfaces if at all possible. + +Applications that do make direct access to the members of png_struct (except +for png_ptr->jmpbuf) must be recompiled whenever the library is updated, +and applications that make direct access to the members of png_info must +be recompiled if they were compiled or loaded with libpng version 1.0.6, +in which the members were in a different order. In version 1.0.7, the +members of the png_info structure reverted to the old order, as they were +in versions 0.97c through 1.0.5. Starting with version 2.0.0, both +structures are going to be hidden, and the contents of the structures will +only be accessible through the png_get/png_set functions. + +The png.h header file is an invaluable reference for programming with libpng. +And while I'm on the topic, make sure you include the libpng header file: + +#include <png.h> + +.SH III. Reading + +We'll now walk you through the possible functions to call when reading +in a PNG file sequentially, briefly explaining the syntax and purpose +of each one. See example.c and png.h for more detail. While +progressive reading is covered in the next section, you will still +need some of the functions discussed in this section to read a PNG +file. + +.SS Setup + +You will want to do the I/O initialization(*) before you get into libpng, +so if it doesn't work, you don't have much to undo. Of course, you +will also want to insure that you are, in fact, dealing with a PNG +file. Libpng provides a simple check to see if a file is a PNG file. +To use it, pass in the first 1 to 8 bytes of the file to the function +png_sig_cmp(), and it will return 0 if the bytes match the corresponding +bytes of the PNG signature, or nonzero otherwise. Of course, the more bytes +you pass in, the greater the accuracy of the prediction. + +If you are intending to keep the file pointer open for use in libpng, +you must ensure you don't read more than 8 bytes from the beginning +of the file, and you also have to make a call to png_set_sig_bytes_read() +with the number of bytes you read from the beginning. Libpng will +then only check the bytes (if any) that your program didn't read. + +(*): If you are not using the standard I/O functions, you will need +to replace them with custom functions. See the discussion under +Customizing libpng. + + + FILE *fp = fopen(file_name, "rb"); + if (!fp) + { + return (ERROR); + } + fread(header, 1, number, fp); + is_png = !png_sig_cmp(header, 0, number); + if (!is_png) + { + return (NOT_PNG); + } + + +Next, png_struct and png_info need to be allocated and initialized. In +order to ensure that the size of these structures is correct even with a +dynamically linked libpng, there are functions to initialize and +allocate the structures. We also pass the library version, optional +pointers to error handling functions, and a pointer to a data struct for +use by the error functions, if necessary (the pointer and functions can +be NULL if the default error handlers are to be used). See the section +on Changes to Libpng below regarding the old initialization functions. +The structure allocation functions quietly return NULL if they fail to +create the structure, so your application should check for that. + + png_structp png_ptr = png_create_read_struct + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn); + if (!png_ptr) + return (ERROR); + + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_read_struct(&png_ptr, + (png_infopp)NULL, (png_infopp)NULL); + return (ERROR); + } + + png_infop end_info = png_create_info_struct(png_ptr); + if (!end_info) + { + png_destroy_read_struct(&png_ptr, &info_ptr, + (png_infopp)NULL); + return (ERROR); + } + +If you want to use your own memory allocation routines, +define PNG_USER_MEM_SUPPORTED and use +png_create_read_struct_2() instead of png_create_read_struct(): + + png_structp png_ptr = png_create_read_struct_2 + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn, (png_voidp) + user_mem_ptr, user_malloc_fn, user_free_fn); + +The error handling routines passed to png_create_read_struct() +and the memory alloc/free routines passed to png_create_struct_2() +are only necessary if you are not using the libpng supplied error +handling and memory alloc/free functions. + +When libpng encounters an error, it expects to longjmp back +to your routine. Therefore, you will need to call setjmp and pass +your png_jmpbuf(png_ptr). If you read the file from different +routines, you will need to update the jmpbuf field every time you enter +a new routine that will call a png_*() function. + +See your documentation of setjmp/longjmp for your compiler for more +information on setjmp/longjmp. See the discussion on libpng error +handling in the Customizing Libpng section below for more information +on the libpng error handling. If an error occurs, and libpng longjmp's +back to your setjmp, you will want to call png_destroy_read_struct() to +free any memory. + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, + &end_info); + fclose(fp); + return (ERROR); + } + +If you would rather avoid the complexity of setjmp/longjmp issues, +you can compile libpng with PNG_SETJMP_NOT_SUPPORTED, in which case +errors will result in a call to PNG_ABORT() which defaults to abort(). + +Now you need to set up the input code. The default for libpng is to +use the C function fread(). If you use this, you will need to pass a +valid FILE * in the function png_init_io(). Be sure that the file is +opened in binary mode. If you wish to handle reading data in another +way, you need not call the png_init_io() function, but you must then +implement the libpng I/O methods discussed in the Customizing Libpng +section below. + + png_init_io(png_ptr, fp); + +If you had previously opened the file and read any of the signature from +the beginning in order to see if this was a PNG file, you need to let +libpng know that there are some bytes missing from the start of the file. + + png_set_sig_bytes(png_ptr, number); + +.SS Setting up callback code + +You can set up a callback function to handle any unknown chunks in the +input stream. You must supply the function + + read_chunk_callback(png_ptr ptr, + png_unknown_chunkp chunk); + { + /* The unknown chunk structure contains your + chunk data: */ + png_byte name[5]; + png_byte *data; + png_size_t size; + /* Note that libpng has already taken care of + the CRC handling */ + + /* put your code here. Return one of the + following: */ + + return (-n); /* chunk had an error */ + return (0); /* did not recognize */ + return (n); /* success */ + } + +(You can give your function another name that you like instead of +"read_chunk_callback") + +To inform libpng about your function, use + + png_set_read_user_chunk_fn(png_ptr, user_chunk_ptr, + read_chunk_callback); + +This names not only the callback function, but also a user pointer that +you can retrieve with + + png_get_user_chunk_ptr(png_ptr); + +At this point, you can set up a callback function that will be +called after each row has been read, which you can use to control +a progress meter or the like. It's demonstrated in pngtest.c. +You must supply a function + + void read_row_callback(png_ptr ptr, png_uint_32 row, + int pass); + { + /* put your code here */ + } + +(You can give it another name that you like instead of "read_row_callback") + +To inform libpng about your function, use + + png_set_read_status_fn(png_ptr, read_row_callback); + +.SS Width and height limits + +The PNG specification allows the width and height of an image to be as +large as 2^31-1 (0x7fffffff), or about 2.147 billion rows and columns. +Since very few applications really need to process such large images, +we have imposed an arbitrary 1-million limit on rows and columns. +Larger images will be rejected immediately with a png_error() call. If +you wish to override this limit, you can use + + png_set_user_limits(png_ptr, width_max, height_max); + +to set your own limits, or use width_max = height_max = 0x7fffffffL +to allow all valid dimensions (libpng may reject some very large images +anyway because of potential buffer overflow conditions). + +You should put this statement after you create the PNG structure and +before calling png_read_info(), png_read_png(), or png_process_data(). +If you need to retrieve the limits that are being applied, use + + width_max = png_get_user_width_max(png_ptr); + height_max = png_get_user_height_max(png_ptr); + +.SS Unknown-chunk handling + +Now you get to set the way the library processes unknown chunks in the +input PNG stream. Both known and unknown chunks will be read. Normal +behavior is that known chunks will be parsed into information in +various info_ptr members; unknown chunks will be discarded. To change +this, you can call: + + png_set_keep_unknown_chunks(png_ptr, keep, + chunk_list, num_chunks); + keep - 0: do not handle as unknown + 1: do not keep + 2: keep only if safe-to-copy + 3: keep even if unsafe-to-copy + You can use these definitions: + PNG_HANDLE_CHUNK_AS_DEFAULT 0 + PNG_HANDLE_CHUNK_NEVER 1 + PNG_HANDLE_CHUNK_IF_SAFE 2 + PNG_HANDLE_CHUNK_ALWAYS 3 + chunk_list - list of chunks affected (a byte string, + five bytes per chunk, NULL or '\0' if + num_chunks is 0) + num_chunks - number of chunks affected; if 0, all + unknown chunks are affected. If nonzero, + only the chunks in the list are affected + +Unknown chunks declared in this way will be saved as raw data onto a +list of png_unknown_chunk structures. If a chunk that is normally +known to libpng is named in the list, it will be handled as unknown, +according to the "keep" directive. If a chunk is named in successive +instances of png_set_keep_unknown_chunks(), the final instance will +take precedence. The IHDR and IEND chunks should not be named in +chunk_list; if they are, libpng will process them normally anyway. + +.SS The high-level read interface + +At this point there are two ways to proceed; through the high-level +read interface, or through a sequence of low-level read operations. +You can use the high-level interface if (a) you are willing to read +the entire image into memory, and (b) the input transformations +you want to do are limited to the following set: + + PNG_TRANSFORM_IDENTITY No transformation + PNG_TRANSFORM_STRIP_16 Strip 16-bit samples to + 8 bits + PNG_TRANSFORM_STRIP_ALPHA Discard the alpha channel + PNG_TRANSFORM_PACKING Expand 1, 2 and 4-bit + samples to bytes + PNG_TRANSFORM_PACKSWAP Change order of packed + pixels to LSB first + PNG_TRANSFORM_EXPAND Perform set_expand() + PNG_TRANSFORM_INVERT_MONO Invert monochrome images + PNG_TRANSFORM_SHIFT Normalize pixels to the + sBIT depth + PNG_TRANSFORM_BGR Flip RGB to BGR, RGBA + to BGRA + PNG_TRANSFORM_SWAP_ALPHA Flip RGBA to ARGB or GA + to AG + PNG_TRANSFORM_INVERT_ALPHA Change alpha from opacity + to transparency + PNG_TRANSFORM_SWAP_ENDIAN Byte-swap 16-bit samples + +(This excludes setting a background color, doing gamma transformation, +dithering, and setting filler.) If this is the case, simply do this: + + png_read_png(png_ptr, info_ptr, png_transforms, NULL) + +where png_transforms is an integer containing the logical OR of +some set of transformation flags. This call is equivalent to png_read_info(), +followed the set of transformations indicated by the transform mask, +then png_read_image(), and finally png_read_end(). + +(The final parameter of this call is not yet used. Someday it might point +to transformation parameters required by some future input transform.) + +You must use png_transforms and not call any png_set_transform() functions +when you use png_read_png(). + +After you have called png_read_png(), you can retrieve the image data +with + + row_pointers = png_get_rows(png_ptr, info_ptr); + +where row_pointers is an array of pointers to the pixel data for each row: + + png_bytep row_pointers[height]; + +If you know your image size and pixel size ahead of time, you can allocate +row_pointers prior to calling png_read_png() with + + if (height > PNG_UINT_32_MAX/png_sizeof(png_byte)) + png_error (png_ptr, + "Image is too tall to process in memory"); + if (width > PNG_UINT_32_MAX/pixel_size) + png_error (png_ptr, + "Image is too wide to process in memory"); + row_pointers = png_malloc(png_ptr, + height*png_sizeof(png_bytep)); + for (int i=0; i<height, i++) + row_pointers[i]=png_malloc(png_ptr, + width*pixel_size); + png_set_rows(png_ptr, info_ptr, &row_pointers); + +Alternatively you could allocate your image in one big block and define +row_pointers[i] to point into the proper places in your block. + +If you use png_set_rows(), the application is responsible for freeing +row_pointers (and row_pointers[i], if they were separately allocated). + +If you don't allocate row_pointers ahead of time, png_read_png() will +do it, and it'll be free'ed when you call png_destroy_*(). + +.SS The low-level read interface + +If you are going the low-level route, you are now ready to read all +the file information up to the actual image data. You do this with a +call to png_read_info(). + + png_read_info(png_ptr, info_ptr); + +This will process all chunks up to but not including the image data. + +.SS Querying the info structure + +Functions are used to get the information from the info_ptr once it +has been read. Note that these fields may not be completely filled +in until png_read_end() has read the chunk data following the image. + + png_get_IHDR(png_ptr, info_ptr, &width, &height, + &bit_depth, &color_type, &interlace_type, + &compression_type, &filter_method); + + width - holds the width of the image + in pixels (up to 2^31). + height - holds the height of the image + in pixels (up to 2^31). + bit_depth - holds the bit depth of one of the + image channels. (valid values are + 1, 2, 4, 8, 16 and depend also on + the color_type. See also + significant bits (sBIT) below). + color_type - describes which color/alpha channels + are present. + PNG_COLOR_TYPE_GRAY + (bit depths 1, 2, 4, 8, 16) + PNG_COLOR_TYPE_GRAY_ALPHA + (bit depths 8, 16) + PNG_COLOR_TYPE_PALETTE + (bit depths 1, 2, 4, 8) + PNG_COLOR_TYPE_RGB + (bit_depths 8, 16) + PNG_COLOR_TYPE_RGB_ALPHA + (bit_depths 8, 16) + + PNG_COLOR_MASK_PALETTE + PNG_COLOR_MASK_COLOR + PNG_COLOR_MASK_ALPHA + + filter_method - (must be PNG_FILTER_TYPE_BASE + for PNG 1.0, and can also be + PNG_INTRAPIXEL_DIFFERENCING if + the PNG datastream is embedded in + a MNG-1.0 datastream) + compression_type - (must be PNG_COMPRESSION_TYPE_BASE + for PNG 1.0) + interlace_type - (PNG_INTERLACE_NONE or + PNG_INTERLACE_ADAM7) + Any or all of interlace_type, compression_type, of + filter_method can be NULL if you are + not interested in their values. + + channels = png_get_channels(png_ptr, info_ptr); + channels - number of channels of info for the + color type (valid values are 1 (GRAY, + PALETTE), 2 (GRAY_ALPHA), 3 (RGB), + 4 (RGB_ALPHA or RGB + filler byte)) + rowbytes = png_get_rowbytes(png_ptr, info_ptr); + rowbytes - number of bytes needed to hold a row + + signature = png_get_signature(png_ptr, info_ptr); + signature - holds the signature read from the + file (if any). The data is kept in + the same offset it would be if the + whole signature were read (i.e. if an + application had already read in 4 + bytes of signature before starting + libpng, the remaining 4 bytes would + be in signature[4] through signature[7] + (see png_set_sig_bytes())). + + + width = png_get_image_width(png_ptr, + info_ptr); + height = png_get_image_height(png_ptr, + info_ptr); + bit_depth = png_get_bit_depth(png_ptr, + info_ptr); + color_type = png_get_color_type(png_ptr, + info_ptr); + filter_method = png_get_filter_type(png_ptr, + info_ptr); + compression_type = png_get_compression_type(png_ptr, + info_ptr); + interlace_type = png_get_interlace_type(png_ptr, + info_ptr); + + +These are also important, but their validity depends on whether the chunk +has been read. The png_get_valid(png_ptr, info_ptr, PNG_INFO_<chunk>) and +png_get_<chunk>(png_ptr, info_ptr, ...) functions return non-zero if the +data has been read, or zero if it is missing. The parameters to the +png_get_<chunk> are set directly if they are simple data types, or a pointer +into the info_ptr is returned for any complex types. + + png_get_PLTE(png_ptr, info_ptr, &palette, + &num_palette); + palette - the palette for the file + (array of png_color) + num_palette - number of entries in the palette + + png_get_gAMA(png_ptr, info_ptr, &gamma); + gamma - the gamma the file is written + at (PNG_INFO_gAMA) + + png_get_sRGB(png_ptr, info_ptr, &srgb_intent); + srgb_intent - the rendering intent (PNG_INFO_sRGB) + The presence of the sRGB chunk + means that the pixel data is in the + sRGB color space. This chunk also + implies specific values of gAMA and + cHRM. + + png_get_iCCP(png_ptr, info_ptr, &name, + &compression_type, &profile, &proflen); + name - The profile name. + compression - The compression type; always + PNG_COMPRESSION_TYPE_BASE for PNG 1.0. + You may give NULL to this argument to + ignore it. + profile - International Color Consortium color + profile data. May contain NULs. + proflen - length of profile data in bytes. + + png_get_sBIT(png_ptr, info_ptr, &sig_bit); + sig_bit - the number of significant bits for + (PNG_INFO_sBIT) each of the gray, + red, green, and blue channels, + whichever are appropriate for the + given color type (png_color_16) + + png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, + &trans_values); + trans - array of transparent entries for + palette (PNG_INFO_tRNS) + trans_values - graylevel or color sample values of + the single transparent color for + non-paletted images (PNG_INFO_tRNS) + num_trans - number of transparent entries + (PNG_INFO_tRNS) + + png_get_hIST(png_ptr, info_ptr, &hist); + (PNG_INFO_hIST) + hist - histogram of palette (array of + png_uint_16) + + png_get_tIME(png_ptr, info_ptr, &mod_time); + mod_time - time image was last modified + (PNG_VALID_tIME) + + png_get_bKGD(png_ptr, info_ptr, &background); + background - background color (PNG_VALID_bKGD) + valid 16-bit red, green and blue + values, regardless of color_type + + num_comments = png_get_text(png_ptr, info_ptr, + &text_ptr, &num_text); + num_comments - number of comments + text_ptr - array of png_text holding image + comments + text_ptr[i].compression - type of compression used + on "text" PNG_TEXT_COMPRESSION_NONE + PNG_TEXT_COMPRESSION_zTXt + PNG_ITXT_COMPRESSION_NONE + PNG_ITXT_COMPRESSION_zTXt + text_ptr[i].key - keyword for comment. Must contain + 1-79 characters. + text_ptr[i].text - text comments for current + keyword. Can be empty. + text_ptr[i].text_length - length of text string, + after decompression, 0 for iTXt + text_ptr[i].itxt_length - length of itxt string, + after decompression, 0 for tEXt/zTXt + text_ptr[i].lang - language of comment (empty + string for unknown). + text_ptr[i].lang_key - keyword in UTF-8 + (empty string for unknown). + num_text - number of comments (same as + num_comments; you can put NULL here + to avoid the duplication) + Note while png_set_text() will accept text, language, + and translated keywords that can be NULL pointers, the + structure returned by png_get_text will always contain + regular zero-terminated C strings. They might be + empty strings but they will never be NULL pointers. + + num_spalettes = png_get_sPLT(png_ptr, info_ptr, + &palette_ptr); + palette_ptr - array of palette structures holding + contents of one or more sPLT chunks + read. + num_spalettes - number of sPLT chunks read. + + png_get_oFFs(png_ptr, info_ptr, &offset_x, &offset_y, + &unit_type); + offset_x - positive offset from the left edge + of the screen + offset_y - positive offset from the top edge + of the screen + unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER + + png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, + &unit_type); + res_x - pixels/unit physical resolution in + x direction + res_y - pixels/unit physical resolution in + x direction + unit_type - PNG_RESOLUTION_UNKNOWN, + PNG_RESOLUTION_METER + + png_get_sCAL(png_ptr, info_ptr, &unit, &width, + &height) + unit - physical scale units (an integer) + width - width of a pixel in physical scale units + height - height of a pixel in physical scale units + (width and height are doubles) + + png_get_sCAL_s(png_ptr, info_ptr, &unit, &width, + &height) + unit - physical scale units (an integer) + width - width of a pixel in physical scale units + height - height of a pixel in physical scale units + (width and height are strings like "2.54") + + num_unknown_chunks = png_get_unknown_chunks(png_ptr, + info_ptr, &unknowns) + unknowns - array of png_unknown_chunk + structures holding unknown chunks + unknowns[i].name - name of unknown chunk + unknowns[i].data - data of unknown chunk + unknowns[i].size - size of unknown chunk's data + unknowns[i].location - position of chunk in file + + The value of "i" corresponds to the order in which the + chunks were read from the PNG file or inserted with the + png_set_unknown_chunks() function. + +The data from the pHYs chunk can be retrieved in several convenient +forms: + + res_x = png_get_x_pixels_per_meter(png_ptr, + info_ptr) + res_y = png_get_y_pixels_per_meter(png_ptr, + info_ptr) + res_x_and_y = png_get_pixels_per_meter(png_ptr, + info_ptr) + res_x = png_get_x_pixels_per_inch(png_ptr, + info_ptr) + res_y = png_get_y_pixels_per_inch(png_ptr, + info_ptr) + res_x_and_y = png_get_pixels_per_inch(png_ptr, + info_ptr) + aspect_ratio = png_get_pixel_aspect_ratio(png_ptr, + info_ptr) + + (Each of these returns 0 [signifying "unknown"] if + the data is not present or if res_x is 0; + res_x_and_y is 0 if res_x != res_y) + +The data from the oFFs chunk can be retrieved in several convenient +forms: + + x_offset = png_get_x_offset_microns(png_ptr, info_ptr); + y_offset = png_get_y_offset_microns(png_ptr, info_ptr); + x_offset = png_get_x_offset_inches(png_ptr, info_ptr); + y_offset = png_get_y_offset_inches(png_ptr, info_ptr); + + (Each of these returns 0 [signifying "unknown" if both + x and y are 0] if the data is not present or if the + chunk is present but the unit is the pixel) + +For more information, see the png_info definition in png.h and the +PNG specification for chunk contents. Be careful with trusting +rowbytes, as some of the transformations could increase the space +needed to hold a row (expand, filler, gray_to_rgb, etc.). +See png_read_update_info(), below. + +A quick word about text_ptr and num_text. PNG stores comments in +keyword/text pairs, one pair per chunk, with no limit on the number +of text chunks, and a 2^31 byte limit on their size. While there are +suggested keywords, there is no requirement to restrict the use to these +strings. It is strongly suggested that keywords and text be sensible +to humans (that's the point), so don't use abbreviations. Non-printing +symbols are not allowed. See the PNG specification for more details. +There is also no requirement to have text after the keyword. + +Keywords should be limited to 79 Latin-1 characters without leading or +trailing spaces, but non-consecutive spaces are allowed within the +keyword. It is possible to have the same keyword any number of times. +The text_ptr is an array of png_text structures, each holding a +pointer to a language string, a pointer to a keyword and a pointer to +a text string. The text string, language code, and translated +keyword may be empty or NULL pointers. The keyword/text +pairs are put into the array in the order that they are received. +However, some or all of the text chunks may be after the image, so, to +make sure you have read all the text chunks, don't mess with these +until after you read the stuff after the image. This will be +mentioned again below in the discussion that goes with png_read_end(). + +.SS Input transformations + +After you've read the header information, you can set up the library +to handle any special transformations of the image data. The various +ways to transform the data will be described in the order that they +should occur. This is important, as some of these change the color +type and/or bit depth of the data, and some others only work on +certain color types and bit depths. Even though each transformation +checks to see if it has data that it can do something with, you should +make sure to only enable a transformation if it will be valid for the +data. For example, don't swap red and blue on grayscale data. + +The colors used for the background and transparency values should be +supplied in the same format/depth as the current image data. They +are stored in the same format/depth as the image data in a bKGD or tRNS +chunk, so this is what libpng expects for this data. The colors are +transformed to keep in sync with the image data when an application +calls the png_read_update_info() routine (see below). + +Data will be decoded into the supplied row buffers packed into bytes +unless the library has been told to transform it into another format. +For example, 4 bit/pixel paletted or grayscale data will be returned +2 pixels/byte with the leftmost pixel in the high-order bits of the +byte, unless png_set_packing() is called. 8-bit RGB data will be stored +in RGB RGB RGB format unless png_set_filler() or png_set_add_alpha() +is called to insert filler bytes, either before or after each RGB triplet. +16-bit RGB data will be returned RRGGBB RRGGBB, with the most significant +byte of the color value first, unless png_set_strip_16() is called to +transform it to regular RGB RGB triplets, or png_set_filler() or +png_set_add alpha() is called to insert filler bytes, either before or +after each RRGGBB triplet. Similarly, 8-bit or 16-bit grayscale data can +be modified with +png_set_filler(), png_set_add_alpha(), or png_set_strip_16(). + +The following code transforms grayscale images of less than 8 to 8 bits, +changes paletted images to RGB, and adds a full alpha channel if there is +transparency information in a tRNS chunk. This is most useful on +grayscale images with bit depths of 2 or 4 or if there is a multiple-image +viewing application that wishes to treat all images in the same way. + + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb(png_ptr); + + if (color_type == PNG_COLOR_TYPE_GRAY && + bit_depth < 8) png_set_gray_1_2_4_to_8(png_ptr); + + if (png_get_valid(png_ptr, info_ptr, + PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); + +These three functions are actually aliases for png_set_expand(), added +in libpng version 1.0.4, with the function names expanded to improve code +readability. In some future version they may actually do different +things. + +PNG can have files with 16 bits per channel. If you only can handle +8 bits per channel, this will strip the pixels down to 8 bit. + + if (bit_depth == 16) + png_set_strip_16(png_ptr); + +If, for some reason, you don't need the alpha channel on an image, +and you want to remove it rather than combining it with the background +(but the image author certainly had in mind that you *would* combine +it with the background, so that's what you should probably do): + + if (color_type & PNG_COLOR_MASK_ALPHA) + png_set_strip_alpha(png_ptr); + +In PNG files, the alpha channel in an image +is the level of opacity. If you need the alpha channel in an image to +be the level of transparency instead of opacity, you can invert the +alpha channel (or the tRNS chunk data) after it's read, so that 0 is +fully opaque and 255 (in 8-bit or paletted images) or 65535 (in 16-bit +images) is fully transparent, with + + png_set_invert_alpha(png_ptr); + +PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as +they can, resulting in, for example, 8 pixels per byte for 1 bit +files. This code expands to 1 pixel per byte without changing the +values of the pixels: + + if (bit_depth < 8) + png_set_packing(png_ptr); + +PNG files have possible bit depths of 1, 2, 4, 8, and 16. All pixels +stored in a PNG image have been "scaled" or "shifted" up to the next +higher possible bit depth (e.g. from 5 bits/sample in the range [0,31] to +8 bits/sample in the range [0, 255]). However, it is also possible to +convert the PNG pixel data back to the original bit depth of the image. +This call reduces the pixels back down to the original bit depth: + + png_color_8p sig_bit; + + if (png_get_sBIT(png_ptr, info_ptr, &sig_bit)) + png_set_shift(png_ptr, sig_bit); + +PNG files store 3-color pixels in red, green, blue order. This code +changes the storage of the pixels to blue, green, red: + + if (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) + png_set_bgr(png_ptr); + +PNG files store RGB pixels packed into 3 or 6 bytes. This code expands them +into 4 or 8 bytes for windowing systems that need them in this format: + + if (color_type == PNG_COLOR_TYPE_RGB) + png_set_filler(png_ptr, filler, PNG_FILLER_BEFORE); + +where "filler" is the 8 or 16-bit number to fill with, and the location is +either PNG_FILLER_BEFORE or PNG_FILLER_AFTER, depending upon whether +you want the filler before the RGB or after. This transformation +does not affect images that already have full alpha channels. To add an +opaque alpha channel, use filler=0xff or 0xffff and PNG_FILLER_AFTER which +will generate RGBA pixels. + +Note that png_set_filler() does not change the color type. If you want +to do that, you can add a true alpha channel with + + if (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_GRAY) + png_set_add_alpha(png_ptr, filler, PNG_FILLER_AFTER); + +where "filler" contains the alpha value to assign to each pixel. +This function was added in libpng-1.2.7. + +If you are reading an image with an alpha channel, and you need the +data as ARGB instead of the normal PNG format RGBA: + + if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) + png_set_swap_alpha(png_ptr); + +For some uses, you may want a grayscale image to be represented as +RGB. This code will do that conversion: + + if (color_type == PNG_COLOR_TYPE_GRAY || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(png_ptr); + +Conversely, you can convert an RGB or RGBA image to grayscale or grayscale +with alpha. + + if (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) + png_set_rgb_to_gray_fixed(png_ptr, error_action, + int red_weight, int green_weight); + + error_action = 1: silently do the conversion + error_action = 2: issue a warning if the original + image has any pixel where + red != green or red != blue + error_action = 3: issue an error and abort the + conversion if the original + image has any pixel where + red != green or red != blue + + red_weight: weight of red component times 100000 + green_weight: weight of green component times 100000 + If either weight is negative, default + weights (21268, 71514) are used. + +If you have set error_action = 1 or 2, you can +later check whether the image really was gray, after processing +the image rows, with the png_get_rgb_to_gray_status(png_ptr) function. +It will return a png_byte that is zero if the image was gray or +1 if there were any non-gray pixels. bKGD and sBIT data +will be silently converted to grayscale, using the green channel +data, regardless of the error_action setting. + +With red_weight+green_weight<=100000, +the normalized graylevel is computed: + + int rw = red_weight * 65536; + int gw = green_weight * 65536; + int bw = 65536 - (rw + gw); + gray = (rw*red + gw*green + bw*blue)/65536; + +The default values approximate those recommended in the Charles +Poynton's Color FAQ, <http://www.inforamp.net/~poynton/> +Copyright (c) 1998-01-04 Charles Poynton <poynton at inforamp.net> + + Y = 0.212671 * R + 0.715160 * G + 0.072169 * B + +Libpng approximates this with + + Y = 0.21268 * R + 0.7151 * G + 0.07217 * B + +which can be expressed with integers as + + Y = (6969 * R + 23434 * G + 2365 * B)/32768 + +The calculation is done in a linear colorspace, if the image gamma +is known. + +If you have a grayscale and you are using png_set_expand_depth(), +png_set_expand(), or png_set_gray_to_rgb to change to truecolor or to +a higher bit-depth, you must either supply the background color as a gray +value at the original file bit-depth (need_expand = 1) or else supply the +background color as an RGB triplet at the final, expanded bit depth +(need_expand = 0). Similarly, if you are reading a paletted image, you +must either supply the background color as a palette index (need_expand = 1) +or as an RGB triplet that may or may not be in the palette (need_expand = 0). + + png_color_16 my_background; + png_color_16p image_background; + + if (png_get_bKGD(png_ptr, info_ptr, &image_background)) + png_set_background(png_ptr, image_background, + PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); + else + png_set_background(png_ptr, &my_background, + PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); + +The png_set_background() function tells libpng to composite images +with alpha or simple transparency against the supplied background +color. If the PNG file contains a bKGD chunk (PNG_INFO_bKGD valid), +you may use this color, or supply another color more suitable for +the current display (e.g., the background color from a web page). You +need to tell libpng whether the color is in the gamma space of the +display (PNG_BACKGROUND_GAMMA_SCREEN for colors you supply), the file +(PNG_BACKGROUND_GAMMA_FILE for colors from the bKGD chunk), or one +that is neither of these gammas (PNG_BACKGROUND_GAMMA_UNIQUE - I don't +know why anyone would use this, but it's here). + +To properly display PNG images on any kind of system, the application needs +to know what the display gamma is. Ideally, the user will know this, and +the application will allow them to set it. One method of allowing the user +to set the display gamma separately for each system is to check for a +SCREEN_GAMMA or DISPLAY_GAMMA environment variable, which will hopefully be +correctly set. + +Note that display_gamma is the overall gamma correction required to produce +pleasing results, which depends on the lighting conditions in the surrounding +environment. In a dim or brightly lit room, no compensation other than +the physical gamma exponent of the monitor is needed, while in a dark room +a slightly smaller exponent is better. + + double gamma, screen_gamma; + + if (/* We have a user-defined screen + gamma value */) + { + screen_gamma = user_defined_screen_gamma; + } + /* One way that applications can share the same + screen gamma value */ + else if ((gamma_str = getenv("SCREEN_GAMMA")) + != NULL) + { + screen_gamma = (double)atof(gamma_str); + } + /* If we don't have another value */ + else + { + screen_gamma = 2.2; /* A good guess for a + PC monitor in a bright office or a dim room */ + screen_gamma = 2.0; /* A good guess for a + PC monitor in a dark room */ + screen_gamma = 1.7 or 1.0; /* A good + guess for Mac systems */ + } + +The png_set_gamma() function handles gamma transformations of the data. +Pass both the file gamma and the current screen_gamma. If the file does +not have a gamma value, you can pass one anyway if you have an idea what +it is (usually 0.45455 is a good guess for GIF images on PCs). Note +that file gammas are inverted from screen gammas. See the discussions +on gamma in the PNG specification for an excellent description of what +gamma is, and why all applications should support it. It is strongly +recommended that PNG viewers support gamma correction. + + if (png_get_gAMA(png_ptr, info_ptr, &gamma)) + png_set_gamma(png_ptr, screen_gamma, gamma); + else + png_set_gamma(png_ptr, screen_gamma, 0.45455); + +If you need to reduce an RGB file to a paletted file, or if a paletted +file has more entries then will fit on your screen, png_set_dither() +will do that. Note that this is a simple match dither that merely +finds the closest color available. This should work fairly well with +optimized palettes, and fairly badly with linear color cubes. If you +pass a palette that is larger then maximum_colors, the file will +reduce the number of colors in the palette so it will fit into +maximum_colors. If there is a histogram, it will use it to make +more intelligent choices when reducing the palette. If there is no +histogram, it may not do as good a job. + + if (color_type & PNG_COLOR_MASK_COLOR) + { + if (png_get_valid(png_ptr, info_ptr, + PNG_INFO_PLTE)) + { + png_uint_16p histogram = NULL; + + png_get_hIST(png_ptr, info_ptr, + &histogram); + png_set_dither(png_ptr, palette, num_palette, + max_screen_colors, histogram, 1); + } + else + { + png_color std_color_cube[MAX_SCREEN_COLORS] = + { ... colors ... }; + + png_set_dither(png_ptr, std_color_cube, + MAX_SCREEN_COLORS, MAX_SCREEN_COLORS, + NULL,0); + } + } + +PNG files describe monochrome as black being zero and white being one. +The following code will reverse this (make black be one and white be +zero): + + if (bit_depth == 1 && color_type == PNG_COLOR_TYPE_GRAY) + png_set_invert_mono(png_ptr); + +This function can also be used to invert grayscale and gray-alpha images: + + if (color_type == PNG_COLOR_TYPE_GRAY || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_invert_mono(png_ptr); + +PNG files store 16 bit pixels in network byte order (big-endian, +ie. most significant bits first). This code changes the storage to the +other way (little-endian, i.e. least significant bits first, the +way PCs store them): + + if (bit_depth == 16) + png_set_swap(png_ptr); + +If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you +need to change the order the pixels are packed into bytes, you can use: + + if (bit_depth < 8) + png_set_packswap(png_ptr); + +Finally, you can write your own transformation function if none of +the existing ones meets your needs. This is done by setting a callback +with + + png_set_read_user_transform_fn(png_ptr, + read_transform_fn); + +You must supply the function + + void read_transform_fn(png_ptr ptr, row_info_ptr + row_info, png_bytep data) + +See pngtest.c for a working example. Your function will be called +after all of the other transformations have been processed. + +You can also set up a pointer to a user structure for use by your +callback function, and you can inform libpng that your transform +function will change the number of channels or bit depth with the +function + + png_set_user_transform_info(png_ptr, user_ptr, + user_depth, user_channels); + +The user's application, not libpng, is responsible for allocating and +freeing any memory required for the user structure. + +You can retrieve the pointer via the function +png_get_user_transform_ptr(). For example: + + voidp read_user_transform_ptr = + png_get_user_transform_ptr(png_ptr); + +The last thing to handle is interlacing; this is covered in detail below, +but you must call the function here if you want libpng to handle expansion +of the interlaced image. + + number_of_passes = png_set_interlace_handling(png_ptr); + +After setting the transformations, libpng can update your png_info +structure to reflect any transformations you've requested with this +call. This is most useful to update the info structure's rowbytes +field so you can use it to allocate your image memory. This function +will also update your palette with the correct screen_gamma and +background if these have been given with the calls above. + + png_read_update_info(png_ptr, info_ptr); + +After you call png_read_update_info(), you can allocate any +memory you need to hold the image. The row data is simply +raw byte data for all forms of images. As the actual allocation +varies among applications, no example will be given. If you +are allocating one large chunk, you will need to build an +array of pointers to each row, as it will be needed for some +of the functions below. + +.SS Reading image data + +After you've allocated memory, you can read the image data. +The simplest way to do this is in one function call. If you are +allocating enough memory to hold the whole image, you can just +call png_read_image() and libpng will read in all the image data +and put it in the memory area supplied. You will need to pass in +an array of pointers to each row. + +This function automatically handles interlacing, so you don't need +to call png_set_interlace_handling() or call this function multiple +times, or any of that other stuff necessary with png_read_rows(). + + png_read_image(png_ptr, row_pointers); + +where row_pointers is: + + png_bytep row_pointers[height]; + +You can point to void or char or whatever you use for pixels. + +If you don't want to read in the whole image at once, you can +use png_read_rows() instead. If there is no interlacing (check +interlace_type == PNG_INTERLACE_NONE), this is simple: + + png_read_rows(png_ptr, row_pointers, NULL, + number_of_rows); + +where row_pointers is the same as in the png_read_image() call. + +If you are doing this just one row at a time, you can do this with +a single row_pointer instead of an array of row_pointers: + + png_bytep row_pointer = row; + png_read_row(png_ptr, row_pointer, NULL); + +If the file is interlaced (interlace_type != 0 in the IHDR chunk), things +get somewhat harder. The only current (PNG Specification version 1.2) +interlacing type for PNG is (interlace_type == PNG_INTERLACE_ADAM7) +is a somewhat complicated 2D interlace scheme, known as Adam7, that +breaks down an image into seven smaller images of varying size, based +on an 8x8 grid. + +libpng can fill out those images or it can give them to you "as is". +If you want them filled out, there are two ways to do that. The one +mentioned in the PNG specification is to expand each pixel to cover +those pixels that have not been read yet (the "rectangle" method). +This results in a blocky image for the first pass, which gradually +smooths out as more pixels are read. The other method is the "sparkle" +method, where pixels are drawn only in their final locations, with the +rest of the image remaining whatever colors they were initialized to +before the start of the read. The first method usually looks better, +but tends to be slower, as there are more pixels to put in the rows. + +If you don't want libpng to handle the interlacing details, just call +png_read_rows() seven times to read in all seven images. Each of the +images is a valid image by itself, or they can all be combined on an +8x8 grid to form a single image (although if you intend to combine them +you would be far better off using the libpng interlace handling). + +The first pass will return an image 1/8 as wide as the entire image +(every 8th column starting in column 0) and 1/8 as high as the original +(every 8th row starting in row 0), the second will be 1/8 as wide +(starting in column 4) and 1/8 as high (also starting in row 0). The +third pass will be 1/4 as wide (every 4th pixel starting in column 0) and +1/8 as high (every 8th row starting in row 4), and the fourth pass will +be 1/4 as wide and 1/4 as high (every 4th column starting in column 2, +and every 4th row starting in row 0). The fifth pass will return an +image 1/2 as wide, and 1/4 as high (starting at column 0 and row 2), +while the sixth pass will be 1/2 as wide and 1/2 as high as the original +(starting in column 1 and row 0). The seventh and final pass will be as +wide as the original, and 1/2 as high, containing all of the odd +numbered scanlines. Phew! + +If you want libpng to expand the images, call this before calling +png_start_read_image() or png_read_update_info(): + + if (interlace_type == PNG_INTERLACE_ADAM7) + number_of_passes + = png_set_interlace_handling(png_ptr); + +This will return the number of passes needed. Currently, this +is seven, but may change if another interlace type is added. +This function can be called even if the file is not interlaced, +where it will return one pass. + +If you are not going to display the image after each pass, but are +going to wait until the entire image is read in, use the sparkle +effect. This effect is faster and the end result of either method +is exactly the same. If you are planning on displaying the image +after each pass, the "rectangle" effect is generally considered the +better looking one. + +If you only want the "sparkle" effect, just call png_read_rows() as +normal, with the third parameter NULL. Make sure you make pass over +the image number_of_passes times, and you don't change the data in the +rows between calls. You can change the locations of the data, just +not the data. Each pass only writes the pixels appropriate for that +pass, and assumes the data from previous passes is still valid. + + png_read_rows(png_ptr, row_pointers, NULL, + number_of_rows); + +If you only want the first effect (the rectangles), do the same as +before except pass the row buffer in the third parameter, and leave +the second parameter NULL. + + png_read_rows(png_ptr, NULL, row_pointers, + number_of_rows); + +.SS Finishing a sequential read + +After you are finished reading the image through either the high- or +low-level interfaces, you can finish reading the file. If you are +interested in comments or time, which may be stored either before or +after the image data, you should pass the separate png_info struct if +you want to keep the comments from before and after the image +separate. If you are not interested, you can pass NULL. + + png_read_end(png_ptr, end_info); + +When you are done, you can free all memory allocated by libpng like this: + + png_destroy_read_struct(&png_ptr, &info_ptr, + &end_info); + +It is also possible to individually free the info_ptr members that +point to libpng-allocated storage with the following function: + + png_free_data(png_ptr, info_ptr, mask, seq) + mask - identifies data to be freed, a mask + containing the logical OR of one or + more of + PNG_FREE_PLTE, PNG_FREE_TRNS, + PNG_FREE_HIST, PNG_FREE_ICCP, + PNG_FREE_PCAL, PNG_FREE_ROWS, + PNG_FREE_SCAL, PNG_FREE_SPLT, + PNG_FREE_TEXT, PNG_FREE_UNKN, + or simply PNG_FREE_ALL + seq - sequence number of item to be freed + (-1 for all items) + +This function may be safely called when the relevant storage has +already been freed, or has not yet been allocated, or was allocated +by the user and not by libpng, and will in those +cases do nothing. The "seq" parameter is ignored if only one item +of the selected data type, such as PLTE, is allowed. If "seq" is not +-1, and multiple items are allowed for the data type identified in +the mask, such as text or sPLT, only the n'th item in the structure +is freed, where n is "seq". + +The default behavior is only to free data that was allocated internally +by libpng. This can be changed, so that libpng will not free the data, +or so that it will free data that was allocated by the user with png_malloc() +or png_zalloc() and passed in via a png_set_*() function, with + + png_data_freer(png_ptr, info_ptr, freer, mask) + mask - which data elements are affected + same choices as in png_free_data() + freer - one of + PNG_DESTROY_WILL_FREE_DATA + PNG_SET_WILL_FREE_DATA + PNG_USER_WILL_FREE_DATA + +This function only affects data that has already been allocated. +You can call this function after reading the PNG data but before calling +any png_set_*() functions, to control whether the user or the png_set_*() +function is responsible for freeing any existing data that might be present, +and again after the png_set_*() functions to control whether the user +or png_destroy_*() is supposed to free the data. When the user assumes +responsibility for libpng-allocated data, the application must use +png_free() to free it, and when the user transfers responsibility to libpng +for data that the user has allocated, the user must have used png_malloc() +or png_zalloc() to allocate it. + +If you allocated your row_pointers in a single block, as suggested above in +the description of the high level read interface, you must not transfer +responsibility for freeing it to the png_set_rows or png_read_destroy function, +because they would also try to free the individual row_pointers[i]. + +If you allocated text_ptr.text, text_ptr.lang, and text_ptr.translated_keyword +separately, do not transfer responsibility for freeing text_ptr to libpng, +because when libpng fills a png_text structure it combines these members with +the key member, and png_free_data() will free only text_ptr.key. Similarly, +if you transfer responsibility for free'ing text_ptr from libpng to your +application, your application must not separately free those members. + +The png_free_data() function will turn off the "valid" flag for anything +it frees. If you need to turn the flag off for a chunk that was freed by your +application instead of by libpng, you can use + + png_set_invalid(png_ptr, info_ptr, mask); + mask - identifies the chunks to be made invalid, + containing the logical OR of one or + more of + PNG_INFO_gAMA, PNG_INFO_sBIT, + PNG_INFO_cHRM, PNG_INFO_PLTE, + PNG_INFO_tRNS, PNG_INFO_bKGD, + PNG_INFO_hIST, PNG_INFO_pHYs, + PNG_INFO_oFFs, PNG_INFO_tIME, + PNG_INFO_pCAL, PNG_INFO_sRGB, + PNG_INFO_iCCP, PNG_INFO_sPLT, + PNG_INFO_sCAL, PNG_INFO_IDAT + +For a more compact example of reading a PNG image, see the file example.c. + +.SS Reading PNG files progressively + +The progressive reader is slightly different then the non-progressive +reader. Instead of calling png_read_info(), png_read_rows(), and +png_read_end(), you make one call to png_process_data(), which calls +callbacks when it has the info, a row, or the end of the image. You +set up these callbacks with png_set_progressive_read_fn(). You don't +have to worry about the input/output functions of libpng, as you are +giving the library the data directly in png_process_data(). I will +assume that you have read the section on reading PNG files above, +so I will only highlight the differences (although I will show +all of the code). + +png_structp png_ptr; +png_infop info_ptr; + + /* An example code fragment of how you would + initialize the progressive reader in your + application. */ + int + initialize_png_reader() + { + png_ptr = png_create_read_struct + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn); + if (!png_ptr) + return (ERROR); + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, + (png_infopp)NULL); + return (ERROR); + } + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, + (png_infopp)NULL); + return (ERROR); + } + + /* This one's new. You can provide functions + to be called when the header info is valid, + when each row is completed, and when the image + is finished. If you aren't using all functions, + you can specify NULL parameters. Even when all + three functions are NULL, you need to call + png_set_progressive_read_fn(). You can use + any struct as the user_ptr (cast to a void pointer + for the function call), and retrieve the pointer + from inside the callbacks using the function + + png_get_progressive_ptr(png_ptr); + + which will return a void pointer, which you have + to cast appropriately. + */ + png_set_progressive_read_fn(png_ptr, (void *)user_ptr, + info_callback, row_callback, end_callback); + + return 0; + } + + /* A code fragment that you call as you receive blocks + of data */ + int + process_data(png_bytep buffer, png_uint_32 length) + { + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, + (png_infopp)NULL); + return (ERROR); + } + + /* This one's new also. Simply give it a chunk + of data from the file stream (in order, of + course). On machines with segmented memory + models machines, don't give it any more than + 64K. The library seems to run fine with sizes + of 4K. Although you can give it much less if + necessary (I assume you can give it chunks of + 1 byte, I haven't tried less then 256 bytes + yet). When this function returns, you may + want to display any rows that were generated + in the row callback if you don't already do + so there. + */ + png_process_data(png_ptr, info_ptr, buffer, length); + return 0; + } + + /* This function is called (as set by + png_set_progressive_read_fn() above) when enough data + has been supplied so all of the header has been + read. + */ + void + info_callback(png_structp png_ptr, png_infop info) + { + /* Do any setup here, including setting any of + the transformations mentioned in the Reading + PNG files section. For now, you _must_ call + either png_start_read_image() or + png_read_update_info() after all the + transformations are set (even if you don't set + any). You may start getting rows before + png_process_data() returns, so this is your + last chance to prepare for that. + */ + } + + /* This function is called when each row of image + data is complete */ + void + row_callback(png_structp png_ptr, png_bytep new_row, + png_uint_32 row_num, int pass) + { + /* If the image is interlaced, and you turned + on the interlace handler, this function will + be called for every row in every pass. Some + of these rows will not be changed from the + previous pass. When the row is not changed, + the new_row variable will be NULL. The rows + and passes are called in order, so you don't + really need the row_num and pass, but I'm + supplying them because it may make your life + easier. + + For the non-NULL rows of interlaced images, + you must call png_progressive_combine_row() + passing in the row and the old row. You can + call this function for NULL rows (it will just + return) and for non-interlaced images (it just + does the memcpy for you) if it will make the + code easier. Thus, you can just do this for + all cases: + */ + + png_progressive_combine_row(png_ptr, old_row, + new_row); + + /* where old_row is what was displayed for + previously for the row. Note that the first + pass (pass == 0, really) will completely cover + the old row, so the rows do not have to be + initialized. After the first pass (and only + for interlaced images), you will have to pass + the current row, and the function will combine + the old row and the new row. + */ + } + + void + end_callback(png_structp png_ptr, png_infop info) + { + /* This function is called after the whole image + has been read, including any chunks after the + image (up to and including the IEND). You + will usually have the same info chunk as you + had in the header, although some data may have + been added to the comments and time fields. + + Most people won't do much here, perhaps setting + a flag that marks the image as finished. + */ + } + + + +.SH IV. Writing + +Much of this is very similar to reading. However, everything of +importance is repeated here, so you won't have to constantly look +back up in the reading section to understand writing. + +.SS Setup + +You will want to do the I/O initialization before you get into libpng, +so if it doesn't work, you don't have anything to undo. If you are not +using the standard I/O functions, you will need to replace them with +custom writing functions. See the discussion under Customizing libpng. + + FILE *fp = fopen(file_name, "wb"); + if (!fp) + { + return (ERROR); + } + +Next, png_struct and png_info need to be allocated and initialized. +As these can be both relatively large, you may not want to store these +on the stack, unless you have stack space to spare. Of course, you +will want to check if they return NULL. If you are also reading, +you won't want to name your read structure and your write structure +both "png_ptr"; you can call them anything you like, such as +"read_ptr" and "write_ptr". Look at pngtest.c, for example. + + png_structp png_ptr = png_create_write_struct + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn); + if (!png_ptr) + return (ERROR); + + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_write_struct(&png_ptr, + (png_infopp)NULL); + return (ERROR); + } + +If you want to use your own memory allocation routines, +define PNG_USER_MEM_SUPPORTED and use +png_create_write_struct_2() instead of png_create_write_struct(): + + png_structp png_ptr = png_create_write_struct_2 + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn, (png_voidp) + user_mem_ptr, user_malloc_fn, user_free_fn); + +After you have these structures, you will need to set up the +error handling. When libpng encounters an error, it expects to +longjmp() back to your routine. Therefore, you will need to call +setjmp() and pass the png_jmpbuf(png_ptr). If you +write the file from different routines, you will need to update +the png_jmpbuf(png_ptr) every time you enter a new routine that will +call a png_*() function. See your documentation of setjmp/longjmp +for your compiler for more information on setjmp/longjmp. See +the discussion on libpng error handling in the Customizing Libpng +section below for more information on the libpng error handling. + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(fp); + return (ERROR); + } + ... + return; + +If you would rather avoid the complexity of setjmp/longjmp issues, +you can compile libpng with PNG_SETJMP_NOT_SUPPORTED, in which case +errors will result in a call to PNG_ABORT() which defaults to abort(). + +Now you need to set up the output code. The default for libpng is to +use the C function fwrite(). If you use this, you will need to pass a +valid FILE * in the function png_init_io(). Be sure that the file is +opened in binary mode. Again, if you wish to handle writing data in +another way, see the discussion on libpng I/O handling in the Customizing +Libpng section below. + + png_init_io(png_ptr, fp); + +.SS Write callbacks + +At this point, you can set up a callback function that will be +called after each row has been written, which you can use to control +a progress meter or the like. It's demonstrated in pngtest.c. +You must supply a function + + void write_row_callback(png_ptr, png_uint_32 row, + int pass); + { + /* put your code here */ + } + +(You can give it another name that you like instead of "write_row_callback") + +To inform libpng about your function, use + + png_set_write_status_fn(png_ptr, write_row_callback); + +You now have the option of modifying how the compression library will +run. The following functions are mainly for testing, but may be useful +in some cases, like if you need to write PNG files extremely fast and +are willing to give up some compression, or if you want to get the +maximum possible compression at the expense of slower writing. If you +have no special needs in this area, let the library do what it wants by +not calling this function at all, as it has been tuned to deliver a good +speed/compression ratio. The second parameter to png_set_filter() is +the filter method, for which the only valid values are 0 (as of the +July 1999 PNG specification, version 1.2) or 64 (if you are writing +a PNG datastream that is to be embedded in a MNG datastream). The third +parameter is a flag that indicates which filter type(s) are to be tested +for each scanline. See the PNG specification for details on the specific filter +types. + + + /* turn on or off filtering, and/or choose + specific filters. You can use either a single + PNG_FILTER_VALUE_NAME or the logical OR of one + or more PNG_FILTER_NAME masks. */ + png_set_filter(png_ptr, 0, + PNG_FILTER_NONE | PNG_FILTER_VALUE_NONE | + PNG_FILTER_SUB | PNG_FILTER_VALUE_SUB | + PNG_FILTER_UP | PNG_FILTER_VALUE_UP | + PNG_FILTER_AVE | PNG_FILTER_VALUE_AVE | + PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH| + PNG_ALL_FILTERS); + +If an application +wants to start and stop using particular filters during compression, +it should start out with all of the filters (to ensure that the previous +row of pixels will be stored in case it's needed later), and then add +and remove them after the start of compression. + +If you are writing a PNG datastream that is to be embedded in a MNG +datastream, the second parameter can be either 0 or 64. + +The png_set_compression_*() functions interface to the zlib compression +library, and should mostly be ignored unless you really know what you are +doing. The only generally useful call is png_set_compression_level() +which changes how much time zlib spends on trying to compress the image +data. See the Compression Library (zlib.h and algorithm.txt, distributed +with zlib) for details on the compression levels. + + /* set the zlib compression level */ + png_set_compression_level(png_ptr, + Z_BEST_COMPRESSION); + + /* set other zlib parameters */ + png_set_compression_mem_level(png_ptr, 8); + png_set_compression_strategy(png_ptr, + Z_DEFAULT_STRATEGY); + png_set_compression_window_bits(png_ptr, 15); + png_set_compression_method(png_ptr, 8); + png_set_compression_buffer_size(png_ptr, 8192) + +extern PNG_EXPORT(void,png_set_zbuf_size) + +.SS Setting the contents of info for output + +You now need to fill in the png_info structure with all the data you +wish to write before the actual image. Note that the only thing you +are allowed to write after the image is the text chunks and the time +chunk (as of PNG Specification 1.2, anyway). See png_write_end() and +the latest PNG specification for more information on that. If you +wish to write them before the image, fill them in now, and flag that +data as being valid. If you want to wait until after the data, don't +fill them until png_write_end(). For all the fields in png_info and +their data types, see png.h. For explanations of what the fields +contain, see the PNG specification. + +Some of the more important parts of the png_info are: + + png_set_IHDR(png_ptr, info_ptr, width, height, + bit_depth, color_type, interlace_type, + compression_type, filter_method) + width - holds the width of the image + in pixels (up to 2^31). + height - holds the height of the image + in pixels (up to 2^31). + bit_depth - holds the bit depth of one of the + image channels. + (valid values are 1, 2, 4, 8, 16 + and depend also on the + color_type. See also significant + bits (sBIT) below). + color_type - describes which color/alpha + channels are present. + PNG_COLOR_TYPE_GRAY + (bit depths 1, 2, 4, 8, 16) + PNG_COLOR_TYPE_GRAY_ALPHA + (bit depths 8, 16) + PNG_COLOR_TYPE_PALETTE + (bit depths 1, 2, 4, 8) + PNG_COLOR_TYPE_RGB + (bit_depths 8, 16) + PNG_COLOR_TYPE_RGB_ALPHA + (bit_depths 8, 16) + + PNG_COLOR_MASK_PALETTE + PNG_COLOR_MASK_COLOR + PNG_COLOR_MASK_ALPHA + + interlace_type - PNG_INTERLACE_NONE or + PNG_INTERLACE_ADAM7 + compression_type - (must be + PNG_COMPRESSION_TYPE_DEFAULT) + filter_method - (must be PNG_FILTER_TYPE_DEFAULT + or, if you are writing a PNG to + be embedded in a MNG datastream, + can also be + PNG_INTRAPIXEL_DIFFERENCING) + + png_set_PLTE(png_ptr, info_ptr, palette, + num_palette); + palette - the palette for the file + (array of png_color) + num_palette - number of entries in the palette + + png_set_gAMA(png_ptr, info_ptr, gamma); + gamma - the gamma the image was created + at (PNG_INFO_gAMA) + + png_set_sRGB(png_ptr, info_ptr, srgb_intent); + srgb_intent - the rendering intent + (PNG_INFO_sRGB) The presence of + the sRGB chunk means that the pixel + data is in the sRGB color space. + This chunk also implies specific + values of gAMA and cHRM. Rendering + intent is the CSS-1 property that + has been defined by the International + Color Consortium + (http://www.color.org). + It can be one of + PNG_sRGB_INTENT_SATURATION, + PNG_sRGB_INTENT_PERCEPTUAL, + PNG_sRGB_INTENT_ABSOLUTE, or + PNG_sRGB_INTENT_RELATIVE. + + + png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, + srgb_intent); + srgb_intent - the rendering intent + (PNG_INFO_sRGB) The presence of the + sRGB chunk means that the pixel + data is in the sRGB color space. + This function also causes gAMA and + cHRM chunks with the specific values + that are consistent with sRGB to be + written. + + png_set_iCCP(png_ptr, info_ptr, name, compression_type, + profile, proflen); + name - The profile name. + compression - The compression type; always + PNG_COMPRESSION_TYPE_BASE for PNG 1.0. + You may give NULL to this argument to + ignore it. + profile - International Color Consortium color + profile data. May contain NULs. + proflen - length of profile data in bytes. + + png_set_sBIT(png_ptr, info_ptr, sig_bit); + sig_bit - the number of significant bits for + (PNG_INFO_sBIT) each of the gray, red, + green, and blue channels, whichever are + appropriate for the given color type + (png_color_16) + + png_set_tRNS(png_ptr, info_ptr, trans, num_trans, + trans_values); + trans - array of transparent entries for + palette (PNG_INFO_tRNS) + trans_values - graylevel or color sample values of + the single transparent color for + non-paletted images (PNG_INFO_tRNS) + num_trans - number of transparent entries + (PNG_INFO_tRNS) + + png_set_hIST(png_ptr, info_ptr, hist); + (PNG_INFO_hIST) + hist - histogram of palette (array of + png_uint_16) + + png_set_tIME(png_ptr, info_ptr, mod_time); + mod_time - time image was last modified + (PNG_VALID_tIME) + + png_set_bKGD(png_ptr, info_ptr, background); + background - background color (PNG_VALID_bKGD) + + png_set_text(png_ptr, info_ptr, text_ptr, num_text); + text_ptr - array of png_text holding image + comments + text_ptr[i].compression - type of compression used + on "text" PNG_TEXT_COMPRESSION_NONE + PNG_TEXT_COMPRESSION_zTXt + PNG_ITXT_COMPRESSION_NONE + PNG_ITXT_COMPRESSION_zTXt + text_ptr[i].key - keyword for comment. Must contain + 1-79 characters. + text_ptr[i].text - text comments for current + keyword. Can be NULL or empty. + text_ptr[i].text_length - length of text string, + after decompression, 0 for iTXt + text_ptr[i].itxt_length - length of itxt string, + after decompression, 0 for tEXt/zTXt + text_ptr[i].lang - language of comment (NULL or + empty for unknown). + text_ptr[i].translated_keyword - keyword in UTF-8 (NULL + or empty for unknown). + num_text - number of comments + + png_set_sPLT(png_ptr, info_ptr, &palette_ptr, + num_spalettes); + palette_ptr - array of png_sPLT_struct structures + to be added to the list of palettes + in the info structure. + num_spalettes - number of palette structures to be + added. + + png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, + unit_type); + offset_x - positive offset from the left + edge of the screen + offset_y - positive offset from the top + edge of the screen + unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER + + png_set_pHYs(png_ptr, info_ptr, res_x, res_y, + unit_type); + res_x - pixels/unit physical resolution + in x direction + res_y - pixels/unit physical resolution + in y direction + unit_type - PNG_RESOLUTION_UNKNOWN, + PNG_RESOLUTION_METER + + png_set_sCAL(png_ptr, info_ptr, unit, width, height) + unit - physical scale units (an integer) + width - width of a pixel in physical scale units + height - height of a pixel in physical scale units + (width and height are doubles) + + png_set_sCAL_s(png_ptr, info_ptr, unit, width, height) + unit - physical scale units (an integer) + width - width of a pixel in physical scale units + height - height of a pixel in physical scale units + (width and height are strings like "2.54") + + png_set_unknown_chunks(png_ptr, info_ptr, &unknowns, + num_unknowns) + unknowns - array of png_unknown_chunk + structures holding unknown chunks + unknowns[i].name - name of unknown chunk + unknowns[i].data - data of unknown chunk + unknowns[i].size - size of unknown chunk's data + unknowns[i].location - position to write chunk in file + 0: do not write chunk + PNG_HAVE_IHDR: before PLTE + PNG_HAVE_PLTE: before IDAT + PNG_AFTER_IDAT: after IDAT + +The "location" member is set automatically according to +what part of the output file has already been written. +You can change its value after calling png_set_unknown_chunks() +as demonstrated in pngtest.c. Within each of the "locations", +the chunks are sequenced according to their position in the +structure (that is, the value of "i", which is the order in which +the chunk was either read from the input file or defined with +png_set_unknown_chunks). + +A quick word about text and num_text. text is an array of png_text +structures. num_text is the number of valid structures in the array. +Each png_text structure holds a language code, a keyword, a text value, +and a compression type. + +The compression types have the same valid numbers as the compression +types of the image data. Currently, the only valid number is zero. +However, you can store text either compressed or uncompressed, unlike +images, which always have to be compressed. So if you don't want the +text compressed, set the compression type to PNG_TEXT_COMPRESSION_NONE. +Because tEXt and zTXt chunks don't have a language field, if you +specify PNG_TEXT_COMPRESSION_NONE or PNG_TEXT_COMPRESSION_zTXt +any language code or translated keyword will not be written out. + +Until text gets around 1000 bytes, it is not worth compressing it. +After the text has been written out to the file, the compression type +is set to PNG_TEXT_COMPRESSION_NONE_WR or PNG_TEXT_COMPRESSION_zTXt_WR, +so that it isn't written out again at the end (in case you are calling +png_write_end() with the same struct. + +The keywords that are given in the PNG Specification are: + + Title Short (one line) title or + caption for image + Author Name of image's creator + Description Description of image (possibly long) + Copyright Copyright notice + Creation Time Time of original image creation + (usually RFC 1123 format, see below) + Software Software used to create the image + Disclaimer Legal disclaimer + Warning Warning of nature of content + Source Device used to create the image + Comment Miscellaneous comment; conversion + from other image format + +The keyword-text pairs work like this. Keywords should be short +simple descriptions of what the comment is about. Some typical +keywords are found in the PNG specification, as is some recommendations +on keywords. You can repeat keywords in a file. You can even write +some text before the image and some after. For example, you may want +to put a description of the image before the image, but leave the +disclaimer until after, so viewers working over modem connections +don't have to wait for the disclaimer to go over the modem before +they start seeing the image. Finally, keywords should be full +words, not abbreviations. Keywords and text are in the ISO 8859-1 +(Latin-1) character set (a superset of regular ASCII) and can not +contain NUL characters, and should not contain control or other +unprintable characters. To make the comments widely readable, stick +with basic ASCII, and avoid machine specific character set extensions +like the IBM-PC character set. The keyword must be present, but +you can leave off the text string on non-compressed pairs. +Compressed pairs must have a text string, as only the text string +is compressed anyway, so the compression would be meaningless. + +PNG supports modification time via the png_time structure. Two +conversion routines are provided, png_convert_from_time_t() for +time_t and png_convert_from_struct_tm() for struct tm. The +time_t routine uses gmtime(). You don't have to use either of +these, but if you wish to fill in the png_time structure directly, +you should provide the time in universal time (GMT) if possible +instead of your local time. Note that the year number is the full +year (e.g. 1998, rather than 98 - PNG is year 2000 compliant!), and +that months start with 1. + +If you want to store the time of the original image creation, you should +use a plain tEXt chunk with the "Creation Time" keyword. This is +necessary because the "creation time" of a PNG image is somewhat vague, +depending on whether you mean the PNG file, the time the image was +created in a non-PNG format, a still photo from which the image was +scanned, or possibly the subject matter itself. In order to facilitate +machine-readable dates, it is recommended that the "Creation Time" +tEXt chunk use RFC 1123 format dates (e.g. "22 May 1997 18:07:10 GMT"), +although this isn't a requirement. Unlike the tIME chunk, the +"Creation Time" tEXt chunk is not expected to be automatically changed +by the software. To facilitate the use of RFC 1123 dates, a function +png_convert_to_rfc1123(png_timep) is provided to convert from PNG +time to an RFC 1123 format string. + +.SS Writing unknown chunks + +You can use the png_set_unknown_chunks function to queue up chunks +for writing. You give it a chunk name, raw data, and a size; that's +all there is to it. The chunks will be written by the next following +png_write_info_before_PLTE, png_write_info, or png_write_end function. +Any chunks previously read into the info structure's unknown-chunk +list will also be written out in a sequence that satisfies the PNG +specification's ordering rules. + +.SS The high-level write interface + +At this point there are two ways to proceed; through the high-level +write interface, or through a sequence of low-level write operations. +You can use the high-level interface if your image data is present +in the info structure. All defined output +transformations are permitted, enabled by the following masks. + + PNG_TRANSFORM_IDENTITY No transformation + PNG_TRANSFORM_PACKING Pack 1, 2 and 4-bit samples + PNG_TRANSFORM_PACKSWAP Change order of packed + pixels to LSB first + PNG_TRANSFORM_INVERT_MONO Invert monochrome images + PNG_TRANSFORM_SHIFT Normalize pixels to the + sBIT depth + PNG_TRANSFORM_BGR Flip RGB to BGR, RGBA + to BGRA + PNG_TRANSFORM_SWAP_ALPHA Flip RGBA to ARGB or GA + to AG + PNG_TRANSFORM_INVERT_ALPHA Change alpha from opacity + to transparency + PNG_TRANSFORM_SWAP_ENDIAN Byte-swap 16-bit samples + PNG_TRANSFORM_STRIP_FILLER Strip out filler bytes. + +If you have valid image data in the info structure (you can use +png_set_rows() to put image data in the info structure), simply do this: + + png_write_png(png_ptr, info_ptr, png_transforms, NULL) + +where png_transforms is an integer containing the logical OR of some set of +transformation flags. This call is equivalent to png_write_info(), +followed the set of transformations indicated by the transform mask, +then png_write_image(), and finally png_write_end(). + +(The final parameter of this call is not yet used. Someday it might point +to transformation parameters required by some future output transform.) + +You must use png_transforms and not call any png_set_transform() functions +when you use png_write_png(). + +.SS The low-level write interface + +If you are going the low-level route instead, you are now ready to +write all the file information up to the actual image data. You do +this with a call to png_write_info(). + + png_write_info(png_ptr, info_ptr); + +Note that there is one transformation you may need to do before +png_write_info(). In PNG files, the alpha channel in an image is the +level of opacity. If your data is supplied as a level of +transparency, you can invert the alpha channel before you write it, so +that 0 is fully transparent and 255 (in 8-bit or paletted images) or +65535 (in 16-bit images) is fully opaque, with + + png_set_invert_alpha(png_ptr); + +This must appear before png_write_info() instead of later with the +other transformations because in the case of paletted images the tRNS +chunk data has to be inverted before the tRNS chunk is written. If +your image is not a paletted image, the tRNS data (which in such cases +represents a single color to be rendered as transparent) won't need to +be changed, and you can safely do this transformation after your +png_write_info() call. + +If you need to write a private chunk that you want to appear before +the PLTE chunk when PLTE is present, you can write the PNG info in +two steps, and insert code to write your own chunk between them: + + png_write_info_before_PLTE(png_ptr, info_ptr); + png_set_unknown_chunks(png_ptr, info_ptr, ...); + png_write_info(png_ptr, info_ptr); + +After you've written the file information, you can set up the library +to handle any special transformations of the image data. The various +ways to transform the data will be described in the order that they +should occur. This is important, as some of these change the color +type and/or bit depth of the data, and some others only work on +certain color types and bit depths. Even though each transformation +checks to see if it has data that it can do something with, you should +make sure to only enable a transformation if it will be valid for the +data. For example, don't swap red and blue on grayscale data. + +PNG files store RGB pixels packed into 3 or 6 bytes. This code tells +the library to strip input data that has 4 or 8 bytes per pixel down +to 3 or 6 bytes (or strip 2 or 4-byte grayscale+filler data to 1 or 2 +bytes per pixel). + + png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); + +where the 0 is unused, and the location is either PNG_FILLER_BEFORE or +PNG_FILLER_AFTER, depending upon whether the filler byte in the pixel +is stored XRGB or RGBX. + +PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as +they can, resulting in, for example, 8 pixels per byte for 1 bit files. +If the data is supplied at 1 pixel per byte, use this code, which will +correctly pack the pixels into a single byte: + + png_set_packing(png_ptr); + +PNG files reduce possible bit depths to 1, 2, 4, 8, and 16. If your +data is of another bit depth, you can write an sBIT chunk into the +file so that decoders can recover the original data if desired. + + /* Set the true bit depth of the image data */ + if (color_type & PNG_COLOR_MASK_COLOR) + { + sig_bit.red = true_bit_depth; + sig_bit.green = true_bit_depth; + sig_bit.blue = true_bit_depth; + } + else + { + sig_bit.gray = true_bit_depth; + } + if (color_type & PNG_COLOR_MASK_ALPHA) + { + sig_bit.alpha = true_bit_depth; + } + + png_set_sBIT(png_ptr, info_ptr, &sig_bit); + +If the data is stored in the row buffer in a bit depth other than +one supported by PNG (e.g. 3 bit data in the range 0-7 for a 4-bit PNG), +this will scale the values to appear to be the correct bit depth as +is required by PNG. + + png_set_shift(png_ptr, &sig_bit); + +PNG files store 16 bit pixels in network byte order (big-endian, +ie. most significant bits first). This code would be used if they are +supplied the other way (little-endian, i.e. least significant bits +first, the way PCs store them): + + if (bit_depth > 8) + png_set_swap(png_ptr); + +If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you +need to change the order the pixels are packed into bytes, you can use: + + if (bit_depth < 8) + png_set_packswap(png_ptr); + +PNG files store 3 color pixels in red, green, blue order. This code +would be used if they are supplied as blue, green, red: + + png_set_bgr(png_ptr); + +PNG files describe monochrome as black being zero and white being +one. This code would be used if the pixels are supplied with this reversed +(black being one and white being zero): + + png_set_invert_mono(png_ptr); + +Finally, you can write your own transformation function if none of +the existing ones meets your needs. This is done by setting a callback +with + + png_set_write_user_transform_fn(png_ptr, + write_transform_fn); + +You must supply the function + + void write_transform_fn(png_ptr ptr, row_info_ptr + row_info, png_bytep data) + +See pngtest.c for a working example. Your function will be called +before any of the other transformations are processed. + +You can also set up a pointer to a user structure for use by your +callback function. + + png_set_user_transform_info(png_ptr, user_ptr, 0, 0); + +The user_channels and user_depth parameters of this function are ignored +when writing; you can set them to zero as shown. + +You can retrieve the pointer via the function png_get_user_transform_ptr(). +For example: + + voidp write_user_transform_ptr = + png_get_user_transform_ptr(png_ptr); + +It is possible to have libpng flush any pending output, either manually, +or automatically after a certain number of lines have been written. To +flush the output stream a single time call: + + png_write_flush(png_ptr); + +and to have libpng flush the output stream periodically after a certain +number of scanlines have been written, call: + + png_set_flush(png_ptr, nrows); + +Note that the distance between rows is from the last time png_write_flush() +was called, or the first row of the image if it has never been called. +So if you write 50 lines, and then png_set_flush 25, it will flush the +output on the next scanline, and every 25 lines thereafter, unless +png_write_flush() is called before 25 more lines have been written. +If nrows is too small (less than about 10 lines for a 640 pixel wide +RGB image) the image compression may decrease noticeably (although this +may be acceptable for real-time applications). Infrequent flushing will +only degrade the compression performance by a few percent over images +that do not use flushing. + +.SS Writing the image data + +That's it for the transformations. Now you can write the image data. +The simplest way to do this is in one function call. If you have the +whole image in memory, you can just call png_write_image() and libpng +will write the image. You will need to pass in an array of pointers to +each row. This function automatically handles interlacing, so you don't +need to call png_set_interlace_handling() or call this function multiple +times, or any of that other stuff necessary with png_write_rows(). + + png_write_image(png_ptr, row_pointers); + +where row_pointers is: + + png_byte *row_pointers[height]; + +You can point to void or char or whatever you use for pixels. + +If you don't want to write the whole image at once, you can +use png_write_rows() instead. If the file is not interlaced, +this is simple: + + png_write_rows(png_ptr, row_pointers, + number_of_rows); + +row_pointers is the same as in the png_write_image() call. + +If you are just writing one row at a time, you can do this with +a single row_pointer instead of an array of row_pointers: + + png_bytep row_pointer = row; + + png_write_row(png_ptr, row_pointer); + +When the file is interlaced, things can get a good deal more +complicated. The only currently (as of the PNG Specification +version 1.2, dated July 1999) defined interlacing scheme for PNG files +is the "Adam7" interlace scheme, that breaks down an +image into seven smaller images of varying size. libpng will build +these images for you, or you can do them yourself. If you want to +build them yourself, see the PNG specification for details of which +pixels to write when. + +If you don't want libpng to handle the interlacing details, just +use png_set_interlace_handling() and call png_write_rows() the +correct number of times to write all seven sub-images. + +If you want libpng to build the sub-images, call this before you start +writing any rows: + + number_of_passes = + png_set_interlace_handling(png_ptr); + +This will return the number of passes needed. Currently, this +is seven, but may change if another interlace type is added. + +Then write the complete image number_of_passes times. + + png_write_rows(png_ptr, row_pointers, + number_of_rows); + +As some of these rows are not used, and thus return immediately, +you may want to read about interlacing in the PNG specification, +and only update the rows that are actually used. + +.SS Finishing a sequential write + +After you are finished writing the image, you should finish writing +the file. If you are interested in writing comments or time, you should +pass an appropriately filled png_info pointer. If you are not interested, +you can pass NULL. + + png_write_end(png_ptr, info_ptr); + +When you are done, you can free all memory used by libpng like this: + + png_destroy_write_struct(&png_ptr, &info_ptr); + +It is also possible to individually free the info_ptr members that +point to libpng-allocated storage with the following function: + + png_free_data(png_ptr, info_ptr, mask, seq) + mask - identifies data to be freed, a mask + containing the logical OR of one or + more of + PNG_FREE_PLTE, PNG_FREE_TRNS, + PNG_FREE_HIST, PNG_FREE_ICCP, + PNG_FREE_PCAL, PNG_FREE_ROWS, + PNG_FREE_SCAL, PNG_FREE_SPLT, + PNG_FREE_TEXT, PNG_FREE_UNKN, + or simply PNG_FREE_ALL + seq - sequence number of item to be freed + (-1 for all items) + +This function may be safely called when the relevant storage has +already been freed, or has not yet been allocated, or was allocated +by the user and not by libpng, and will in those +cases do nothing. The "seq" parameter is ignored if only one item +of the selected data type, such as PLTE, is allowed. If "seq" is not +-1, and multiple items are allowed for the data type identified in +the mask, such as text or sPLT, only the n'th item in the structure +is freed, where n is "seq". + +If you allocated data such as a palette that you passed +in to libpng with png_set_*, you must not free it until just before the call to +png_destroy_write_struct(). + +The default behavior is only to free data that was allocated internally +by libpng. This can be changed, so that libpng will not free the data, +or so that it will free data that was allocated by the user with png_malloc() +or png_zalloc() and passed in via a png_set_*() function, with + + png_data_freer(png_ptr, info_ptr, freer, mask) + mask - which data elements are affected + same choices as in png_free_data() + freer - one of + PNG_DESTROY_WILL_FREE_DATA + PNG_SET_WILL_FREE_DATA + PNG_USER_WILL_FREE_DATA + +For example, to transfer responsibility for some data from a read structure +to a write structure, you could use + + png_data_freer(read_ptr, read_info_ptr, + PNG_USER_WILL_FREE_DATA, + PNG_FREE_PLTE|PNG_FREE_tRNS|PNG_FREE_hIST) + png_data_freer(write_ptr, write_info_ptr, + PNG_DESTROY_WILL_FREE_DATA, + PNG_FREE_PLTE|PNG_FREE_tRNS|PNG_FREE_hIST) + +thereby briefly reassigning responsibility for freeing to the user but +immediately afterwards reassigning it once more to the write_destroy +function. Having done this, it would then be safe to destroy the read +structure and continue to use the PLTE, tRNS, and hIST data in the write +structure. + +This function only affects data that has already been allocated. +You can call this function before calling after the png_set_*() functions +to control whether the user or png_destroy_*() is supposed to free the data. +When the user assumes responsibility for libpng-allocated data, the +application must use +png_free() to free it, and when the user transfers responsibility to libpng +for data that the user has allocated, the user must have used png_malloc() +or png_zalloc() to allocate it. + +If you allocated text_ptr.text, text_ptr.lang, and text_ptr.translated_keyword +separately, do not transfer responsibility for freeing text_ptr to libpng, +because when libpng fills a png_text structure it combines these members with +the key member, and png_free_data() will free only text_ptr.key. Similarly, +if you transfer responsibility for free'ing text_ptr from libpng to your +application, your application must not separately free those members. +For a more compact example of writing a PNG image, see the file example.c. + +.SH V. Modifying/Customizing libpng: + +There are three issues here. The first is changing how libpng does +standard things like memory allocation, input/output, and error handling. +The second deals with more complicated things like adding new chunks, +adding new transformations, and generally changing how libpng works. +Both of those are compile-time issues; that is, they are generally +determined at the time the code is written, and there is rarely a need +to provide the user with a means of changing them. The third is a +run-time issue: choosing between and/or tuning one or more alternate +versions of computationally intensive routines; specifically, optimized +assembly-language (and therefore compiler- and platform-dependent) +versions. + +Memory allocation, input/output, and error handling + +All of the memory allocation, input/output, and error handling in libpng +goes through callbacks that are user-settable. The default routines are +in pngmem.c, pngrio.c, pngwio.c, and pngerror.c, respectively. To change +these functions, call the appropriate png_set_*_fn() function. + +Memory allocation is done through the functions png_malloc() +and png_free(). These currently just call the standard C functions. If +your pointers can't access more then 64K at a time, you will want to set +MAXSEG_64K in zlib.h. Since it is unlikely that the method of handling +memory allocation on a platform will change between applications, these +functions must be modified in the library at compile time. If you prefer +to use a different method of allocating and freeing data, you can use +png_create_read_struct_2() or png_create_write_struct_2() to register +your own functions as described above. +These functions also provide a void pointer that can be retrieved via + + mem_ptr=png_get_mem_ptr(png_ptr); + +Your replacement memory functions must have prototypes as follows: + + png_voidp malloc_fn(png_structp png_ptr, + png_size_t size); + void free_fn(png_structp png_ptr, png_voidp ptr); + +Your malloc_fn() must return NULL in case of failure. The png_malloc() +function will normally call png_error() if it receives a NULL from the +system memory allocator or from your replacement malloc_fn(). + +Input/Output in libpng is done through png_read() and png_write(), +which currently just call fread() and fwrite(). The FILE * is stored in +png_struct and is initialized via png_init_io(). If you wish to change +the method of I/O, the library supplies callbacks that you can set +through the function png_set_read_fn() and png_set_write_fn() at run +time, instead of calling the png_init_io() function. These functions +also provide a void pointer that can be retrieved via the function +png_get_io_ptr(). For example: + + png_set_read_fn(png_structp read_ptr, + voidp read_io_ptr, png_rw_ptr read_data_fn) + + png_set_write_fn(png_structp write_ptr, + voidp write_io_ptr, png_rw_ptr write_data_fn, + png_flush_ptr output_flush_fn); + + voidp read_io_ptr = png_get_io_ptr(read_ptr); + voidp write_io_ptr = png_get_io_ptr(write_ptr); + +The replacement I/O functions must have prototypes as follows: + + void user_read_data(png_structp png_ptr, + png_bytep data, png_size_t length); + void user_write_data(png_structp png_ptr, + png_bytep data, png_size_t length); + void user_flush_data(png_structp png_ptr); + +Supplying NULL for the read, write, or flush functions sets them back +to using the default C stream functions. It is an error to read from +a write stream, and vice versa. + +Error handling in libpng is done through png_error() and png_warning(). +Errors handled through png_error() are fatal, meaning that png_error() +should never return to its caller. Currently, this is handled via +setjmp() and longjmp() (unless you have compiled libpng with +PNG_SETJMP_NOT_SUPPORTED, in which case it is handled via PNG_ABORT()), +but you could change this to do things like exit() if you should wish. + +On non-fatal errors, png_warning() is called +to print a warning message, and then control returns to the calling code. +By default png_error() and png_warning() print a message on stderr via +fprintf() unless the library is compiled with PNG_NO_CONSOLE_IO defined +(because you don't want the messages) or PNG_NO_STDIO defined (because +fprintf() isn't available). If you wish to change the behavior of the error +functions, you will need to set up your own message callbacks. These +functions are normally supplied at the time that the png_struct is created. +It is also possible to redirect errors and warnings to your own replacement +functions after png_create_*_struct() has been called by calling: + + png_set_error_fn(png_structp png_ptr, + png_voidp error_ptr, png_error_ptr error_fn, + png_error_ptr warning_fn); + + png_voidp error_ptr = png_get_error_ptr(png_ptr); + +If NULL is supplied for either error_fn or warning_fn, then the libpng +default function will be used, calling fprintf() and/or longjmp() if a +problem is encountered. The replacement error functions should have +parameters as follows: + + void user_error_fn(png_structp png_ptr, + png_const_charp error_msg); + void user_warning_fn(png_structp png_ptr, + png_const_charp warning_msg); + +The motivation behind using setjmp() and longjmp() is the C++ throw and +catch exception handling methods. This makes the code much easier to write, +as there is no need to check every return code of every function call. +However, there are some uncertainties about the status of local variables +after a longjmp, so the user may want to be careful about doing anything after +setjmp returns non-zero besides returning itself. Consult your compiler +documentation for more details. For an alternative approach, you may wish +to use the "cexcept" facility (see http://cexcept.sourceforge.net). + +.SS Custom chunks + +If you need to read or write custom chunks, you may need to get deeper +into the libpng code. The library now has mechanisms for storing +and writing chunks of unknown type; you can even declare callbacks +for custom chunks. Hoewver, this may not be good enough if the +library code itself needs to know about interactions between your +chunk and existing `intrinsic' chunks. + +If you need to write a new intrinsic chunk, first read the PNG +specification. Acquire a first level of +understanding of how it works. Pay particular attention to the +sections that describe chunk names, and look at how other chunks were +designed, so you can do things similarly. Second, check out the +sections of libpng that read and write chunks. Try to find a chunk +that is similar to yours and use it as a template. More details can +be found in the comments inside the code. It is best to handle unknown +chunks in a generic method, via callback functions, instead of by +modifying libpng functions. + +If you wish to write your own transformation for the data, look through +the part of the code that does the transformations, and check out some of +the simpler ones to get an idea of how they work. Try to find a similar +transformation to the one you want to add and copy off of it. More details +can be found in the comments inside the code itself. + +.SS Configuring for 16 bit platforms + +You will want to look into zconf.h to tell zlib (and thus libpng) that +it cannot allocate more then 64K at a time. Even if you can, the memory +won't be accessible. So limit zlib and libpng to 64K by defining MAXSEG_64K. + +.SS Configuring for DOS + +For DOS users who only have access to the lower 640K, you will +have to limit zlib's memory usage via a png_set_compression_mem_level() +call. See zlib.h or zconf.h in the zlib library for more information. + +.SS Configuring for Medium Model + +Libpng's support for medium model has been tested on most of the popular +compilers. Make sure MAXSEG_64K gets defined, USE_FAR_KEYWORD gets +defined, and FAR gets defined to far in pngconf.h, and you should be +all set. Everything in the library (except for zlib's structure) is +expecting far data. You must use the typedefs with the p or pp on +the end for pointers (or at least look at them and be careful). Make +note that the rows of data are defined as png_bytepp, which is an +unsigned char far * far *. + +.SS Configuring for gui/windowing platforms: + +You will need to write new error and warning functions that use the GUI +interface, as described previously, and set them to be the error and +warning functions at the time that png_create_*_struct() is called, +in order to have them available during the structure initialization. +They can be changed later via png_set_error_fn(). On some compilers, +you may also have to change the memory allocators (png_malloc, etc.). + +.SS Configuring for compiler xxx: + +All includes for libpng are in pngconf.h. If you need to add/change/delete +an include, this is the place to do it. The includes that are not +needed outside libpng are protected by the PNG_INTERNAL definition, +which is only defined for those routines inside libpng itself. The +files in libpng proper only include png.h, which includes pngconf.h. + +.SS Configuring zlib: + +There are special functions to configure the compression. Perhaps the +most useful one changes the compression level, which currently uses +input compression values in the range 0 - 9. The library normally +uses the default compression level (Z_DEFAULT_COMPRESSION = 6). Tests +have shown that for a large majority of images, compression values in +the range 3-6 compress nearly as well as higher levels, and do so much +faster. For online applications it may be desirable to have maximum speed +(Z_BEST_SPEED = 1). With versions of zlib after v0.99, you can also +specify no compression (Z_NO_COMPRESSION = 0), but this would create +files larger than just storing the raw bitmap. You can specify the +compression level by calling: + + png_set_compression_level(png_ptr, level); + +Another useful one is to reduce the memory level used by the library. +The memory level defaults to 8, but it can be lowered if you are +short on memory (running DOS, for example, where you only have 640K). +Note that the memory level does have an effect on compression; among +other things, lower levels will result in sections of incompressible +data being emitted in smaller stored blocks, with a correspondingly +larger relative overhead of up to 15% in the worst case. + + png_set_compression_mem_level(png_ptr, level); + +The other functions are for configuring zlib. They are not recommended +for normal use and may result in writing an invalid PNG file. See +zlib.h for more information on what these mean. + + png_set_compression_strategy(png_ptr, + strategy); + png_set_compression_window_bits(png_ptr, + window_bits); + png_set_compression_method(png_ptr, method); + png_set_compression_buffer_size(png_ptr, size); + +.SS Controlling row filtering + +If you want to control whether libpng uses filtering or not, which +filters are used, and how it goes about picking row filters, you +can call one of these functions. The selection and configuration +of row filters can have a significant impact on the size and +encoding speed and a somewhat lesser impact on the decoding speed +of an image. Filtering is enabled by default for RGB and grayscale +images (with and without alpha), but not for paletted images nor +for any images with bit depths less than 8 bits/pixel. + +The 'method' parameter sets the main filtering method, which is +currently only '0' in the PNG 1.2 specification. The 'filters' +parameter sets which filter(s), if any, should be used for each +scanline. Possible values are PNG_ALL_FILTERS and PNG_NO_FILTERS +to turn filtering on and off, respectively. + +Individual filter types are PNG_FILTER_NONE, PNG_FILTER_SUB, +PNG_FILTER_UP, PNG_FILTER_AVG, PNG_FILTER_PAETH, which can be bitwise +ORed together with '|' to specify one or more filters to use. +These filters are described in more detail in the PNG specification. +If you intend to change the filter type during the course of writing +the image, you should start with flags set for all of the filters +you intend to use so that libpng can initialize its internal +structures appropriately for all of the filter types. (Note that this +means the first row must always be adaptively filtered, because libpng +currently does not allocate the filter buffers until png_write_row() +is called for the first time.) + + filters = PNG_FILTER_NONE | PNG_FILTER_SUB + PNG_FILTER_UP | PNG_FILTER_AVE | + PNG_FILTER_PAETH | PNG_ALL_FILTERS; + + png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, + filters); + The second parameter can also be + PNG_INTRAPIXEL_DIFFERENCING if you are + writing a PNG to be embedded in a MNG + datastream. This parameter must be the + same as the value of filter_method used + in png_set_IHDR(). + +It is also possible to influence how libpng chooses from among the +available filters. This is done in one or both of two ways - by +telling it how important it is to keep the same filter for successive +rows, and by telling it the relative computational costs of the filters. + + double weights[3] = {1.5, 1.3, 1.1}, + costs[PNG_FILTER_VALUE_LAST] = + {1.0, 1.3, 1.3, 1.5, 1.7}; + + png_set_filter_heuristics(png_ptr, + PNG_FILTER_HEURISTIC_WEIGHTED, 3, + weights, costs); + +The weights are multiplying factors that indicate to libpng that the +row filter should be the same for successive rows unless another row filter +is that many times better than the previous filter. In the above example, +if the previous 3 filters were SUB, SUB, NONE, the SUB filter could have a +"sum of absolute differences" 1.5 x 1.3 times higher than other filters +and still be chosen, while the NONE filter could have a sum 1.1 times +higher than other filters and still be chosen. Unspecified weights are +taken to be 1.0, and the specified weights should probably be declining +like those above in order to emphasize recent filters over older filters. + +The filter costs specify for each filter type a relative decoding cost +to be considered when selecting row filters. This means that filters +with higher costs are less likely to be chosen over filters with lower +costs, unless their "sum of absolute differences" is that much smaller. +The costs do not necessarily reflect the exact computational speeds of +the various filters, since this would unduly influence the final image +size. + +Note that the numbers above were invented purely for this example and +are given only to help explain the function usage. Little testing has +been done to find optimum values for either the costs or the weights. + +.SS Removing unwanted object code + +There are a bunch of #define's in pngconf.h that control what parts of +libpng are compiled. All the defines end in _SUPPORTED. If you are +never going to use a capability, you can change the #define to #undef +before recompiling libpng and save yourself code and data space, or +you can turn off individual capabilities with defines that begin with +PNG_NO_. + +You can also turn all of the transforms and ancillary chunk capabilities +off en masse with compiler directives that define +PNG_NO_READ[or WRITE]_TRANSFORMS, or PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS, +or all four, +along with directives to turn on any of the capabilities that you do +want. The PNG_NO_READ[or WRITE]_TRANSFORMS directives disable +the extra transformations but still leave the library fully capable of reading +and writing PNG files with all known public chunks +Use of the PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS directive +produces a library that is incapable of reading or writing ancillary chunks. +If you are not using the progressive reading capability, you can +turn that off with PNG_NO_PROGRESSIVE_READ (don't confuse +this with the INTERLACING capability, which you'll still have). + +All the reading and writing specific code are in separate files, so the +linker should only grab the files it needs. However, if you want to +make sure, or if you are building a stand alone library, all the +reading files start with pngr and all the writing files start with +pngw. The files that don't match either (like png.c, pngtrans.c, etc.) +are used for both reading and writing, and always need to be included. +The progressive reader is in pngpread.c + +If you are creating or distributing a dynamically linked library (a .so +or DLL file), you should not remove or disable any parts of the library, +as this will cause applications linked with different versions of the +library to fail if they call functions not available in your library. +The size of the library itself should not be an issue, because only +those sections that are actually used will be loaded into memory. + +.SS Requesting debug printout + +The macro definition PNG_DEBUG can be used to request debugging +printout. Set it to an integer value in the range 0 to 3. Higher +numbers result in increasing amounts of debugging information. The +information is printed to the "stderr" file, unless another file +name is specified in the PNG_DEBUG_FILE macro definition. + +When PNG_DEBUG > 0, the following functions (macros) become available: + + png_debug(level, message) + png_debug1(level, message, p1) + png_debug2(level, message, p1, p2) + +in which "level" is compared to PNG_DEBUG to decide whether to print +the message, "message" is the formatted string to be printed, +and p1 and p2 are parameters that are to be embedded in the string +according to printf-style formatting directives. For example, + + png_debug1(2, "foo=%d\n", foo); + +is expanded to + + if(PNG_DEBUG > 2) + fprintf(PNG_DEBUG_FILE, "foo=%d\n", foo); + +When PNG_DEBUG is defined but is zero, the macros aren't defined, but you +can still use PNG_DEBUG to control your own debugging: + + #ifdef PNG_DEBUG + fprintf(stderr, ... + #endif + +When PNG_DEBUG = 1, the macros are defined, but only png_debug statements +having level = 0 will be printed. There aren't any such statements in +this version of libpng, but if you insert some they will be printed. + +.SH VI. Runtime optimization + +A new feature in libpng 1.2.0 is the ability to dynamically switch between +standard and optimized versions of some routines. Currently these are +limited to three computationally intensive tasks when reading PNG files: +decoding row filters, expanding interlacing, and combining interlaced or +transparent row data with previous row data. Currently the optimized +versions are available only for x86 (Intel, AMD, etc.) platforms with +MMX support, though this may change in future versions. (For example, +the non-MMX assembler optimizations for zlib might become similarly +runtime-selectable in future releases, in which case libpng could be +extended to support them. Alternatively, the compile-time choice of +floating-point versus integer routines for gamma correction might become +runtime-selectable.) + +Because such optimizations tend to be very platform- and compiler-dependent, +both in how they are written and in how they perform, the new runtime code +in libpng has been written to allow programs to query, enable, and disable +either specific optimizations or all such optimizations. For example, to +enable all possible optimizations (bearing in mind that some "optimizations" +may actually run more slowly in rare cases): + + #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200) + png_uint_32 mask, flags; + + flags = png_get_asm_flags(png_ptr); + mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE); + png_set_asm_flags(png_ptr, flags | mask); + #endif + +To enable only optimizations relevant to reading PNGs, use PNG_SELECT_READ +by itself when calling png_get_asm_flagmask(); similarly for optimizing +only writing. To disable all optimizations: + + #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200) + flags = png_get_asm_flags(png_ptr); + mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE); + png_set_asm_flags(png_ptr, flags & ~mask); + #endif + +To enable or disable only MMX-related features, use png_get_mmx_flagmask() +in place of png_get_asm_flagmask(). The mmx version takes one additional +parameter: + + #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200) + int selection = PNG_SELECT_READ | PNG_SELECT_WRITE; + int compilerID; + + mask = png_get_mmx_flagmask(selection, &compilerID); + #endif + +On return, compilerID will indicate which version of the MMX assembler +optimizations was compiled. Currently two flavors exist: Microsoft +Visual C++ (compilerID == 1) and GNU C (a.k.a. gcc/gas, compilerID == 2). +On non-x86 platforms or on systems compiled without MMX optimizations, a +value of -1 is used. + +Note that both png_get_asm_flagmask() and png_get_mmx_flagmask() return +all valid, settable optimization bits for the version of the library that's +currently in use. In the case of shared (dynamically linked) libraries, +this may include optimizations that did not exist at the time the code was +written and compiled. It is also possible, of course, to enable only known, +specific optimizations; for example: + + #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200) + flags = PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \ + | PNG_ASM_FLAG_MMX_READ_INTERLACE \ + | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \ + | PNG_ASM_FLAG_MMX_READ_FILTER_UP \ + | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \ + | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ; + png_set_asm_flags(png_ptr, flags); + #endif + +This method would enable only the MMX read-optimizations available at the +time of libpng 1.2.0's release, regardless of whether a later version of +the DLL were actually being used. (Also note that these functions did not +exist in versions older than 1.2.0, so any attempt to run a dynamically +linked app on such an older version would fail.) + +To determine whether the processor supports MMX instructions at all, use +the png_mmx_support() function: + + #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200) + mmxsupport = png_mmx_support(); + #endif + +It returns -1 if MMX support is not compiled into libpng, 0 if MMX code +is compiled but MMX is not supported by the processor, or 1 if MMX support +is fully available. Note that png_mmx_support(), png_get_mmx_flagmask(), +and png_get_asm_flagmask() all may be called without allocating and ini- +tializing any PNG structures (for example, as part of a usage screen or +"about" box). + +The following code can be used to prevent an application from using the +thread_unsafe features, even if libpng was built with PNG_THREAD_UNSAFE_OK +defined: + +#if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) \ + && defined(PNG_THREAD_UNSAFE_OK) + /* Disable thread-unsafe features of pnggccrd */ + if (png_access_version() >= 10200) + { + png_uint_32 mmx_disable_mask = 0; + png_uint_32 asm_flags; + + mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \ + | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \ + | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \ + | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ); + asm_flags = png_get_asm_flags(png_ptr); + png_set_asm_flags(png_ptr, asm_flags & ~mmx_disable_mask); + } +#endif + +For more extensive examples of runtime querying, enabling and disabling +of optimized features, see contrib/gregbook/readpng2.c in the libpng +source-code distribution. + +.SH VII. MNG support + +The MNG specification (available at http://www.libpng.org/pub/mng) allows +certain extensions to PNG for PNG images that are embedded in MNG datastreams. +Libpng can support some of these extensions. To enable them, use the +png_permit_mng_features() function: + + feature_set = png_permit_mng_features(png_ptr, mask) + mask is a png_uint_32 containing the logical OR of the + features you want to enable. These include + PNG_FLAG_MNG_EMPTY_PLTE + PNG_FLAG_MNG_FILTER_64 + PNG_ALL_MNG_FEATURES + feature_set is a png_uint_32 that is the logical AND of + your mask with the set of MNG features that is + supported by the version of libpng that you are using. + +It is an error to use this function when reading or writing a standalone +PNG file with the PNG 8-byte signature. The PNG datastream must be wrapped +in a MNG datastream. As a minimum, it must have the MNG 8-byte signature +and the MHDR and MEND chunks. Libpng does not provide support for these +or any other MNG chunks; your application must provide its own support for +them. You may wish to consider using libmng (available at +http://www.libmng.com) instead. + +.SH VIII. Changes to Libpng from version 0.88 + +It should be noted that versions of libpng later than 0.96 are not +distributed by the original libpng author, Guy Schalnat, nor by +Andreas Dilger, who had taken over from Guy during 1996 and 1997, and +distributed versions 0.89 through 0.96, but rather by another member +of the original PNG Group, Glenn Randers-Pehrson. Guy and Andreas are +still alive and well, but they have moved on to other things. + +The old libpng functions png_read_init(), png_write_init(), +png_info_init(), png_read_destroy(), and png_write_destroy() have been +moved to PNG_INTERNAL in version 0.95 to discourage their use. These +functions will be removed from libpng version 2.0.0. + +The preferred method of creating and initializing the libpng structures is +via the png_create_read_struct(), png_create_write_struct(), and +png_create_info_struct() because they isolate the size of the structures +from the application, allow version error checking, and also allow the +use of custom error handling routines during the initialization, which +the old functions do not. The functions png_read_destroy() and +png_write_destroy() do not actually free the memory that libpng +allocated for these structs, but just reset the data structures, so they +can be used instead of png_destroy_read_struct() and +png_destroy_write_struct() if you feel there is too much system overhead +allocating and freeing the png_struct for each image read. + +Setting the error callbacks via png_set_message_fn() before +png_read_init() as was suggested in libpng-0.88 is no longer supported +because this caused applications that do not use custom error functions +to fail if the png_ptr was not initialized to zero. It is still possible +to set the error callbacks AFTER png_read_init(), or to change them with +png_set_error_fn(), which is essentially the same function, but with a new +name to force compilation errors with applications that try to use the old +method. + +Starting with version 1.0.7, you can find out which version of the library +you are using at run-time: + + png_uint_32 libpng_vn = png_access_version_number(); + +The number libpng_vn is constructed from the major version, minor +version with leading zero, and release number with leading zero, +(e.g., libpng_vn for version 1.0.7 is 10007). + +You can also check which version of png.h you used when compiling your +application: + + png_uint_32 application_vn = PNG_LIBPNG_VER; + +.SH IX. Y2K Compliance in libpng + +December 3, 2004 + +Since the PNG Development group is an ad-hoc body, we can't make +an official declaration. + +This is your unofficial assurance that libpng from version 0.71 and +upward through 1.2.8 are Y2K compliant. It is my belief that earlier +versions were also Y2K compliant. + +Libpng only has three year fields. One is a 2-byte unsigned integer that +will hold years up to 65535. The other two hold the date in text +format, and will hold years up to 9999. + +The integer is + "png_uint_16 year" in png_time_struct. + +The strings are + "png_charp time_buffer" in png_struct and + "near_time_buffer", which is a local character string in png.c. + +There are seven time-related functions: + + png_convert_to_rfc_1123() in png.c + (formerly png_convert_to_rfc_1152() in error) + png_convert_from_struct_tm() in pngwrite.c, called + in pngwrite.c + png_convert_from_time_t() in pngwrite.c + png_get_tIME() in pngget.c + png_handle_tIME() in pngrutil.c, called in pngread.c + png_set_tIME() in pngset.c + png_write_tIME() in pngwutil.c, called in pngwrite.c + +All appear to handle dates properly in a Y2K environment. The +png_convert_from_time_t() function calls gmtime() to convert from system +clock time, which returns (year - 1900), which we properly convert to +the full 4-digit year. There is a possibility that applications using +libpng are not passing 4-digit years into the png_convert_to_rfc_1123() +function, or that they are incorrectly passing only a 2-digit year +instead of "year - 1900" into the png_convert_from_struct_tm() function, +but this is not under our control. The libpng documentation has always +stated that it works with 4-digit years, and the APIs have been +documented as such. + +The tIME chunk itself is also Y2K compliant. It uses a 2-byte unsigned +integer to hold the year, and can hold years as large as 65535. + +zlib, upon which libpng depends, is also Y2K compliant. It contains +no date-related code. + + + Glenn Randers-Pehrson + libpng maintainer + PNG Development Group + +.SH NOTE + +Note about libpng version numbers: + +Due to various miscommunications, unforeseen code incompatibilities +and occasional factors outside the authors' control, version numbering +on the library has not always been consistent and straightforward. +The following table summarizes matters since version 0.89c, which was +the first widely used release: + + source png.h png.h shared-lib + version string int version + ------- ------ ----- ---------- + 0.89c ("beta 3") 0.89 89 1.0.89 + 0.90 ("beta 4") 0.90 90 0.90 + 0.95 ("beta 5") 0.95 95 0.95 + 0.96 ("beta 6") 0.96 96 0.96 + 0.97b ("beta 7") 1.00.97 97 1.0.1 + 0.97c 0.97 97 2.0.97 + 0.98 0.98 98 2.0.98 + 0.99 0.99 98 2.0.99 + 0.99a-m 0.99 99 2.0.99 + 1.00 1.00 100 2.1.0 + 1.0.0 1.0.0 100 2.1.0 + 1.0.0 (from here on, the 100 2.1.0 + 1.0.1 png.h string is 10001 2.1.0 + 1.0.1a-e identical to the 10002 from here on, the + 1.0.2 source version) 10002 shared library is 2.V + 1.0.2a-b 10003 where V is the source + 1.0.1 10001 code version except as + 1.0.1a-e 10002 2.1.0.1a-e noted. + 1.0.2 10002 2.1.0.2 + 1.0.2a-b 10003 2.1.0.2a-b + 1.0.3 10003 2.1.0.3 + 1.0.3a-d 10004 2.1.0.3a-d + 1.0.4 10004 2.1.0.4 + 1.0.4a-f 10005 2.1.0.4a-f + 1.0.5 (+ 2 patches) 10005 2.1.0.5 + 1.0.5a-d 10006 2.1.0.5a-d + 1.0.5e-r 10100 2.1.0.5e-r + 1.0.5s-v 10006 2.1.0.5s-v + 1.0.6 (+ 3 patches) 10006 2.1.0.6 + 1.0.6d-g 10007 2.1.0.6d-g + 1.0.6h 10007 10.6h + 1.0.6i 10007 10.6i + 1.0.6j 10007 2.1.0.6j + 1.0.7beta11-14 DLLNUM 10007 2.1.0.7beta11-14 + 1.0.7beta15-18 1 10007 2.1.0.7beta15-18 + 1.0.7rc1-2 1 10007 2.1.0.7rc1-2 + 1.0.7 1 10007 2.1.0.7 + 1.0.8beta1-4 1 10008 2.1.0.8beta1-4 + 1.0.8rc1 1 10008 2.1.0.8rc1 + 1.0.8 1 10008 2.1.0.8 + 1.0.9beta1-6 1 10009 2.1.0.9beta1-6 + 1.0.9rc1 1 10009 2.1.0.9rc1 + 1.0.9beta7-10 1 10009 2.1.0.9beta7-10 + 1.0.9rc2 1 10009 2.1.0.9rc2 + 1.0.9 1 10009 2.1.0.9 + 1.0.10beta1 1 10010 2.1.0.10beta1 + 1.0.10rc1 1 10010 2.1.0.10rc1 + 1.0.10 1 10010 2.1.0.10 + 1.0.11beta1-3 1 10011 2.1.0.11beta1-3 + 1.0.11rc1 1 10011 2.1.0.11rc1 + 1.0.11 1 10011 2.1.0.11 + 1.0.12beta1-2 2 10012 2.1.0.12beta1-2 + 1.0.12rc1 2 10012 2.1.0.12rc1 + 1.0.12 2 10012 2.1.0.12 + 1.1.0a-f - 10100 2.1.1.0a-f abandoned + 1.2.0beta1-2 2 10200 2.1.2.0beta1-2 + 1.2.0beta3-5 3 10200 3.1.2.0beta3-5 + 1.2.0rc1 3 10200 3.1.2.0rc1 + 1.2.0 3 10200 3.1.2.0 + 1.2.1beta-4 3 10201 3.1.2.1beta1-4 + 1.2.1rc1-2 3 10201 3.1.2.1rc1-2 + 1.2.1 3 10201 3.1.2.1 + 1.2.2beta1-6 12 10202 12.so.0.1.2.2beta1-6 + 1.0.13beta1 10 10013 10.so.0.1.0.13beta1 + 1.0.13rc1 10 10013 10.so.0.1.0.13rc1 + 1.2.2rc1 12 10202 12.so.0.1.2.2rc1 + 1.0.13 10 10013 10.so.0.1.0.13 + 1.2.2 12 10202 12.so.0.1.2.2 + 1.2.3rc1-6 12 10203 12.so.0.1.2.3rc1-6 + 1.2.3 12 10203 12.so.0.1.2.3 + 1.2.4beta1-3 13 10204 12.so.0.1.2.4beta1-3 + 1.2.4rc1 13 10204 12.so.0.1.2.4rc1 + 1.0.14 10 10014 10.so.0.1.0.14 + 1.2.4 13 10204 12.so.0.1.2.4 + 1.2.5beta1-2 13 10205 12.so.0.1.2.5beta1-2 + 1.0.15rc1 10 10015 10.so.0.1.0.15rc1 + 1.0.15 10 10015 10.so.0.1.0.15 + 1.2.5 13 10205 12.so.0.1.2.5 + 1.2.6beta1-4 13 10206 12.so.0.1.2.6beta1-4 + 1.2.6rc1-5 13 10206 12.so.0.1.2.6rc1-5 + 1.0.16 10 10016 10.so.0.1.0.16 + 1.2.6 13 10206 12.so.0.1.2.6 + 1.2.7beta1-2 13 10207 12.so.0.1.2.7beta1-2 + 1.0.17rc1 10 10017 12.so.0.1.0.17rc1 + 1.2.7rc1 13 10207 12.so.0.1.2.7rc1 + 1.0.17 10 10017 12.so.0.1.0.17 + 1.2.7 13 10207 12.so.0.1.2.7 + 1.2.8beta1-5 13 10208 12.so.0.1.2.8beta1-5 + 1.0.18rc1-5 10 10018 12.so.0.1.0.18rc1-5 + 1.2.8rc1-5 13 10208 12.so.0.1.2.8rc1-5 + 1.0.18 10 10018 12.so.0.1.0.18 + 1.2.8 13 10208 12.so.0.1.2.8 + +Henceforth the source version will match the shared-library minor +and patch numbers; the shared-library major version number will be +used for changes in backward compatibility, as it is intended. The +PNG_PNGLIB_VER macro, which is not used within libpng but is available +for applications, is an unsigned integer of the form xyyzz corresponding +to the source version x.y.z (leading zeros in y and z). Beta versions +were given the previous public release number plus a letter, until +version 1.0.6j; from then on they were given the upcoming public +release number plus "betaNN" or "rcN". + +.SH "SEE ALSO" +libpngpf(3), png(5) +.LP +.IR libpng : +.IP +http://libpng.sourceforge.net (follow the [DOWNLOAD] link) +http://www.libpng.org/pub/png + +.LP +.IR zlib : +.IP +(generally) at the same location as +.I libpng +or at +.br +ftp://ftp.info-zip.org/pub/infozip/zlib + +.LP +.IR PNG specification: RFC 2083 +.IP +(generally) at the same location as +.I libpng +or at +.br +ftp://ds.internic.net/rfc/rfc2083.txt +.br +or (as a W3C Recommendation) at +.br +http://www.w3.org/TR/REC-png.html + +.LP +In the case of any inconsistency between the PNG specification +and this library, the specification takes precedence. + +.SH AUTHORS +This man page: Glenn Randers-Pehrson +<glennrp at users.sourceforge.net> + +The contributing authors would like to thank all those who helped +with testing, bug fixes, and patience. This wouldn't have been +possible without all of you. + +Thanks to Frank J. T. Wojcik for helping with the documentation. + +Libpng version 1.2.8 - December 3, 2004: +Initially created in 1995 by Guy Eric Schalnat, then of Group 42, Inc. +Currently maintained by Glenn Randers-Pehrson (glennrp at users.sourceforge.net). + +Supported by the PNG development group +.br +png-implement at ccrc.wustl.edu (subscription required; write to +majordomo at ccrc.wustl.edu with "subscribe png-implement" in the message). + +.SH COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: + +(This copy of the libpng notices is provided for your convenience. In case of +any discrepancy between this copy and the notices in the file png.h that is +included in the libpng distribution, the latter shall prevail.) + +If you modify libpng you may insert additional notices immediately following +this sentence. + +libpng version 1.2.6, December 3, 2004, is +Copyright (c) 2004 Glenn Randers-Pehrson, and is +distributed according to the same disclaimer and license as libpng-1.2.5 +with the following individual added to the list of Contributing Authors + + Cosmin Truta + +libpng versions 1.0.7, July 1, 2000, through 1.2.5 - October 3, 2002, are +Copyright (c) 2000-2002 Glenn Randers-Pehrson, and are +distributed according to the same disclaimer and license as libpng-1.0.6 +with the following individuals added to the list of Contributing Authors + + Simon-Pierre Cadieux + Eric S. Raymond + Gilles Vollant + +and with the following additions to the disclaimer: + + There is no warranty against interference with your + enjoyment of the library or against infringement. + There is no warranty that our efforts or the library + will fulfill any of your particular purposes or needs. + This library is provided with all faults, and the entire + risk of satisfactory quality, performance, accuracy, and + effort is with the user. + +libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are +Copyright (c) 1998, 1999 Glenn Randers-Pehrson +Distributed according to the same disclaimer and license as libpng-0.96, +with the following individuals added to the list of Contributing Authors: + + Tom Lane + Glenn Randers-Pehrson + Willem van Schaik + +libpng versions 0.89, June 1996, through 0.96, May 1997, are +Copyright (c) 1996, 1997 Andreas Dilger +Distributed according to the same disclaimer and license as libpng-0.88, +with the following individuals added to the list of Contributing Authors: + + John Bowler + Kevin Bracey + Sam Bushell + Magnus Holmgren + Greg Roelofs + Tom Tanner + +libpng versions 0.5, May 1995, through 0.88, January 1996, are +Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. + +For the purposes of this copyright and license, "Contributing Authors" +is defined as the following set of individuals: + + Andreas Dilger + Dave Martindale + Guy Eric Schalnat + Paul Schmidt + Tim Wegner + +The PNG Reference Library is supplied "AS IS". The Contributing Authors +and Group 42, Inc. disclaim all warranties, expressed or implied, +including, without limitation, the warranties of merchantability and of +fitness for any purpose. The Contributing Authors and Group 42, Inc. +assume no liability for direct, indirect, incidental, special, exemplary, +or consequential damages, which may result from the use of the PNG +Reference Library, even if advised of the possibility of such damage. + +Permission is hereby granted to use, copy, modify, and distribute this +source code, or portions hereof, for any purpose, without fee, subject +to the following restrictions: + +1. The origin of this source code must not be misrepresented. + +2. Altered versions must be plainly marked as such and + must not be misrepresented as being the original source. + +3. This Copyright notice may not be removed or altered from + any source or altered source distribution. + +The Contributing Authors and Group 42, Inc. specifically permit, without +fee, and encourage the use of this source code as a component to +supporting the PNG file format in commercial products. If you use this +source code in a product, acknowledgment is not required but would be +appreciated. + + +A "png_get_copyright" function is available, for convenient use in "about" +boxes and the like: + + printf("%s",png_get_copyright(NULL)); + +Also, the PNG logo (in PNG format, of course) is supplied in the +files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31). + +Libpng is OSI Certified Open Source Software. OSI Certified Open Source is a +certification mark of the Open Source Initiative. + +Glenn Randers-Pehrson +glennrp at users.sourceforge.net +December 3, 2004 + +.\" end of man page + diff --git a/syslinux/com32/lib/libpng/libpng.txt b/syslinux/com32/lib/libpng/libpng.txt new file mode 100644 index 0000000..9360f33 --- /dev/null +++ b/syslinux/com32/lib/libpng/libpng.txt @@ -0,0 +1,2959 @@ +libpng.txt - A description on how to use and modify libpng + + libpng version 1.2.8 - December 3, 2004 + Updated and distributed by Glenn Randers-Pehrson + <glennrp at users.sourceforge.net> + Copyright (c) 1998-2004 Glenn Randers-Pehrson + For conditions of distribution and use, see copyright + notice in png.h. + + based on: + + libpng 1.0 beta 6 version 0.96 May 28, 1997 + Updated and distributed by Andreas Dilger + Copyright (c) 1996, 1997 Andreas Dilger + + libpng 1.0 beta 2 - version 0.88 January 26, 1996 + For conditions of distribution and use, see copyright + notice in png.h. Copyright (c) 1995, 1996 Guy Eric + Schalnat, Group 42, Inc. + + Updated/rewritten per request in the libpng FAQ + Copyright (c) 1995, 1996 Frank J. T. Wojcik + December 18, 1995 & January 20, 1996 + +I. Introduction + +This file describes how to use and modify the PNG reference library +(known as libpng) for your own use. There are five sections to this +file: introduction, structures, reading, writing, and modification and +configuration notes for various special platforms. In addition to this +file, example.c is a good starting point for using the library, as +it is heavily commented and should include everything most people +will need. We assume that libpng is already installed; see the +INSTALL file for instructions on how to install libpng. + +Libpng was written as a companion to the PNG specification, as a way +of reducing the amount of time and effort it takes to support the PNG +file format in application programs. + +The PNG specification (second edition), November 2003, is available as +a W3C Recommendation and as an ISO Standard (ISO/IEC 15948:2003 (E)) at +<http://www.w3.org/TR/2003/REC-PNG-20031110/ +The W3C and ISO documents have identical technical content. + +The PNG-1.2 specification is available at +<http://www.libpng.org/pub/png/documents/> + +The PNG-1.0 specification is available +as RFC 2083 <http://www.libpng.org/pub/png/documents/> and as a +W3C Recommendation <http://www.w3.org/TR/REC.png.html>. Some +additional chunks are described in the special-purpose public chunks +documents at <http://www.libpng.org/pub/png/documents/>. + +Other information +about PNG, and the latest version of libpng, can be found at the PNG home +page, <http://www.libpng.org/pub/png/>. + +Most users will not have to modify the library significantly; advanced +users may want to modify it more. All attempts were made to make it as +complete as possible, while keeping the code easy to understand. +Currently, this library only supports C. Support for other languages +is being considered. + +Libpng has been designed to handle multiple sessions at one time, +to be easily modifiable, to be portable to the vast majority of +machines (ANSI, K&R, 16-, 32-, and 64-bit) available, and to be easy +to use. The ultimate goal of libpng is to promote the acceptance of +the PNG file format in whatever way possible. While there is still +work to be done (see the TODO file), libpng should cover the +majority of the needs of its users. + +Libpng uses zlib for its compression and decompression of PNG files. +Further information about zlib, and the latest version of zlib, can +be found at the zlib home page, <http://www.info-zip.org/pub/infozip/zlib/>. +The zlib compression utility is a general purpose utility that is +useful for more than PNG files, and can be used without libpng. +See the documentation delivered with zlib for more details. +You can usually find the source files for the zlib utility wherever you +find the libpng source files. + +Libpng is thread safe, provided the threads are using different +instances of the structures. Each thread should have its own +png_struct and png_info instances, and thus its own image. +Libpng does not protect itself against two threads using the +same instance of a structure. Note: thread safety may be defeated +by use of some of the MMX assembler code in pnggccrd.c, which is only +compiled when the user defines PNG_THREAD_UNSAFE_OK. + +II. Structures + +There are two main structures that are important to libpng, png_struct +and png_info. The first, png_struct, is an internal structure that +will not, for the most part, be used by a user except as the first +variable passed to every libpng function call. + +The png_info structure is designed to provide information about the +PNG file. At one time, the fields of png_info were intended to be +directly accessible to the user. However, this tended to cause problems +with applications using dynamically loaded libraries, and as a result +a set of interface functions for png_info (the png_get_*() and png_set_*() +functions) was developed. The fields of png_info are still available for +older applications, but it is suggested that applications use the new +interfaces if at all possible. + +Applications that do make direct access to the members of png_struct (except +for png_ptr->jmpbuf) must be recompiled whenever the library is updated, +and applications that make direct access to the members of png_info must +be recompiled if they were compiled or loaded with libpng version 1.0.6, +in which the members were in a different order. In version 1.0.7, the +members of the png_info structure reverted to the old order, as they were +in versions 0.97c through 1.0.5. Starting with version 2.0.0, both +structures are going to be hidden, and the contents of the structures will +only be accessible through the png_get/png_set functions. + +The png.h header file is an invaluable reference for programming with libpng. +And while I'm on the topic, make sure you include the libpng header file: + +#include <png.h> + +III. Reading + +We'll now walk you through the possible functions to call when reading +in a PNG file sequentially, briefly explaining the syntax and purpose +of each one. See example.c and png.h for more detail. While +progressive reading is covered in the next section, you will still +need some of the functions discussed in this section to read a PNG +file. + +Setup + +You will want to do the I/O initialization(*) before you get into libpng, +so if it doesn't work, you don't have much to undo. Of course, you +will also want to insure that you are, in fact, dealing with a PNG +file. Libpng provides a simple check to see if a file is a PNG file. +To use it, pass in the first 1 to 8 bytes of the file to the function +png_sig_cmp(), and it will return 0 if the bytes match the corresponding +bytes of the PNG signature, or nonzero otherwise. Of course, the more bytes +you pass in, the greater the accuracy of the prediction. + +If you are intending to keep the file pointer open for use in libpng, +you must ensure you don't read more than 8 bytes from the beginning +of the file, and you also have to make a call to png_set_sig_bytes_read() +with the number of bytes you read from the beginning. Libpng will +then only check the bytes (if any) that your program didn't read. + +(*): If you are not using the standard I/O functions, you will need +to replace them with custom functions. See the discussion under +Customizing libpng. + + + FILE *fp = fopen(file_name, "rb"); + if (!fp) + { + return (ERROR); + } + fread(header, 1, number, fp); + is_png = !png_sig_cmp(header, 0, number); + if (!is_png) + { + return (NOT_PNG); + } + + +Next, png_struct and png_info need to be allocated and initialized. In +order to ensure that the size of these structures is correct even with a +dynamically linked libpng, there are functions to initialize and +allocate the structures. We also pass the library version, optional +pointers to error handling functions, and a pointer to a data struct for +use by the error functions, if necessary (the pointer and functions can +be NULL if the default error handlers are to be used). See the section +on Changes to Libpng below regarding the old initialization functions. +The structure allocation functions quietly return NULL if they fail to +create the structure, so your application should check for that. + + png_structp png_ptr = png_create_read_struct + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn); + if (!png_ptr) + return (ERROR); + + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_read_struct(&png_ptr, + (png_infopp)NULL, (png_infopp)NULL); + return (ERROR); + } + + png_infop end_info = png_create_info_struct(png_ptr); + if (!end_info) + { + png_destroy_read_struct(&png_ptr, &info_ptr, + (png_infopp)NULL); + return (ERROR); + } + +If you want to use your own memory allocation routines, +define PNG_USER_MEM_SUPPORTED and use +png_create_read_struct_2() instead of png_create_read_struct(): + + png_structp png_ptr = png_create_read_struct_2 + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn, (png_voidp) + user_mem_ptr, user_malloc_fn, user_free_fn); + +The error handling routines passed to png_create_read_struct() +and the memory alloc/free routines passed to png_create_struct_2() +are only necessary if you are not using the libpng supplied error +handling and memory alloc/free functions. + +When libpng encounters an error, it expects to longjmp back +to your routine. Therefore, you will need to call setjmp and pass +your png_jmpbuf(png_ptr). If you read the file from different +routines, you will need to update the jmpbuf field every time you enter +a new routine that will call a png_*() function. + +See your documentation of setjmp/longjmp for your compiler for more +information on setjmp/longjmp. See the discussion on libpng error +handling in the Customizing Libpng section below for more information +on the libpng error handling. If an error occurs, and libpng longjmp's +back to your setjmp, you will want to call png_destroy_read_struct() to +free any memory. + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, + &end_info); + fclose(fp); + return (ERROR); + } + +If you would rather avoid the complexity of setjmp/longjmp issues, +you can compile libpng with PNG_SETJMP_NOT_SUPPORTED, in which case +errors will result in a call to PNG_ABORT() which defaults to abort(). + +Now you need to set up the input code. The default for libpng is to +use the C function fread(). If you use this, you will need to pass a +valid FILE * in the function png_init_io(). Be sure that the file is +opened in binary mode. If you wish to handle reading data in another +way, you need not call the png_init_io() function, but you must then +implement the libpng I/O methods discussed in the Customizing Libpng +section below. + + png_init_io(png_ptr, fp); + +If you had previously opened the file and read any of the signature from +the beginning in order to see if this was a PNG file, you need to let +libpng know that there are some bytes missing from the start of the file. + + png_set_sig_bytes(png_ptr, number); + +Setting up callback code + +You can set up a callback function to handle any unknown chunks in the +input stream. You must supply the function + + read_chunk_callback(png_ptr ptr, + png_unknown_chunkp chunk); + { + /* The unknown chunk structure contains your + chunk data: */ + png_byte name[5]; + png_byte *data; + png_size_t size; + /* Note that libpng has already taken care of + the CRC handling */ + + /* put your code here. Return one of the + following: */ + + return (-n); /* chunk had an error */ + return (0); /* did not recognize */ + return (n); /* success */ + } + +(You can give your function another name that you like instead of +"read_chunk_callback") + +To inform libpng about your function, use + + png_set_read_user_chunk_fn(png_ptr, user_chunk_ptr, + read_chunk_callback); + +This names not only the callback function, but also a user pointer that +you can retrieve with + + png_get_user_chunk_ptr(png_ptr); + +At this point, you can set up a callback function that will be +called after each row has been read, which you can use to control +a progress meter or the like. It's demonstrated in pngtest.c. +You must supply a function + + void read_row_callback(png_ptr ptr, png_uint_32 row, + int pass); + { + /* put your code here */ + } + +(You can give it another name that you like instead of "read_row_callback") + +To inform libpng about your function, use + + png_set_read_status_fn(png_ptr, read_row_callback); + +Width and height limits + +The PNG specification allows the width and height of an image to be as +large as 2^31-1 (0x7fffffff), or about 2.147 billion rows and columns. +Since very few applications really need to process such large images, +we have imposed an arbitrary 1-million limit on rows and columns. +Larger images will be rejected immediately with a png_error() call. If +you wish to override this limit, you can use + + png_set_user_limits(png_ptr, width_max, height_max); + +to set your own limits, or use width_max = height_max = 0x7fffffffL +to allow all valid dimensions (libpng may reject some very large images +anyway because of potential buffer overflow conditions). + +You should put this statement after you create the PNG structure and +before calling png_read_info(), png_read_png(), or png_process_data(). +If you need to retrieve the limits that are being applied, use + + width_max = png_get_user_width_max(png_ptr); + height_max = png_get_user_height_max(png_ptr); + +Unknown-chunk handling + +Now you get to set the way the library processes unknown chunks in the +input PNG stream. Both known and unknown chunks will be read. Normal +behavior is that known chunks will be parsed into information in +various info_ptr members; unknown chunks will be discarded. To change +this, you can call: + + png_set_keep_unknown_chunks(png_ptr, keep, + chunk_list, num_chunks); + keep - 0: do not handle as unknown + 1: do not keep + 2: keep only if safe-to-copy + 3: keep even if unsafe-to-copy + You can use these definitions: + PNG_HANDLE_CHUNK_AS_DEFAULT 0 + PNG_HANDLE_CHUNK_NEVER 1 + PNG_HANDLE_CHUNK_IF_SAFE 2 + PNG_HANDLE_CHUNK_ALWAYS 3 + chunk_list - list of chunks affected (a byte string, + five bytes per chunk, NULL or '\0' if + num_chunks is 0) + num_chunks - number of chunks affected; if 0, all + unknown chunks are affected. If nonzero, + only the chunks in the list are affected + +Unknown chunks declared in this way will be saved as raw data onto a +list of png_unknown_chunk structures. If a chunk that is normally +known to libpng is named in the list, it will be handled as unknown, +according to the "keep" directive. If a chunk is named in successive +instances of png_set_keep_unknown_chunks(), the final instance will +take precedence. The IHDR and IEND chunks should not be named in +chunk_list; if they are, libpng will process them normally anyway. + +The high-level read interface + +At this point there are two ways to proceed; through the high-level +read interface, or through a sequence of low-level read operations. +You can use the high-level interface if (a) you are willing to read +the entire image into memory, and (b) the input transformations +you want to do are limited to the following set: + + PNG_TRANSFORM_IDENTITY No transformation + PNG_TRANSFORM_STRIP_16 Strip 16-bit samples to + 8 bits + PNG_TRANSFORM_STRIP_ALPHA Discard the alpha channel + PNG_TRANSFORM_PACKING Expand 1, 2 and 4-bit + samples to bytes + PNG_TRANSFORM_PACKSWAP Change order of packed + pixels to LSB first + PNG_TRANSFORM_EXPAND Perform set_expand() + PNG_TRANSFORM_INVERT_MONO Invert monochrome images + PNG_TRANSFORM_SHIFT Normalize pixels to the + sBIT depth + PNG_TRANSFORM_BGR Flip RGB to BGR, RGBA + to BGRA + PNG_TRANSFORM_SWAP_ALPHA Flip RGBA to ARGB or GA + to AG + PNG_TRANSFORM_INVERT_ALPHA Change alpha from opacity + to transparency + PNG_TRANSFORM_SWAP_ENDIAN Byte-swap 16-bit samples + +(This excludes setting a background color, doing gamma transformation, +dithering, and setting filler.) If this is the case, simply do this: + + png_read_png(png_ptr, info_ptr, png_transforms, NULL) + +where png_transforms is an integer containing the logical OR of +some set of transformation flags. This call is equivalent to png_read_info(), +followed the set of transformations indicated by the transform mask, +then png_read_image(), and finally png_read_end(). + +(The final parameter of this call is not yet used. Someday it might point +to transformation parameters required by some future input transform.) + +You must use png_transforms and not call any png_set_transform() functions +when you use png_read_png(). + +After you have called png_read_png(), you can retrieve the image data +with + + row_pointers = png_get_rows(png_ptr, info_ptr); + +where row_pointers is an array of pointers to the pixel data for each row: + + png_bytep row_pointers[height]; + +If you know your image size and pixel size ahead of time, you can allocate +row_pointers prior to calling png_read_png() with + + if (height > PNG_UINT_32_MAX/png_sizeof(png_byte)) + png_error (png_ptr, + "Image is too tall to process in memory"); + if (width > PNG_UINT_32_MAX/pixel_size) + png_error (png_ptr, + "Image is too wide to process in memory"); + row_pointers = png_malloc(png_ptr, + height*png_sizeof(png_bytep)); + for (int i=0; i<height, i++) + row_pointers[i]=png_malloc(png_ptr, + width*pixel_size); + png_set_rows(png_ptr, info_ptr, &row_pointers); + +Alternatively you could allocate your image in one big block and define +row_pointers[i] to point into the proper places in your block. + +If you use png_set_rows(), the application is responsible for freeing +row_pointers (and row_pointers[i], if they were separately allocated). + +If you don't allocate row_pointers ahead of time, png_read_png() will +do it, and it'll be free'ed when you call png_destroy_*(). + +The low-level read interface + +If you are going the low-level route, you are now ready to read all +the file information up to the actual image data. You do this with a +call to png_read_info(). + + png_read_info(png_ptr, info_ptr); + +This will process all chunks up to but not including the image data. + +Querying the info structure + +Functions are used to get the information from the info_ptr once it +has been read. Note that these fields may not be completely filled +in until png_read_end() has read the chunk data following the image. + + png_get_IHDR(png_ptr, info_ptr, &width, &height, + &bit_depth, &color_type, &interlace_type, + &compression_type, &filter_method); + + width - holds the width of the image + in pixels (up to 2^31). + height - holds the height of the image + in pixels (up to 2^31). + bit_depth - holds the bit depth of one of the + image channels. (valid values are + 1, 2, 4, 8, 16 and depend also on + the color_type. See also + significant bits (sBIT) below). + color_type - describes which color/alpha channels + are present. + PNG_COLOR_TYPE_GRAY + (bit depths 1, 2, 4, 8, 16) + PNG_COLOR_TYPE_GRAY_ALPHA + (bit depths 8, 16) + PNG_COLOR_TYPE_PALETTE + (bit depths 1, 2, 4, 8) + PNG_COLOR_TYPE_RGB + (bit_depths 8, 16) + PNG_COLOR_TYPE_RGB_ALPHA + (bit_depths 8, 16) + + PNG_COLOR_MASK_PALETTE + PNG_COLOR_MASK_COLOR + PNG_COLOR_MASK_ALPHA + + filter_method - (must be PNG_FILTER_TYPE_BASE + for PNG 1.0, and can also be + PNG_INTRAPIXEL_DIFFERENCING if + the PNG datastream is embedded in + a MNG-1.0 datastream) + compression_type - (must be PNG_COMPRESSION_TYPE_BASE + for PNG 1.0) + interlace_type - (PNG_INTERLACE_NONE or + PNG_INTERLACE_ADAM7) + Any or all of interlace_type, compression_type, of + filter_method can be NULL if you are + not interested in their values. + + channels = png_get_channels(png_ptr, info_ptr); + channels - number of channels of info for the + color type (valid values are 1 (GRAY, + PALETTE), 2 (GRAY_ALPHA), 3 (RGB), + 4 (RGB_ALPHA or RGB + filler byte)) + rowbytes = png_get_rowbytes(png_ptr, info_ptr); + rowbytes - number of bytes needed to hold a row + + signature = png_get_signature(png_ptr, info_ptr); + signature - holds the signature read from the + file (if any). The data is kept in + the same offset it would be if the + whole signature were read (i.e. if an + application had already read in 4 + bytes of signature before starting + libpng, the remaining 4 bytes would + be in signature[4] through signature[7] + (see png_set_sig_bytes())). + + + width = png_get_image_width(png_ptr, + info_ptr); + height = png_get_image_height(png_ptr, + info_ptr); + bit_depth = png_get_bit_depth(png_ptr, + info_ptr); + color_type = png_get_color_type(png_ptr, + info_ptr); + filter_method = png_get_filter_type(png_ptr, + info_ptr); + compression_type = png_get_compression_type(png_ptr, + info_ptr); + interlace_type = png_get_interlace_type(png_ptr, + info_ptr); + + +These are also important, but their validity depends on whether the chunk +has been read. The png_get_valid(png_ptr, info_ptr, PNG_INFO_<chunk>) and +png_get_<chunk>(png_ptr, info_ptr, ...) functions return non-zero if the +data has been read, or zero if it is missing. The parameters to the +png_get_<chunk> are set directly if they are simple data types, or a pointer +into the info_ptr is returned for any complex types. + + png_get_PLTE(png_ptr, info_ptr, &palette, + &num_palette); + palette - the palette for the file + (array of png_color) + num_palette - number of entries in the palette + + png_get_gAMA(png_ptr, info_ptr, &gamma); + gamma - the gamma the file is written + at (PNG_INFO_gAMA) + + png_get_sRGB(png_ptr, info_ptr, &srgb_intent); + srgb_intent - the rendering intent (PNG_INFO_sRGB) + The presence of the sRGB chunk + means that the pixel data is in the + sRGB color space. This chunk also + implies specific values of gAMA and + cHRM. + + png_get_iCCP(png_ptr, info_ptr, &name, + &compression_type, &profile, &proflen); + name - The profile name. + compression - The compression type; always + PNG_COMPRESSION_TYPE_BASE for PNG 1.0. + You may give NULL to this argument to + ignore it. + profile - International Color Consortium color + profile data. May contain NULs. + proflen - length of profile data in bytes. + + png_get_sBIT(png_ptr, info_ptr, &sig_bit); + sig_bit - the number of significant bits for + (PNG_INFO_sBIT) each of the gray, + red, green, and blue channels, + whichever are appropriate for the + given color type (png_color_16) + + png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, + &trans_values); + trans - array of transparent entries for + palette (PNG_INFO_tRNS) + trans_values - graylevel or color sample values of + the single transparent color for + non-paletted images (PNG_INFO_tRNS) + num_trans - number of transparent entries + (PNG_INFO_tRNS) + + png_get_hIST(png_ptr, info_ptr, &hist); + (PNG_INFO_hIST) + hist - histogram of palette (array of + png_uint_16) + + png_get_tIME(png_ptr, info_ptr, &mod_time); + mod_time - time image was last modified + (PNG_VALID_tIME) + + png_get_bKGD(png_ptr, info_ptr, &background); + background - background color (PNG_VALID_bKGD) + valid 16-bit red, green and blue + values, regardless of color_type + + num_comments = png_get_text(png_ptr, info_ptr, + &text_ptr, &num_text); + num_comments - number of comments + text_ptr - array of png_text holding image + comments + text_ptr[i].compression - type of compression used + on "text" PNG_TEXT_COMPRESSION_NONE + PNG_TEXT_COMPRESSION_zTXt + PNG_ITXT_COMPRESSION_NONE + PNG_ITXT_COMPRESSION_zTXt + text_ptr[i].key - keyword for comment. Must contain + 1-79 characters. + text_ptr[i].text - text comments for current + keyword. Can be empty. + text_ptr[i].text_length - length of text string, + after decompression, 0 for iTXt + text_ptr[i].itxt_length - length of itxt string, + after decompression, 0 for tEXt/zTXt + text_ptr[i].lang - language of comment (empty + string for unknown). + text_ptr[i].lang_key - keyword in UTF-8 + (empty string for unknown). + num_text - number of comments (same as + num_comments; you can put NULL here + to avoid the duplication) + Note while png_set_text() will accept text, language, + and translated keywords that can be NULL pointers, the + structure returned by png_get_text will always contain + regular zero-terminated C strings. They might be + empty strings but they will never be NULL pointers. + + num_spalettes = png_get_sPLT(png_ptr, info_ptr, + &palette_ptr); + palette_ptr - array of palette structures holding + contents of one or more sPLT chunks + read. + num_spalettes - number of sPLT chunks read. + + png_get_oFFs(png_ptr, info_ptr, &offset_x, &offset_y, + &unit_type); + offset_x - positive offset from the left edge + of the screen + offset_y - positive offset from the top edge + of the screen + unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER + + png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, + &unit_type); + res_x - pixels/unit physical resolution in + x direction + res_y - pixels/unit physical resolution in + x direction + unit_type - PNG_RESOLUTION_UNKNOWN, + PNG_RESOLUTION_METER + + png_get_sCAL(png_ptr, info_ptr, &unit, &width, + &height) + unit - physical scale units (an integer) + width - width of a pixel in physical scale units + height - height of a pixel in physical scale units + (width and height are doubles) + + png_get_sCAL_s(png_ptr, info_ptr, &unit, &width, + &height) + unit - physical scale units (an integer) + width - width of a pixel in physical scale units + height - height of a pixel in physical scale units + (width and height are strings like "2.54") + + num_unknown_chunks = png_get_unknown_chunks(png_ptr, + info_ptr, &unknowns) + unknowns - array of png_unknown_chunk + structures holding unknown chunks + unknowns[i].name - name of unknown chunk + unknowns[i].data - data of unknown chunk + unknowns[i].size - size of unknown chunk's data + unknowns[i].location - position of chunk in file + + The value of "i" corresponds to the order in which the + chunks were read from the PNG file or inserted with the + png_set_unknown_chunks() function. + +The data from the pHYs chunk can be retrieved in several convenient +forms: + + res_x = png_get_x_pixels_per_meter(png_ptr, + info_ptr) + res_y = png_get_y_pixels_per_meter(png_ptr, + info_ptr) + res_x_and_y = png_get_pixels_per_meter(png_ptr, + info_ptr) + res_x = png_get_x_pixels_per_inch(png_ptr, + info_ptr) + res_y = png_get_y_pixels_per_inch(png_ptr, + info_ptr) + res_x_and_y = png_get_pixels_per_inch(png_ptr, + info_ptr) + aspect_ratio = png_get_pixel_aspect_ratio(png_ptr, + info_ptr) + + (Each of these returns 0 [signifying "unknown"] if + the data is not present or if res_x is 0; + res_x_and_y is 0 if res_x != res_y) + +The data from the oFFs chunk can be retrieved in several convenient +forms: + + x_offset = png_get_x_offset_microns(png_ptr, info_ptr); + y_offset = png_get_y_offset_microns(png_ptr, info_ptr); + x_offset = png_get_x_offset_inches(png_ptr, info_ptr); + y_offset = png_get_y_offset_inches(png_ptr, info_ptr); + + (Each of these returns 0 [signifying "unknown" if both + x and y are 0] if the data is not present or if the + chunk is present but the unit is the pixel) + +For more information, see the png_info definition in png.h and the +PNG specification for chunk contents. Be careful with trusting +rowbytes, as some of the transformations could increase the space +needed to hold a row (expand, filler, gray_to_rgb, etc.). +See png_read_update_info(), below. + +A quick word about text_ptr and num_text. PNG stores comments in +keyword/text pairs, one pair per chunk, with no limit on the number +of text chunks, and a 2^31 byte limit on their size. While there are +suggested keywords, there is no requirement to restrict the use to these +strings. It is strongly suggested that keywords and text be sensible +to humans (that's the point), so don't use abbreviations. Non-printing +symbols are not allowed. See the PNG specification for more details. +There is also no requirement to have text after the keyword. + +Keywords should be limited to 79 Latin-1 characters without leading or +trailing spaces, but non-consecutive spaces are allowed within the +keyword. It is possible to have the same keyword any number of times. +The text_ptr is an array of png_text structures, each holding a +pointer to a language string, a pointer to a keyword and a pointer to +a text string. The text string, language code, and translated +keyword may be empty or NULL pointers. The keyword/text +pairs are put into the array in the order that they are received. +However, some or all of the text chunks may be after the image, so, to +make sure you have read all the text chunks, don't mess with these +until after you read the stuff after the image. This will be +mentioned again below in the discussion that goes with png_read_end(). + +Input transformations + +After you've read the header information, you can set up the library +to handle any special transformations of the image data. The various +ways to transform the data will be described in the order that they +should occur. This is important, as some of these change the color +type and/or bit depth of the data, and some others only work on +certain color types and bit depths. Even though each transformation +checks to see if it has data that it can do something with, you should +make sure to only enable a transformation if it will be valid for the +data. For example, don't swap red and blue on grayscale data. + +The colors used for the background and transparency values should be +supplied in the same format/depth as the current image data. They +are stored in the same format/depth as the image data in a bKGD or tRNS +chunk, so this is what libpng expects for this data. The colors are +transformed to keep in sync with the image data when an application +calls the png_read_update_info() routine (see below). + +Data will be decoded into the supplied row buffers packed into bytes +unless the library has been told to transform it into another format. +For example, 4 bit/pixel paletted or grayscale data will be returned +2 pixels/byte with the leftmost pixel in the high-order bits of the +byte, unless png_set_packing() is called. 8-bit RGB data will be stored +in RGB RGB RGB format unless png_set_filler() or png_set_add_alpha() +is called to insert filler bytes, either before or after each RGB triplet. +16-bit RGB data will be returned RRGGBB RRGGBB, with the most significant +byte of the color value first, unless png_set_strip_16() is called to +transform it to regular RGB RGB triplets, or png_set_filler() or +png_set_add alpha() is called to insert filler bytes, either before or +after each RRGGBB triplet. Similarly, 8-bit or 16-bit grayscale data can +be modified with +png_set_filler(), png_set_add_alpha(), or png_set_strip_16(). + +The following code transforms grayscale images of less than 8 to 8 bits, +changes paletted images to RGB, and adds a full alpha channel if there is +transparency information in a tRNS chunk. This is most useful on +grayscale images with bit depths of 2 or 4 or if there is a multiple-image +viewing application that wishes to treat all images in the same way. + + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb(png_ptr); + + if (color_type == PNG_COLOR_TYPE_GRAY && + bit_depth < 8) png_set_gray_1_2_4_to_8(png_ptr); + + if (png_get_valid(png_ptr, info_ptr, + PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); + +These three functions are actually aliases for png_set_expand(), added +in libpng version 1.0.4, with the function names expanded to improve code +readability. In some future version they may actually do different +things. + +PNG can have files with 16 bits per channel. If you only can handle +8 bits per channel, this will strip the pixels down to 8 bit. + + if (bit_depth == 16) + png_set_strip_16(png_ptr); + +If, for some reason, you don't need the alpha channel on an image, +and you want to remove it rather than combining it with the background +(but the image author certainly had in mind that you *would* combine +it with the background, so that's what you should probably do): + + if (color_type & PNG_COLOR_MASK_ALPHA) + png_set_strip_alpha(png_ptr); + +In PNG files, the alpha channel in an image +is the level of opacity. If you need the alpha channel in an image to +be the level of transparency instead of opacity, you can invert the +alpha channel (or the tRNS chunk data) after it's read, so that 0 is +fully opaque and 255 (in 8-bit or paletted images) or 65535 (in 16-bit +images) is fully transparent, with + + png_set_invert_alpha(png_ptr); + +PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as +they can, resulting in, for example, 8 pixels per byte for 1 bit +files. This code expands to 1 pixel per byte without changing the +values of the pixels: + + if (bit_depth < 8) + png_set_packing(png_ptr); + +PNG files have possible bit depths of 1, 2, 4, 8, and 16. All pixels +stored in a PNG image have been "scaled" or "shifted" up to the next +higher possible bit depth (e.g. from 5 bits/sample in the range [0,31] to +8 bits/sample in the range [0, 255]). However, it is also possible to +convert the PNG pixel data back to the original bit depth of the image. +This call reduces the pixels back down to the original bit depth: + + png_color_8p sig_bit; + + if (png_get_sBIT(png_ptr, info_ptr, &sig_bit)) + png_set_shift(png_ptr, sig_bit); + +PNG files store 3-color pixels in red, green, blue order. This code +changes the storage of the pixels to blue, green, red: + + if (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) + png_set_bgr(png_ptr); + +PNG files store RGB pixels packed into 3 or 6 bytes. This code expands them +into 4 or 8 bytes for windowing systems that need them in this format: + + if (color_type == PNG_COLOR_TYPE_RGB) + png_set_filler(png_ptr, filler, PNG_FILLER_BEFORE); + +where "filler" is the 8 or 16-bit number to fill with, and the location is +either PNG_FILLER_BEFORE or PNG_FILLER_AFTER, depending upon whether +you want the filler before the RGB or after. This transformation +does not affect images that already have full alpha channels. To add an +opaque alpha channel, use filler=0xff or 0xffff and PNG_FILLER_AFTER which +will generate RGBA pixels. + +Note that png_set_filler() does not change the color type. If you want +to do that, you can add a true alpha channel with + + if (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_GRAY) + png_set_add_alpha(png_ptr, filler, PNG_FILLER_AFTER); + +where "filler" contains the alpha value to assign to each pixel. +This function was added in libpng-1.2.7. + +If you are reading an image with an alpha channel, and you need the +data as ARGB instead of the normal PNG format RGBA: + + if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) + png_set_swap_alpha(png_ptr); + +For some uses, you may want a grayscale image to be represented as +RGB. This code will do that conversion: + + if (color_type == PNG_COLOR_TYPE_GRAY || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(png_ptr); + +Conversely, you can convert an RGB or RGBA image to grayscale or grayscale +with alpha. + + if (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) + png_set_rgb_to_gray_fixed(png_ptr, error_action, + int red_weight, int green_weight); + + error_action = 1: silently do the conversion + error_action = 2: issue a warning if the original + image has any pixel where + red != green or red != blue + error_action = 3: issue an error and abort the + conversion if the original + image has any pixel where + red != green or red != blue + + red_weight: weight of red component times 100000 + green_weight: weight of green component times 100000 + If either weight is negative, default + weights (21268, 71514) are used. + +If you have set error_action = 1 or 2, you can +later check whether the image really was gray, after processing +the image rows, with the png_get_rgb_to_gray_status(png_ptr) function. +It will return a png_byte that is zero if the image was gray or +1 if there were any non-gray pixels. bKGD and sBIT data +will be silently converted to grayscale, using the green channel +data, regardless of the error_action setting. + +With red_weight+green_weight<=100000, +the normalized graylevel is computed: + + int rw = red_weight * 65536; + int gw = green_weight * 65536; + int bw = 65536 - (rw + gw); + gray = (rw*red + gw*green + bw*blue)/65536; + +The default values approximate those recommended in the Charles +Poynton's Color FAQ, <http://www.inforamp.net/~poynton/> +Copyright (c) 1998-01-04 Charles Poynton <poynton at inforamp.net> + + Y = 0.212671 * R + 0.715160 * G + 0.072169 * B + +Libpng approximates this with + + Y = 0.21268 * R + 0.7151 * G + 0.07217 * B + +which can be expressed with integers as + + Y = (6969 * R + 23434 * G + 2365 * B)/32768 + +The calculation is done in a linear colorspace, if the image gamma +is known. + +If you have a grayscale and you are using png_set_expand_depth(), +png_set_expand(), or png_set_gray_to_rgb to change to truecolor or to +a higher bit-depth, you must either supply the background color as a gray +value at the original file bit-depth (need_expand = 1) or else supply the +background color as an RGB triplet at the final, expanded bit depth +(need_expand = 0). Similarly, if you are reading a paletted image, you +must either supply the background color as a palette index (need_expand = 1) +or as an RGB triplet that may or may not be in the palette (need_expand = 0). + + png_color_16 my_background; + png_color_16p image_background; + + if (png_get_bKGD(png_ptr, info_ptr, &image_background)) + png_set_background(png_ptr, image_background, + PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); + else + png_set_background(png_ptr, &my_background, + PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); + +The png_set_background() function tells libpng to composite images +with alpha or simple transparency against the supplied background +color. If the PNG file contains a bKGD chunk (PNG_INFO_bKGD valid), +you may use this color, or supply another color more suitable for +the current display (e.g., the background color from a web page). You +need to tell libpng whether the color is in the gamma space of the +display (PNG_BACKGROUND_GAMMA_SCREEN for colors you supply), the file +(PNG_BACKGROUND_GAMMA_FILE for colors from the bKGD chunk), or one +that is neither of these gammas (PNG_BACKGROUND_GAMMA_UNIQUE - I don't +know why anyone would use this, but it's here). + +To properly display PNG images on any kind of system, the application needs +to know what the display gamma is. Ideally, the user will know this, and +the application will allow them to set it. One method of allowing the user +to set the display gamma separately for each system is to check for a +SCREEN_GAMMA or DISPLAY_GAMMA environment variable, which will hopefully be +correctly set. + +Note that display_gamma is the overall gamma correction required to produce +pleasing results, which depends on the lighting conditions in the surrounding +environment. In a dim or brightly lit room, no compensation other than +the physical gamma exponent of the monitor is needed, while in a dark room +a slightly smaller exponent is better. + + double gamma, screen_gamma; + + if (/* We have a user-defined screen + gamma value */) + { + screen_gamma = user_defined_screen_gamma; + } + /* One way that applications can share the same + screen gamma value */ + else if ((gamma_str = getenv("SCREEN_GAMMA")) + != NULL) + { + screen_gamma = (double)atof(gamma_str); + } + /* If we don't have another value */ + else + { + screen_gamma = 2.2; /* A good guess for a + PC monitor in a bright office or a dim room */ + screen_gamma = 2.0; /* A good guess for a + PC monitor in a dark room */ + screen_gamma = 1.7 or 1.0; /* A good + guess for Mac systems */ + } + +The png_set_gamma() function handles gamma transformations of the data. +Pass both the file gamma and the current screen_gamma. If the file does +not have a gamma value, you can pass one anyway if you have an idea what +it is (usually 0.45455 is a good guess for GIF images on PCs). Note +that file gammas are inverted from screen gammas. See the discussions +on gamma in the PNG specification for an excellent description of what +gamma is, and why all applications should support it. It is strongly +recommended that PNG viewers support gamma correction. + + if (png_get_gAMA(png_ptr, info_ptr, &gamma)) + png_set_gamma(png_ptr, screen_gamma, gamma); + else + png_set_gamma(png_ptr, screen_gamma, 0.45455); + +If you need to reduce an RGB file to a paletted file, or if a paletted +file has more entries then will fit on your screen, png_set_dither() +will do that. Note that this is a simple match dither that merely +finds the closest color available. This should work fairly well with +optimized palettes, and fairly badly with linear color cubes. If you +pass a palette that is larger then maximum_colors, the file will +reduce the number of colors in the palette so it will fit into +maximum_colors. If there is a histogram, it will use it to make +more intelligent choices when reducing the palette. If there is no +histogram, it may not do as good a job. + + if (color_type & PNG_COLOR_MASK_COLOR) + { + if (png_get_valid(png_ptr, info_ptr, + PNG_INFO_PLTE)) + { + png_uint_16p histogram = NULL; + + png_get_hIST(png_ptr, info_ptr, + &histogram); + png_set_dither(png_ptr, palette, num_palette, + max_screen_colors, histogram, 1); + } + else + { + png_color std_color_cube[MAX_SCREEN_COLORS] = + { ... colors ... }; + + png_set_dither(png_ptr, std_color_cube, + MAX_SCREEN_COLORS, MAX_SCREEN_COLORS, + NULL,0); + } + } + +PNG files describe monochrome as black being zero and white being one. +The following code will reverse this (make black be one and white be +zero): + + if (bit_depth == 1 && color_type == PNG_COLOR_TYPE_GRAY) + png_set_invert_mono(png_ptr); + +This function can also be used to invert grayscale and gray-alpha images: + + if (color_type == PNG_COLOR_TYPE_GRAY || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_invert_mono(png_ptr); + +PNG files store 16 bit pixels in network byte order (big-endian, +ie. most significant bits first). This code changes the storage to the +other way (little-endian, i.e. least significant bits first, the +way PCs store them): + + if (bit_depth == 16) + png_set_swap(png_ptr); + +If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you +need to change the order the pixels are packed into bytes, you can use: + + if (bit_depth < 8) + png_set_packswap(png_ptr); + +Finally, you can write your own transformation function if none of +the existing ones meets your needs. This is done by setting a callback +with + + png_set_read_user_transform_fn(png_ptr, + read_transform_fn); + +You must supply the function + + void read_transform_fn(png_ptr ptr, row_info_ptr + row_info, png_bytep data) + +See pngtest.c for a working example. Your function will be called +after all of the other transformations have been processed. + +You can also set up a pointer to a user structure for use by your +callback function, and you can inform libpng that your transform +function will change the number of channels or bit depth with the +function + + png_set_user_transform_info(png_ptr, user_ptr, + user_depth, user_channels); + +The user's application, not libpng, is responsible for allocating and +freeing any memory required for the user structure. + +You can retrieve the pointer via the function +png_get_user_transform_ptr(). For example: + + voidp read_user_transform_ptr = + png_get_user_transform_ptr(png_ptr); + +The last thing to handle is interlacing; this is covered in detail below, +but you must call the function here if you want libpng to handle expansion +of the interlaced image. + + number_of_passes = png_set_interlace_handling(png_ptr); + +After setting the transformations, libpng can update your png_info +structure to reflect any transformations you've requested with this +call. This is most useful to update the info structure's rowbytes +field so you can use it to allocate your image memory. This function +will also update your palette with the correct screen_gamma and +background if these have been given with the calls above. + + png_read_update_info(png_ptr, info_ptr); + +After you call png_read_update_info(), you can allocate any +memory you need to hold the image. The row data is simply +raw byte data for all forms of images. As the actual allocation +varies among applications, no example will be given. If you +are allocating one large chunk, you will need to build an +array of pointers to each row, as it will be needed for some +of the functions below. + +Reading image data + +After you've allocated memory, you can read the image data. +The simplest way to do this is in one function call. If you are +allocating enough memory to hold the whole image, you can just +call png_read_image() and libpng will read in all the image data +and put it in the memory area supplied. You will need to pass in +an array of pointers to each row. + +This function automatically handles interlacing, so you don't need +to call png_set_interlace_handling() or call this function multiple +times, or any of that other stuff necessary with png_read_rows(). + + png_read_image(png_ptr, row_pointers); + +where row_pointers is: + + png_bytep row_pointers[height]; + +You can point to void or char or whatever you use for pixels. + +If you don't want to read in the whole image at once, you can +use png_read_rows() instead. If there is no interlacing (check +interlace_type == PNG_INTERLACE_NONE), this is simple: + + png_read_rows(png_ptr, row_pointers, NULL, + number_of_rows); + +where row_pointers is the same as in the png_read_image() call. + +If you are doing this just one row at a time, you can do this with +a single row_pointer instead of an array of row_pointers: + + png_bytep row_pointer = row; + png_read_row(png_ptr, row_pointer, NULL); + +If the file is interlaced (interlace_type != 0 in the IHDR chunk), things +get somewhat harder. The only current (PNG Specification version 1.2) +interlacing type for PNG is (interlace_type == PNG_INTERLACE_ADAM7) +is a somewhat complicated 2D interlace scheme, known as Adam7, that +breaks down an image into seven smaller images of varying size, based +on an 8x8 grid. + +libpng can fill out those images or it can give them to you "as is". +If you want them filled out, there are two ways to do that. The one +mentioned in the PNG specification is to expand each pixel to cover +those pixels that have not been read yet (the "rectangle" method). +This results in a blocky image for the first pass, which gradually +smooths out as more pixels are read. The other method is the "sparkle" +method, where pixels are drawn only in their final locations, with the +rest of the image remaining whatever colors they were initialized to +before the start of the read. The first method usually looks better, +but tends to be slower, as there are more pixels to put in the rows. + +If you don't want libpng to handle the interlacing details, just call +png_read_rows() seven times to read in all seven images. Each of the +images is a valid image by itself, or they can all be combined on an +8x8 grid to form a single image (although if you intend to combine them +you would be far better off using the libpng interlace handling). + +The first pass will return an image 1/8 as wide as the entire image +(every 8th column starting in column 0) and 1/8 as high as the original +(every 8th row starting in row 0), the second will be 1/8 as wide +(starting in column 4) and 1/8 as high (also starting in row 0). The +third pass will be 1/4 as wide (every 4th pixel starting in column 0) and +1/8 as high (every 8th row starting in row 4), and the fourth pass will +be 1/4 as wide and 1/4 as high (every 4th column starting in column 2, +and every 4th row starting in row 0). The fifth pass will return an +image 1/2 as wide, and 1/4 as high (starting at column 0 and row 2), +while the sixth pass will be 1/2 as wide and 1/2 as high as the original +(starting in column 1 and row 0). The seventh and final pass will be as +wide as the original, and 1/2 as high, containing all of the odd +numbered scanlines. Phew! + +If you want libpng to expand the images, call this before calling +png_start_read_image() or png_read_update_info(): + + if (interlace_type == PNG_INTERLACE_ADAM7) + number_of_passes + = png_set_interlace_handling(png_ptr); + +This will return the number of passes needed. Currently, this +is seven, but may change if another interlace type is added. +This function can be called even if the file is not interlaced, +where it will return one pass. + +If you are not going to display the image after each pass, but are +going to wait until the entire image is read in, use the sparkle +effect. This effect is faster and the end result of either method +is exactly the same. If you are planning on displaying the image +after each pass, the "rectangle" effect is generally considered the +better looking one. + +If you only want the "sparkle" effect, just call png_read_rows() as +normal, with the third parameter NULL. Make sure you make pass over +the image number_of_passes times, and you don't change the data in the +rows between calls. You can change the locations of the data, just +not the data. Each pass only writes the pixels appropriate for that +pass, and assumes the data from previous passes is still valid. + + png_read_rows(png_ptr, row_pointers, NULL, + number_of_rows); + +If you only want the first effect (the rectangles), do the same as +before except pass the row buffer in the third parameter, and leave +the second parameter NULL. + + png_read_rows(png_ptr, NULL, row_pointers, + number_of_rows); + +Finishing a sequential read + +After you are finished reading the image through either the high- or +low-level interfaces, you can finish reading the file. If you are +interested in comments or time, which may be stored either before or +after the image data, you should pass the separate png_info struct if +you want to keep the comments from before and after the image +separate. If you are not interested, you can pass NULL. + + png_read_end(png_ptr, end_info); + +When you are done, you can free all memory allocated by libpng like this: + + png_destroy_read_struct(&png_ptr, &info_ptr, + &end_info); + +It is also possible to individually free the info_ptr members that +point to libpng-allocated storage with the following function: + + png_free_data(png_ptr, info_ptr, mask, seq) + mask - identifies data to be freed, a mask + containing the logical OR of one or + more of + PNG_FREE_PLTE, PNG_FREE_TRNS, + PNG_FREE_HIST, PNG_FREE_ICCP, + PNG_FREE_PCAL, PNG_FREE_ROWS, + PNG_FREE_SCAL, PNG_FREE_SPLT, + PNG_FREE_TEXT, PNG_FREE_UNKN, + or simply PNG_FREE_ALL + seq - sequence number of item to be freed + (-1 for all items) + +This function may be safely called when the relevant storage has +already been freed, or has not yet been allocated, or was allocated +by the user and not by libpng, and will in those +cases do nothing. The "seq" parameter is ignored if only one item +of the selected data type, such as PLTE, is allowed. If "seq" is not +-1, and multiple items are allowed for the data type identified in +the mask, such as text or sPLT, only the n'th item in the structure +is freed, where n is "seq". + +The default behavior is only to free data that was allocated internally +by libpng. This can be changed, so that libpng will not free the data, +or so that it will free data that was allocated by the user with png_malloc() +or png_zalloc() and passed in via a png_set_*() function, with + + png_data_freer(png_ptr, info_ptr, freer, mask) + mask - which data elements are affected + same choices as in png_free_data() + freer - one of + PNG_DESTROY_WILL_FREE_DATA + PNG_SET_WILL_FREE_DATA + PNG_USER_WILL_FREE_DATA + +This function only affects data that has already been allocated. +You can call this function after reading the PNG data but before calling +any png_set_*() functions, to control whether the user or the png_set_*() +function is responsible for freeing any existing data that might be present, +and again after the png_set_*() functions to control whether the user +or png_destroy_*() is supposed to free the data. When the user assumes +responsibility for libpng-allocated data, the application must use +png_free() to free it, and when the user transfers responsibility to libpng +for data that the user has allocated, the user must have used png_malloc() +or png_zalloc() to allocate it. + +If you allocated your row_pointers in a single block, as suggested above in +the description of the high level read interface, you must not transfer +responsibility for freeing it to the png_set_rows or png_read_destroy function, +because they would also try to free the individual row_pointers[i]. + +If you allocated text_ptr.text, text_ptr.lang, and text_ptr.translated_keyword +separately, do not transfer responsibility for freeing text_ptr to libpng, +because when libpng fills a png_text structure it combines these members with +the key member, and png_free_data() will free only text_ptr.key. Similarly, +if you transfer responsibility for free'ing text_ptr from libpng to your +application, your application must not separately free those members. + +The png_free_data() function will turn off the "valid" flag for anything +it frees. If you need to turn the flag off for a chunk that was freed by your +application instead of by libpng, you can use + + png_set_invalid(png_ptr, info_ptr, mask); + mask - identifies the chunks to be made invalid, + containing the logical OR of one or + more of + PNG_INFO_gAMA, PNG_INFO_sBIT, + PNG_INFO_cHRM, PNG_INFO_PLTE, + PNG_INFO_tRNS, PNG_INFO_bKGD, + PNG_INFO_hIST, PNG_INFO_pHYs, + PNG_INFO_oFFs, PNG_INFO_tIME, + PNG_INFO_pCAL, PNG_INFO_sRGB, + PNG_INFO_iCCP, PNG_INFO_sPLT, + PNG_INFO_sCAL, PNG_INFO_IDAT + +For a more compact example of reading a PNG image, see the file example.c. + +Reading PNG files progressively + +The progressive reader is slightly different then the non-progressive +reader. Instead of calling png_read_info(), png_read_rows(), and +png_read_end(), you make one call to png_process_data(), which calls +callbacks when it has the info, a row, or the end of the image. You +set up these callbacks with png_set_progressive_read_fn(). You don't +have to worry about the input/output functions of libpng, as you are +giving the library the data directly in png_process_data(). I will +assume that you have read the section on reading PNG files above, +so I will only highlight the differences (although I will show +all of the code). + +png_structp png_ptr; +png_infop info_ptr; + + /* An example code fragment of how you would + initialize the progressive reader in your + application. */ + int + initialize_png_reader() + { + png_ptr = png_create_read_struct + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn); + if (!png_ptr) + return (ERROR); + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, + (png_infopp)NULL); + return (ERROR); + } + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, + (png_infopp)NULL); + return (ERROR); + } + + /* This one's new. You can provide functions + to be called when the header info is valid, + when each row is completed, and when the image + is finished. If you aren't using all functions, + you can specify NULL parameters. Even when all + three functions are NULL, you need to call + png_set_progressive_read_fn(). You can use + any struct as the user_ptr (cast to a void pointer + for the function call), and retrieve the pointer + from inside the callbacks using the function + + png_get_progressive_ptr(png_ptr); + + which will return a void pointer, which you have + to cast appropriately. + */ + png_set_progressive_read_fn(png_ptr, (void *)user_ptr, + info_callback, row_callback, end_callback); + + return 0; + } + + /* A code fragment that you call as you receive blocks + of data */ + int + process_data(png_bytep buffer, png_uint_32 length) + { + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, + (png_infopp)NULL); + return (ERROR); + } + + /* This one's new also. Simply give it a chunk + of data from the file stream (in order, of + course). On machines with segmented memory + models machines, don't give it any more than + 64K. The library seems to run fine with sizes + of 4K. Although you can give it much less if + necessary (I assume you can give it chunks of + 1 byte, I haven't tried less then 256 bytes + yet). When this function returns, you may + want to display any rows that were generated + in the row callback if you don't already do + so there. + */ + png_process_data(png_ptr, info_ptr, buffer, length); + return 0; + } + + /* This function is called (as set by + png_set_progressive_read_fn() above) when enough data + has been supplied so all of the header has been + read. + */ + void + info_callback(png_structp png_ptr, png_infop info) + { + /* Do any setup here, including setting any of + the transformations mentioned in the Reading + PNG files section. For now, you _must_ call + either png_start_read_image() or + png_read_update_info() after all the + transformations are set (even if you don't set + any). You may start getting rows before + png_process_data() returns, so this is your + last chance to prepare for that. + */ + } + + /* This function is called when each row of image + data is complete */ + void + row_callback(png_structp png_ptr, png_bytep new_row, + png_uint_32 row_num, int pass) + { + /* If the image is interlaced, and you turned + on the interlace handler, this function will + be called for every row in every pass. Some + of these rows will not be changed from the + previous pass. When the row is not changed, + the new_row variable will be NULL. The rows + and passes are called in order, so you don't + really need the row_num and pass, but I'm + supplying them because it may make your life + easier. + + For the non-NULL rows of interlaced images, + you must call png_progressive_combine_row() + passing in the row and the old row. You can + call this function for NULL rows (it will just + return) and for non-interlaced images (it just + does the memcpy for you) if it will make the + code easier. Thus, you can just do this for + all cases: + */ + + png_progressive_combine_row(png_ptr, old_row, + new_row); + + /* where old_row is what was displayed for + previously for the row. Note that the first + pass (pass == 0, really) will completely cover + the old row, so the rows do not have to be + initialized. After the first pass (and only + for interlaced images), you will have to pass + the current row, and the function will combine + the old row and the new row. + */ + } + + void + end_callback(png_structp png_ptr, png_infop info) + { + /* This function is called after the whole image + has been read, including any chunks after the + image (up to and including the IEND). You + will usually have the same info chunk as you + had in the header, although some data may have + been added to the comments and time fields. + + Most people won't do much here, perhaps setting + a flag that marks the image as finished. + */ + } + + + +IV. Writing + +Much of this is very similar to reading. However, everything of +importance is repeated here, so you won't have to constantly look +back up in the reading section to understand writing. + +Setup + +You will want to do the I/O initialization before you get into libpng, +so if it doesn't work, you don't have anything to undo. If you are not +using the standard I/O functions, you will need to replace them with +custom writing functions. See the discussion under Customizing libpng. + + FILE *fp = fopen(file_name, "wb"); + if (!fp) + { + return (ERROR); + } + +Next, png_struct and png_info need to be allocated and initialized. +As these can be both relatively large, you may not want to store these +on the stack, unless you have stack space to spare. Of course, you +will want to check if they return NULL. If you are also reading, +you won't want to name your read structure and your write structure +both "png_ptr"; you can call them anything you like, such as +"read_ptr" and "write_ptr". Look at pngtest.c, for example. + + png_structp png_ptr = png_create_write_struct + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn); + if (!png_ptr) + return (ERROR); + + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_write_struct(&png_ptr, + (png_infopp)NULL); + return (ERROR); + } + +If you want to use your own memory allocation routines, +define PNG_USER_MEM_SUPPORTED and use +png_create_write_struct_2() instead of png_create_write_struct(): + + png_structp png_ptr = png_create_write_struct_2 + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn, (png_voidp) + user_mem_ptr, user_malloc_fn, user_free_fn); + +After you have these structures, you will need to set up the +error handling. When libpng encounters an error, it expects to +longjmp() back to your routine. Therefore, you will need to call +setjmp() and pass the png_jmpbuf(png_ptr). If you +write the file from different routines, you will need to update +the png_jmpbuf(png_ptr) every time you enter a new routine that will +call a png_*() function. See your documentation of setjmp/longjmp +for your compiler for more information on setjmp/longjmp. See +the discussion on libpng error handling in the Customizing Libpng +section below for more information on the libpng error handling. + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(fp); + return (ERROR); + } + ... + return; + +If you would rather avoid the complexity of setjmp/longjmp issues, +you can compile libpng with PNG_SETJMP_NOT_SUPPORTED, in which case +errors will result in a call to PNG_ABORT() which defaults to abort(). + +Now you need to set up the output code. The default for libpng is to +use the C function fwrite(). If you use this, you will need to pass a +valid FILE * in the function png_init_io(). Be sure that the file is +opened in binary mode. Again, if you wish to handle writing data in +another way, see the discussion on libpng I/O handling in the Customizing +Libpng section below. + + png_init_io(png_ptr, fp); + +Write callbacks + +At this point, you can set up a callback function that will be +called after each row has been written, which you can use to control +a progress meter or the like. It's demonstrated in pngtest.c. +You must supply a function + + void write_row_callback(png_ptr, png_uint_32 row, + int pass); + { + /* put your code here */ + } + +(You can give it another name that you like instead of "write_row_callback") + +To inform libpng about your function, use + + png_set_write_status_fn(png_ptr, write_row_callback); + +You now have the option of modifying how the compression library will +run. The following functions are mainly for testing, but may be useful +in some cases, like if you need to write PNG files extremely fast and +are willing to give up some compression, or if you want to get the +maximum possible compression at the expense of slower writing. If you +have no special needs in this area, let the library do what it wants by +not calling this function at all, as it has been tuned to deliver a good +speed/compression ratio. The second parameter to png_set_filter() is +the filter method, for which the only valid values are 0 (as of the +July 1999 PNG specification, version 1.2) or 64 (if you are writing +a PNG datastream that is to be embedded in a MNG datastream). The third +parameter is a flag that indicates which filter type(s) are to be tested +for each scanline. See the PNG specification for details on the specific filter +types. + + + /* turn on or off filtering, and/or choose + specific filters. You can use either a single + PNG_FILTER_VALUE_NAME or the logical OR of one + or more PNG_FILTER_NAME masks. */ + png_set_filter(png_ptr, 0, + PNG_FILTER_NONE | PNG_FILTER_VALUE_NONE | + PNG_FILTER_SUB | PNG_FILTER_VALUE_SUB | + PNG_FILTER_UP | PNG_FILTER_VALUE_UP | + PNG_FILTER_AVE | PNG_FILTER_VALUE_AVE | + PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH| + PNG_ALL_FILTERS); + +If an application +wants to start and stop using particular filters during compression, +it should start out with all of the filters (to ensure that the previous +row of pixels will be stored in case it's needed later), and then add +and remove them after the start of compression. + +If you are writing a PNG datastream that is to be embedded in a MNG +datastream, the second parameter can be either 0 or 64. + +The png_set_compression_*() functions interface to the zlib compression +library, and should mostly be ignored unless you really know what you are +doing. The only generally useful call is png_set_compression_level() +which changes how much time zlib spends on trying to compress the image +data. See the Compression Library (zlib.h and algorithm.txt, distributed +with zlib) for details on the compression levels. + + /* set the zlib compression level */ + png_set_compression_level(png_ptr, + Z_BEST_COMPRESSION); + + /* set other zlib parameters */ + png_set_compression_mem_level(png_ptr, 8); + png_set_compression_strategy(png_ptr, + Z_DEFAULT_STRATEGY); + png_set_compression_window_bits(png_ptr, 15); + png_set_compression_method(png_ptr, 8); + png_set_compression_buffer_size(png_ptr, 8192) + +extern PNG_EXPORT(void,png_set_zbuf_size) + +Setting the contents of info for output + +You now need to fill in the png_info structure with all the data you +wish to write before the actual image. Note that the only thing you +are allowed to write after the image is the text chunks and the time +chunk (as of PNG Specification 1.2, anyway). See png_write_end() and +the latest PNG specification for more information on that. If you +wish to write them before the image, fill them in now, and flag that +data as being valid. If you want to wait until after the data, don't +fill them until png_write_end(). For all the fields in png_info and +their data types, see png.h. For explanations of what the fields +contain, see the PNG specification. + +Some of the more important parts of the png_info are: + + png_set_IHDR(png_ptr, info_ptr, width, height, + bit_depth, color_type, interlace_type, + compression_type, filter_method) + width - holds the width of the image + in pixels (up to 2^31). + height - holds the height of the image + in pixels (up to 2^31). + bit_depth - holds the bit depth of one of the + image channels. + (valid values are 1, 2, 4, 8, 16 + and depend also on the + color_type. See also significant + bits (sBIT) below). + color_type - describes which color/alpha + channels are present. + PNG_COLOR_TYPE_GRAY + (bit depths 1, 2, 4, 8, 16) + PNG_COLOR_TYPE_GRAY_ALPHA + (bit depths 8, 16) + PNG_COLOR_TYPE_PALETTE + (bit depths 1, 2, 4, 8) + PNG_COLOR_TYPE_RGB + (bit_depths 8, 16) + PNG_COLOR_TYPE_RGB_ALPHA + (bit_depths 8, 16) + + PNG_COLOR_MASK_PALETTE + PNG_COLOR_MASK_COLOR + PNG_COLOR_MASK_ALPHA + + interlace_type - PNG_INTERLACE_NONE or + PNG_INTERLACE_ADAM7 + compression_type - (must be + PNG_COMPRESSION_TYPE_DEFAULT) + filter_method - (must be PNG_FILTER_TYPE_DEFAULT + or, if you are writing a PNG to + be embedded in a MNG datastream, + can also be + PNG_INTRAPIXEL_DIFFERENCING) + + png_set_PLTE(png_ptr, info_ptr, palette, + num_palette); + palette - the palette for the file + (array of png_color) + num_palette - number of entries in the palette + + png_set_gAMA(png_ptr, info_ptr, gamma); + gamma - the gamma the image was created + at (PNG_INFO_gAMA) + + png_set_sRGB(png_ptr, info_ptr, srgb_intent); + srgb_intent - the rendering intent + (PNG_INFO_sRGB) The presence of + the sRGB chunk means that the pixel + data is in the sRGB color space. + This chunk also implies specific + values of gAMA and cHRM. Rendering + intent is the CSS-1 property that + has been defined by the International + Color Consortium + (http://www.color.org). + It can be one of + PNG_sRGB_INTENT_SATURATION, + PNG_sRGB_INTENT_PERCEPTUAL, + PNG_sRGB_INTENT_ABSOLUTE, or + PNG_sRGB_INTENT_RELATIVE. + + + png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, + srgb_intent); + srgb_intent - the rendering intent + (PNG_INFO_sRGB) The presence of the + sRGB chunk means that the pixel + data is in the sRGB color space. + This function also causes gAMA and + cHRM chunks with the specific values + that are consistent with sRGB to be + written. + + png_set_iCCP(png_ptr, info_ptr, name, compression_type, + profile, proflen); + name - The profile name. + compression - The compression type; always + PNG_COMPRESSION_TYPE_BASE for PNG 1.0. + You may give NULL to this argument to + ignore it. + profile - International Color Consortium color + profile data. May contain NULs. + proflen - length of profile data in bytes. + + png_set_sBIT(png_ptr, info_ptr, sig_bit); + sig_bit - the number of significant bits for + (PNG_INFO_sBIT) each of the gray, red, + green, and blue channels, whichever are + appropriate for the given color type + (png_color_16) + + png_set_tRNS(png_ptr, info_ptr, trans, num_trans, + trans_values); + trans - array of transparent entries for + palette (PNG_INFO_tRNS) + trans_values - graylevel or color sample values of + the single transparent color for + non-paletted images (PNG_INFO_tRNS) + num_trans - number of transparent entries + (PNG_INFO_tRNS) + + png_set_hIST(png_ptr, info_ptr, hist); + (PNG_INFO_hIST) + hist - histogram of palette (array of + png_uint_16) + + png_set_tIME(png_ptr, info_ptr, mod_time); + mod_time - time image was last modified + (PNG_VALID_tIME) + + png_set_bKGD(png_ptr, info_ptr, background); + background - background color (PNG_VALID_bKGD) + + png_set_text(png_ptr, info_ptr, text_ptr, num_text); + text_ptr - array of png_text holding image + comments + text_ptr[i].compression - type of compression used + on "text" PNG_TEXT_COMPRESSION_NONE + PNG_TEXT_COMPRESSION_zTXt + PNG_ITXT_COMPRESSION_NONE + PNG_ITXT_COMPRESSION_zTXt + text_ptr[i].key - keyword for comment. Must contain + 1-79 characters. + text_ptr[i].text - text comments for current + keyword. Can be NULL or empty. + text_ptr[i].text_length - length of text string, + after decompression, 0 for iTXt + text_ptr[i].itxt_length - length of itxt string, + after decompression, 0 for tEXt/zTXt + text_ptr[i].lang - language of comment (NULL or + empty for unknown). + text_ptr[i].translated_keyword - keyword in UTF-8 (NULL + or empty for unknown). + num_text - number of comments + + png_set_sPLT(png_ptr, info_ptr, &palette_ptr, + num_spalettes); + palette_ptr - array of png_sPLT_struct structures + to be added to the list of palettes + in the info structure. + num_spalettes - number of palette structures to be + added. + + png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, + unit_type); + offset_x - positive offset from the left + edge of the screen + offset_y - positive offset from the top + edge of the screen + unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER + + png_set_pHYs(png_ptr, info_ptr, res_x, res_y, + unit_type); + res_x - pixels/unit physical resolution + in x direction + res_y - pixels/unit physical resolution + in y direction + unit_type - PNG_RESOLUTION_UNKNOWN, + PNG_RESOLUTION_METER + + png_set_sCAL(png_ptr, info_ptr, unit, width, height) + unit - physical scale units (an integer) + width - width of a pixel in physical scale units + height - height of a pixel in physical scale units + (width and height are doubles) + + png_set_sCAL_s(png_ptr, info_ptr, unit, width, height) + unit - physical scale units (an integer) + width - width of a pixel in physical scale units + height - height of a pixel in physical scale units + (width and height are strings like "2.54") + + png_set_unknown_chunks(png_ptr, info_ptr, &unknowns, + num_unknowns) + unknowns - array of png_unknown_chunk + structures holding unknown chunks + unknowns[i].name - name of unknown chunk + unknowns[i].data - data of unknown chunk + unknowns[i].size - size of unknown chunk's data + unknowns[i].location - position to write chunk in file + 0: do not write chunk + PNG_HAVE_IHDR: before PLTE + PNG_HAVE_PLTE: before IDAT + PNG_AFTER_IDAT: after IDAT + +The "location" member is set automatically according to +what part of the output file has already been written. +You can change its value after calling png_set_unknown_chunks() +as demonstrated in pngtest.c. Within each of the "locations", +the chunks are sequenced according to their position in the +structure (that is, the value of "i", which is the order in which +the chunk was either read from the input file or defined with +png_set_unknown_chunks). + +A quick word about text and num_text. text is an array of png_text +structures. num_text is the number of valid structures in the array. +Each png_text structure holds a language code, a keyword, a text value, +and a compression type. + +The compression types have the same valid numbers as the compression +types of the image data. Currently, the only valid number is zero. +However, you can store text either compressed or uncompressed, unlike +images, which always have to be compressed. So if you don't want the +text compressed, set the compression type to PNG_TEXT_COMPRESSION_NONE. +Because tEXt and zTXt chunks don't have a language field, if you +specify PNG_TEXT_COMPRESSION_NONE or PNG_TEXT_COMPRESSION_zTXt +any language code or translated keyword will not be written out. + +Until text gets around 1000 bytes, it is not worth compressing it. +After the text has been written out to the file, the compression type +is set to PNG_TEXT_COMPRESSION_NONE_WR or PNG_TEXT_COMPRESSION_zTXt_WR, +so that it isn't written out again at the end (in case you are calling +png_write_end() with the same struct. + +The keywords that are given in the PNG Specification are: + + Title Short (one line) title or + caption for image + Author Name of image's creator + Description Description of image (possibly long) + Copyright Copyright notice + Creation Time Time of original image creation + (usually RFC 1123 format, see below) + Software Software used to create the image + Disclaimer Legal disclaimer + Warning Warning of nature of content + Source Device used to create the image + Comment Miscellaneous comment; conversion + from other image format + +The keyword-text pairs work like this. Keywords should be short +simple descriptions of what the comment is about. Some typical +keywords are found in the PNG specification, as is some recommendations +on keywords. You can repeat keywords in a file. You can even write +some text before the image and some after. For example, you may want +to put a description of the image before the image, but leave the +disclaimer until after, so viewers working over modem connections +don't have to wait for the disclaimer to go over the modem before +they start seeing the image. Finally, keywords should be full +words, not abbreviations. Keywords and text are in the ISO 8859-1 +(Latin-1) character set (a superset of regular ASCII) and can not +contain NUL characters, and should not contain control or other +unprintable characters. To make the comments widely readable, stick +with basic ASCII, and avoid machine specific character set extensions +like the IBM-PC character set. The keyword must be present, but +you can leave off the text string on non-compressed pairs. +Compressed pairs must have a text string, as only the text string +is compressed anyway, so the compression would be meaningless. + +PNG supports modification time via the png_time structure. Two +conversion routines are provided, png_convert_from_time_t() for +time_t and png_convert_from_struct_tm() for struct tm. The +time_t routine uses gmtime(). You don't have to use either of +these, but if you wish to fill in the png_time structure directly, +you should provide the time in universal time (GMT) if possible +instead of your local time. Note that the year number is the full +year (e.g. 1998, rather than 98 - PNG is year 2000 compliant!), and +that months start with 1. + +If you want to store the time of the original image creation, you should +use a plain tEXt chunk with the "Creation Time" keyword. This is +necessary because the "creation time" of a PNG image is somewhat vague, +depending on whether you mean the PNG file, the time the image was +created in a non-PNG format, a still photo from which the image was +scanned, or possibly the subject matter itself. In order to facilitate +machine-readable dates, it is recommended that the "Creation Time" +tEXt chunk use RFC 1123 format dates (e.g. "22 May 1997 18:07:10 GMT"), +although this isn't a requirement. Unlike the tIME chunk, the +"Creation Time" tEXt chunk is not expected to be automatically changed +by the software. To facilitate the use of RFC 1123 dates, a function +png_convert_to_rfc1123(png_timep) is provided to convert from PNG +time to an RFC 1123 format string. + +Writing unknown chunks + +You can use the png_set_unknown_chunks function to queue up chunks +for writing. You give it a chunk name, raw data, and a size; that's +all there is to it. The chunks will be written by the next following +png_write_info_before_PLTE, png_write_info, or png_write_end function. +Any chunks previously read into the info structure's unknown-chunk +list will also be written out in a sequence that satisfies the PNG +specification's ordering rules. + +The high-level write interface + +At this point there are two ways to proceed; through the high-level +write interface, or through a sequence of low-level write operations. +You can use the high-level interface if your image data is present +in the info structure. All defined output +transformations are permitted, enabled by the following masks. + + PNG_TRANSFORM_IDENTITY No transformation + PNG_TRANSFORM_PACKING Pack 1, 2 and 4-bit samples + PNG_TRANSFORM_PACKSWAP Change order of packed + pixels to LSB first + PNG_TRANSFORM_INVERT_MONO Invert monochrome images + PNG_TRANSFORM_SHIFT Normalize pixels to the + sBIT depth + PNG_TRANSFORM_BGR Flip RGB to BGR, RGBA + to BGRA + PNG_TRANSFORM_SWAP_ALPHA Flip RGBA to ARGB or GA + to AG + PNG_TRANSFORM_INVERT_ALPHA Change alpha from opacity + to transparency + PNG_TRANSFORM_SWAP_ENDIAN Byte-swap 16-bit samples + PNG_TRANSFORM_STRIP_FILLER Strip out filler bytes. + +If you have valid image data in the info structure (you can use +png_set_rows() to put image data in the info structure), simply do this: + + png_write_png(png_ptr, info_ptr, png_transforms, NULL) + +where png_transforms is an integer containing the logical OR of some set of +transformation flags. This call is equivalent to png_write_info(), +followed the set of transformations indicated by the transform mask, +then png_write_image(), and finally png_write_end(). + +(The final parameter of this call is not yet used. Someday it might point +to transformation parameters required by some future output transform.) + +You must use png_transforms and not call any png_set_transform() functions +when you use png_write_png(). + +The low-level write interface + +If you are going the low-level route instead, you are now ready to +write all the file information up to the actual image data. You do +this with a call to png_write_info(). + + png_write_info(png_ptr, info_ptr); + +Note that there is one transformation you may need to do before +png_write_info(). In PNG files, the alpha channel in an image is the +level of opacity. If your data is supplied as a level of +transparency, you can invert the alpha channel before you write it, so +that 0 is fully transparent and 255 (in 8-bit or paletted images) or +65535 (in 16-bit images) is fully opaque, with + + png_set_invert_alpha(png_ptr); + +This must appear before png_write_info() instead of later with the +other transformations because in the case of paletted images the tRNS +chunk data has to be inverted before the tRNS chunk is written. If +your image is not a paletted image, the tRNS data (which in such cases +represents a single color to be rendered as transparent) won't need to +be changed, and you can safely do this transformation after your +png_write_info() call. + +If you need to write a private chunk that you want to appear before +the PLTE chunk when PLTE is present, you can write the PNG info in +two steps, and insert code to write your own chunk between them: + + png_write_info_before_PLTE(png_ptr, info_ptr); + png_set_unknown_chunks(png_ptr, info_ptr, ...); + png_write_info(png_ptr, info_ptr); + +After you've written the file information, you can set up the library +to handle any special transformations of the image data. The various +ways to transform the data will be described in the order that they +should occur. This is important, as some of these change the color +type and/or bit depth of the data, and some others only work on +certain color types and bit depths. Even though each transformation +checks to see if it has data that it can do something with, you should +make sure to only enable a transformation if it will be valid for the +data. For example, don't swap red and blue on grayscale data. + +PNG files store RGB pixels packed into 3 or 6 bytes. This code tells +the library to strip input data that has 4 or 8 bytes per pixel down +to 3 or 6 bytes (or strip 2 or 4-byte grayscale+filler data to 1 or 2 +bytes per pixel). + + png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); + +where the 0 is unused, and the location is either PNG_FILLER_BEFORE or +PNG_FILLER_AFTER, depending upon whether the filler byte in the pixel +is stored XRGB or RGBX. + +PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as +they can, resulting in, for example, 8 pixels per byte for 1 bit files. +If the data is supplied at 1 pixel per byte, use this code, which will +correctly pack the pixels into a single byte: + + png_set_packing(png_ptr); + +PNG files reduce possible bit depths to 1, 2, 4, 8, and 16. If your +data is of another bit depth, you can write an sBIT chunk into the +file so that decoders can recover the original data if desired. + + /* Set the true bit depth of the image data */ + if (color_type & PNG_COLOR_MASK_COLOR) + { + sig_bit.red = true_bit_depth; + sig_bit.green = true_bit_depth; + sig_bit.blue = true_bit_depth; + } + else + { + sig_bit.gray = true_bit_depth; + } + if (color_type & PNG_COLOR_MASK_ALPHA) + { + sig_bit.alpha = true_bit_depth; + } + + png_set_sBIT(png_ptr, info_ptr, &sig_bit); + +If the data is stored in the row buffer in a bit depth other than +one supported by PNG (e.g. 3 bit data in the range 0-7 for a 4-bit PNG), +this will scale the values to appear to be the correct bit depth as +is required by PNG. + + png_set_shift(png_ptr, &sig_bit); + +PNG files store 16 bit pixels in network byte order (big-endian, +ie. most significant bits first). This code would be used if they are +supplied the other way (little-endian, i.e. least significant bits +first, the way PCs store them): + + if (bit_depth > 8) + png_set_swap(png_ptr); + +If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you +need to change the order the pixels are packed into bytes, you can use: + + if (bit_depth < 8) + png_set_packswap(png_ptr); + +PNG files store 3 color pixels in red, green, blue order. This code +would be used if they are supplied as blue, green, red: + + png_set_bgr(png_ptr); + +PNG files describe monochrome as black being zero and white being +one. This code would be used if the pixels are supplied with this reversed +(black being one and white being zero): + + png_set_invert_mono(png_ptr); + +Finally, you can write your own transformation function if none of +the existing ones meets your needs. This is done by setting a callback +with + + png_set_write_user_transform_fn(png_ptr, + write_transform_fn); + +You must supply the function + + void write_transform_fn(png_ptr ptr, row_info_ptr + row_info, png_bytep data) + +See pngtest.c for a working example. Your function will be called +before any of the other transformations are processed. + +You can also set up a pointer to a user structure for use by your +callback function. + + png_set_user_transform_info(png_ptr, user_ptr, 0, 0); + +The user_channels and user_depth parameters of this function are ignored +when writing; you can set them to zero as shown. + +You can retrieve the pointer via the function png_get_user_transform_ptr(). +For example: + + voidp write_user_transform_ptr = + png_get_user_transform_ptr(png_ptr); + +It is possible to have libpng flush any pending output, either manually, +or automatically after a certain number of lines have been written. To +flush the output stream a single time call: + + png_write_flush(png_ptr); + +and to have libpng flush the output stream periodically after a certain +number of scanlines have been written, call: + + png_set_flush(png_ptr, nrows); + +Note that the distance between rows is from the last time png_write_flush() +was called, or the first row of the image if it has never been called. +So if you write 50 lines, and then png_set_flush 25, it will flush the +output on the next scanline, and every 25 lines thereafter, unless +png_write_flush() is called before 25 more lines have been written. +If nrows is too small (less than about 10 lines for a 640 pixel wide +RGB image) the image compression may decrease noticeably (although this +may be acceptable for real-time applications). Infrequent flushing will +only degrade the compression performance by a few percent over images +that do not use flushing. + +Writing the image data + +That's it for the transformations. Now you can write the image data. +The simplest way to do this is in one function call. If you have the +whole image in memory, you can just call png_write_image() and libpng +will write the image. You will need to pass in an array of pointers to +each row. This function automatically handles interlacing, so you don't +need to call png_set_interlace_handling() or call this function multiple +times, or any of that other stuff necessary with png_write_rows(). + + png_write_image(png_ptr, row_pointers); + +where row_pointers is: + + png_byte *row_pointers[height]; + +You can point to void or char or whatever you use for pixels. + +If you don't want to write the whole image at once, you can +use png_write_rows() instead. If the file is not interlaced, +this is simple: + + png_write_rows(png_ptr, row_pointers, + number_of_rows); + +row_pointers is the same as in the png_write_image() call. + +If you are just writing one row at a time, you can do this with +a single row_pointer instead of an array of row_pointers: + + png_bytep row_pointer = row; + + png_write_row(png_ptr, row_pointer); + +When the file is interlaced, things can get a good deal more +complicated. The only currently (as of the PNG Specification +version 1.2, dated July 1999) defined interlacing scheme for PNG files +is the "Adam7" interlace scheme, that breaks down an +image into seven smaller images of varying size. libpng will build +these images for you, or you can do them yourself. If you want to +build them yourself, see the PNG specification for details of which +pixels to write when. + +If you don't want libpng to handle the interlacing details, just +use png_set_interlace_handling() and call png_write_rows() the +correct number of times to write all seven sub-images. + +If you want libpng to build the sub-images, call this before you start +writing any rows: + + number_of_passes = + png_set_interlace_handling(png_ptr); + +This will return the number of passes needed. Currently, this +is seven, but may change if another interlace type is added. + +Then write the complete image number_of_passes times. + + png_write_rows(png_ptr, row_pointers, + number_of_rows); + +As some of these rows are not used, and thus return immediately, +you may want to read about interlacing in the PNG specification, +and only update the rows that are actually used. + +Finishing a sequential write + +After you are finished writing the image, you should finish writing +the file. If you are interested in writing comments or time, you should +pass an appropriately filled png_info pointer. If you are not interested, +you can pass NULL. + + png_write_end(png_ptr, info_ptr); + +When you are done, you can free all memory used by libpng like this: + + png_destroy_write_struct(&png_ptr, &info_ptr); + +It is also possible to individually free the info_ptr members that +point to libpng-allocated storage with the following function: + + png_free_data(png_ptr, info_ptr, mask, seq) + mask - identifies data to be freed, a mask + containing the logical OR of one or + more of + PNG_FREE_PLTE, PNG_FREE_TRNS, + PNG_FREE_HIST, PNG_FREE_ICCP, + PNG_FREE_PCAL, PNG_FREE_ROWS, + PNG_FREE_SCAL, PNG_FREE_SPLT, + PNG_FREE_TEXT, PNG_FREE_UNKN, + or simply PNG_FREE_ALL + seq - sequence number of item to be freed + (-1 for all items) + +This function may be safely called when the relevant storage has +already been freed, or has not yet been allocated, or was allocated +by the user and not by libpng, and will in those +cases do nothing. The "seq" parameter is ignored if only one item +of the selected data type, such as PLTE, is allowed. If "seq" is not +-1, and multiple items are allowed for the data type identified in +the mask, such as text or sPLT, only the n'th item in the structure +is freed, where n is "seq". + +If you allocated data such as a palette that you passed +in to libpng with png_set_*, you must not free it until just before the call to +png_destroy_write_struct(). + +The default behavior is only to free data that was allocated internally +by libpng. This can be changed, so that libpng will not free the data, +or so that it will free data that was allocated by the user with png_malloc() +or png_zalloc() and passed in via a png_set_*() function, with + + png_data_freer(png_ptr, info_ptr, freer, mask) + mask - which data elements are affected + same choices as in png_free_data() + freer - one of + PNG_DESTROY_WILL_FREE_DATA + PNG_SET_WILL_FREE_DATA + PNG_USER_WILL_FREE_DATA + +For example, to transfer responsibility for some data from a read structure +to a write structure, you could use + + png_data_freer(read_ptr, read_info_ptr, + PNG_USER_WILL_FREE_DATA, + PNG_FREE_PLTE|PNG_FREE_tRNS|PNG_FREE_hIST) + png_data_freer(write_ptr, write_info_ptr, + PNG_DESTROY_WILL_FREE_DATA, + PNG_FREE_PLTE|PNG_FREE_tRNS|PNG_FREE_hIST) + +thereby briefly reassigning responsibility for freeing to the user but +immediately afterwards reassigning it once more to the write_destroy +function. Having done this, it would then be safe to destroy the read +structure and continue to use the PLTE, tRNS, and hIST data in the write +structure. + +This function only affects data that has already been allocated. +You can call this function before calling after the png_set_*() functions +to control whether the user or png_destroy_*() is supposed to free the data. +When the user assumes responsibility for libpng-allocated data, the +application must use +png_free() to free it, and when the user transfers responsibility to libpng +for data that the user has allocated, the user must have used png_malloc() +or png_zalloc() to allocate it. + +If you allocated text_ptr.text, text_ptr.lang, and text_ptr.translated_keyword +separately, do not transfer responsibility for freeing text_ptr to libpng, +because when libpng fills a png_text structure it combines these members with +the key member, and png_free_data() will free only text_ptr.key. Similarly, +if you transfer responsibility for free'ing text_ptr from libpng to your +application, your application must not separately free those members. +For a more compact example of writing a PNG image, see the file example.c. + +V. Modifying/Customizing libpng: + +There are three issues here. The first is changing how libpng does +standard things like memory allocation, input/output, and error handling. +The second deals with more complicated things like adding new chunks, +adding new transformations, and generally changing how libpng works. +Both of those are compile-time issues; that is, they are generally +determined at the time the code is written, and there is rarely a need +to provide the user with a means of changing them. The third is a +run-time issue: choosing between and/or tuning one or more alternate +versions of computationally intensive routines; specifically, optimized +assembly-language (and therefore compiler- and platform-dependent) +versions. + +Memory allocation, input/output, and error handling + +All of the memory allocation, input/output, and error handling in libpng +goes through callbacks that are user-settable. The default routines are +in pngmem.c, pngrio.c, pngwio.c, and pngerror.c, respectively. To change +these functions, call the appropriate png_set_*_fn() function. + +Memory allocation is done through the functions png_malloc() +and png_free(). These currently just call the standard C functions. If +your pointers can't access more then 64K at a time, you will want to set +MAXSEG_64K in zlib.h. Since it is unlikely that the method of handling +memory allocation on a platform will change between applications, these +functions must be modified in the library at compile time. If you prefer +to use a different method of allocating and freeing data, you can use +png_create_read_struct_2() or png_create_write_struct_2() to register +your own functions as described above. +These functions also provide a void pointer that can be retrieved via + + mem_ptr=png_get_mem_ptr(png_ptr); + +Your replacement memory functions must have prototypes as follows: + + png_voidp malloc_fn(png_structp png_ptr, + png_size_t size); + void free_fn(png_structp png_ptr, png_voidp ptr); + +Your malloc_fn() must return NULL in case of failure. The png_malloc() +function will normally call png_error() if it receives a NULL from the +system memory allocator or from your replacement malloc_fn(). + +Input/Output in libpng is done through png_read() and png_write(), +which currently just call fread() and fwrite(). The FILE * is stored in +png_struct and is initialized via png_init_io(). If you wish to change +the method of I/O, the library supplies callbacks that you can set +through the function png_set_read_fn() and png_set_write_fn() at run +time, instead of calling the png_init_io() function. These functions +also provide a void pointer that can be retrieved via the function +png_get_io_ptr(). For example: + + png_set_read_fn(png_structp read_ptr, + voidp read_io_ptr, png_rw_ptr read_data_fn) + + png_set_write_fn(png_structp write_ptr, + voidp write_io_ptr, png_rw_ptr write_data_fn, + png_flush_ptr output_flush_fn); + + voidp read_io_ptr = png_get_io_ptr(read_ptr); + voidp write_io_ptr = png_get_io_ptr(write_ptr); + +The replacement I/O functions must have prototypes as follows: + + void user_read_data(png_structp png_ptr, + png_bytep data, png_size_t length); + void user_write_data(png_structp png_ptr, + png_bytep data, png_size_t length); + void user_flush_data(png_structp png_ptr); + +Supplying NULL for the read, write, or flush functions sets them back +to using the default C stream functions. It is an error to read from +a write stream, and vice versa. + +Error handling in libpng is done through png_error() and png_warning(). +Errors handled through png_error() are fatal, meaning that png_error() +should never return to its caller. Currently, this is handled via +setjmp() and longjmp() (unless you have compiled libpng with +PNG_SETJMP_NOT_SUPPORTED, in which case it is handled via PNG_ABORT()), +but you could change this to do things like exit() if you should wish. + +On non-fatal errors, png_warning() is called +to print a warning message, and then control returns to the calling code. +By default png_error() and png_warning() print a message on stderr via +fprintf() unless the library is compiled with PNG_NO_CONSOLE_IO defined +(because you don't want the messages) or PNG_NO_STDIO defined (because +fprintf() isn't available). If you wish to change the behavior of the error +functions, you will need to set up your own message callbacks. These +functions are normally supplied at the time that the png_struct is created. +It is also possible to redirect errors and warnings to your own replacement +functions after png_create_*_struct() has been called by calling: + + png_set_error_fn(png_structp png_ptr, + png_voidp error_ptr, png_error_ptr error_fn, + png_error_ptr warning_fn); + + png_voidp error_ptr = png_get_error_ptr(png_ptr); + +If NULL is supplied for either error_fn or warning_fn, then the libpng +default function will be used, calling fprintf() and/or longjmp() if a +problem is encountered. The replacement error functions should have +parameters as follows: + + void user_error_fn(png_structp png_ptr, + png_const_charp error_msg); + void user_warning_fn(png_structp png_ptr, + png_const_charp warning_msg); + +The motivation behind using setjmp() and longjmp() is the C++ throw and +catch exception handling methods. This makes the code much easier to write, +as there is no need to check every return code of every function call. +However, there are some uncertainties about the status of local variables +after a longjmp, so the user may want to be careful about doing anything after +setjmp returns non-zero besides returning itself. Consult your compiler +documentation for more details. For an alternative approach, you may wish +to use the "cexcept" facility (see http://cexcept.sourceforge.net). + +Custom chunks + +If you need to read or write custom chunks, you may need to get deeper +into the libpng code. The library now has mechanisms for storing +and writing chunks of unknown type; you can even declare callbacks +for custom chunks. Hoewver, this may not be good enough if the +library code itself needs to know about interactions between your +chunk and existing `intrinsic' chunks. + +If you need to write a new intrinsic chunk, first read the PNG +specification. Acquire a first level of +understanding of how it works. Pay particular attention to the +sections that describe chunk names, and look at how other chunks were +designed, so you can do things similarly. Second, check out the +sections of libpng that read and write chunks. Try to find a chunk +that is similar to yours and use it as a template. More details can +be found in the comments inside the code. It is best to handle unknown +chunks in a generic method, via callback functions, instead of by +modifying libpng functions. + +If you wish to write your own transformation for the data, look through +the part of the code that does the transformations, and check out some of +the simpler ones to get an idea of how they work. Try to find a similar +transformation to the one you want to add and copy off of it. More details +can be found in the comments inside the code itself. + +Configuring for 16 bit platforms + +You will want to look into zconf.h to tell zlib (and thus libpng) that +it cannot allocate more then 64K at a time. Even if you can, the memory +won't be accessible. So limit zlib and libpng to 64K by defining MAXSEG_64K. + +Configuring for DOS + +For DOS users who only have access to the lower 640K, you will +have to limit zlib's memory usage via a png_set_compression_mem_level() +call. See zlib.h or zconf.h in the zlib library for more information. + +Configuring for Medium Model + +Libpng's support for medium model has been tested on most of the popular +compilers. Make sure MAXSEG_64K gets defined, USE_FAR_KEYWORD gets +defined, and FAR gets defined to far in pngconf.h, and you should be +all set. Everything in the library (except for zlib's structure) is +expecting far data. You must use the typedefs with the p or pp on +the end for pointers (or at least look at them and be careful). Make +note that the rows of data are defined as png_bytepp, which is an +unsigned char far * far *. + +Configuring for gui/windowing platforms: + +You will need to write new error and warning functions that use the GUI +interface, as described previously, and set them to be the error and +warning functions at the time that png_create_*_struct() is called, +in order to have them available during the structure initialization. +They can be changed later via png_set_error_fn(). On some compilers, +you may also have to change the memory allocators (png_malloc, etc.). + +Configuring for compiler xxx: + +All includes for libpng are in pngconf.h. If you need to add/change/delete +an include, this is the place to do it. The includes that are not +needed outside libpng are protected by the PNG_INTERNAL definition, +which is only defined for those routines inside libpng itself. The +files in libpng proper only include png.h, which includes pngconf.h. + +Configuring zlib: + +There are special functions to configure the compression. Perhaps the +most useful one changes the compression level, which currently uses +input compression values in the range 0 - 9. The library normally +uses the default compression level (Z_DEFAULT_COMPRESSION = 6). Tests +have shown that for a large majority of images, compression values in +the range 3-6 compress nearly as well as higher levels, and do so much +faster. For online applications it may be desirable to have maximum speed +(Z_BEST_SPEED = 1). With versions of zlib after v0.99, you can also +specify no compression (Z_NO_COMPRESSION = 0), but this would create +files larger than just storing the raw bitmap. You can specify the +compression level by calling: + + png_set_compression_level(png_ptr, level); + +Another useful one is to reduce the memory level used by the library. +The memory level defaults to 8, but it can be lowered if you are +short on memory (running DOS, for example, where you only have 640K). +Note that the memory level does have an effect on compression; among +other things, lower levels will result in sections of incompressible +data being emitted in smaller stored blocks, with a correspondingly +larger relative overhead of up to 15% in the worst case. + + png_set_compression_mem_level(png_ptr, level); + +The other functions are for configuring zlib. They are not recommended +for normal use and may result in writing an invalid PNG file. See +zlib.h for more information on what these mean. + + png_set_compression_strategy(png_ptr, + strategy); + png_set_compression_window_bits(png_ptr, + window_bits); + png_set_compression_method(png_ptr, method); + png_set_compression_buffer_size(png_ptr, size); + +Controlling row filtering + +If you want to control whether libpng uses filtering or not, which +filters are used, and how it goes about picking row filters, you +can call one of these functions. The selection and configuration +of row filters can have a significant impact on the size and +encoding speed and a somewhat lesser impact on the decoding speed +of an image. Filtering is enabled by default for RGB and grayscale +images (with and without alpha), but not for paletted images nor +for any images with bit depths less than 8 bits/pixel. + +The 'method' parameter sets the main filtering method, which is +currently only '0' in the PNG 1.2 specification. The 'filters' +parameter sets which filter(s), if any, should be used for each +scanline. Possible values are PNG_ALL_FILTERS and PNG_NO_FILTERS +to turn filtering on and off, respectively. + +Individual filter types are PNG_FILTER_NONE, PNG_FILTER_SUB, +PNG_FILTER_UP, PNG_FILTER_AVG, PNG_FILTER_PAETH, which can be bitwise +ORed together with '|' to specify one or more filters to use. +These filters are described in more detail in the PNG specification. +If you intend to change the filter type during the course of writing +the image, you should start with flags set for all of the filters +you intend to use so that libpng can initialize its internal +structures appropriately for all of the filter types. (Note that this +means the first row must always be adaptively filtered, because libpng +currently does not allocate the filter buffers until png_write_row() +is called for the first time.) + + filters = PNG_FILTER_NONE | PNG_FILTER_SUB + PNG_FILTER_UP | PNG_FILTER_AVE | + PNG_FILTER_PAETH | PNG_ALL_FILTERS; + + png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, + filters); + The second parameter can also be + PNG_INTRAPIXEL_DIFFERENCING if you are + writing a PNG to be embedded in a MNG + datastream. This parameter must be the + same as the value of filter_method used + in png_set_IHDR(). + +It is also possible to influence how libpng chooses from among the +available filters. This is done in one or both of two ways - by +telling it how important it is to keep the same filter for successive +rows, and by telling it the relative computational costs of the filters. + + double weights[3] = {1.5, 1.3, 1.1}, + costs[PNG_FILTER_VALUE_LAST] = + {1.0, 1.3, 1.3, 1.5, 1.7}; + + png_set_filter_heuristics(png_ptr, + PNG_FILTER_HEURISTIC_WEIGHTED, 3, + weights, costs); + +The weights are multiplying factors that indicate to libpng that the +row filter should be the same for successive rows unless another row filter +is that many times better than the previous filter. In the above example, +if the previous 3 filters were SUB, SUB, NONE, the SUB filter could have a +"sum of absolute differences" 1.5 x 1.3 times higher than other filters +and still be chosen, while the NONE filter could have a sum 1.1 times +higher than other filters and still be chosen. Unspecified weights are +taken to be 1.0, and the specified weights should probably be declining +like those above in order to emphasize recent filters over older filters. + +The filter costs specify for each filter type a relative decoding cost +to be considered when selecting row filters. This means that filters +with higher costs are less likely to be chosen over filters with lower +costs, unless their "sum of absolute differences" is that much smaller. +The costs do not necessarily reflect the exact computational speeds of +the various filters, since this would unduly influence the final image +size. + +Note that the numbers above were invented purely for this example and +are given only to help explain the function usage. Little testing has +been done to find optimum values for either the costs or the weights. + +Removing unwanted object code + +There are a bunch of #define's in pngconf.h that control what parts of +libpng are compiled. All the defines end in _SUPPORTED. If you are +never going to use a capability, you can change the #define to #undef +before recompiling libpng and save yourself code and data space, or +you can turn off individual capabilities with defines that begin with +PNG_NO_. + +You can also turn all of the transforms and ancillary chunk capabilities +off en masse with compiler directives that define +PNG_NO_READ[or WRITE]_TRANSFORMS, or PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS, +or all four, +along with directives to turn on any of the capabilities that you do +want. The PNG_NO_READ[or WRITE]_TRANSFORMS directives disable +the extra transformations but still leave the library fully capable of reading +and writing PNG files with all known public chunks +Use of the PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS directive +produces a library that is incapable of reading or writing ancillary chunks. +If you are not using the progressive reading capability, you can +turn that off with PNG_NO_PROGRESSIVE_READ (don't confuse +this with the INTERLACING capability, which you'll still have). + +All the reading and writing specific code are in separate files, so the +linker should only grab the files it needs. However, if you want to +make sure, or if you are building a stand alone library, all the +reading files start with pngr and all the writing files start with +pngw. The files that don't match either (like png.c, pngtrans.c, etc.) +are used for both reading and writing, and always need to be included. +The progressive reader is in pngpread.c + +If you are creating or distributing a dynamically linked library (a .so +or DLL file), you should not remove or disable any parts of the library, +as this will cause applications linked with different versions of the +library to fail if they call functions not available in your library. +The size of the library itself should not be an issue, because only +those sections that are actually used will be loaded into memory. + +Requesting debug printout + +The macro definition PNG_DEBUG can be used to request debugging +printout. Set it to an integer value in the range 0 to 3. Higher +numbers result in increasing amounts of debugging information. The +information is printed to the "stderr" file, unless another file +name is specified in the PNG_DEBUG_FILE macro definition. + +When PNG_DEBUG > 0, the following functions (macros) become available: + + png_debug(level, message) + png_debug1(level, message, p1) + png_debug2(level, message, p1, p2) + +in which "level" is compared to PNG_DEBUG to decide whether to print +the message, "message" is the formatted string to be printed, +and p1 and p2 are parameters that are to be embedded in the string +according to printf-style formatting directives. For example, + + png_debug1(2, "foo=%d\n", foo); + +is expanded to + + if(PNG_DEBUG > 2) + fprintf(PNG_DEBUG_FILE, "foo=%d\n", foo); + +When PNG_DEBUG is defined but is zero, the macros aren't defined, but you +can still use PNG_DEBUG to control your own debugging: + + #ifdef PNG_DEBUG + fprintf(stderr, ... + #endif + +When PNG_DEBUG = 1, the macros are defined, but only png_debug statements +having level = 0 will be printed. There aren't any such statements in +this version of libpng, but if you insert some they will be printed. + +VI. Runtime optimization + +A new feature in libpng 1.2.0 is the ability to dynamically switch between +standard and optimized versions of some routines. Currently these are +limited to three computationally intensive tasks when reading PNG files: +decoding row filters, expanding interlacing, and combining interlaced or +transparent row data with previous row data. Currently the optimized +versions are available only for x86 (Intel, AMD, etc.) platforms with +MMX support, though this may change in future versions. (For example, +the non-MMX assembler optimizations for zlib might become similarly +runtime-selectable in future releases, in which case libpng could be +extended to support them. Alternatively, the compile-time choice of +floating-point versus integer routines for gamma correction might become +runtime-selectable.) + +Because such optimizations tend to be very platform- and compiler-dependent, +both in how they are written and in how they perform, the new runtime code +in libpng has been written to allow programs to query, enable, and disable +either specific optimizations or all such optimizations. For example, to +enable all possible optimizations (bearing in mind that some "optimizations" +may actually run more slowly in rare cases): + + #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200) + png_uint_32 mask, flags; + + flags = png_get_asm_flags(png_ptr); + mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE); + png_set_asm_flags(png_ptr, flags | mask); + #endif + +To enable only optimizations relevant to reading PNGs, use PNG_SELECT_READ +by itself when calling png_get_asm_flagmask(); similarly for optimizing +only writing. To disable all optimizations: + + #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200) + flags = png_get_asm_flags(png_ptr); + mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE); + png_set_asm_flags(png_ptr, flags & ~mask); + #endif + +To enable or disable only MMX-related features, use png_get_mmx_flagmask() +in place of png_get_asm_flagmask(). The mmx version takes one additional +parameter: + + #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200) + int selection = PNG_SELECT_READ | PNG_SELECT_WRITE; + int compilerID; + + mask = png_get_mmx_flagmask(selection, &compilerID); + #endif + +On return, compilerID will indicate which version of the MMX assembler +optimizations was compiled. Currently two flavors exist: Microsoft +Visual C++ (compilerID == 1) and GNU C (a.k.a. gcc/gas, compilerID == 2). +On non-x86 platforms or on systems compiled without MMX optimizations, a +value of -1 is used. + +Note that both png_get_asm_flagmask() and png_get_mmx_flagmask() return +all valid, settable optimization bits for the version of the library that's +currently in use. In the case of shared (dynamically linked) libraries, +this may include optimizations that did not exist at the time the code was +written and compiled. It is also possible, of course, to enable only known, +specific optimizations; for example: + + #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200) + flags = PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \ + | PNG_ASM_FLAG_MMX_READ_INTERLACE \ + | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \ + | PNG_ASM_FLAG_MMX_READ_FILTER_UP \ + | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \ + | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ; + png_set_asm_flags(png_ptr, flags); + #endif + +This method would enable only the MMX read-optimizations available at the +time of libpng 1.2.0's release, regardless of whether a later version of +the DLL were actually being used. (Also note that these functions did not +exist in versions older than 1.2.0, so any attempt to run a dynamically +linked app on such an older version would fail.) + +To determine whether the processor supports MMX instructions at all, use +the png_mmx_support() function: + + #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200) + mmxsupport = png_mmx_support(); + #endif + +It returns -1 if MMX support is not compiled into libpng, 0 if MMX code +is compiled but MMX is not supported by the processor, or 1 if MMX support +is fully available. Note that png_mmx_support(), png_get_mmx_flagmask(), +and png_get_asm_flagmask() all may be called without allocating and ini- +tializing any PNG structures (for example, as part of a usage screen or +"about" box). + +The following code can be used to prevent an application from using the +thread_unsafe features, even if libpng was built with PNG_THREAD_UNSAFE_OK +defined: + +#if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) \ + && defined(PNG_THREAD_UNSAFE_OK) + /* Disable thread-unsafe features of pnggccrd */ + if (png_access_version() >= 10200) + { + png_uint_32 mmx_disable_mask = 0; + png_uint_32 asm_flags; + + mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \ + | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \ + | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \ + | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ); + asm_flags = png_get_asm_flags(png_ptr); + png_set_asm_flags(png_ptr, asm_flags & ~mmx_disable_mask); + } +#endif + +For more extensive examples of runtime querying, enabling and disabling +of optimized features, see contrib/gregbook/readpng2.c in the libpng +source-code distribution. + +VII. MNG support + +The MNG specification (available at http://www.libpng.org/pub/mng) allows +certain extensions to PNG for PNG images that are embedded in MNG datastreams. +Libpng can support some of these extensions. To enable them, use the +png_permit_mng_features() function: + + feature_set = png_permit_mng_features(png_ptr, mask) + mask is a png_uint_32 containing the logical OR of the + features you want to enable. These include + PNG_FLAG_MNG_EMPTY_PLTE + PNG_FLAG_MNG_FILTER_64 + PNG_ALL_MNG_FEATURES + feature_set is a png_uint_32 that is the logical AND of + your mask with the set of MNG features that is + supported by the version of libpng that you are using. + +It is an error to use this function when reading or writing a standalone +PNG file with the PNG 8-byte signature. The PNG datastream must be wrapped +in a MNG datastream. As a minimum, it must have the MNG 8-byte signature +and the MHDR and MEND chunks. Libpng does not provide support for these +or any other MNG chunks; your application must provide its own support for +them. You may wish to consider using libmng (available at +http://www.libmng.com) instead. + +VIII. Changes to Libpng from version 0.88 + +It should be noted that versions of libpng later than 0.96 are not +distributed by the original libpng author, Guy Schalnat, nor by +Andreas Dilger, who had taken over from Guy during 1996 and 1997, and +distributed versions 0.89 through 0.96, but rather by another member +of the original PNG Group, Glenn Randers-Pehrson. Guy and Andreas are +still alive and well, but they have moved on to other things. + +The old libpng functions png_read_init(), png_write_init(), +png_info_init(), png_read_destroy(), and png_write_destroy() have been +moved to PNG_INTERNAL in version 0.95 to discourage their use. These +functions will be removed from libpng version 2.0.0. + +The preferred method of creating and initializing the libpng structures is +via the png_create_read_struct(), png_create_write_struct(), and +png_create_info_struct() because they isolate the size of the structures +from the application, allow version error checking, and also allow the +use of custom error handling routines during the initialization, which +the old functions do not. The functions png_read_destroy() and +png_write_destroy() do not actually free the memory that libpng +allocated for these structs, but just reset the data structures, so they +can be used instead of png_destroy_read_struct() and +png_destroy_write_struct() if you feel there is too much system overhead +allocating and freeing the png_struct for each image read. + +Setting the error callbacks via png_set_message_fn() before +png_read_init() as was suggested in libpng-0.88 is no longer supported +because this caused applications that do not use custom error functions +to fail if the png_ptr was not initialized to zero. It is still possible +to set the error callbacks AFTER png_read_init(), or to change them with +png_set_error_fn(), which is essentially the same function, but with a new +name to force compilation errors with applications that try to use the old +method. + +Starting with version 1.0.7, you can find out which version of the library +you are using at run-time: + + png_uint_32 libpng_vn = png_access_version_number(); + +The number libpng_vn is constructed from the major version, minor +version with leading zero, and release number with leading zero, +(e.g., libpng_vn for version 1.0.7 is 10007). + +You can also check which version of png.h you used when compiling your +application: + + png_uint_32 application_vn = PNG_LIBPNG_VER; + +IX. Y2K Compliance in libpng + +December 3, 2004 + +Since the PNG Development group is an ad-hoc body, we can't make +an official declaration. + +This is your unofficial assurance that libpng from version 0.71 and +upward through 1.2.8 are Y2K compliant. It is my belief that earlier +versions were also Y2K compliant. + +Libpng only has three year fields. One is a 2-byte unsigned integer that +will hold years up to 65535. The other two hold the date in text +format, and will hold years up to 9999. + +The integer is + "png_uint_16 year" in png_time_struct. + +The strings are + "png_charp time_buffer" in png_struct and + "near_time_buffer", which is a local character string in png.c. + +There are seven time-related functions: + + png_convert_to_rfc_1123() in png.c + (formerly png_convert_to_rfc_1152() in error) + png_convert_from_struct_tm() in pngwrite.c, called + in pngwrite.c + png_convert_from_time_t() in pngwrite.c + png_get_tIME() in pngget.c + png_handle_tIME() in pngrutil.c, called in pngread.c + png_set_tIME() in pngset.c + png_write_tIME() in pngwutil.c, called in pngwrite.c + +All appear to handle dates properly in a Y2K environment. The +png_convert_from_time_t() function calls gmtime() to convert from system +clock time, which returns (year - 1900), which we properly convert to +the full 4-digit year. There is a possibility that applications using +libpng are not passing 4-digit years into the png_convert_to_rfc_1123() +function, or that they are incorrectly passing only a 2-digit year +instead of "year - 1900" into the png_convert_from_struct_tm() function, +but this is not under our control. The libpng documentation has always +stated that it works with 4-digit years, and the APIs have been +documented as such. + +The tIME chunk itself is also Y2K compliant. It uses a 2-byte unsigned +integer to hold the year, and can hold years as large as 65535. + +zlib, upon which libpng depends, is also Y2K compliant. It contains +no date-related code. + + + Glenn Randers-Pehrson + libpng maintainer + PNG Development Group diff --git a/syslinux/com32/lib/libpng/libpngpf.3 b/syslinux/com32/lib/libpng/libpngpf.3 new file mode 100644 index 0000000..d196d70 --- /dev/null +++ b/syslinux/com32/lib/libpng/libpngpf.3 @@ -0,0 +1,1096 @@ +.TH LIBPNGPF 3 "December 3, 2004" +.SH NAME +libpng \- Portable Network Graphics (PNG) Reference Library 1.2.8 +(private functions) +.SH SYNOPSIS +\fB\fB#include <png.h>\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_build_gamma_table (png_structp \fI\fIpng_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_build_grayscale_palette (int \fP\fI\fP\fIbit_depth\fP\fB\fP\fB, png_colorp \fI\fIpalette\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_calculate_crc (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_bytep \fP\fI\fP\fIptr\fP\fB\fP\fB, png_size_t \fI\fIlength\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_check_chunk_name (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_bytep \fI\fIchunk_name\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBpng_size_t png_check_keyword (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_charp \fP\fI\fP\fIkey\fP\fB\fP\fB, png_charpp \fI\fInew_key\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_combine_row (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_bytep \fP\fI\fP\fIrow\fP\fB\fP\fB, int \fI\fImask\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_correct_palette (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_colorp \fP\fI\fP\fIpalette\fP\fB\fP\fB, int \fI\fInum_palette\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBint png_crc_error (png_structp \fI\fIpng_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBint png_crc_finish (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_uint_32 \fI\fIskip\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_crc_read (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_bytep \fP\fI\fP\fIbuf\fP\fB\fP\fB, png_size_t \fI\fIlength\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBpng_voidp png_create_struct (int \fI\fItype\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBpng_voidp png_create_struct_2 (int \fP\fI\fP\fItype\fP\fB\fP\fB, png_malloc_ptr \fP\fI\fP\fImalloc_fn\fP\fB\fP\fB, png_voidp \fI\fImem_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBpng_charp png_decompress_chunk (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, int \fP\fI\fP\fIcomp_type\fP\fB\fP\fB, png_charp \fP\fI\fP\fIchunkdata\fP\fB\fP\fB, png_size_t \fP\fI\fP\fIchunklength\fP\fB\fP\fB, png_size_t \fP\fI\fP\fIprefix_length\fP\fB\fP\fB, png_size_t \fI\fI*data_length\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_destroy_struct (png_voidp \fI\fIstruct_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_destroy_struct_2 (png_voidp \fP\fI\fP\fIstruct_ptr\fP\fB\fP\fB, png_free_ptr \fP\fI\fP\fIfree_fn\fP\fB\fP\fB, png_voidp \fI\fImem_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_do_background (png_row_infop \fP\fI\fP\fIrow_info\fP\fB\fP\fB, png_bytep \fP\fI\fP\fIrow\fP\fB\fP\fB, png_color_16p \fP\fI\fP\fItrans_values\fP\fB\fP\fB, png_color_16p \fP\fI\fP\fIbackground\fP\fB\fP\fB, png_color_16p \fP\fI\fP\fIbackground_1\fP\fB\fP\fB, png_bytep \fP\fI\fP\fIgamma_table\fP\fB\fP\fB, png_bytep \fP\fI\fP\fIgamma_from_1\fP\fB\fP\fB, png_bytep \fP\fI\fP\fIgamma_to_1\fP\fB\fP\fB, png_uint_16pp \fP\fI\fP\fIgamma_16\fP\fB\fP\fB, png_uint_16pp \fP\fI\fP\fIgamma_16_from_1\fP\fB\fP\fB, png_uint_16pp \fP\fI\fP\fIgamma_16_to_1\fP\fB\fP\fB, int \fI\fIgamma_shift\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_do_bgr (png_row_infop \fP\fI\fP\fIrow_info\fP\fB\fP\fB, png_bytep \fI\fIrow\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_do_chop (png_row_infop \fP\fI\fP\fIrow_info\fP\fB\fP\fB, png_bytep \fI\fIrow\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_do_dither (png_row_infop \fP\fI\fP\fIrow_info\fP\fB\fP\fB, png_bytep \fP\fI\fP\fIrow\fP\fB\fP\fB, png_bytep \fP\fI\fP\fIpalette_lookup\fP\fB\fP\fB, png_bytep \fI\fIdither_lookup\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_do_expand (png_row_infop \fP\fI\fP\fIrow_info\fP\fB\fP\fB, png_bytep \fP\fI\fP\fIrow\fP\fB\fP\fB, png_color_16p \fI\fItrans_value\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_do_expand_palette (png_row_infop \fP\fI\fP\fIrow_info\fP\fB\fP\fB, png_bytep \fP\fI\fP\fIrow\fP\fB\fP\fB, png_colorp \fP\fI\fP\fIpalette\fP\fB\fP\fB, png_bytep \fP\fI\fP\fItrans\fP\fB\fP\fB, int \fI\fInum_trans\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_do_gamma (png_row_infop \fP\fI\fP\fIrow_info\fP\fB\fP\fB, png_bytep \fP\fI\fP\fIrow\fP\fB\fP\fB, png_bytep \fP\fI\fP\fIgamma_table\fP\fB\fP\fB, png_uint_16pp \fP\fI\fP\fIgamma_16_table\fP\fB\fP\fB, int \fI\fIgamma_shift\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_do_gray_to_rgb (png_row_infop \fP\fI\fP\fIrow_info\fP\fB\fP\fB, png_bytep \fI\fIrow\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_do_invert (png_row_infop \fP\fI\fP\fIrow_info\fP\fB\fP\fB, png_bytep \fI\fIrow\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_do_pack (png_row_infop \fP\fI\fP\fIrow_info\fP\fB\fP\fB, png_bytep \fP\fI\fP\fIrow\fP\fB\fP\fB, png_uint_32 \fI\fIbit_depth\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_do_packswap (png_row_infop \fP\fI\fP\fIrow_info\fP\fB\fP\fB, png_bytep \fI\fIrow\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_do_read_filler (png_row_infop \fP\fI\fP\fIrow_info\fP\fB\fP\fB, png_bytep \fP\fI\fP\fIrow\fP\fB\fP\fB, png_uint_32 \fP\fI\fP\fIfiller\fP\fB\fP\fB, png_uint_32 \fI\fIflags\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_do_read_interlace (png_row_infop \fP\fI\fP\fIrow_info\fP\fB\fP\fB, png_bytep \fP\fI\fP\fIrow\fP\fB\fP\fB, int \fP\fI\fP\fIpass\fP\fB\fP\fB, png_uint_32 \fI\fItransformations\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_do_read_invert_alpha (png_row_infop \fP\fI\fP\fIrow_info\fP\fB\fP\fB, png_bytep \fI\fIrow\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_do_read_swap_alpha (png_row_infop \fP\fI\fP\fIrow_info\fP\fB\fP\fB, png_bytep \fI\fIrow\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_do_read_transformations (png_structp \fI\fIpng_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBint png_do_rgb_to_gray (png_row_infop \fP\fI\fP\fIrow_info\fP\fB\fP\fB, png_bytep \fI\fIrow\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_do_shift (png_row_infop \fP\fI\fP\fIrow_info\fP\fB\fP\fB, png_bytep \fP\fI\fP\fIrow\fP\fB\fP\fB, png_color_8p \fI\fIbit_depth\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_do_strip_filler (png_row_infop \fP\fI\fP\fIrow_info\fP\fB\fP\fB, png_bytep \fP\fI\fP\fIrow\fP\fB\fP\fB, png_uint_32 \fI\fIflags\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_do_swap (png_row_infop \fP\fI\fP\fIrow_info\fP\fB\fP\fB, png_bytep \fI\fIrow\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_do_unpack (png_row_infop \fP\fI\fP\fIrow_info\fP\fB\fP\fB, png_bytep \fI\fIrow\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_do_unshift (png_row_infop \fP\fI\fP\fIrow_info\fP\fB\fP\fB, png_bytep \fP\fI\fP\fIrow\fP\fB\fP\fB, png_color_8p \fI\fIsig_bits\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_do_write_interlace (png_row_infop \fP\fI\fP\fIrow_info\fP\fB\fP\fB, png_bytep \fP\fI\fP\fIrow\fP\fB\fP\fB, int \fI\fIpass\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_do_write_invert_alpha (png_row_infop \fP\fI\fP\fIrow_info\fP\fB\fP\fB, png_bytep \fI\fIrow\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_do_write_swap_alpha (png_row_infop \fP\fI\fP\fIrow_info\fP\fB\fP\fB, png_bytep \fI\fIrow\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_do_write_transformations (png_structp \fI\fIpng_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid *png_far_to_near (png_structp png_ptr,png_voidp \fP\fI\fP\fIptr\fP\fB\fP\fB, int \fI\fIcheck\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_flush (png_structp \fI\fIpng_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBpng_int_32 png_get_int_32 (png_bytep \fI\fIbuf\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBpng_uint_16 png_get_uint_16 (png_bytep \fI\fIbuf\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBpng_uint_32 png_get_uint_31 (png_bytep \fI\fIbuf\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBpng_uint_32 png_get_uint_32 (png_bytep \fI\fIbuf\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_handle_bKGD (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fP\fI\fP\fIinfo_ptr\fP\fB\fP\fB, png_uint_32 \fI\fIlength\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_handle_cHRM (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fP\fI\fP\fIinfo_ptr\fP\fB\fP\fB, png_uint_32 \fI\fIlength\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_handle_gAMA (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fP\fI\fP\fIinfo_ptr\fP\fB\fP\fB, png_uint_32 \fI\fIlength\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_handle_hIST (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fP\fI\fP\fIinfo_ptr\fP\fB\fP\fB, png_uint_32 \fI\fIlength\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_handle_IEND (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fP\fI\fP\fIinfo_ptr\fP\fB\fP\fB, png_uint_32 \fI\fIlength\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_handle_IHDR (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fP\fI\fP\fIinfo_ptr\fP\fB\fP\fB, png_uint_32 \fI\fIlength\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_handle_iCCP (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fP\fI\fP\fIinfo_ptr\fP\fB\fP\fB, png_uint_32 \fI\fIlength\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_handle_iTXt (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fP\fI\fP\fIinfo_ptr\fP\fB\fP\fB, png_uint_32 \fI\fIlength\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_handle_oFFs (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fP\fI\fP\fIinfo_ptr\fP\fB\fP\fB, png_uint_32 \fI\fIlength\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_handle_pCAL (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fP\fI\fP\fIinfo_ptr\fP\fB\fP\fB, png_uint_32 \fI\fIlength\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_handle_pHYs (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fP\fI\fP\fIinfo_ptr\fP\fB\fP\fB, png_uint_32 \fI\fIlength\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_handle_PLTE (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fP\fI\fP\fIinfo_ptr\fP\fB\fP\fB, png_uint_32 \fI\fIlength\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_handle_sBIT (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fP\fI\fP\fIinfo_ptr\fP\fB\fP\fB, png_uint_32 \fI\fIlength\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_handle_sCAL (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fP\fI\fP\fIinfo_ptr\fP\fB\fP\fB, png_uint_32 \fI\fIlength\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_handle_sPLT (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fP\fI\fP\fIinfo_ptr\fP\fB\fP\fB, png_uint_32 \fI\fIlength\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_handle_sRGB (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fP\fI\fP\fIinfo_ptr\fP\fB\fP\fB, png_uint_32 \fI\fIlength\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_handle_tEXt (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fP\fI\fP\fIinfo_ptr\fP\fB\fP\fB, png_uint_32 \fI\fIlength\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_handle_tIME (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fP\fI\fP\fIinfo_ptr\fP\fB\fP\fB, png_uint_32 \fI\fIlength\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_handle_tRNS (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fP\fI\fP\fIinfo_ptr\fP\fB\fP\fB, png_uint_32 \fI\fIlength\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_handle_unknown (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fP\fI\fP\fIinfo_ptr\fP\fB\fP\fB, png_uint_32 \fI\fIlength\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_handle_zTXt (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fP\fI\fP\fIinfo_ptr\fP\fB\fP\fB, png_uint_32 \fI\fIlength\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_info_destroy (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fI\fIinfo_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_init_mmx_flags (png_structp \fI\fIpng_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_init_read_transformations (png_structp \fI\fIpng_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_process_IDAT_data (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_bytep \fP\fI\fP\fIbuffer\fP\fB\fP\fB, png_size_t \fI\fIbuffer_length\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_process_some_data (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fI\fIinfo_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_push_check_crc (png_structp \fI\fIpng_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_push_crc_finish (png_structp \fI\fIpng_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_push_crc_skip (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_uint_32 \fI\fIlength\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_push_fill_buffer (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_bytep \fP\fI\fP\fIbuffer\fP\fB\fP\fB, png_size_t \fI\fIlength\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_push_handle_tEXt (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fP\fI\fP\fIinfo_ptr\fP\fB\fP\fB, png_uint_32 \fI\fIlength\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_push_handle_unknown (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fP\fI\fP\fIinfo_ptr\fP\fB\fP\fB, png_uint_32 \fI\fIlength\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_push_handle_zTXt (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fP\fI\fP\fIinfo_ptr\fP\fB\fP\fB, png_uint_32 \fI\fIlength\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_push_have_end (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fI\fIinfo_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_push_have_info (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fI\fIinfo_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_push_have_row (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_bytep \fI\fIrow\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_push_process_row (png_structp \fI\fIpng_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_push_read_chunk (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fI\fIinfo_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_push_read_end (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fI\fIinfo_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_push_read_IDAT (png_structp \fI\fIpng_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_push_read_sig (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fI\fIinfo_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_push_read_tEXt (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fI\fIinfo_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_push_read_zTXt (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fI\fIinfo_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_push_restore_buffer (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_bytep \fP\fI\fP\fIbuffer\fP\fB\fP\fB, png_size_t \fI\fIbuffer_length\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_push_save_buffer (png_structp \fI\fIpng_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_read_data (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_bytep \fP\fI\fP\fIdata\fP\fB\fP\fB, png_size_t \fI\fIlength\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_read_filter_row (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_row_infop \fP\fI\fP\fIrow_info\fP\fB\fP\fB, png_bytep \fP\fI\fP\fIrow\fP\fB\fP\fB, png_bytep \fP\fI\fP\fIprev_row\fP\fB\fP\fB, int \fI\fIfilter\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_read_finish_row (png_structp \fI\fIpng_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_read_push_finish_row (png_structp \fI\fIpng_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_read_start_row (png_structp \fI\fIpng_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_read_transform_info (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fI\fIinfo_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_reset_crc (png_structp \fI\fIpng_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_save_int_32 (png_bytep \fP\fI\fP\fIbuf\fP\fB\fP\fB, png_int_32 \fI\fIi\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_save_uint_16 (png_bytep \fP\fI\fP\fIbuf\fP\fB\fP\fB, unsigned int \fI\fIi\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_save_uint_32 (png_bytep \fP\fI\fP\fIbuf\fP\fB\fP\fB, png_uint_32 \fI\fIi\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBint png_set_text_2 (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_infop \fP\fI\fP\fIinfo_ptr\fP\fB\fP\fB, png_textp \fP\fI\fP\fItext_ptr\fP\fB\fP\fB, int \fI\fInum_text\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_write_cHRM (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, double \fP\fI\fP\fIwhite_x\fP\fB\fP\fB, double \fP\fI\fP\fIwhite_y\fP\fB\fP\fB, double \fP\fI\fP\fIred_x\fP\fB\fP\fB, double \fP\fI\fP\fIred_y\fP\fB\fP\fB, double \fP\fI\fP\fIgreen_x\fP\fB\fP\fB, double \fP\fI\fP\fIgreen_y\fP\fB\fP\fB, double \fP\fI\fP\fIblue_x\fP\fB\fP\fB, double \fI\fIblue_y\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_write_cHRM_fixed (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_uint_32 \fP\fI\fP\fIwhite_x\fP\fB\fP\fB, png_uint_32 \fP\fI\fP\fIwhite_y\fP\fB\fP\fB, png_uint_32 \fP\fI\fP\fIred_x\fP\fB\fP\fB, png_uint_32 \fP\fI\fP\fIred_y\fP\fB\fP\fB, png_uint_32 \fP\fI\fP\fIgreen_x\fP\fB\fP\fB, png_uint_32 \fP\fI\fP\fIgreen_y\fP\fB\fP\fB, png_uint_32 \fP\fI\fP\fIblue_x\fP\fB\fP\fB, png_uint_32 \fI\fIblue_y\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_write_data (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_bytep \fP\fI\fP\fIdata\fP\fB\fP\fB, png_size_t \fI\fIlength\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_write_filtered_row (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_bytep \fI\fIfiltered_row\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_write_find_filter (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_row_infop \fI\fIrow_info\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_write_finish_row (png_structp \fI\fIpng_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_write_gAMA (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, double \fI\fIfile_gamma\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_write_gAMA_fixed (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_uint_32 \fI\fIint_file_gamma\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_write_hIST (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_uint_16p \fP\fI\fP\fIhist\fP\fB\fP\fB, int \fI\fInum_hist\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_write_iCCP (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_charp \fP\fI\fP\fIname\fP\fB\fP\fB, int \fP\fI\fP\fIcompression_type\fP\fB\fP\fB, png_charp \fP\fI\fP\fIprofile\fP\fB\fP\fB, int \fI\fIproflen\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_write_IDAT (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_bytep \fP\fI\fP\fIdata\fP\fB\fP\fB, png_size_t \fI\fIlength\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_write_IEND (png_structp \fI\fIpng_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_write_IHDR (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_uint_32 \fP\fI\fP\fIwidth\fP\fB\fP\fB, png_uint_32 \fP\fI\fP\fIheight\fP\fB\fP\fB, int \fP\fI\fP\fIbit_depth\fP\fB\fP\fB, int \fP\fI\fP\fIcolor_type\fP\fB\fP\fB, int \fP\fI\fP\fIcompression_type\fP\fB\fP\fB, int \fP\fI\fP\fIfilter_type\fP\fB\fP\fB, int \fI\fIinterlace_type\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_write_iTXt (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, int \fP\fI\fP\fIcompression\fP\fB\fP\fB, png_charp \fP\fI\fP\fIkey\fP\fB\fP\fB, png_charp \fP\fI\fP\fIlang\fP\fB\fP\fB, png_charp \fP\fI\fP\fItranslated_key\fP\fB\fP\fB, png_charp \fI\fItext\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_write_oFFs (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_uint_32 \fP\fI\fP\fIx_offset\fP\fB\fP\fB, png_uint_32 \fP\fI\fP\fIy_offset\fP\fB\fP\fB, int \fI\fIunit_type\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_write_pCAL (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_charp \fP\fI\fP\fIpurpose\fP\fB\fP\fB, png_int_32 \fP\fI\fP\fIX0\fP\fB\fP\fB, png_int_32 \fP\fI\fP\fIX1\fP\fB\fP\fB, int \fP\fI\fP\fItype\fP\fB\fP\fB, int \fP\fI\fP\fInparams\fP\fB\fP\fB, png_charp \fP\fI\fP\fIunits\fP\fB\fP\fB, png_charpp \fI\fIparams\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_write_pHYs (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_uint_32 \fP\fI\fP\fIx_pixels_per_unit\fP\fB\fP\fB, png_uint_32 \fP\fI\fP\fIy_pixels_per_unit\fP\fB\fP\fB, int \fI\fIunit_type\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_write_PLTE (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_colorp \fP\fI\fP\fIpalette\fP\fB\fP\fB, png_uint_32 \fI\fInum_pal\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_write_sBIT (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_color_8p \fP\fI\fP\fIsbit\fP\fB\fP\fB, int \fI\fIcolor_type\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_write_sCAL (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_charp \fP\fI\fP\fIunit\fP\fB\fP\fB, double \fP\fI\fP\fIwidth\fP\fB\fP\fB, double \fI\fIheight\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_write_sCAL_s (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_charp \fP\fI\fP\fIunit\fP\fB\fP\fB, png_charp \fP\fI\fP\fIwidth\fP\fB\fP\fB, png_charp \fI\fIheight\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_write_sig (png_structp \fI\fIpng_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_write_sRGB (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, int \fI\fIintent\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_write_sPLT (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_spalette_p \fI\fIpalette\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_write_start_row (png_structp \fI\fIpng_ptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_write_tEXt (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_charp \fP\fI\fP\fIkey\fP\fB\fP\fB, png_charp \fP\fI\fP\fItext\fP\fB\fP\fB, png_size_t \fI\fItext_len\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_write_tIME (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_timep \fI\fImod_time\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_write_tRNS (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_bytep \fP\fI\fP\fItrans\fP\fB\fP\fB, png_color_16p \fP\fI\fP\fIvalues\fP\fB\fP\fB, int \fP\fI\fP\fInumber\fP\fB\fP\fB, int \fI\fIcolor_type\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_write_zTXt (png_structp \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, png_charp \fP\fI\fP\fIkey\fP\fB\fP\fB, png_charp \fP\fI\fP\fItext\fP\fB\fP\fB, png_size_t \fP\fI\fP\fItext_len\fP\fB\fP\fB, int \fI\fIcompression\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoidpf png_zalloc (voidpf \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, uInt \fP\fI\fP\fIitems\fP\fB\fP\fB, uInt \fI\fIsize\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +\fB\fBvoid png_zfree (voidpf \fP\fI\fP\fIpng_ptr\fP\fB\fP\fB, voidpf \fI\fIptr\fP\fB\fP\fB);\fP\fP + +\fI\fB + +\fI\fB\fI\fB + +\fI\fB + +.SH DESCRIPTION +The functions listed above are used privately by libpng +and are not recommended for use by applications. They are +not "exported" to applications using shared libraries. They +are listed alphabetically here as an aid to libpng maintainers. +See png.h for more information on these functions. + +.SH SEE ALSO +libpng(3), png(5) +.SH AUTHOR +Glenn Randers-Pehrson diff --git a/syslinux/com32/lib/libpng/png.5 b/syslinux/com32/lib/libpng/png.5 new file mode 100644 index 0000000..db7c834 --- /dev/null +++ b/syslinux/com32/lib/libpng/png.5 @@ -0,0 +1,74 @@ +.TH PNG 5 "December 3, 2004" +.SH NAME +png \- Portable Network Graphics (PNG) format +.SH DESCRIPTION +PNG (Portable Network Graphics) is an extensible file format for the +lossless, portable, well-compressed storage of raster images. PNG provides +a patent-free replacement for GIF and can also replace many +common uses of TIFF. Indexed-color, grayscale, and truecolor images are +supported, plus an optional alpha channel. Sample depths range from +1 to 16 bits. +.br + +PNG is designed to work well in online viewing applications, such as the +World Wide Web, so it is fully streamable with a progressive display +option. PNG is robust, providing both full file integrity checking and +fast, simple detection of common transmission errors. Also, PNG can store +gamma and chromaticity data for improved color matching on heterogeneous +platforms. + +.SH "SEE ALSO" +.IR libpng(3), zlib(3), deflate(5), and zlib(5) +.LP +PNG specification (second edition), November 2003: +.IP +.br + <http://www.w3.org/TR/2003/REC-PNG-20031110/ +PNG 1.2 specification, July 1999: +.IP +.br +http://www.libpng.org/pub/png +.LP +PNG 1.0 specification, October 1996: +.IP +.br +RFC 2083 +.IP +.br +ftp://ds.internic.net/rfc/rfc2083.txt +.br +or (as a W3C Recommendation) at +.br +http://www.w3.org/TR/REC-png.html +.SH AUTHORS +This man page: Glenn Randers-Pehrson +.LP +Portable Network Graphics (PNG) Specification (Second Edition) +Information technology - Computer graphics and image processing - +Portable Network Graphics (PNG): Functional specification. +ISO/IEC 15948:2003 (E) (November 10, 2003): David Duce and others. +.LP +Portable Network Graphics (PNG) Specification Version 1.2 (July 8, 1999): +Glenn Randers-Pehrson and others (png-list). +.LP +Portable Network Graphics (PNG) Specification Version 1.0 (October 1, 1996): +Thomas Boutell and others (png-list). +.LP + + +.SH COPYRIGHT NOTICE +.LP +This man page is Copyright (c) 1998-2004 Glenn Randers-Pehrson. See png.h +for conditions of use and distribution. +.LP +The PNG Specification (Second Edition) is +Copyright (c) 2003 W3C. (MIT, ERCIM, Keio), All Rights Reserved. +.LP +The PNG-1.2 specification is copyright (c) 1999 Glenn Randers-Pehrson. +See the specification for conditions of use and distribution. +.LP +The PNG-1.0 specification is copyright (c) 1996 Massachusetts Institute of +Technology. See the specification for conditions of use and distribution. +.LP +.\" end of man page + diff --git a/syslinux/com32/lib/libpng/png.c b/syslinux/com32/lib/libpng/png.c new file mode 100644 index 0000000..608ea2c --- /dev/null +++ b/syslinux/com32/lib/libpng/png.c @@ -0,0 +1,828 @@ + +/* png.c - location for general purpose libpng functions + * + * libpng version 1.2.8 - December 3, 2004 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2004 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + */ + +#define PNG_INTERNAL +#define PNG_NO_EXTERN +#include "png.h" + +/* Generate a compiler error if there is an old png.h in the search path. */ +typedef version_1_2_8 Your_png_h_is_not_version_1_2_8; + +/* Version information for C files. This had better match the version + * string defined in png.h. */ + +#ifdef PNG_USE_GLOBAL_ARRAYS +/* png_libpng_ver was changed to a function in version 1.0.5c */ +const char png_libpng_ver[18] = PNG_LIBPNG_VER_STRING; + +/* png_sig was changed to a function in version 1.0.5c */ +/* Place to hold the signature string for a PNG file. */ +const png_byte FARDATA png_sig[8] = {137, 80, 78, 71, 13, 10, 26, 10}; + +/* Invoke global declarations for constant strings for known chunk types */ +PNG_IHDR; +PNG_IDAT; +PNG_IEND; +PNG_PLTE; +PNG_bKGD; +PNG_cHRM; +PNG_gAMA; +PNG_hIST; +PNG_iCCP; +PNG_iTXt; +PNG_oFFs; +PNG_pCAL; +PNG_sCAL; +PNG_pHYs; +PNG_sBIT; +PNG_sPLT; +PNG_sRGB; +PNG_tEXt; +PNG_tIME; +PNG_tRNS; +PNG_zTXt; + +/* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + +/* start of interlace block */ +const int FARDATA png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; + +/* offset to next interlace block */ +const int FARDATA png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; + +/* start of interlace block in the y direction */ +const int FARDATA png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1}; + +/* offset to next interlace block in the y direction */ +const int FARDATA png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2}; + +/* width of interlace block (used in assembler routines only) */ +#ifdef PNG_HAVE_ASSEMBLER_COMBINE_ROW +const int FARDATA png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; +#endif + +/* Height of interlace block. This is not currently used - if you need + * it, uncomment it here and in png.h +const int FARDATA png_pass_height[] = {8, 8, 4, 4, 2, 2, 1}; +*/ + +/* Mask to determine which pixels are valid in a pass */ +const int FARDATA png_pass_mask[] = {0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff}; + +/* Mask to determine which pixels to overwrite while displaying */ +const int FARDATA png_pass_dsp_mask[] + = {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff}; + +#endif /* PNG_USE_GLOBAL_ARRAYS */ + +/* Tells libpng that we have already handled the first "num_bytes" bytes + * of the PNG file signature. If the PNG data is embedded into another + * stream we can set num_bytes = 8 so that libpng will not attempt to read + * or write any of the magic bytes before it starts on the IHDR. + */ + +void PNGAPI +png_set_sig_bytes(png_structp png_ptr, int num_bytes) +{ + png_debug(1, "in png_set_sig_bytes\n"); + if (num_bytes > 8) + png_error(png_ptr, "Too many bytes for PNG signature."); + + png_ptr->sig_bytes = (png_byte)(num_bytes < 0 ? 0 : num_bytes); +} + +/* Checks whether the supplied bytes match the PNG signature. We allow + * checking less than the full 8-byte signature so that those apps that + * already read the first few bytes of a file to determine the file type + * can simply check the remaining bytes for extra assurance. Returns + * an integer less than, equal to, or greater than zero if sig is found, + * respectively, to be less than, to match, or be greater than the correct + * PNG signature (this is the same behaviour as strcmp, memcmp, etc). + */ +int PNGAPI +png_sig_cmp(png_bytep sig, png_size_t start, png_size_t num_to_check) +{ + png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; + if (num_to_check > 8) + num_to_check = 8; + else if (num_to_check < 1) + return (0); + + if (start > 7) + return (0); + + if (start + num_to_check > 8) + num_to_check = 8 - start; + + return ((int)(png_memcmp(&sig[start], &png_signature[start], num_to_check))); +} + +/* (Obsolete) function to check signature bytes. It does not allow one + * to check a partial signature. This function might be removed in the + * future - use png_sig_cmp(). Returns true (nonzero) if the file is a PNG. + */ +int PNGAPI +png_check_sig(png_bytep sig, int num) +{ + return ((int)!png_sig_cmp(sig, (png_size_t)0, (png_size_t)num)); +} + +/* Function to allocate memory for zlib and clear it to 0. */ +#ifdef PNG_1_0_X +voidpf PNGAPI +#else +voidpf /* private */ +#endif +png_zalloc(voidpf png_ptr, uInt items, uInt size) +{ + png_voidp ptr; + png_structp p=png_ptr; + png_uint_32 save_flags=p->flags; + png_uint_32 num_bytes; + + if (items > PNG_UINT_32_MAX/size) + { + png_warning (png_ptr, "Potential overflow in png_zalloc()"); + return (NULL); + } + num_bytes = (png_uint_32)items * size; + + p->flags|=PNG_FLAG_MALLOC_NULL_MEM_OK; + ptr = (png_voidp)png_malloc((png_structp)png_ptr, num_bytes); + p->flags=save_flags; + +#if defined(PNG_1_0_X) && !defined(PNG_NO_ZALLOC_ZERO) + if (ptr == NULL) + return ((voidpf)ptr); + + if (num_bytes > (png_uint_32)0x8000L) + { + png_memset(ptr, 0, (png_size_t)0x8000L); + png_memset((png_bytep)ptr + (png_size_t)0x8000L, 0, + (png_size_t)(num_bytes - (png_uint_32)0x8000L)); + } + else + { + png_memset(ptr, 0, (png_size_t)num_bytes); + } +#endif + return ((voidpf)ptr); +} + +/* function to free memory for zlib */ +#ifdef PNG_1_0_X +void PNGAPI +#else +void /* private */ +#endif +png_zfree(voidpf png_ptr, voidpf ptr) +{ + png_free((png_structp)png_ptr, (png_voidp)ptr); +} + +/* Reset the CRC variable to 32 bits of 1's. Care must be taken + * in case CRC is > 32 bits to leave the top bits 0. + */ +void /* PRIVATE */ +png_reset_crc(png_structp png_ptr) +{ + png_ptr->crc = crc32(0, Z_NULL, 0); +} + +/* Calculate the CRC over a section of data. We can only pass as + * much data to this routine as the largest single buffer size. We + * also check that this data will actually be used before going to the + * trouble of calculating it. + */ +void /* PRIVATE */ +png_calculate_crc(png_structp png_ptr, png_bytep ptr, png_size_t length) +{ + int need_crc = 1; + + if (png_ptr->chunk_name[0] & 0x20) /* ancillary */ + { + if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == + (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) + need_crc = 0; + } + else /* critical */ + { + if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) + need_crc = 0; + } + + if (need_crc) + png_ptr->crc = crc32(png_ptr->crc, ptr, (uInt)length); +} + +/* Allocate the memory for an info_struct for the application. We don't + * really need the png_ptr, but it could potentially be useful in the + * future. This should be used in favour of malloc(png_sizeof(png_info)) + * and png_info_init() so that applications that want to use a shared + * libpng don't have to be recompiled if png_info changes size. + */ +png_infop PNGAPI +png_create_info_struct(png_structp png_ptr) +{ + png_infop info_ptr; + + png_debug(1, "in png_create_info_struct\n"); + if(png_ptr == NULL) return (NULL); +#ifdef PNG_USER_MEM_SUPPORTED + info_ptr = (png_infop)png_create_struct_2(PNG_STRUCT_INFO, + png_ptr->malloc_fn, png_ptr->mem_ptr); +#else + info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO); +#endif + if (info_ptr != NULL) + png_info_init_3(&info_ptr, png_sizeof(png_info)); + + return (info_ptr); +} + +/* This function frees the memory associated with a single info struct. + * Normally, one would use either png_destroy_read_struct() or + * png_destroy_write_struct() to free an info struct, but this may be + * useful for some applications. + */ +void PNGAPI +png_destroy_info_struct(png_structp png_ptr, png_infopp info_ptr_ptr) +{ + png_infop info_ptr = NULL; + + png_debug(1, "in png_destroy_info_struct\n"); + if (info_ptr_ptr != NULL) + info_ptr = *info_ptr_ptr; + + if (info_ptr != NULL) + { + png_info_destroy(png_ptr, info_ptr); + +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2((png_voidp)info_ptr, png_ptr->free_fn, + png_ptr->mem_ptr); +#else + png_destroy_struct((png_voidp)info_ptr); +#endif + *info_ptr_ptr = NULL; + } +} + +/* Initialize the info structure. This is now an internal function (0.89) + * and applications using it are urged to use png_create_info_struct() + * instead. + */ +#if defined(PNG_1_0_X) || defined (PNG_1_2_X) +#undef png_info_init +void PNGAPI +png_info_init(png_infop info_ptr) +{ + /* We only come here via pre-1.0.12-compiled applications */ + png_info_init_3(&info_ptr, 0); +} +#endif + +void PNGAPI +png_info_init_3(png_infopp ptr_ptr, png_size_t png_info_struct_size) +{ + png_infop info_ptr = *ptr_ptr; + + png_debug(1, "in png_info_init_3\n"); + + if(png_sizeof(png_info) > png_info_struct_size) + { + png_destroy_struct(info_ptr); + info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO); + *ptr_ptr = info_ptr; + } + + /* set everything to 0 */ + png_memset(info_ptr, 0, png_sizeof (png_info)); +} + +#ifdef PNG_FREE_ME_SUPPORTED +void PNGAPI +png_data_freer(png_structp png_ptr, png_infop info_ptr, + int freer, png_uint_32 mask) +{ + png_debug(1, "in png_data_freer\n"); + if (png_ptr == NULL || info_ptr == NULL) + return; + if(freer == PNG_DESTROY_WILL_FREE_DATA) + info_ptr->free_me |= mask; + else if(freer == PNG_USER_WILL_FREE_DATA) + info_ptr->free_me &= ~mask; + else + png_warning(png_ptr, + "Unknown freer parameter in png_data_freer."); +} +#endif + +void PNGAPI +png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask, + int num) +{ + png_debug(1, "in png_free_data\n"); + if (png_ptr == NULL || info_ptr == NULL) + return; + +#if defined(PNG_TEXT_SUPPORTED) +/* free text item num or (if num == -1) all text items */ +#ifdef PNG_FREE_ME_SUPPORTED +if ((mask & PNG_FREE_TEXT) & info_ptr->free_me) +#else +if (mask & PNG_FREE_TEXT) +#endif +{ + if (num != -1) + { + if (info_ptr->text && info_ptr->text[num].key) + { + png_free(png_ptr, info_ptr->text[num].key); + info_ptr->text[num].key = NULL; + } + } + else + { + int i; + for (i = 0; i < info_ptr->num_text; i++) + png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, i); + png_free(png_ptr, info_ptr->text); + info_ptr->text = NULL; + info_ptr->num_text=0; + } +} +#endif + +#if defined(PNG_tRNS_SUPPORTED) +/* free any tRNS entry */ +#ifdef PNG_FREE_ME_SUPPORTED +if ((mask & PNG_FREE_TRNS) & info_ptr->free_me) +#else +if ((mask & PNG_FREE_TRNS) && (png_ptr->flags & PNG_FLAG_FREE_TRNS)) +#endif +{ + png_free(png_ptr, info_ptr->trans); + info_ptr->valid &= ~PNG_INFO_tRNS; +#ifndef PNG_FREE_ME_SUPPORTED + png_ptr->flags &= ~PNG_FLAG_FREE_TRNS; +#endif + info_ptr->trans = NULL; +} +#endif + +#if defined(PNG_sCAL_SUPPORTED) +/* free any sCAL entry */ +#ifdef PNG_FREE_ME_SUPPORTED +if ((mask & PNG_FREE_SCAL) & info_ptr->free_me) +#else +if (mask & PNG_FREE_SCAL) +#endif +{ +#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED) + png_free(png_ptr, info_ptr->scal_s_width); + png_free(png_ptr, info_ptr->scal_s_height); + info_ptr->scal_s_width = NULL; + info_ptr->scal_s_height = NULL; +#endif + info_ptr->valid &= ~PNG_INFO_sCAL; +} +#endif + +#if defined(PNG_pCAL_SUPPORTED) +/* free any pCAL entry */ +#ifdef PNG_FREE_ME_SUPPORTED +if ((mask & PNG_FREE_PCAL) & info_ptr->free_me) +#else +if (mask & PNG_FREE_PCAL) +#endif +{ + png_free(png_ptr, info_ptr->pcal_purpose); + png_free(png_ptr, info_ptr->pcal_units); + info_ptr->pcal_purpose = NULL; + info_ptr->pcal_units = NULL; + if (info_ptr->pcal_params != NULL) + { + int i; + for (i = 0; i < (int)info_ptr->pcal_nparams; i++) + { + png_free(png_ptr, info_ptr->pcal_params[i]); + info_ptr->pcal_params[i]=NULL; + } + png_free(png_ptr, info_ptr->pcal_params); + info_ptr->pcal_params = NULL; + } + info_ptr->valid &= ~PNG_INFO_pCAL; +} +#endif + +#if defined(PNG_iCCP_SUPPORTED) +/* free any iCCP entry */ +#ifdef PNG_FREE_ME_SUPPORTED +if ((mask & PNG_FREE_ICCP) & info_ptr->free_me) +#else +if (mask & PNG_FREE_ICCP) +#endif +{ + png_free(png_ptr, info_ptr->iccp_name); + png_free(png_ptr, info_ptr->iccp_profile); + info_ptr->iccp_name = NULL; + info_ptr->iccp_profile = NULL; + info_ptr->valid &= ~PNG_INFO_iCCP; +} +#endif + +#if defined(PNG_sPLT_SUPPORTED) +/* free a given sPLT entry, or (if num == -1) all sPLT entries */ +#ifdef PNG_FREE_ME_SUPPORTED +if ((mask & PNG_FREE_SPLT) & info_ptr->free_me) +#else +if (mask & PNG_FREE_SPLT) +#endif +{ + if (num != -1) + { + if(info_ptr->splt_palettes) + { + png_free(png_ptr, info_ptr->splt_palettes[num].name); + png_free(png_ptr, info_ptr->splt_palettes[num].entries); + info_ptr->splt_palettes[num].name = NULL; + info_ptr->splt_palettes[num].entries = NULL; + } + } + else + { + if(info_ptr->splt_palettes_num) + { + int i; + for (i = 0; i < (int)info_ptr->splt_palettes_num; i++) + png_free_data(png_ptr, info_ptr, PNG_FREE_SPLT, i); + + png_free(png_ptr, info_ptr->splt_palettes); + info_ptr->splt_palettes = NULL; + info_ptr->splt_palettes_num = 0; + } + info_ptr->valid &= ~PNG_INFO_sPLT; + } +} +#endif + +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) +#ifdef PNG_FREE_ME_SUPPORTED +if ((mask & PNG_FREE_UNKN) & info_ptr->free_me) +#else +if (mask & PNG_FREE_UNKN) +#endif +{ + if (num != -1) + { + if(info_ptr->unknown_chunks) + { + png_free(png_ptr, info_ptr->unknown_chunks[num].data); + info_ptr->unknown_chunks[num].data = NULL; + } + } + else + { + int i; + + if(info_ptr->unknown_chunks_num) + { + for (i = 0; i < (int)info_ptr->unknown_chunks_num; i++) + png_free_data(png_ptr, info_ptr, PNG_FREE_UNKN, i); + + png_free(png_ptr, info_ptr->unknown_chunks); + info_ptr->unknown_chunks = NULL; + info_ptr->unknown_chunks_num = 0; + } + } +} +#endif + +#if defined(PNG_hIST_SUPPORTED) +/* free any hIST entry */ +#ifdef PNG_FREE_ME_SUPPORTED +if ((mask & PNG_FREE_HIST) & info_ptr->free_me) +#else +if ((mask & PNG_FREE_HIST) && (png_ptr->flags & PNG_FLAG_FREE_HIST)) +#endif +{ + png_free(png_ptr, info_ptr->hist); + info_ptr->hist = NULL; + info_ptr->valid &= ~PNG_INFO_hIST; +#ifndef PNG_FREE_ME_SUPPORTED + png_ptr->flags &= ~PNG_FLAG_FREE_HIST; +#endif +} +#endif + +/* free any PLTE entry that was internally allocated */ +#ifdef PNG_FREE_ME_SUPPORTED +if ((mask & PNG_FREE_PLTE) & info_ptr->free_me) +#else +if ((mask & PNG_FREE_PLTE) && (png_ptr->flags & PNG_FLAG_FREE_PLTE)) +#endif +{ + png_zfree(png_ptr, info_ptr->palette); + info_ptr->palette = NULL; + info_ptr->valid &= ~PNG_INFO_PLTE; +#ifndef PNG_FREE_ME_SUPPORTED + png_ptr->flags &= ~PNG_FLAG_FREE_PLTE; +#endif + info_ptr->num_palette = 0; +} + +#if defined(PNG_INFO_IMAGE_SUPPORTED) +/* free any image bits attached to the info structure */ +#ifdef PNG_FREE_ME_SUPPORTED +if ((mask & PNG_FREE_ROWS) & info_ptr->free_me) +#else +if (mask & PNG_FREE_ROWS) +#endif +{ + if(info_ptr->row_pointers) + { + int row; + for (row = 0; row < (int)info_ptr->height; row++) + { + png_free(png_ptr, info_ptr->row_pointers[row]); + info_ptr->row_pointers[row]=NULL; + } + png_free(png_ptr, info_ptr->row_pointers); + info_ptr->row_pointers=NULL; + } + info_ptr->valid &= ~PNG_INFO_IDAT; +} +#endif + +#ifdef PNG_FREE_ME_SUPPORTED + if(num == -1) + info_ptr->free_me &= ~mask; + else + info_ptr->free_me &= ~(mask & ~PNG_FREE_MUL); +#endif +} + +/* This is an internal routine to free any memory that the info struct is + * pointing to before re-using it or freeing the struct itself. Recall + * that png_free() checks for NULL pointers for us. + */ +void /* PRIVATE */ +png_info_destroy(png_structp png_ptr, png_infop info_ptr) +{ + png_debug(1, "in png_info_destroy\n"); + + png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); + +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) + if (png_ptr->num_chunk_list) + { + png_free(png_ptr, png_ptr->chunk_list); + png_ptr->chunk_list=NULL; + png_ptr->num_chunk_list=0; + } +#endif + + png_info_init_3(&info_ptr, png_sizeof(png_info)); +} + +/* This function returns a pointer to the io_ptr associated with the user + * functions. The application should free any memory associated with this + * pointer before png_write_destroy() or png_read_destroy() are called. + */ +png_voidp PNGAPI +png_get_io_ptr(png_structp png_ptr) +{ + return (png_ptr->io_ptr); +} + +#if !defined(PNG_NO_STDIO) +/* Initialize the default input/output functions for the PNG file. If you + * use your own read or write routines, you can call either png_set_read_fn() + * or png_set_write_fn() instead of png_init_io(). If you have defined + * PNG_NO_STDIO, you must use a function of your own because "FILE *" isn't + * necessarily available. + */ +void PNGAPI +png_init_io(png_structp png_ptr, png_FILE_p fp) +{ + png_debug(1, "in png_init_io\n"); + png_ptr->io_ptr = (png_voidp)fp; +} +#endif + +#if defined(PNG_TIME_RFC1123_SUPPORTED) +/* Convert the supplied time into an RFC 1123 string suitable for use in + * a "Creation Time" or other text-based time string. + */ +png_charp PNGAPI +png_convert_to_rfc1123(png_structp png_ptr, png_timep ptime) +{ + static PNG_CONST char short_months[12][4] = + {"Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + + if (png_ptr->time_buffer == NULL) + { + png_ptr->time_buffer = (png_charp)png_malloc(png_ptr, (png_uint_32)(29* + png_sizeof(char))); + } + +#if defined(_WIN32_WCE) + { + wchar_t time_buf[29]; + wsprintf(time_buf, TEXT("%d %S %d %02d:%02d:%02d +0000"), + ptime->day % 32, short_months[(ptime->month - 1) % 12], + ptime->year, ptime->hour % 24, ptime->minute % 60, + ptime->second % 61); + WideCharToMultiByte(CP_ACP, 0, time_buf, -1, png_ptr->time_buffer, 29, + NULL, NULL); + } +#else +#ifdef USE_FAR_KEYWORD + { + char near_time_buf[29]; + sprintf(near_time_buf, "%d %s %d %02d:%02d:%02d +0000", + ptime->day % 32, short_months[(ptime->month - 1) % 12], + ptime->year, ptime->hour % 24, ptime->minute % 60, + ptime->second % 61); + png_memcpy(png_ptr->time_buffer, near_time_buf, + 29*png_sizeof(char)); + } +#else + sprintf(png_ptr->time_buffer, "%d %s %d %02d:%02d:%02d +0000", + ptime->day % 32, short_months[(ptime->month - 1) % 12], + ptime->year, ptime->hour % 24, ptime->minute % 60, + ptime->second % 61); +#endif +#endif /* _WIN32_WCE */ + return ((png_charp)png_ptr->time_buffer); +} +#endif /* PNG_TIME_RFC1123_SUPPORTED */ + +#if 0 +/* Signature string for a PNG file. */ +png_bytep PNGAPI +png_sig_bytes(void) +{ + return ((png_bytep)"\211\120\116\107\015\012\032\012"); +} +#endif + +png_charp PNGAPI +png_get_copyright(png_structp png_ptr) +{ + if (&png_ptr != NULL) /* silence compiler warning about unused png_ptr */ + return ((png_charp) "\n libpng version 1.2.8 - December 3, 2004\n\ + Copyright (c) 1998-2004 Glenn Randers-Pehrson\n\ + Copyright (c) 1996-1997 Andreas Dilger\n\ + Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n"); + return ((png_charp) ""); +} + +/* The following return the library version as a short string in the + * format 1.0.0 through 99.99.99zz. To get the version of *.h files + * used with your application, print out PNG_LIBPNG_VER_STRING, which + * is defined in png.h. + * Note: now there is no difference between png_get_libpng_ver() and + * png_get_header_ver(). Due to the version_nn_nn_nn typedef guard, + * it is guaranteed that png.c uses the correct version of png.h. + */ +png_charp PNGAPI +png_get_libpng_ver(png_structp png_ptr) +{ + /* Version of *.c files used when building libpng */ + if (&png_ptr != NULL) /* silence compiler warning about unused png_ptr */ + return ((png_charp) PNG_LIBPNG_VER_STRING); + return ((png_charp) ""); +} + +png_charp PNGAPI +png_get_header_ver(png_structp png_ptr) +{ + /* Version of *.h files used when building libpng */ + if (&png_ptr != NULL) /* silence compiler warning about unused png_ptr */ + return ((png_charp) PNG_LIBPNG_VER_STRING); + return ((png_charp) ""); +} + +png_charp PNGAPI +png_get_header_version(png_structp png_ptr) +{ + /* Returns longer string containing both version and date */ + if (&png_ptr != NULL) /* silence compiler warning about unused png_ptr */ + return ((png_charp) PNG_HEADER_VERSION_STRING); + return ((png_charp) ""); +} + +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +int PNGAPI +png_handle_as_unknown(png_structp png_ptr, png_bytep chunk_name) +{ + /* check chunk_name and return "keep" value if it's on the list, else 0 */ + int i; + png_bytep p; + if((png_ptr == NULL && chunk_name == NULL) || png_ptr->num_chunk_list<=0) + return 0; + p=png_ptr->chunk_list+png_ptr->num_chunk_list*5-5; + for (i = png_ptr->num_chunk_list; i; i--, p-=5) + if (!png_memcmp(chunk_name, p, 4)) + return ((int)*(p+4)); + return 0; +} +#endif + +/* This function, added to libpng-1.0.6g, is untested. */ +int PNGAPI +png_reset_zstream(png_structp png_ptr) +{ + return (inflateReset(&png_ptr->zstream)); +} + +/* This function was added to libpng-1.0.7 */ +png_uint_32 PNGAPI +png_access_version_number(void) +{ + /* Version of *.c files used when building libpng */ + return((png_uint_32) PNG_LIBPNG_VER); +} + + +#if !defined(PNG_1_0_X) +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) + /* GRR: could add this: && defined(PNG_MMX_CODE_SUPPORTED) */ +/* this INTERNAL function was added to libpng 1.2.0 */ +void /* PRIVATE */ +png_init_mmx_flags (png_structp png_ptr) +{ + png_ptr->mmx_rowbytes_threshold = 0; + png_ptr->mmx_bitdepth_threshold = 0; + +# if (defined(PNG_USE_PNGVCRD) || defined(PNG_USE_PNGGCCRD)) + + png_ptr->asm_flags |= PNG_ASM_FLAG_MMX_SUPPORT_COMPILED; + + if (png_mmx_support() > 0) { + png_ptr->asm_flags |= PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU +# ifdef PNG_HAVE_ASSEMBLER_COMBINE_ROW + | PNG_ASM_FLAG_MMX_READ_COMBINE_ROW +# endif +# ifdef PNG_HAVE_ASSEMBLER_READ_INTERLACE + | PNG_ASM_FLAG_MMX_READ_INTERLACE +# endif +# ifndef PNG_HAVE_ASSEMBLER_READ_FILTER_ROW + ; +# else + | PNG_ASM_FLAG_MMX_READ_FILTER_SUB + | PNG_ASM_FLAG_MMX_READ_FILTER_UP + | PNG_ASM_FLAG_MMX_READ_FILTER_AVG + | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ; + + png_ptr->mmx_rowbytes_threshold = PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT; + png_ptr->mmx_bitdepth_threshold = PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT; +# endif + } else { + png_ptr->asm_flags &= ~( PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU + | PNG_MMX_READ_FLAGS + | PNG_MMX_WRITE_FLAGS ); + } + +# else /* !((PNGVCRD || PNGGCCRD) && PNG_ASSEMBLER_CODE_SUPPORTED)) */ + + /* clear all MMX flags; no support is compiled in */ + png_ptr->asm_flags &= ~( PNG_MMX_FLAGS ); + +# endif /* ?(PNGVCRD || PNGGCCRD) */ +} + +#endif /* !(PNG_ASSEMBLER_CODE_SUPPORTED) */ + +/* this function was added to libpng 1.2.0 */ +#if !defined(PNG_USE_PNGGCCRD) && \ + !(defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_USE_PNGVCRD)) +int PNGAPI +png_mmx_support(void) +{ + return -1; +} +#endif +#endif /* PNG_1_0_X */ + +#ifdef PNG_SIZE_T +/* Added at libpng version 1.2.6 */ + PNG_EXTERN png_size_t PNGAPI png_convert_size PNGARG((size_t size)); +png_size_t PNGAPI +png_convert_size(size_t size) +{ + if (size > (png_size_t)-1) + PNG_ABORT(); /* We haven't got access to png_ptr, so no png_error() */ + return ((png_size_t)size); +} +#endif /* PNG_SIZE_T */ diff --git a/syslinux/com32/lib/libpng/pngerror.c b/syslinux/com32/lib/libpng/pngerror.c new file mode 100644 index 0000000..6fa4012 --- /dev/null +++ b/syslinux/com32/lib/libpng/pngerror.c @@ -0,0 +1,295 @@ + +/* pngerror.c - stub functions for i/o and memory allocation + * + * libpng version 1.2.8 - December 3, 2004 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2004 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This file provides a location for all error handling. Users who + * need special error handling are expected to write replacement functions + * and use png_set_error_fn() to use those functions. See the instructions + * at each function. + */ + +#define PNG_INTERNAL +#include "png.h" + +static void /* PRIVATE */ +png_default_error PNGARG((png_structp png_ptr, + png_const_charp error_message)); +static void /* PRIVATE */ +png_default_warning PNGARG((png_structp png_ptr, + png_const_charp warning_message)); + +/* This function is called whenever there is a fatal error. This function + * should not be changed. If there is a need to handle errors differently, + * you should supply a replacement error function and use png_set_error_fn() + * to replace the error function at run-time. + */ +void PNGAPI +png_error(png_structp png_ptr, png_const_charp error_message) +{ +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + char msg[16]; + if (png_ptr->flags&(PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) + { + if (*error_message == '#') + { + int offset; + for (offset=1; offset<15; offset++) + if (*(error_message+offset) == ' ') + break; + if (png_ptr->flags&PNG_FLAG_STRIP_ERROR_TEXT) + { + int i; + for (i=0; i<offset-1; i++) + msg[i]=error_message[i+1]; + msg[i]='\0'; + error_message=msg; + } + else + error_message+=offset; + } + else + { + if (png_ptr->flags&PNG_FLAG_STRIP_ERROR_TEXT) + { + msg[0]='0'; + msg[1]='\0'; + error_message=msg; + } + } + } +#endif + if (png_ptr != NULL && png_ptr->error_fn != NULL) + (*(png_ptr->error_fn))(png_ptr, error_message); + + /* If the custom handler doesn't exist, or if it returns, + use the default handler, which will not return. */ + png_default_error(png_ptr, error_message); +} + +/* This function is called whenever there is a non-fatal error. This function + * should not be changed. If there is a need to handle warnings differently, + * you should supply a replacement warning function and use + * png_set_error_fn() to replace the warning function at run-time. + */ +void PNGAPI +png_warning(png_structp png_ptr, png_const_charp warning_message) +{ + int offset = 0; +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + if (png_ptr->flags&(PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) +#endif + { + if (*warning_message == '#') + { + for (offset=1; offset<15; offset++) + if (*(warning_message+offset) == ' ') + break; + } + } + if (png_ptr != NULL && png_ptr->warning_fn != NULL) + (*(png_ptr->warning_fn))(png_ptr, warning_message+offset); + else + png_default_warning(png_ptr, warning_message+offset); +} + +/* These utilities are used internally to build an error message that relates + * to the current chunk. The chunk name comes from png_ptr->chunk_name, + * this is used to prefix the message. The message is limited in length + * to 63 bytes, the name characters are output as hex digits wrapped in [] + * if the character is invalid. + */ +#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97)) +static PNG_CONST char png_digit[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F' +}; + +static void /* PRIVATE */ +png_format_buffer(png_structp png_ptr, png_charp buffer, png_const_charp + error_message) +{ + int iout = 0, iin = 0; + + while (iin < 4) + { + int c = png_ptr->chunk_name[iin++]; + if (isnonalpha(c)) + { + buffer[iout++] = '['; + buffer[iout++] = png_digit[(c & 0xf0) >> 4]; + buffer[iout++] = png_digit[c & 0x0f]; + buffer[iout++] = ']'; + } + else + { + buffer[iout++] = (png_byte)c; + } + } + + if (error_message == NULL) + buffer[iout] = 0; + else + { + buffer[iout++] = ':'; + buffer[iout++] = ' '; + png_strncpy(buffer+iout, error_message, 63); + buffer[iout+63] = 0; + } +} + +void PNGAPI +png_chunk_error(png_structp png_ptr, png_const_charp error_message) +{ + char msg[18+64]; + png_format_buffer(png_ptr, msg, error_message); + png_error(png_ptr, msg); +} + +void PNGAPI +png_chunk_warning(png_structp png_ptr, png_const_charp warning_message) +{ + char msg[18+64]; + png_format_buffer(png_ptr, msg, warning_message); + png_warning(png_ptr, msg); +} + +/* This is the default error handling function. Note that replacements for + * this function MUST NOT RETURN, or the program will likely crash. This + * function is used by default, or if the program supplies NULL for the + * error function pointer in png_set_error_fn(). + */ +static void /* PRIVATE */ +png_default_error(png_structp png_ptr, png_const_charp error_message) +{ +#ifndef PNG_NO_CONSOLE_IO +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + if (*error_message == '#') + { + int offset; + char error_number[16]; + for (offset=0; offset<15; offset++) + { + error_number[offset] = *(error_message+offset+1); + if (*(error_message+offset) == ' ') + break; + } + if((offset > 1) && (offset < 15)) + { + error_number[offset-1]='\0'; + fprintf(stderr, "libpng error no. %s: %s\n", error_number, + error_message+offset); + } + else + fprintf(stderr, "libpng error: %s, offset=%d\n", error_message,offset); + } + else +#endif + fprintf(stderr, "libpng error: %s\n", error_message); +#endif + +#ifdef PNG_SETJMP_SUPPORTED +# ifdef USE_FAR_KEYWORD + { + jmp_buf jmpbuf; + png_memcpy(jmpbuf,png_ptr->jmpbuf,png_sizeof(jmp_buf)); + longjmp(jmpbuf, 1); + } +# else + longjmp(png_ptr->jmpbuf, 1); +# endif +#else + /* make compiler happy */ ; + if (png_ptr) + PNG_ABORT(); +#endif +#ifdef PNG_NO_CONSOLE_IO + /* make compiler happy */ ; + if (&error_message != NULL) + return; +#endif +} + +/* This function is called when there is a warning, but the library thinks + * it can continue anyway. Replacement functions don't have to do anything + * here if you don't want them to. In the default configuration, png_ptr is + * not used, but it is passed in case it may be useful. + */ +static void /* PRIVATE */ +png_default_warning(png_structp png_ptr, png_const_charp warning_message) +{ +#ifndef PNG_NO_CONSOLE_IO +# ifdef PNG_ERROR_NUMBERS_SUPPORTED + if (*warning_message == '#') + { + int offset; + char warning_number[16]; + for (offset=0; offset<15; offset++) + { + warning_number[offset]=*(warning_message+offset+1); + if (*(warning_message+offset) == ' ') + break; + } + if((offset > 1) && (offset < 15)) + { + warning_number[offset-1]='\0'; + fprintf(stderr, "libpng warning no. %s: %s\n", warning_number, + warning_message+offset); + } + else + fprintf(stderr, "libpng warning: %s\n", warning_message); + } + else +# endif + fprintf(stderr, "libpng warning: %s\n", warning_message); +#else + /* make compiler happy */ ; + if (warning_message) + return; +#endif + /* make compiler happy */ ; + if (png_ptr) + return; +} + +/* This function is called when the application wants to use another method + * of handling errors and warnings. Note that the error function MUST NOT + * return to the calling routine or serious problems will occur. The return + * method used in the default routine calls longjmp(png_ptr->jmpbuf, 1) + */ +void PNGAPI +png_set_error_fn(png_structp png_ptr, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warning_fn) +{ + png_ptr->error_ptr = error_ptr; + png_ptr->error_fn = error_fn; + png_ptr->warning_fn = warning_fn; +} + + +/* This function returns a pointer to the error_ptr associated with the user + * functions. The application should free any memory associated with this + * pointer before png_write_destroy and png_read_destroy are called. + */ +png_voidp PNGAPI +png_get_error_ptr(png_structp png_ptr) +{ + return ((png_voidp)png_ptr->error_ptr); +} + + +#ifdef PNG_ERROR_NUMBERS_SUPPORTED +void PNGAPI +png_set_strip_error_numbers(png_structp png_ptr, png_uint_32 strip_mode) +{ + if(png_ptr != NULL) + { + png_ptr->flags &= + ((~(PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT))&strip_mode); + } +} +#endif diff --git a/syslinux/com32/lib/libpng/pnggccrd.c b/syslinux/com32/lib/libpng/pnggccrd.c new file mode 100644 index 0000000..248e1b3 --- /dev/null +++ b/syslinux/com32/lib/libpng/pnggccrd.c @@ -0,0 +1,5408 @@ +/* pnggccrd.c - mixed C/assembler version of utilities to read a PNG file + * + * For Intel x86 CPU (Pentium-MMX or later) and GNU C compiler. + * + * See http://www.intel.com/drg/pentiumII/appnotes/916/916.htm + * and http://www.intel.com/drg/pentiumII/appnotes/923/923.htm + * for Intel's performance analysis of the MMX vs. non-MMX code. + * + * libpng version 1.2.8 - December 3, 2004 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2004 Glenn Randers-Pehrson + * Copyright (c) 1998, Intel Corporation + * + * Based on MSVC code contributed by Nirav Chhatrapati, Intel Corp., 1998. + * Interface to libpng contributed by Gilles Vollant, 1999. + * GNU C port by Greg Roelofs, 1999-2001. + * + * Lines 2350-4300 converted in place with intel2gas 1.3.1: + * + * intel2gas -mdI pnggccrd.c.partially-msvc -o pnggccrd.c + * + * and then cleaned up by hand. See http://hermes.terminal.at/intel2gas/ . + * + * NOTE: A sufficiently recent version of GNU as (or as.exe under DOS/Windows) + * is required to assemble the newer MMX instructions such as movq. + * For djgpp, see + * + * ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/bnu281b.zip + * + * (or a later version in the same directory). For Linux, check your + * distribution's web site(s) or try these links: + * + * http://rufus.w3.org/linux/RPM/binutils.html + * http://www.debian.org/Packages/stable/devel/binutils.html + * ftp://ftp.slackware.com/pub/linux/slackware/slackware/slakware/d1/ + * binutils.tgz + * + * For other platforms, see the main GNU site: + * + * ftp://ftp.gnu.org/pub/gnu/binutils/ + * + * Version 2.5.2l.15 is definitely too old... + */ + +/* + * TEMPORARY PORTING NOTES AND CHANGELOG (mostly by Greg Roelofs) + * ===================================== + * + * 19991006: + * - fixed sign error in post-MMX cleanup code (16- & 32-bit cases) + * + * 19991007: + * - additional optimizations (possible or definite): + * x [DONE] write MMX code for 64-bit case (pixel_bytes == 8) [not tested] + * - write MMX code for 48-bit case (pixel_bytes == 6) + * - figure out what's up with 24-bit case (pixel_bytes == 3): + * why subtract 8 from width_mmx in the pass 4/5 case? + * (only width_mmx case) (near line 1606) + * x [DONE] replace pixel_bytes within each block with the true + * constant value (or are compilers smart enough to do that?) + * - rewrite all MMX interlacing code so it's aligned with + * the *beginning* of the row buffer, not the end. This + * would not only allow one to eliminate half of the memory + * writes for odd passes (that is, pass == odd), it may also + * eliminate some unaligned-data-access exceptions (assuming + * there's a penalty for not aligning 64-bit accesses on + * 64-bit boundaries). The only catch is that the "leftover" + * pixel(s) at the end of the row would have to be saved, + * but there are enough unused MMX registers in every case, + * so this is not a problem. A further benefit is that the + * post-MMX cleanup code (C code) in at least some of the + * cases could be done within the assembler block. + * x [DONE] the "v3 v2 v1 v0 v7 v6 v5 v4" comments are confusing, + * inconsistent, and don't match the MMX Programmer's Reference + * Manual conventions anyway. They should be changed to + * "b7 b6 b5 b4 b3 b2 b1 b0," where b0 indicates the byte that + * was lowest in memory (e.g., corresponding to a left pixel) + * and b7 is the byte that was highest (e.g., a right pixel). + * + * 19991016: + * - Brennan's Guide notwithstanding, gcc under Linux does *not* + * want globals prefixed by underscores when referencing them-- + * i.e., if the variable is const4, then refer to it as const4, + * not _const4. This seems to be a djgpp-specific requirement. + * Also, such variables apparently *must* be declared outside + * of functions; neither static nor automatic variables work if + * defined within the scope of a single function, but both + * static and truly global (multi-module) variables work fine. + * + * 19991023: + * - fixed png_combine_row() non-MMX replication bug (odd passes only?) + * - switched from string-concatenation-with-macros to cleaner method of + * renaming global variables for djgpp--i.e., always use prefixes in + * inlined assembler code (== strings) and conditionally rename the + * variables, not the other way around. Hence _const4, _mask8_0, etc. + * + * 19991024: + * - fixed mmxsupport()/png_do_read_interlace() first-row bug + * This one was severely weird: even though mmxsupport() doesn't touch + * ebx (where "row" pointer was stored), it nevertheless managed to zero + * the register (even in static/non-fPIC code--see below), which in turn + * caused png_do_read_interlace() to return prematurely on the first row of + * interlaced images (i.e., without expanding the interlaced pixels). + * Inspection of the generated assembly code didn't turn up any clues, + * although it did point at a minor optimization (i.e., get rid of + * mmx_supported_local variable and just use eax). Possibly the CPUID + * instruction is more destructive than it looks? (Not yet checked.) + * - "info gcc" was next to useless, so compared fPIC and non-fPIC assembly + * listings... Apparently register spillage has to do with ebx, since + * it's used to index the global offset table. Commenting it out of the + * input-reg lists in png_combine_row() eliminated compiler barfage, so + * ifdef'd with __PIC__ macro: if defined, use a global for unmask + * + * 19991107: + * - verified CPUID clobberage: 12-char string constant ("GenuineIntel", + * "AuthenticAMD", etc.) placed in ebx:ecx:edx. Still need to polish. + * + * 19991120: + * - made "diff" variable (now "_dif") global to simplify conversion of + * filtering routines (running out of regs, sigh). "diff" is still used + * in interlacing routines, however. + * - fixed up both versions of mmxsupport() (ORIG_THAT_USED_TO_CLOBBER_EBX + * macro determines which is used); original not yet tested. + * + * 20000213: + * - when compiling with gcc, be sure to use -fomit-frame-pointer + * + * 20000319: + * - fixed a register-name typo in png_do_read_interlace(), default (MMX) case, + * pass == 4 or 5, that caused visible corruption of interlaced images + * + * 20000623: + * - Various problems were reported with gcc 2.95.2 in the Cygwin environment, + * many of the form "forbidden register 0 (ax) was spilled for class AREG." + * This is explained at http://gcc.gnu.org/fom_serv/cache/23.html, and + * Chuck Wilson supplied a patch involving dummy output registers. See + * http://sourceforge.net/bugs/?func=detailbug&bug_id=108741&group_id=5624 + * for the original (anonymous) SourceForge bug report. + * + * 20000706: + * - Chuck Wilson passed along these remaining gcc 2.95.2 errors: + * pnggccrd.c: In function `png_combine_row': + * pnggccrd.c:525: more than 10 operands in `asm' + * pnggccrd.c:669: more than 10 operands in `asm' + * pnggccrd.c:828: more than 10 operands in `asm' + * pnggccrd.c:994: more than 10 operands in `asm' + * pnggccrd.c:1177: more than 10 operands in `asm' + * They are all the same problem and can be worked around by using the + * global _unmask variable unconditionally, not just in the -fPIC case. + * Reportedly earlier versions of gcc also have the problem with more than + * 10 operands; they just don't report it. Much strangeness ensues, etc. + * + * 20000729: + * - enabled png_read_filter_row_mmx_up() (shortest remaining unconverted + * MMX routine); began converting png_read_filter_row_mmx_sub() + * - to finish remaining sections: + * - clean up indentation and comments + * - preload local variables + * - add output and input regs (order of former determines numerical + * mapping of latter) + * - avoid all usage of ebx (including bx, bh, bl) register [20000823] + * - remove "$" from addressing of Shift and Mask variables [20000823] + * + * 20000731: + * - global union vars causing segfaults in png_read_filter_row_mmx_sub()? + * + * 20000822: + * - ARGH, stupid png_read_filter_row_mmx_sub() segfault only happens with + * shared-library (-fPIC) version! Code works just fine as part of static + * library. Damn damn damn damn damn, should have tested that sooner. + * ebx is getting clobbered again (explicitly this time); need to save it + * on stack or rewrite asm code to avoid using it altogether. Blargh! + * + * 20000823: + * - first section was trickiest; all remaining sections have ebx -> edx now. + * (-fPIC works again.) Also added missing underscores to various Shift* + * and *Mask* globals and got rid of leading "$" signs. + * + * 20000826: + * - added visual separators to help navigate microscopic printed copies + * (http://pobox.com/~newt/code/gpr-latest.zip, mode 10); started working + * on png_read_filter_row_mmx_avg() + * + * 20000828: + * - finished png_read_filter_row_mmx_avg(): only Paeth left! (930 lines...) + * What the hell, did png_read_filter_row_mmx_paeth(), too. Comments not + * cleaned up/shortened in either routine, but functionality is complete + * and seems to be working fine. + * + * 20000829: + * - ahhh, figured out last(?) bit of gcc/gas asm-fu: if register is listed + * as an input reg (with dummy output variables, etc.), then it *cannot* + * also appear in the clobber list or gcc 2.95.2 will barf. The solution + * is simple enough... + * + * 20000914: + * - bug in png_read_filter_row_mmx_avg(): 16-bit grayscale not handled + * correctly (but 48-bit RGB just fine) + * + * 20000916: + * - fixed bug in png_read_filter_row_mmx_avg(), bpp == 2 case; three errors: + * - "_ShiftBpp.use = 24;" should have been "_ShiftBpp.use = 16;" + * - "_ShiftRem.use = 40;" should have been "_ShiftRem.use = 48;" + * - "psllq _ShiftRem, %%mm2" should have been "psrlq _ShiftRem, %%mm2" + * + * 20010101: + * - added new png_init_mmx_flags() function (here only because it needs to + * call mmxsupport(), which should probably become global png_mmxsupport()); + * modified other MMX routines to run conditionally (png_ptr->asm_flags) + * + * 20010103: + * - renamed mmxsupport() to png_mmx_support(), with auto-set of mmx_supported, + * and made it public; moved png_init_mmx_flags() to png.c as internal func + * + * 20010104: + * - removed dependency on png_read_filter_row_c() (C code already duplicated + * within MMX version of png_read_filter_row()) so no longer necessary to + * compile it into pngrutil.o + * + * 20010310: + * - fixed buffer-overrun bug in png_combine_row() C code (non-MMX) + * + * 20020304: + * - eliminated incorrect use of width_mmx in pixel_bytes == 8 case + * + * 20040724: + * - more tinkering with clobber list at lines 4529 and 5033, to get + * it to compile on gcc-3.4. + * + * STILL TO DO: + * - test png_do_read_interlace() 64-bit case (pixel_bytes == 8) + * - write MMX code for 48-bit case (pixel_bytes == 6) + * - figure out what's up with 24-bit case (pixel_bytes == 3): + * why subtract 8 from width_mmx in the pass 4/5 case? + * (only width_mmx case) (near line 1606) + * - rewrite all MMX interlacing code so it's aligned with beginning + * of the row buffer, not the end (see 19991007 for details) + * x pick one version of mmxsupport() and get rid of the other + * - add error messages to any remaining bogus default cases + * - enable pixel_depth == 8 cases in png_read_filter_row()? (test speed) + * x add support for runtime enable/disable/query of various MMX routines + */ + +#define PNG_INTERNAL +#include "png.h" + +#if defined(PNG_USE_PNGGCCRD) + +int PNGAPI png_mmx_support(void); + +#ifdef PNG_USE_LOCAL_ARRAYS +static const int FARDATA png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; +static const int FARDATA png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; +static const int FARDATA png_pass_width[7] = {8, 4, 4, 2, 2, 1, 1}; +#endif + +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) +/* djgpp, Win32, and Cygwin add their own underscores to global variables, + * so define them without: */ +#if defined(__DJGPP__) || defined(WIN32) || defined(__CYGWIN__) +# define _mmx_supported mmx_supported +# define _const4 const4 +# define _const6 const6 +# define _mask8_0 mask8_0 +# define _mask16_1 mask16_1 +# define _mask16_0 mask16_0 +# define _mask24_2 mask24_2 +# define _mask24_1 mask24_1 +# define _mask24_0 mask24_0 +# define _mask32_3 mask32_3 +# define _mask32_2 mask32_2 +# define _mask32_1 mask32_1 +# define _mask32_0 mask32_0 +# define _mask48_5 mask48_5 +# define _mask48_4 mask48_4 +# define _mask48_3 mask48_3 +# define _mask48_2 mask48_2 +# define _mask48_1 mask48_1 +# define _mask48_0 mask48_0 +# define _LBCarryMask LBCarryMask +# define _HBClearMask HBClearMask +# define _ActiveMask ActiveMask +# define _ActiveMask2 ActiveMask2 +# define _ActiveMaskEnd ActiveMaskEnd +# define _ShiftBpp ShiftBpp +# define _ShiftRem ShiftRem +#ifdef PNG_THREAD_UNSAFE_OK +# define _unmask unmask +# define _FullLength FullLength +# define _MMXLength MMXLength +# define _dif dif +# define _patemp patemp +# define _pbtemp pbtemp +# define _pctemp pctemp +#endif +#endif + + +/* These constants are used in the inlined MMX assembly code. + Ignore gcc's "At top level: defined but not used" warnings. */ + +/* GRR 20000706: originally _unmask was needed only when compiling with -fPIC, + * since that case uses the %ebx register for indexing the Global Offset Table + * and there were no other registers available. But gcc 2.95 and later emit + * "more than 10 operands in `asm'" errors when %ebx is used to preload unmask + * in the non-PIC case, so we'll just use the global unconditionally now. + */ +#ifdef PNG_THREAD_UNSAFE_OK +static int _unmask; +#endif + +static unsigned long long _mask8_0 = 0x0102040810204080LL; + +static unsigned long long _mask16_1 = 0x0101020204040808LL; +static unsigned long long _mask16_0 = 0x1010202040408080LL; + +static unsigned long long _mask24_2 = 0x0101010202020404LL; +static unsigned long long _mask24_1 = 0x0408080810101020LL; +static unsigned long long _mask24_0 = 0x2020404040808080LL; + +static unsigned long long _mask32_3 = 0x0101010102020202LL; +static unsigned long long _mask32_2 = 0x0404040408080808LL; +static unsigned long long _mask32_1 = 0x1010101020202020LL; +static unsigned long long _mask32_0 = 0x4040404080808080LL; + +static unsigned long long _mask48_5 = 0x0101010101010202LL; +static unsigned long long _mask48_4 = 0x0202020204040404LL; +static unsigned long long _mask48_3 = 0x0404080808080808LL; +static unsigned long long _mask48_2 = 0x1010101010102020LL; +static unsigned long long _mask48_1 = 0x2020202040404040LL; +static unsigned long long _mask48_0 = 0x4040808080808080LL; + +static unsigned long long _const4 = 0x0000000000FFFFFFLL; +//static unsigned long long _const5 = 0x000000FFFFFF0000LL; // NOT USED +static unsigned long long _const6 = 0x00000000000000FFLL; + +// These are used in the row-filter routines and should/would be local +// variables if not for gcc addressing limitations. +// WARNING: Their presence probably defeats the thread safety of libpng. + +#ifdef PNG_THREAD_UNSAFE_OK +static png_uint_32 _FullLength; +static png_uint_32 _MMXLength; +static int _dif; +static int _patemp; // temp variables for Paeth routine +static int _pbtemp; +static int _pctemp; +#endif + +void /* PRIVATE */ +png_squelch_warnings(void) +{ +#ifdef PNG_THREAD_UNSAFE_OK + _dif = _dif; + _patemp = _patemp; + _pbtemp = _pbtemp; + _pctemp = _pctemp; + _MMXLength = _MMXLength; +#endif + _const4 = _const4; + _const6 = _const6; + _mask8_0 = _mask8_0; + _mask16_1 = _mask16_1; + _mask16_0 = _mask16_0; + _mask24_2 = _mask24_2; + _mask24_1 = _mask24_1; + _mask24_0 = _mask24_0; + _mask32_3 = _mask32_3; + _mask32_2 = _mask32_2; + _mask32_1 = _mask32_1; + _mask32_0 = _mask32_0; + _mask48_5 = _mask48_5; + _mask48_4 = _mask48_4; + _mask48_3 = _mask48_3; + _mask48_2 = _mask48_2; + _mask48_1 = _mask48_1; + _mask48_0 = _mask48_0; +} +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ + + +static int _mmx_supported = 2; + +/*===========================================================================*/ +/* */ +/* P N G _ C O M B I N E _ R O W */ +/* */ +/*===========================================================================*/ + +#if defined(PNG_HAVE_ASSEMBLER_COMBINE_ROW) + +#define BPP2 2 +#define BPP3 3 /* bytes per pixel (a.k.a. pixel_bytes) */ +#define BPP4 4 +#define BPP6 6 /* (defined only to help avoid cut-and-paste errors) */ +#define BPP8 8 + +/* Combines the row recently read in with the previous row. + This routine takes care of alpha and transparency if requested. + This routine also handles the two methods of progressive display + of interlaced images, depending on the mask value. + The mask value describes which pixels are to be combined with + the row. The pattern always repeats every 8 pixels, so just 8 + bits are needed. A one indicates the pixel is to be combined; a + zero indicates the pixel is to be skipped. This is in addition + to any alpha or transparency value associated with the pixel. + If you want all pixels to be combined, pass 0xff (255) in mask. */ + +/* Use this routine for the x86 platform - it uses a faster MMX routine + if the machine supports MMX. */ + +void /* PRIVATE */ +png_combine_row(png_structp png_ptr, png_bytep row, int mask) +{ + png_debug(1, "in png_combine_row (pnggccrd.c)\n"); + +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) + if (_mmx_supported == 2) { +#if !defined(PNG_1_0_X) + /* this should have happened in png_init_mmx_flags() already */ + png_warning(png_ptr, "asm_flags may not have been initialized"); +#endif + png_mmx_support(); + } +#endif + + if (mask == 0xff) + { + png_debug(2,"mask == 0xff: doing single png_memcpy()\n"); + png_memcpy(row, png_ptr->row_buf + 1, + (png_size_t)PNG_ROWBYTES(png_ptr->row_info.pixel_depth,png_ptr->width)); + } + else /* (png_combine_row() is never called with mask == 0) */ + { + switch (png_ptr->row_info.pixel_depth) + { + case 1: /* png_ptr->row_info.pixel_depth */ + { + png_bytep sp; + png_bytep dp; + int s_inc, s_start, s_end; + int m; + int shift; + png_uint_32 i; + + sp = png_ptr->row_buf + 1; + dp = row; + m = 0x80; +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + { + s_start = 0; + s_end = 7; + s_inc = 1; + } + else +#endif + { + s_start = 7; + s_end = 0; + s_inc = -1; + } + + shift = s_start; + + for (i = 0; i < png_ptr->width; i++) + { + if (m & mask) + { + int value; + + value = (*sp >> shift) & 0x1; + *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff); + *dp |= (png_byte)(value << shift); + } + + if (shift == s_end) + { + shift = s_start; + sp++; + dp++; + } + else + shift += s_inc; + + if (m == 1) + m = 0x80; + else + m >>= 1; + } + break; + } + + case 2: /* png_ptr->row_info.pixel_depth */ + { + png_bytep sp; + png_bytep dp; + int s_start, s_end, s_inc; + int m; + int shift; + png_uint_32 i; + int value; + + sp = png_ptr->row_buf + 1; + dp = row; + m = 0x80; +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + { + s_start = 0; + s_end = 6; + s_inc = 2; + } + else +#endif + { + s_start = 6; + s_end = 0; + s_inc = -2; + } + + shift = s_start; + + for (i = 0; i < png_ptr->width; i++) + { + if (m & mask) + { + value = (*sp >> shift) & 0x3; + *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); + *dp |= (png_byte)(value << shift); + } + + if (shift == s_end) + { + shift = s_start; + sp++; + dp++; + } + else + shift += s_inc; + if (m == 1) + m = 0x80; + else + m >>= 1; + } + break; + } + + case 4: /* png_ptr->row_info.pixel_depth */ + { + png_bytep sp; + png_bytep dp; + int s_start, s_end, s_inc; + int m; + int shift; + png_uint_32 i; + int value; + + sp = png_ptr->row_buf + 1; + dp = row; + m = 0x80; +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + { + s_start = 0; + s_end = 4; + s_inc = 4; + } + else +#endif + { + s_start = 4; + s_end = 0; + s_inc = -4; + } + shift = s_start; + + for (i = 0; i < png_ptr->width; i++) + { + if (m & mask) + { + value = (*sp >> shift) & 0xf; + *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); + *dp |= (png_byte)(value << shift); + } + + if (shift == s_end) + { + shift = s_start; + sp++; + dp++; + } + else + shift += s_inc; + if (m == 1) + m = 0x80; + else + m >>= 1; + } + break; + } + + case 8: /* png_ptr->row_info.pixel_depth */ + { + png_bytep srcptr; + png_bytep dstptr; + +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK) +#if !defined(PNG_1_0_X) + if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW) + /* && _mmx_supported */ ) +#else + if (_mmx_supported) +#endif + { + png_uint_32 len; + int diff; + int dummy_value_a; // fix 'forbidden register spilled' error + int dummy_value_d; + int dummy_value_c; + int dummy_value_S; + int dummy_value_D; + _unmask = ~mask; // global variable for -fPIC version + srcptr = png_ptr->row_buf + 1; + dstptr = row; + len = png_ptr->width &~7; // reduce to multiple of 8 + diff = (int) (png_ptr->width & 7); // amount lost + + __asm__ __volatile__ ( + "movd _unmask, %%mm7 \n\t" // load bit pattern + "psubb %%mm6, %%mm6 \n\t" // zero mm6 + "punpcklbw %%mm7, %%mm7 \n\t" + "punpcklwd %%mm7, %%mm7 \n\t" + "punpckldq %%mm7, %%mm7 \n\t" // fill reg with 8 masks + + "movq _mask8_0, %%mm0 \n\t" + "pand %%mm7, %%mm0 \n\t" // nonzero if keep byte + "pcmpeqb %%mm6, %%mm0 \n\t" // zeros->1s, v versa + +// preload "movl len, %%ecx \n\t" // load length of line +// preload "movl srcptr, %%esi \n\t" // load source +// preload "movl dstptr, %%edi \n\t" // load dest + + "cmpl $0, %%ecx \n\t" // len == 0 ? + "je mainloop8end \n\t" + + "mainloop8: \n\t" + "movq (%%esi), %%mm4 \n\t" // *srcptr + "pand %%mm0, %%mm4 \n\t" + "movq %%mm0, %%mm6 \n\t" + "pandn (%%edi), %%mm6 \n\t" // *dstptr + "por %%mm6, %%mm4 \n\t" + "movq %%mm4, (%%edi) \n\t" + "addl $8, %%esi \n\t" // inc by 8 bytes processed + "addl $8, %%edi \n\t" + "subl $8, %%ecx \n\t" // dec by 8 pixels processed + "ja mainloop8 \n\t" + + "mainloop8end: \n\t" +// preload "movl diff, %%ecx \n\t" // (diff is in eax) + "movl %%eax, %%ecx \n\t" + "cmpl $0, %%ecx \n\t" + "jz end8 \n\t" +// preload "movl mask, %%edx \n\t" + "sall $24, %%edx \n\t" // make low byte, high byte + + "secondloop8: \n\t" + "sall %%edx \n\t" // move high bit to CF + "jnc skip8 \n\t" // if CF = 0 + "movb (%%esi), %%al \n\t" + "movb %%al, (%%edi) \n\t" + + "skip8: \n\t" + "incl %%esi \n\t" + "incl %%edi \n\t" + "decl %%ecx \n\t" + "jnz secondloop8 \n\t" + + "end8: \n\t" + "EMMS \n\t" // DONE + + : "=a" (dummy_value_a), // output regs (dummy) + "=d" (dummy_value_d), + "=c" (dummy_value_c), + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "3" (srcptr), // esi // input regs + "4" (dstptr), // edi + "0" (diff), // eax +// was (unmask) "b" RESERVED // ebx // Global Offset Table idx + "2" (len), // ecx + "1" (mask) // edx + +#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0", "%mm4", "%mm6", "%mm7" // clobber list +#endif + ); + } + else /* mmx _not supported - Use modified C routine */ +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ + { + register png_uint_32 i; + png_uint_32 initial_val = png_pass_start[png_ptr->pass]; + /* png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */ + register int stride = png_pass_inc[png_ptr->pass]; + /* png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */ + register int rep_bytes = png_pass_width[png_ptr->pass]; + /* png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */ + png_uint_32 len = png_ptr->width &~7; /* reduce to mult. of 8 */ + int diff = (int) (png_ptr->width & 7); /* amount lost */ + register png_uint_32 final_val = len; /* GRR bugfix */ + + srcptr = png_ptr->row_buf + 1 + initial_val; + dstptr = row + initial_val; + + for (i = initial_val; i < final_val; i += stride) + { + png_memcpy(dstptr, srcptr, rep_bytes); + srcptr += stride; + dstptr += stride; + } + if (diff) /* number of leftover pixels: 3 for pngtest */ + { + final_val+=diff /* *BPP1 */ ; + for (; i < final_val; i += stride) + { + if (rep_bytes > (int)(final_val-i)) + rep_bytes = (int)(final_val-i); + png_memcpy(dstptr, srcptr, rep_bytes); + srcptr += stride; + dstptr += stride; + } + } + + } /* end of else (_mmx_supported) */ + + break; + } /* end 8 bpp */ + + case 16: /* png_ptr->row_info.pixel_depth */ + { + png_bytep srcptr; + png_bytep dstptr; + +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK) +#if !defined(PNG_1_0_X) + if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW) + /* && _mmx_supported */ ) +#else + if (_mmx_supported) +#endif + { + png_uint_32 len; + int diff; + int dummy_value_a; // fix 'forbidden register spilled' error + int dummy_value_d; + int dummy_value_c; + int dummy_value_S; + int dummy_value_D; + _unmask = ~mask; // global variable for -fPIC version + srcptr = png_ptr->row_buf + 1; + dstptr = row; + len = png_ptr->width &~7; // reduce to multiple of 8 + diff = (int) (png_ptr->width & 7); // amount lost // + + __asm__ __volatile__ ( + "movd _unmask, %%mm7 \n\t" // load bit pattern + "psubb %%mm6, %%mm6 \n\t" // zero mm6 + "punpcklbw %%mm7, %%mm7 \n\t" + "punpcklwd %%mm7, %%mm7 \n\t" + "punpckldq %%mm7, %%mm7 \n\t" // fill reg with 8 masks + + "movq _mask16_0, %%mm0 \n\t" + "movq _mask16_1, %%mm1 \n\t" + + "pand %%mm7, %%mm0 \n\t" + "pand %%mm7, %%mm1 \n\t" + + "pcmpeqb %%mm6, %%mm0 \n\t" + "pcmpeqb %%mm6, %%mm1 \n\t" + +// preload "movl len, %%ecx \n\t" // load length of line +// preload "movl srcptr, %%esi \n\t" // load source +// preload "movl dstptr, %%edi \n\t" // load dest + + "cmpl $0, %%ecx \n\t" + "jz mainloop16end \n\t" + + "mainloop16: \n\t" + "movq (%%esi), %%mm4 \n\t" + "pand %%mm0, %%mm4 \n\t" + "movq %%mm0, %%mm6 \n\t" + "movq (%%edi), %%mm7 \n\t" + "pandn %%mm7, %%mm6 \n\t" + "por %%mm6, %%mm4 \n\t" + "movq %%mm4, (%%edi) \n\t" + + "movq 8(%%esi), %%mm5 \n\t" + "pand %%mm1, %%mm5 \n\t" + "movq %%mm1, %%mm7 \n\t" + "movq 8(%%edi), %%mm6 \n\t" + "pandn %%mm6, %%mm7 \n\t" + "por %%mm7, %%mm5 \n\t" + "movq %%mm5, 8(%%edi) \n\t" + + "addl $16, %%esi \n\t" // inc by 16 bytes processed + "addl $16, %%edi \n\t" + "subl $8, %%ecx \n\t" // dec by 8 pixels processed + "ja mainloop16 \n\t" + + "mainloop16end: \n\t" +// preload "movl diff, %%ecx \n\t" // (diff is in eax) + "movl %%eax, %%ecx \n\t" + "cmpl $0, %%ecx \n\t" + "jz end16 \n\t" +// preload "movl mask, %%edx \n\t" + "sall $24, %%edx \n\t" // make low byte, high byte + + "secondloop16: \n\t" + "sall %%edx \n\t" // move high bit to CF + "jnc skip16 \n\t" // if CF = 0 + "movw (%%esi), %%ax \n\t" + "movw %%ax, (%%edi) \n\t" + + "skip16: \n\t" + "addl $2, %%esi \n\t" + "addl $2, %%edi \n\t" + "decl %%ecx \n\t" + "jnz secondloop16 \n\t" + + "end16: \n\t" + "EMMS \n\t" // DONE + + : "=a" (dummy_value_a), // output regs (dummy) + "=c" (dummy_value_c), + "=d" (dummy_value_d), + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "0" (diff), // eax // input regs +// was (unmask) " " RESERVED // ebx // Global Offset Table idx + "1" (len), // ecx + "2" (mask), // edx + "3" (srcptr), // esi + "4" (dstptr) // edi + +#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0", "%mm1", "%mm4" // clobber list + , "%mm5", "%mm6", "%mm7" +#endif + ); + } + else /* mmx _not supported - Use modified C routine */ +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ + { + register png_uint_32 i; + png_uint_32 initial_val = BPP2 * png_pass_start[png_ptr->pass]; + /* png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */ + register int stride = BPP2 * png_pass_inc[png_ptr->pass]; + /* png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */ + register int rep_bytes = BPP2 * png_pass_width[png_ptr->pass]; + /* png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */ + png_uint_32 len = png_ptr->width &~7; /* reduce to mult. of 8 */ + int diff = (int) (png_ptr->width & 7); /* amount lost */ + register png_uint_32 final_val = BPP2 * len; /* GRR bugfix */ + + srcptr = png_ptr->row_buf + 1 + initial_val; + dstptr = row + initial_val; + + for (i = initial_val; i < final_val; i += stride) + { + png_memcpy(dstptr, srcptr, rep_bytes); + srcptr += stride; + dstptr += stride; + } + if (diff) /* number of leftover pixels: 3 for pngtest */ + { + final_val+=diff*BPP2; + for (; i < final_val; i += stride) + { + if (rep_bytes > (int)(final_val-i)) + rep_bytes = (int)(final_val-i); + png_memcpy(dstptr, srcptr, rep_bytes); + srcptr += stride; + dstptr += stride; + } + } + } /* end of else (_mmx_supported) */ + + break; + } /* end 16 bpp */ + + case 24: /* png_ptr->row_info.pixel_depth */ + { + png_bytep srcptr; + png_bytep dstptr; + +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK) +#if !defined(PNG_1_0_X) + if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW) + /* && _mmx_supported */ ) +#else + if (_mmx_supported) +#endif + { + png_uint_32 len; + int diff; + int dummy_value_a; // fix 'forbidden register spilled' error + int dummy_value_d; + int dummy_value_c; + int dummy_value_S; + int dummy_value_D; + _unmask = ~mask; // global variable for -fPIC version + srcptr = png_ptr->row_buf + 1; + dstptr = row; + len = png_ptr->width &~7; // reduce to multiple of 8 + diff = (int) (png_ptr->width & 7); // amount lost // + + __asm__ __volatile__ ( + "movd _unmask, %%mm7 \n\t" // load bit pattern + "psubb %%mm6, %%mm6 \n\t" // zero mm6 + "punpcklbw %%mm7, %%mm7 \n\t" + "punpcklwd %%mm7, %%mm7 \n\t" + "punpckldq %%mm7, %%mm7 \n\t" // fill reg with 8 masks + + "movq _mask24_0, %%mm0 \n\t" + "movq _mask24_1, %%mm1 \n\t" + "movq _mask24_2, %%mm2 \n\t" + + "pand %%mm7, %%mm0 \n\t" + "pand %%mm7, %%mm1 \n\t" + "pand %%mm7, %%mm2 \n\t" + + "pcmpeqb %%mm6, %%mm0 \n\t" + "pcmpeqb %%mm6, %%mm1 \n\t" + "pcmpeqb %%mm6, %%mm2 \n\t" + +// preload "movl len, %%ecx \n\t" // load length of line +// preload "movl srcptr, %%esi \n\t" // load source +// preload "movl dstptr, %%edi \n\t" // load dest + + "cmpl $0, %%ecx \n\t" + "jz mainloop24end \n\t" + + "mainloop24: \n\t" + "movq (%%esi), %%mm4 \n\t" + "pand %%mm0, %%mm4 \n\t" + "movq %%mm0, %%mm6 \n\t" + "movq (%%edi), %%mm7 \n\t" + "pandn %%mm7, %%mm6 \n\t" + "por %%mm6, %%mm4 \n\t" + "movq %%mm4, (%%edi) \n\t" + + "movq 8(%%esi), %%mm5 \n\t" + "pand %%mm1, %%mm5 \n\t" + "movq %%mm1, %%mm7 \n\t" + "movq 8(%%edi), %%mm6 \n\t" + "pandn %%mm6, %%mm7 \n\t" + "por %%mm7, %%mm5 \n\t" + "movq %%mm5, 8(%%edi) \n\t" + + "movq 16(%%esi), %%mm6 \n\t" + "pand %%mm2, %%mm6 \n\t" + "movq %%mm2, %%mm4 \n\t" + "movq 16(%%edi), %%mm7 \n\t" + "pandn %%mm7, %%mm4 \n\t" + "por %%mm4, %%mm6 \n\t" + "movq %%mm6, 16(%%edi) \n\t" + + "addl $24, %%esi \n\t" // inc by 24 bytes processed + "addl $24, %%edi \n\t" + "subl $8, %%ecx \n\t" // dec by 8 pixels processed + + "ja mainloop24 \n\t" + + "mainloop24end: \n\t" +// preload "movl diff, %%ecx \n\t" // (diff is in eax) + "movl %%eax, %%ecx \n\t" + "cmpl $0, %%ecx \n\t" + "jz end24 \n\t" +// preload "movl mask, %%edx \n\t" + "sall $24, %%edx \n\t" // make low byte, high byte + + "secondloop24: \n\t" + "sall %%edx \n\t" // move high bit to CF + "jnc skip24 \n\t" // if CF = 0 + "movw (%%esi), %%ax \n\t" + "movw %%ax, (%%edi) \n\t" + "xorl %%eax, %%eax \n\t" + "movb 2(%%esi), %%al \n\t" + "movb %%al, 2(%%edi) \n\t" + + "skip24: \n\t" + "addl $3, %%esi \n\t" + "addl $3, %%edi \n\t" + "decl %%ecx \n\t" + "jnz secondloop24 \n\t" + + "end24: \n\t" + "EMMS \n\t" // DONE + + : "=a" (dummy_value_a), // output regs (dummy) + "=d" (dummy_value_d), + "=c" (dummy_value_c), + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "3" (srcptr), // esi // input regs + "4" (dstptr), // edi + "0" (diff), // eax +// was (unmask) "b" RESERVED // ebx // Global Offset Table idx + "2" (len), // ecx + "1" (mask) // edx + +#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0", "%mm1", "%mm2" // clobber list + , "%mm4", "%mm5", "%mm6", "%mm7" +#endif + ); + } + else /* mmx _not supported - Use modified C routine */ +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ + { + register png_uint_32 i; + png_uint_32 initial_val = BPP3 * png_pass_start[png_ptr->pass]; + /* png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */ + register int stride = BPP3 * png_pass_inc[png_ptr->pass]; + /* png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */ + register int rep_bytes = BPP3 * png_pass_width[png_ptr->pass]; + /* png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */ + png_uint_32 len = png_ptr->width &~7; /* reduce to mult. of 8 */ + int diff = (int) (png_ptr->width & 7); /* amount lost */ + register png_uint_32 final_val = BPP3 * len; /* GRR bugfix */ + + srcptr = png_ptr->row_buf + 1 + initial_val; + dstptr = row + initial_val; + + for (i = initial_val; i < final_val; i += stride) + { + png_memcpy(dstptr, srcptr, rep_bytes); + srcptr += stride; + dstptr += stride; + } + if (diff) /* number of leftover pixels: 3 for pngtest */ + { + final_val+=diff*BPP3; + for (; i < final_val; i += stride) + { + if (rep_bytes > (int)(final_val-i)) + rep_bytes = (int)(final_val-i); + png_memcpy(dstptr, srcptr, rep_bytes); + srcptr += stride; + dstptr += stride; + } + } + } /* end of else (_mmx_supported) */ + + break; + } /* end 24 bpp */ + + case 32: /* png_ptr->row_info.pixel_depth */ + { + png_bytep srcptr; + png_bytep dstptr; + +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK) +#if !defined(PNG_1_0_X) + if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW) + /* && _mmx_supported */ ) +#else + if (_mmx_supported) +#endif + { + png_uint_32 len; + int diff; + int dummy_value_a; // fix 'forbidden register spilled' error + int dummy_value_d; + int dummy_value_c; + int dummy_value_S; + int dummy_value_D; + _unmask = ~mask; // global variable for -fPIC version + srcptr = png_ptr->row_buf + 1; + dstptr = row; + len = png_ptr->width &~7; // reduce to multiple of 8 + diff = (int) (png_ptr->width & 7); // amount lost // + + __asm__ __volatile__ ( + "movd _unmask, %%mm7 \n\t" // load bit pattern + "psubb %%mm6, %%mm6 \n\t" // zero mm6 + "punpcklbw %%mm7, %%mm7 \n\t" + "punpcklwd %%mm7, %%mm7 \n\t" + "punpckldq %%mm7, %%mm7 \n\t" // fill reg with 8 masks + + "movq _mask32_0, %%mm0 \n\t" + "movq _mask32_1, %%mm1 \n\t" + "movq _mask32_2, %%mm2 \n\t" + "movq _mask32_3, %%mm3 \n\t" + + "pand %%mm7, %%mm0 \n\t" + "pand %%mm7, %%mm1 \n\t" + "pand %%mm7, %%mm2 \n\t" + "pand %%mm7, %%mm3 \n\t" + + "pcmpeqb %%mm6, %%mm0 \n\t" + "pcmpeqb %%mm6, %%mm1 \n\t" + "pcmpeqb %%mm6, %%mm2 \n\t" + "pcmpeqb %%mm6, %%mm3 \n\t" + +// preload "movl len, %%ecx \n\t" // load length of line +// preload "movl srcptr, %%esi \n\t" // load source +// preload "movl dstptr, %%edi \n\t" // load dest + + "cmpl $0, %%ecx \n\t" // lcr + "jz mainloop32end \n\t" + + "mainloop32: \n\t" + "movq (%%esi), %%mm4 \n\t" + "pand %%mm0, %%mm4 \n\t" + "movq %%mm0, %%mm6 \n\t" + "movq (%%edi), %%mm7 \n\t" + "pandn %%mm7, %%mm6 \n\t" + "por %%mm6, %%mm4 \n\t" + "movq %%mm4, (%%edi) \n\t" + + "movq 8(%%esi), %%mm5 \n\t" + "pand %%mm1, %%mm5 \n\t" + "movq %%mm1, %%mm7 \n\t" + "movq 8(%%edi), %%mm6 \n\t" + "pandn %%mm6, %%mm7 \n\t" + "por %%mm7, %%mm5 \n\t" + "movq %%mm5, 8(%%edi) \n\t" + + "movq 16(%%esi), %%mm6 \n\t" + "pand %%mm2, %%mm6 \n\t" + "movq %%mm2, %%mm4 \n\t" + "movq 16(%%edi), %%mm7 \n\t" + "pandn %%mm7, %%mm4 \n\t" + "por %%mm4, %%mm6 \n\t" + "movq %%mm6, 16(%%edi) \n\t" + + "movq 24(%%esi), %%mm7 \n\t" + "pand %%mm3, %%mm7 \n\t" + "movq %%mm3, %%mm5 \n\t" + "movq 24(%%edi), %%mm4 \n\t" + "pandn %%mm4, %%mm5 \n\t" + "por %%mm5, %%mm7 \n\t" + "movq %%mm7, 24(%%edi) \n\t" + + "addl $32, %%esi \n\t" // inc by 32 bytes processed + "addl $32, %%edi \n\t" + "subl $8, %%ecx \n\t" // dec by 8 pixels processed + "ja mainloop32 \n\t" + + "mainloop32end: \n\t" +// preload "movl diff, %%ecx \n\t" // (diff is in eax) + "movl %%eax, %%ecx \n\t" + "cmpl $0, %%ecx \n\t" + "jz end32 \n\t" +// preload "movl mask, %%edx \n\t" + "sall $24, %%edx \n\t" // low byte => high byte + + "secondloop32: \n\t" + "sall %%edx \n\t" // move high bit to CF + "jnc skip32 \n\t" // if CF = 0 + "movl (%%esi), %%eax \n\t" + "movl %%eax, (%%edi) \n\t" + + "skip32: \n\t" + "addl $4, %%esi \n\t" + "addl $4, %%edi \n\t" + "decl %%ecx \n\t" + "jnz secondloop32 \n\t" + + "end32: \n\t" + "EMMS \n\t" // DONE + + : "=a" (dummy_value_a), // output regs (dummy) + "=d" (dummy_value_d), + "=c" (dummy_value_c), + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "3" (srcptr), // esi // input regs + "4" (dstptr), // edi + "0" (diff), // eax +// was (unmask) "b" RESERVED // ebx // Global Offset Table idx + "2" (len), // ecx + "1" (mask) // edx + +#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0", "%mm1", "%mm2", "%mm3" // clobber list + , "%mm4", "%mm5", "%mm6", "%mm7" +#endif + ); + } + else /* mmx _not supported - Use modified C routine */ +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ + { + register png_uint_32 i; + png_uint_32 initial_val = BPP4 * png_pass_start[png_ptr->pass]; + /* png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */ + register int stride = BPP4 * png_pass_inc[png_ptr->pass]; + /* png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */ + register int rep_bytes = BPP4 * png_pass_width[png_ptr->pass]; + /* png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */ + png_uint_32 len = png_ptr->width &~7; /* reduce to mult. of 8 */ + int diff = (int) (png_ptr->width & 7); /* amount lost */ + register png_uint_32 final_val = BPP4 * len; /* GRR bugfix */ + + srcptr = png_ptr->row_buf + 1 + initial_val; + dstptr = row + initial_val; + + for (i = initial_val; i < final_val; i += stride) + { + png_memcpy(dstptr, srcptr, rep_bytes); + srcptr += stride; + dstptr += stride; + } + if (diff) /* number of leftover pixels: 3 for pngtest */ + { + final_val+=diff*BPP4; + for (; i < final_val; i += stride) + { + if (rep_bytes > (int)(final_val-i)) + rep_bytes = (int)(final_val-i); + png_memcpy(dstptr, srcptr, rep_bytes); + srcptr += stride; + dstptr += stride; + } + } + } /* end of else (_mmx_supported) */ + + break; + } /* end 32 bpp */ + + case 48: /* png_ptr->row_info.pixel_depth */ + { + png_bytep srcptr; + png_bytep dstptr; + +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK) +#if !defined(PNG_1_0_X) + if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW) + /* && _mmx_supported */ ) +#else + if (_mmx_supported) +#endif + { + png_uint_32 len; + int diff; + int dummy_value_a; // fix 'forbidden register spilled' error + int dummy_value_d; + int dummy_value_c; + int dummy_value_S; + int dummy_value_D; + _unmask = ~mask; // global variable for -fPIC version + srcptr = png_ptr->row_buf + 1; + dstptr = row; + len = png_ptr->width &~7; // reduce to multiple of 8 + diff = (int) (png_ptr->width & 7); // amount lost // + + __asm__ __volatile__ ( + "movd _unmask, %%mm7 \n\t" // load bit pattern + "psubb %%mm6, %%mm6 \n\t" // zero mm6 + "punpcklbw %%mm7, %%mm7 \n\t" + "punpcklwd %%mm7, %%mm7 \n\t" + "punpckldq %%mm7, %%mm7 \n\t" // fill reg with 8 masks + + "movq _mask48_0, %%mm0 \n\t" + "movq _mask48_1, %%mm1 \n\t" + "movq _mask48_2, %%mm2 \n\t" + "movq _mask48_3, %%mm3 \n\t" + "movq _mask48_4, %%mm4 \n\t" + "movq _mask48_5, %%mm5 \n\t" + + "pand %%mm7, %%mm0 \n\t" + "pand %%mm7, %%mm1 \n\t" + "pand %%mm7, %%mm2 \n\t" + "pand %%mm7, %%mm3 \n\t" + "pand %%mm7, %%mm4 \n\t" + "pand %%mm7, %%mm5 \n\t" + + "pcmpeqb %%mm6, %%mm0 \n\t" + "pcmpeqb %%mm6, %%mm1 \n\t" + "pcmpeqb %%mm6, %%mm2 \n\t" + "pcmpeqb %%mm6, %%mm3 \n\t" + "pcmpeqb %%mm6, %%mm4 \n\t" + "pcmpeqb %%mm6, %%mm5 \n\t" + +// preload "movl len, %%ecx \n\t" // load length of line +// preload "movl srcptr, %%esi \n\t" // load source +// preload "movl dstptr, %%edi \n\t" // load dest + + "cmpl $0, %%ecx \n\t" + "jz mainloop48end \n\t" + + "mainloop48: \n\t" + "movq (%%esi), %%mm7 \n\t" + "pand %%mm0, %%mm7 \n\t" + "movq %%mm0, %%mm6 \n\t" + "pandn (%%edi), %%mm6 \n\t" + "por %%mm6, %%mm7 \n\t" + "movq %%mm7, (%%edi) \n\t" + + "movq 8(%%esi), %%mm6 \n\t" + "pand %%mm1, %%mm6 \n\t" + "movq %%mm1, %%mm7 \n\t" + "pandn 8(%%edi), %%mm7 \n\t" + "por %%mm7, %%mm6 \n\t" + "movq %%mm6, 8(%%edi) \n\t" + + "movq 16(%%esi), %%mm6 \n\t" + "pand %%mm2, %%mm6 \n\t" + "movq %%mm2, %%mm7 \n\t" + "pandn 16(%%edi), %%mm7 \n\t" + "por %%mm7, %%mm6 \n\t" + "movq %%mm6, 16(%%edi) \n\t" + + "movq 24(%%esi), %%mm7 \n\t" + "pand %%mm3, %%mm7 \n\t" + "movq %%mm3, %%mm6 \n\t" + "pandn 24(%%edi), %%mm6 \n\t" + "por %%mm6, %%mm7 \n\t" + "movq %%mm7, 24(%%edi) \n\t" + + "movq 32(%%esi), %%mm6 \n\t" + "pand %%mm4, %%mm6 \n\t" + "movq %%mm4, %%mm7 \n\t" + "pandn 32(%%edi), %%mm7 \n\t" + "por %%mm7, %%mm6 \n\t" + "movq %%mm6, 32(%%edi) \n\t" + + "movq 40(%%esi), %%mm7 \n\t" + "pand %%mm5, %%mm7 \n\t" + "movq %%mm5, %%mm6 \n\t" + "pandn 40(%%edi), %%mm6 \n\t" + "por %%mm6, %%mm7 \n\t" + "movq %%mm7, 40(%%edi) \n\t" + + "addl $48, %%esi \n\t" // inc by 48 bytes processed + "addl $48, %%edi \n\t" + "subl $8, %%ecx \n\t" // dec by 8 pixels processed + + "ja mainloop48 \n\t" + + "mainloop48end: \n\t" +// preload "movl diff, %%ecx \n\t" // (diff is in eax) + "movl %%eax, %%ecx \n\t" + "cmpl $0, %%ecx \n\t" + "jz end48 \n\t" +// preload "movl mask, %%edx \n\t" + "sall $24, %%edx \n\t" // make low byte, high byte + + "secondloop48: \n\t" + "sall %%edx \n\t" // move high bit to CF + "jnc skip48 \n\t" // if CF = 0 + "movl (%%esi), %%eax \n\t" + "movl %%eax, (%%edi) \n\t" + + "skip48: \n\t" + "addl $4, %%esi \n\t" + "addl $4, %%edi \n\t" + "decl %%ecx \n\t" + "jnz secondloop48 \n\t" + + "end48: \n\t" + "EMMS \n\t" // DONE + + : "=a" (dummy_value_a), // output regs (dummy) + "=d" (dummy_value_d), + "=c" (dummy_value_c), + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "3" (srcptr), // esi // input regs + "4" (dstptr), // edi + "0" (diff), // eax +// was (unmask) "b" RESERVED // ebx // Global Offset Table idx + "2" (len), // ecx + "1" (mask) // edx + +#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0", "%mm1", "%mm2", "%mm3" // clobber list + , "%mm4", "%mm5", "%mm6", "%mm7" +#endif + ); + } + else /* mmx _not supported - Use modified C routine */ +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ + { + register png_uint_32 i; + png_uint_32 initial_val = BPP6 * png_pass_start[png_ptr->pass]; + /* png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */ + register int stride = BPP6 * png_pass_inc[png_ptr->pass]; + /* png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */ + register int rep_bytes = BPP6 * png_pass_width[png_ptr->pass]; + /* png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */ + png_uint_32 len = png_ptr->width &~7; /* reduce to mult. of 8 */ + int diff = (int) (png_ptr->width & 7); /* amount lost */ + register png_uint_32 final_val = BPP6 * len; /* GRR bugfix */ + + srcptr = png_ptr->row_buf + 1 + initial_val; + dstptr = row + initial_val; + + for (i = initial_val; i < final_val; i += stride) + { + png_memcpy(dstptr, srcptr, rep_bytes); + srcptr += stride; + dstptr += stride; + } + if (diff) /* number of leftover pixels: 3 for pngtest */ + { + final_val+=diff*BPP6; + for (; i < final_val; i += stride) + { + if (rep_bytes > (int)(final_val-i)) + rep_bytes = (int)(final_val-i); + png_memcpy(dstptr, srcptr, rep_bytes); + srcptr += stride; + dstptr += stride; + } + } + } /* end of else (_mmx_supported) */ + + break; + } /* end 48 bpp */ + + case 64: /* png_ptr->row_info.pixel_depth */ + { + png_bytep srcptr; + png_bytep dstptr; + register png_uint_32 i; + png_uint_32 initial_val = BPP8 * png_pass_start[png_ptr->pass]; + /* png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */ + register int stride = BPP8 * png_pass_inc[png_ptr->pass]; + /* png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */ + register int rep_bytes = BPP8 * png_pass_width[png_ptr->pass]; + /* png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */ + png_uint_32 len = png_ptr->width &~7; /* reduce to mult. of 8 */ + int diff = (int) (png_ptr->width & 7); /* amount lost */ + register png_uint_32 final_val = BPP8 * len; /* GRR bugfix */ + + srcptr = png_ptr->row_buf + 1 + initial_val; + dstptr = row + initial_val; + + for (i = initial_val; i < final_val; i += stride) + { + png_memcpy(dstptr, srcptr, rep_bytes); + srcptr += stride; + dstptr += stride; + } + if (diff) /* number of leftover pixels: 3 for pngtest */ + { + final_val+=diff*BPP8; + for (; i < final_val; i += stride) + { + if (rep_bytes > (int)(final_val-i)) + rep_bytes = (int)(final_val-i); + png_memcpy(dstptr, srcptr, rep_bytes); + srcptr += stride; + dstptr += stride; + } + } + + break; + } /* end 64 bpp */ + + default: /* png_ptr->row_info.pixel_depth != 1,2,4,8,16,24,32,48,64 */ + { + /* this should never happen */ + png_warning(png_ptr, "Invalid row_info.pixel_depth in pnggccrd"); + break; + } + } /* end switch (png_ptr->row_info.pixel_depth) */ + + } /* end if (non-trivial mask) */ + +} /* end png_combine_row() */ + +#endif /* PNG_HAVE_ASSEMBLER_COMBINE_ROW */ + + + + +/*===========================================================================*/ +/* */ +/* P N G _ D O _ R E A D _ I N T E R L A C E */ +/* */ +/*===========================================================================*/ + +#if defined(PNG_READ_INTERLACING_SUPPORTED) +#if defined(PNG_HAVE_ASSEMBLER_READ_INTERLACE) + +/* png_do_read_interlace() is called after any 16-bit to 8-bit conversion + * has taken place. [GRR: what other steps come before and/or after?] + */ + +void /* PRIVATE */ +png_do_read_interlace(png_structp png_ptr) +{ + png_row_infop row_info = &(png_ptr->row_info); + png_bytep row = png_ptr->row_buf + 1; + int pass = png_ptr->pass; +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + png_uint_32 transformations = png_ptr->transformations; +#endif + + png_debug(1, "in png_do_read_interlace (pnggccrd.c)\n"); + +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) + if (_mmx_supported == 2) { +#if !defined(PNG_1_0_X) + /* this should have happened in png_init_mmx_flags() already */ + png_warning(png_ptr, "asm_flags may not have been initialized"); +#endif + png_mmx_support(); + } +#endif + + if (row != NULL && row_info != NULL) + { + png_uint_32 final_width; + + final_width = row_info->width * png_pass_inc[pass]; + + switch (row_info->pixel_depth) + { + case 1: + { + png_bytep sp, dp; + int sshift, dshift; + int s_start, s_end, s_inc; + png_byte v; + png_uint_32 i; + int j; + + sp = row + (png_size_t)((row_info->width - 1) >> 3); + dp = row + (png_size_t)((final_width - 1) >> 3); +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (transformations & PNG_PACKSWAP) + { + sshift = (int)((row_info->width + 7) & 7); + dshift = (int)((final_width + 7) & 7); + s_start = 7; + s_end = 0; + s_inc = -1; + } + else +#endif + { + sshift = 7 - (int)((row_info->width + 7) & 7); + dshift = 7 - (int)((final_width + 7) & 7); + s_start = 0; + s_end = 7; + s_inc = 1; + } + + for (i = row_info->width; i; i--) + { + v = (png_byte)((*sp >> sshift) & 0x1); + for (j = 0; j < png_pass_inc[pass]; j++) + { + *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff); + *dp |= (png_byte)(v << dshift); + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + else + dshift += s_inc; + } + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + else + sshift += s_inc; + } + break; + } + + case 2: + { + png_bytep sp, dp; + int sshift, dshift; + int s_start, s_end, s_inc; + png_uint_32 i; + + sp = row + (png_size_t)((row_info->width - 1) >> 2); + dp = row + (png_size_t)((final_width - 1) >> 2); +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (transformations & PNG_PACKSWAP) + { + sshift = (png_size_t)(((row_info->width + 3) & 3) << 1); + dshift = (png_size_t)(((final_width + 3) & 3) << 1); + s_start = 6; + s_end = 0; + s_inc = -2; + } + else +#endif + { + sshift = (png_size_t)((3 - ((row_info->width + 3) & 3)) << 1); + dshift = (png_size_t)((3 - ((final_width + 3) & 3)) << 1); + s_start = 0; + s_end = 6; + s_inc = 2; + } + + for (i = row_info->width; i; i--) + { + png_byte v; + int j; + + v = (png_byte)((*sp >> sshift) & 0x3); + for (j = 0; j < png_pass_inc[pass]; j++) + { + *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff); + *dp |= (png_byte)(v << dshift); + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + else + dshift += s_inc; + } + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + else + sshift += s_inc; + } + break; + } + + case 4: + { + png_bytep sp, dp; + int sshift, dshift; + int s_start, s_end, s_inc; + png_uint_32 i; + + sp = row + (png_size_t)((row_info->width - 1) >> 1); + dp = row + (png_size_t)((final_width - 1) >> 1); +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (transformations & PNG_PACKSWAP) + { + sshift = (png_size_t)(((row_info->width + 1) & 1) << 2); + dshift = (png_size_t)(((final_width + 1) & 1) << 2); + s_start = 4; + s_end = 0; + s_inc = -4; + } + else +#endif + { + sshift = (png_size_t)((1 - ((row_info->width + 1) & 1)) << 2); + dshift = (png_size_t)((1 - ((final_width + 1) & 1)) << 2); + s_start = 0; + s_end = 4; + s_inc = 4; + } + + for (i = row_info->width; i; i--) + { + png_byte v; + int j; + + v = (png_byte)((*sp >> sshift) & 0xf); + for (j = 0; j < png_pass_inc[pass]; j++) + { + *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff); + *dp |= (png_byte)(v << dshift); + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + else + dshift += s_inc; + } + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + else + sshift += s_inc; + } + break; + } + + /*====================================================================*/ + + default: /* 8-bit or larger (this is where the routine is modified) */ + { +#if 0 +// static unsigned long long _const4 = 0x0000000000FFFFFFLL; no good +// static unsigned long long const4 = 0x0000000000FFFFFFLL; no good +// unsigned long long _const4 = 0x0000000000FFFFFFLL; no good +// unsigned long long const4 = 0x0000000000FFFFFFLL; no good +#endif + png_bytep sptr, dp; + png_uint_32 i; + png_size_t pixel_bytes; + int width = (int)row_info->width; + + pixel_bytes = (row_info->pixel_depth >> 3); + + /* point sptr at the last pixel in the pre-expanded row: */ + sptr = row + (width - 1) * pixel_bytes; + + /* point dp at the last pixel position in the expanded row: */ + dp = row + (final_width - 1) * pixel_bytes; + + /* New code by Nirav Chhatrapati - Intel Corporation */ + +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) +#if !defined(PNG_1_0_X) + if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_INTERLACE) + /* && _mmx_supported */ ) +#else + if (_mmx_supported) +#endif + { + //-------------------------------------------------------------- + if (pixel_bytes == 3) + { + if (((pass == 0) || (pass == 1)) && width) + { + int dummy_value_c; // fix 'forbidden register spilled' + int dummy_value_S; + int dummy_value_D; + + __asm__ __volatile__ ( + "subl $21, %%edi \n\t" + // (png_pass_inc[pass] - 1)*pixel_bytes + + ".loop3_pass0: \n\t" + "movd (%%esi), %%mm0 \n\t" // x x x x x 2 1 0 + "pand _const4, %%mm0 \n\t" // z z z z z 2 1 0 + "movq %%mm0, %%mm1 \n\t" // z z z z z 2 1 0 + "psllq $16, %%mm0 \n\t" // z z z 2 1 0 z z + "movq %%mm0, %%mm2 \n\t" // z z z 2 1 0 z z + "psllq $24, %%mm0 \n\t" // 2 1 0 z z z z z + "psrlq $8, %%mm1 \n\t" // z z z z z z 2 1 + "por %%mm2, %%mm0 \n\t" // 2 1 0 2 1 0 z z + "por %%mm1, %%mm0 \n\t" // 2 1 0 2 1 0 2 1 + "movq %%mm0, %%mm3 \n\t" // 2 1 0 2 1 0 2 1 + "psllq $16, %%mm0 \n\t" // 0 2 1 0 2 1 z z + "movq %%mm3, %%mm4 \n\t" // 2 1 0 2 1 0 2 1 + "punpckhdq %%mm0, %%mm3 \n\t" // 0 2 1 0 2 1 0 2 + "movq %%mm4, 16(%%edi) \n\t" + "psrlq $32, %%mm0 \n\t" // z z z z 0 2 1 0 + "movq %%mm3, 8(%%edi) \n\t" + "punpckldq %%mm4, %%mm0 \n\t" // 1 0 2 1 0 2 1 0 + "subl $3, %%esi \n\t" + "movq %%mm0, (%%edi) \n\t" + "subl $24, %%edi \n\t" + "decl %%ecx \n\t" + "jnz .loop3_pass0 \n\t" + "EMMS \n\t" // DONE + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "1" (sptr), // esi // input regs + "2" (dp), // edi + "0" (width), // ecx + "rim" (_const4) // %1(?) (0x0000000000FFFFFFLL) + +#if 0 /* %mm0, ..., %mm4 not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0", "%mm1", "%mm2" // clobber list + , "%mm3", "%mm4" +#endif + ); + } + else if (((pass == 2) || (pass == 3)) && width) + { + int dummy_value_c; // fix 'forbidden register spilled' + int dummy_value_S; + int dummy_value_D; + + __asm__ __volatile__ ( + "subl $9, %%edi \n\t" + // (png_pass_inc[pass] - 1)*pixel_bytes + + ".loop3_pass2: \n\t" + "movd (%%esi), %%mm0 \n\t" // x x x x x 2 1 0 + "pand _const4, %%mm0 \n\t" // z z z z z 2 1 0 + "movq %%mm0, %%mm1 \n\t" // z z z z z 2 1 0 + "psllq $16, %%mm0 \n\t" // z z z 2 1 0 z z + "movq %%mm0, %%mm2 \n\t" // z z z 2 1 0 z z + "psllq $24, %%mm0 \n\t" // 2 1 0 z z z z z + "psrlq $8, %%mm1 \n\t" // z z z z z z 2 1 + "por %%mm2, %%mm0 \n\t" // 2 1 0 2 1 0 z z + "por %%mm1, %%mm0 \n\t" // 2 1 0 2 1 0 2 1 + "movq %%mm0, 4(%%edi) \n\t" + "psrlq $16, %%mm0 \n\t" // z z 2 1 0 2 1 0 + "subl $3, %%esi \n\t" + "movd %%mm0, (%%edi) \n\t" + "subl $12, %%edi \n\t" + "decl %%ecx \n\t" + "jnz .loop3_pass2 \n\t" + "EMMS \n\t" // DONE + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "1" (sptr), // esi // input regs + "2" (dp), // edi + "0" (width), // ecx + "rim" (_const4) // (0x0000000000FFFFFFLL) + +#if 0 /* %mm0, ..., %mm2 not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0", "%mm1", "%mm2" // clobber list +#endif + ); + } + else if (width) /* && ((pass == 4) || (pass == 5)) */ + { + int width_mmx = ((width >> 1) << 1) - 8; // GRR: huh? + if (width_mmx < 0) + width_mmx = 0; + width -= width_mmx; // 8 or 9 pix, 24 or 27 bytes + if (width_mmx) + { + // png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; + // sptr points at last pixel in pre-expanded row + // dp points at last pixel position in expanded row + int dummy_value_c; // fix 'forbidden register spilled' + int dummy_value_S; + int dummy_value_D; + + __asm__ __volatile__ ( + "subl $3, %%esi \n\t" + "subl $9, %%edi \n\t" + // (png_pass_inc[pass] + 1)*pixel_bytes + + ".loop3_pass4: \n\t" + "movq (%%esi), %%mm0 \n\t" // x x 5 4 3 2 1 0 + "movq %%mm0, %%mm1 \n\t" // x x 5 4 3 2 1 0 + "movq %%mm0, %%mm2 \n\t" // x x 5 4 3 2 1 0 + "psllq $24, %%mm0 \n\t" // 4 3 2 1 0 z z z + "pand _const4, %%mm1 \n\t" // z z z z z 2 1 0 + "psrlq $24, %%mm2 \n\t" // z z z x x 5 4 3 + "por %%mm1, %%mm0 \n\t" // 4 3 2 1 0 2 1 0 + "movq %%mm2, %%mm3 \n\t" // z z z x x 5 4 3 + "psllq $8, %%mm2 \n\t" // z z x x 5 4 3 z + "movq %%mm0, (%%edi) \n\t" + "psrlq $16, %%mm3 \n\t" // z z z z z x x 5 + "pand _const6, %%mm3 \n\t" // z z z z z z z 5 + "por %%mm3, %%mm2 \n\t" // z z x x 5 4 3 5 + "subl $6, %%esi \n\t" + "movd %%mm2, 8(%%edi) \n\t" + "subl $12, %%edi \n\t" + "subl $2, %%ecx \n\t" + "jnz .loop3_pass4 \n\t" + "EMMS \n\t" // DONE + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "1" (sptr), // esi // input regs + "2" (dp), // edi + "0" (width_mmx), // ecx + "rim" (_const4), // 0x0000000000FFFFFFLL + "rim" (_const6) // 0x00000000000000FFLL + +#if 0 /* %mm0, ..., %mm3 not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0", "%mm1" // clobber list + , "%mm2", "%mm3" +#endif + ); + } + + sptr -= width_mmx*3; + dp -= width_mmx*6; + for (i = width; i; i--) + { + png_byte v[8]; + int j; + + png_memcpy(v, sptr, 3); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, 3); + dp -= 3; + } + sptr -= 3; + } + } + } /* end of pixel_bytes == 3 */ + + //-------------------------------------------------------------- + else if (pixel_bytes == 1) + { + if (((pass == 0) || (pass == 1)) && width) + { + int width_mmx = ((width >> 2) << 2); + width -= width_mmx; // 0-3 pixels => 0-3 bytes + if (width_mmx) + { + int dummy_value_c; // fix 'forbidden register spilled' + int dummy_value_S; + int dummy_value_D; + + __asm__ __volatile__ ( + "subl $3, %%esi \n\t" + "subl $31, %%edi \n\t" + + ".loop1_pass0: \n\t" + "movd (%%esi), %%mm0 \n\t" // x x x x 3 2 1 0 + "movq %%mm0, %%mm1 \n\t" // x x x x 3 2 1 0 + "punpcklbw %%mm0, %%mm0 \n\t" // 3 3 2 2 1 1 0 0 + "movq %%mm0, %%mm2 \n\t" // 3 3 2 2 1 1 0 0 + "punpcklwd %%mm0, %%mm0 \n\t" // 1 1 1 1 0 0 0 0 + "movq %%mm0, %%mm3 \n\t" // 1 1 1 1 0 0 0 0 + "punpckldq %%mm0, %%mm0 \n\t" // 0 0 0 0 0 0 0 0 + "punpckhdq %%mm3, %%mm3 \n\t" // 1 1 1 1 1 1 1 1 + "movq %%mm0, (%%edi) \n\t" + "punpckhwd %%mm2, %%mm2 \n\t" // 3 3 3 3 2 2 2 2 + "movq %%mm3, 8(%%edi) \n\t" + "movq %%mm2, %%mm4 \n\t" // 3 3 3 3 2 2 2 2 + "punpckldq %%mm2, %%mm2 \n\t" // 2 2 2 2 2 2 2 2 + "punpckhdq %%mm4, %%mm4 \n\t" // 3 3 3 3 3 3 3 3 + "movq %%mm2, 16(%%edi) \n\t" + "subl $4, %%esi \n\t" + "movq %%mm4, 24(%%edi) \n\t" + "subl $32, %%edi \n\t" + "subl $4, %%ecx \n\t" + "jnz .loop1_pass0 \n\t" + "EMMS \n\t" // DONE + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "1" (sptr), // esi // input regs + "2" (dp), // edi + "0" (width_mmx) // ecx + +#if 0 /* %mm0, ..., %mm4 not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0", "%mm1", "%mm2" // clobber list + , "%mm3", "%mm4" +#endif + ); + } + + sptr -= width_mmx; + dp -= width_mmx*8; + for (i = width; i; i--) + { + int j; + + /* I simplified this part in version 1.0.4e + * here and in several other instances where + * pixel_bytes == 1 -- GR-P + * + * Original code: + * + * png_byte v[8]; + * png_memcpy(v, sptr, pixel_bytes); + * for (j = 0; j < png_pass_inc[pass]; j++) + * { + * png_memcpy(dp, v, pixel_bytes); + * dp -= pixel_bytes; + * } + * sptr -= pixel_bytes; + * + * Replacement code is in the next three lines: + */ + + for (j = 0; j < png_pass_inc[pass]; j++) + { + *dp-- = *sptr; + } + --sptr; + } + } + else if (((pass == 2) || (pass == 3)) && width) + { + int width_mmx = ((width >> 2) << 2); + width -= width_mmx; // 0-3 pixels => 0-3 bytes + if (width_mmx) + { + int dummy_value_c; // fix 'forbidden register spilled' + int dummy_value_S; + int dummy_value_D; + + __asm__ __volatile__ ( + "subl $3, %%esi \n\t" + "subl $15, %%edi \n\t" + + ".loop1_pass2: \n\t" + "movd (%%esi), %%mm0 \n\t" // x x x x 3 2 1 0 + "punpcklbw %%mm0, %%mm0 \n\t" // 3 3 2 2 1 1 0 0 + "movq %%mm0, %%mm1 \n\t" // 3 3 2 2 1 1 0 0 + "punpcklwd %%mm0, %%mm0 \n\t" // 1 1 1 1 0 0 0 0 + "punpckhwd %%mm1, %%mm1 \n\t" // 3 3 3 3 2 2 2 2 + "movq %%mm0, (%%edi) \n\t" + "subl $4, %%esi \n\t" + "movq %%mm1, 8(%%edi) \n\t" + "subl $16, %%edi \n\t" + "subl $4, %%ecx \n\t" + "jnz .loop1_pass2 \n\t" + "EMMS \n\t" // DONE + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "1" (sptr), // esi // input regs + "2" (dp), // edi + "0" (width_mmx) // ecx + +#if 0 /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0", "%mm1" // clobber list +#endif + ); + } + + sptr -= width_mmx; + dp -= width_mmx*4; + for (i = width; i; i--) + { + int j; + + for (j = 0; j < png_pass_inc[pass]; j++) + { + *dp-- = *sptr; + } + --sptr; + } + } + else if (width) /* && ((pass == 4) || (pass == 5)) */ + { + int width_mmx = ((width >> 3) << 3); + width -= width_mmx; // 0-3 pixels => 0-3 bytes + if (width_mmx) + { + int dummy_value_c; // fix 'forbidden register spilled' + int dummy_value_S; + int dummy_value_D; + + __asm__ __volatile__ ( + "subl $7, %%esi \n\t" + "subl $15, %%edi \n\t" + + ".loop1_pass4: \n\t" + "movq (%%esi), %%mm0 \n\t" // 7 6 5 4 3 2 1 0 + "movq %%mm0, %%mm1 \n\t" // 7 6 5 4 3 2 1 0 + "punpcklbw %%mm0, %%mm0 \n\t" // 3 3 2 2 1 1 0 0 + "punpckhbw %%mm1, %%mm1 \n\t" // 7 7 6 6 5 5 4 4 + "movq %%mm1, 8(%%edi) \n\t" + "subl $8, %%esi \n\t" + "movq %%mm0, (%%edi) \n\t" + "subl $16, %%edi \n\t" + "subl $8, %%ecx \n\t" + "jnz .loop1_pass4 \n\t" + "EMMS \n\t" // DONE + + : "=c" (dummy_value_c), // output regs (none) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "1" (sptr), // esi // input regs + "2" (dp), // edi + "0" (width_mmx) // ecx + +#if 0 /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0", "%mm1" // clobber list +#endif + ); + } + + sptr -= width_mmx; + dp -= width_mmx*2; + for (i = width; i; i--) + { + int j; + + for (j = 0; j < png_pass_inc[pass]; j++) + { + *dp-- = *sptr; + } + --sptr; + } + } + } /* end of pixel_bytes == 1 */ + + //-------------------------------------------------------------- + else if (pixel_bytes == 2) + { + if (((pass == 0) || (pass == 1)) && width) + { + int width_mmx = ((width >> 1) << 1); + width -= width_mmx; // 0,1 pixels => 0,2 bytes + if (width_mmx) + { + int dummy_value_c; // fix 'forbidden register spilled' + int dummy_value_S; + int dummy_value_D; + + __asm__ __volatile__ ( + "subl $2, %%esi \n\t" + "subl $30, %%edi \n\t" + + ".loop2_pass0: \n\t" + "movd (%%esi), %%mm0 \n\t" // x x x x 3 2 1 0 + "punpcklwd %%mm0, %%mm0 \n\t" // 3 2 3 2 1 0 1 0 + "movq %%mm0, %%mm1 \n\t" // 3 2 3 2 1 0 1 0 + "punpckldq %%mm0, %%mm0 \n\t" // 1 0 1 0 1 0 1 0 + "punpckhdq %%mm1, %%mm1 \n\t" // 3 2 3 2 3 2 3 2 + "movq %%mm0, (%%edi) \n\t" + "movq %%mm0, 8(%%edi) \n\t" + "movq %%mm1, 16(%%edi) \n\t" + "subl $4, %%esi \n\t" + "movq %%mm1, 24(%%edi) \n\t" + "subl $32, %%edi \n\t" + "subl $2, %%ecx \n\t" + "jnz .loop2_pass0 \n\t" + "EMMS \n\t" // DONE + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "1" (sptr), // esi // input regs + "2" (dp), // edi + "0" (width_mmx) // ecx + +#if 0 /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0", "%mm1" // clobber list +#endif + ); + } + + sptr -= (width_mmx*2 - 2); // sign fixed + dp -= (width_mmx*16 - 2); // sign fixed + for (i = width; i; i--) + { + png_byte v[8]; + int j; + sptr -= 2; + png_memcpy(v, sptr, 2); + for (j = 0; j < png_pass_inc[pass]; j++) + { + dp -= 2; + png_memcpy(dp, v, 2); + } + } + } + else if (((pass == 2) || (pass == 3)) && width) + { + int width_mmx = ((width >> 1) << 1) ; + width -= width_mmx; // 0,1 pixels => 0,2 bytes + if (width_mmx) + { + int dummy_value_c; // fix 'forbidden register spilled' + int dummy_value_S; + int dummy_value_D; + + __asm__ __volatile__ ( + "subl $2, %%esi \n\t" + "subl $14, %%edi \n\t" + + ".loop2_pass2: \n\t" + "movd (%%esi), %%mm0 \n\t" // x x x x 3 2 1 0 + "punpcklwd %%mm0, %%mm0 \n\t" // 3 2 3 2 1 0 1 0 + "movq %%mm0, %%mm1 \n\t" // 3 2 3 2 1 0 1 0 + "punpckldq %%mm0, %%mm0 \n\t" // 1 0 1 0 1 0 1 0 + "punpckhdq %%mm1, %%mm1 \n\t" // 3 2 3 2 3 2 3 2 + "movq %%mm0, (%%edi) \n\t" + "subl $4, %%esi \n\t" + "movq %%mm1, 8(%%edi) \n\t" + "subl $16, %%edi \n\t" + "subl $2, %%ecx \n\t" + "jnz .loop2_pass2 \n\t" + "EMMS \n\t" // DONE + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "1" (sptr), // esi // input regs + "2" (dp), // edi + "0" (width_mmx) // ecx + +#if 0 /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0", "%mm1" // clobber list +#endif + ); + } + + sptr -= (width_mmx*2 - 2); // sign fixed + dp -= (width_mmx*8 - 2); // sign fixed + for (i = width; i; i--) + { + png_byte v[8]; + int j; + sptr -= 2; + png_memcpy(v, sptr, 2); + for (j = 0; j < png_pass_inc[pass]; j++) + { + dp -= 2; + png_memcpy(dp, v, 2); + } + } + } + else if (width) // pass == 4 or 5 + { + int width_mmx = ((width >> 1) << 1) ; + width -= width_mmx; // 0,1 pixels => 0,2 bytes + if (width_mmx) + { + int dummy_value_c; // fix 'forbidden register spilled' + int dummy_value_S; + int dummy_value_D; + + __asm__ __volatile__ ( + "subl $2, %%esi \n\t" + "subl $6, %%edi \n\t" + + ".loop2_pass4: \n\t" + "movd (%%esi), %%mm0 \n\t" // x x x x 3 2 1 0 + "punpcklwd %%mm0, %%mm0 \n\t" // 3 2 3 2 1 0 1 0 + "subl $4, %%esi \n\t" + "movq %%mm0, (%%edi) \n\t" + "subl $8, %%edi \n\t" + "subl $2, %%ecx \n\t" + "jnz .loop2_pass4 \n\t" + "EMMS \n\t" // DONE + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "1" (sptr), // esi // input regs + "2" (dp), // edi + "0" (width_mmx) // ecx + +#if 0 /* %mm0 not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0" // clobber list +#endif + ); + } + + sptr -= (width_mmx*2 - 2); // sign fixed + dp -= (width_mmx*4 - 2); // sign fixed + for (i = width; i; i--) + { + png_byte v[8]; + int j; + sptr -= 2; + png_memcpy(v, sptr, 2); + for (j = 0; j < png_pass_inc[pass]; j++) + { + dp -= 2; + png_memcpy(dp, v, 2); + } + } + } + } /* end of pixel_bytes == 2 */ + + //-------------------------------------------------------------- + else if (pixel_bytes == 4) + { + if (((pass == 0) || (pass == 1)) && width) + { + int width_mmx = ((width >> 1) << 1); + width -= width_mmx; // 0,1 pixels => 0,4 bytes + if (width_mmx) + { + int dummy_value_c; // fix 'forbidden register spilled' + int dummy_value_S; + int dummy_value_D; + + __asm__ __volatile__ ( + "subl $4, %%esi \n\t" + "subl $60, %%edi \n\t" + + ".loop4_pass0: \n\t" + "movq (%%esi), %%mm0 \n\t" // 7 6 5 4 3 2 1 0 + "movq %%mm0, %%mm1 \n\t" // 7 6 5 4 3 2 1 0 + "punpckldq %%mm0, %%mm0 \n\t" // 3 2 1 0 3 2 1 0 + "punpckhdq %%mm1, %%mm1 \n\t" // 7 6 5 4 7 6 5 4 + "movq %%mm0, (%%edi) \n\t" + "movq %%mm0, 8(%%edi) \n\t" + "movq %%mm0, 16(%%edi) \n\t" + "movq %%mm0, 24(%%edi) \n\t" + "movq %%mm1, 32(%%edi) \n\t" + "movq %%mm1, 40(%%edi) \n\t" + "movq %%mm1, 48(%%edi) \n\t" + "subl $8, %%esi \n\t" + "movq %%mm1, 56(%%edi) \n\t" + "subl $64, %%edi \n\t" + "subl $2, %%ecx \n\t" + "jnz .loop4_pass0 \n\t" + "EMMS \n\t" // DONE + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "1" (sptr), // esi // input regs + "2" (dp), // edi + "0" (width_mmx) // ecx + +#if 0 /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0", "%mm1" // clobber list +#endif + ); + } + + sptr -= (width_mmx*4 - 4); // sign fixed + dp -= (width_mmx*32 - 4); // sign fixed + for (i = width; i; i--) + { + png_byte v[8]; + int j; + sptr -= 4; + png_memcpy(v, sptr, 4); + for (j = 0; j < png_pass_inc[pass]; j++) + { + dp -= 4; + png_memcpy(dp, v, 4); + } + } + } + else if (((pass == 2) || (pass == 3)) && width) + { + int width_mmx = ((width >> 1) << 1); + width -= width_mmx; // 0,1 pixels => 0,4 bytes + if (width_mmx) + { + int dummy_value_c; // fix 'forbidden register spilled' + int dummy_value_S; + int dummy_value_D; + + __asm__ __volatile__ ( + "subl $4, %%esi \n\t" + "subl $28, %%edi \n\t" + + ".loop4_pass2: \n\t" + "movq (%%esi), %%mm0 \n\t" // 7 6 5 4 3 2 1 0 + "movq %%mm0, %%mm1 \n\t" // 7 6 5 4 3 2 1 0 + "punpckldq %%mm0, %%mm0 \n\t" // 3 2 1 0 3 2 1 0 + "punpckhdq %%mm1, %%mm1 \n\t" // 7 6 5 4 7 6 5 4 + "movq %%mm0, (%%edi) \n\t" + "movq %%mm0, 8(%%edi) \n\t" + "movq %%mm1, 16(%%edi) \n\t" + "movq %%mm1, 24(%%edi) \n\t" + "subl $8, %%esi \n\t" + "subl $32, %%edi \n\t" + "subl $2, %%ecx \n\t" + "jnz .loop4_pass2 \n\t" + "EMMS \n\t" // DONE + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "1" (sptr), // esi // input regs + "2" (dp), // edi + "0" (width_mmx) // ecx + +#if 0 /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0", "%mm1" // clobber list +#endif + ); + } + + sptr -= (width_mmx*4 - 4); // sign fixed + dp -= (width_mmx*16 - 4); // sign fixed + for (i = width; i; i--) + { + png_byte v[8]; + int j; + sptr -= 4; + png_memcpy(v, sptr, 4); + for (j = 0; j < png_pass_inc[pass]; j++) + { + dp -= 4; + png_memcpy(dp, v, 4); + } + } + } + else if (width) // pass == 4 or 5 + { + int width_mmx = ((width >> 1) << 1) ; + width -= width_mmx; // 0,1 pixels => 0,4 bytes + if (width_mmx) + { + int dummy_value_c; // fix 'forbidden register spilled' + int dummy_value_S; + int dummy_value_D; + + __asm__ __volatile__ ( + "subl $4, %%esi \n\t" + "subl $12, %%edi \n\t" + + ".loop4_pass4: \n\t" + "movq (%%esi), %%mm0 \n\t" // 7 6 5 4 3 2 1 0 + "movq %%mm0, %%mm1 \n\t" // 7 6 5 4 3 2 1 0 + "punpckldq %%mm0, %%mm0 \n\t" // 3 2 1 0 3 2 1 0 + "punpckhdq %%mm1, %%mm1 \n\t" // 7 6 5 4 7 6 5 4 + "movq %%mm0, (%%edi) \n\t" + "subl $8, %%esi \n\t" + "movq %%mm1, 8(%%edi) \n\t" + "subl $16, %%edi \n\t" + "subl $2, %%ecx \n\t" + "jnz .loop4_pass4 \n\t" + "EMMS \n\t" // DONE + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "1" (sptr), // esi // input regs + "2" (dp), // edi + "0" (width_mmx) // ecx + +#if 0 /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0", "%mm1" // clobber list +#endif + ); + } + + sptr -= (width_mmx*4 - 4); // sign fixed + dp -= (width_mmx*8 - 4); // sign fixed + for (i = width; i; i--) + { + png_byte v[8]; + int j; + sptr -= 4; + png_memcpy(v, sptr, 4); + for (j = 0; j < png_pass_inc[pass]; j++) + { + dp -= 4; + png_memcpy(dp, v, 4); + } + } + } + } /* end of pixel_bytes == 4 */ + + //-------------------------------------------------------------- + else if (pixel_bytes == 8) + { +// GRR TEST: should work, but needs testing (special 64-bit version of rpng2?) + // GRR NOTE: no need to combine passes here! + if (((pass == 0) || (pass == 1)) && width) + { + int dummy_value_c; // fix 'forbidden register spilled' + int dummy_value_S; + int dummy_value_D; + + // source is 8-byte RRGGBBAA + // dest is 64-byte RRGGBBAA RRGGBBAA RRGGBBAA RRGGBBAA ... + __asm__ __volatile__ ( + "subl $56, %%edi \n\t" // start of last block + + ".loop8_pass0: \n\t" + "movq (%%esi), %%mm0 \n\t" // 7 6 5 4 3 2 1 0 + "movq %%mm0, (%%edi) \n\t" + "movq %%mm0, 8(%%edi) \n\t" + "movq %%mm0, 16(%%edi) \n\t" + "movq %%mm0, 24(%%edi) \n\t" + "movq %%mm0, 32(%%edi) \n\t" + "movq %%mm0, 40(%%edi) \n\t" + "movq %%mm0, 48(%%edi) \n\t" + "subl $8, %%esi \n\t" + "movq %%mm0, 56(%%edi) \n\t" + "subl $64, %%edi \n\t" + "decl %%ecx \n\t" + "jnz .loop8_pass0 \n\t" + "EMMS \n\t" // DONE + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "1" (sptr), // esi // input regs + "2" (dp), // edi + "0" (width) // ecx + +#if 0 /* %mm0 not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0" // clobber list +#endif + ); + } + else if (((pass == 2) || (pass == 3)) && width) + { + // source is 8-byte RRGGBBAA + // dest is 32-byte RRGGBBAA RRGGBBAA RRGGBBAA RRGGBBAA + // (recall that expansion is _in place_: sptr and dp + // both point at locations within same row buffer) + { + int dummy_value_c; // fix 'forbidden register spilled' + int dummy_value_S; + int dummy_value_D; + + __asm__ __volatile__ ( + "subl $24, %%edi \n\t" // start of last block + + ".loop8_pass2: \n\t" + "movq (%%esi), %%mm0 \n\t" // 7 6 5 4 3 2 1 0 + "movq %%mm0, (%%edi) \n\t" + "movq %%mm0, 8(%%edi) \n\t" + "movq %%mm0, 16(%%edi) \n\t" + "subl $8, %%esi \n\t" + "movq %%mm0, 24(%%edi) \n\t" + "subl $32, %%edi \n\t" + "decl %%ecx \n\t" + "jnz .loop8_pass2 \n\t" + "EMMS \n\t" // DONE + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "1" (sptr), // esi // input regs + "2" (dp), // edi + "0" (width) // ecx + +#if 0 /* %mm0 not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0" // clobber list +#endif + ); + } + } + else if (width) // pass == 4 or 5 + { + // source is 8-byte RRGGBBAA + // dest is 16-byte RRGGBBAA RRGGBBAA + { + int dummy_value_c; // fix 'forbidden register spilled' + int dummy_value_S; + int dummy_value_D; + + __asm__ __volatile__ ( + "subl $8, %%edi \n\t" // start of last block + + ".loop8_pass4: \n\t" + "movq (%%esi), %%mm0 \n\t" // 7 6 5 4 3 2 1 0 + "movq %%mm0, (%%edi) \n\t" + "subl $8, %%esi \n\t" + "movq %%mm0, 8(%%edi) \n\t" + "subl $16, %%edi \n\t" + "decl %%ecx \n\t" + "jnz .loop8_pass4 \n\t" + "EMMS \n\t" // DONE + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "1" (sptr), // esi // input regs + "2" (dp), // edi + "0" (width) // ecx + +#if 0 /* %mm0 not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0" // clobber list +#endif + ); + } + } + + } /* end of pixel_bytes == 8 */ + + //-------------------------------------------------------------- + else if (pixel_bytes == 6) + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, 6); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, 6); + dp -= 6; + } + sptr -= 6; + } + } /* end of pixel_bytes == 6 */ + + //-------------------------------------------------------------- + else + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, pixel_bytes); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, pixel_bytes); + dp -= pixel_bytes; + } + sptr-= pixel_bytes; + } + } + } // end of _mmx_supported ======================================== + + else /* MMX not supported: use modified C code - takes advantage + * of inlining of png_memcpy for a constant */ + /* GRR 19991007: does it? or should pixel_bytes in each + * block be replaced with immediate value (e.g., 1)? */ + /* GRR 19991017: replaced with constants in each case */ +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ + { + if (pixel_bytes == 1) + { + for (i = width; i; i--) + { + int j; + for (j = 0; j < png_pass_inc[pass]; j++) + { + *dp-- = *sptr; + } + --sptr; + } + } + else if (pixel_bytes == 3) + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, 3); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, 3); + dp -= 3; + } + sptr -= 3; + } + } + else if (pixel_bytes == 2) + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, 2); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, 2); + dp -= 2; + } + sptr -= 2; + } + } + else if (pixel_bytes == 4) + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, 4); + for (j = 0; j < png_pass_inc[pass]; j++) + { +#ifdef PNG_DEBUG + if (dp < row || dp+3 > row+png_ptr->row_buf_size) + { + printf("dp out of bounds: row=%d, dp=%d, rp=%d\n", + row, dp, row+png_ptr->row_buf_size); + printf("row_buf=%d\n",png_ptr->row_buf_size); + } +#endif + png_memcpy(dp, v, 4); + dp -= 4; + } + sptr -= 4; + } + } + else if (pixel_bytes == 6) + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, 6); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, 6); + dp -= 6; + } + sptr -= 6; + } + } + else if (pixel_bytes == 8) + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, 8); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, 8); + dp -= 8; + } + sptr -= 8; + } + } + else /* GRR: should never be reached */ + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, pixel_bytes); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, pixel_bytes); + dp -= pixel_bytes; + } + sptr -= pixel_bytes; + } + } + + } /* end if (MMX not supported) */ + break; + } + } /* end switch (row_info->pixel_depth) */ + + row_info->width = final_width; + + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,final_width); + } + +} /* end png_do_read_interlace() */ + +#endif /* PNG_HAVE_ASSEMBLER_READ_INTERLACE */ +#endif /* PNG_READ_INTERLACING_SUPPORTED */ + + + +#if defined(PNG_HAVE_ASSEMBLER_READ_FILTER_ROW) +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) + +// These variables are utilized in the functions below. They are declared +// globally here to ensure alignment on 8-byte boundaries. + +union uAll { + long long use; + double align; +} _LBCarryMask = {0x0101010101010101LL}, + _HBClearMask = {0x7f7f7f7f7f7f7f7fLL}, + _ActiveMask, _ActiveMask2, _ActiveMaskEnd, _ShiftBpp, _ShiftRem; + +#ifdef PNG_THREAD_UNSAFE_OK +//===========================================================================// +// // +// P N G _ R E A D _ F I L T E R _ R O W _ M M X _ A V G // +// // +//===========================================================================// + +// Optimized code for PNG Average filter decoder + +static void /* PRIVATE */ +png_read_filter_row_mmx_avg(png_row_infop row_info, png_bytep row, + png_bytep prev_row) +{ + int bpp; + int dummy_value_c; // fix 'forbidden register 2 (cx) was spilled' error + int dummy_value_S; + int dummy_value_D; + + bpp = (row_info->pixel_depth + 7) >> 3; // get # bytes per pixel + _FullLength = row_info->rowbytes; // # of bytes to filter + + __asm__ __volatile__ ( + // initialize address pointers and offset +#ifdef __PIC__ + "pushl %%ebx \n\t" // save index to Global Offset Table +#endif +//pre "movl row, %%edi \n\t" // edi: Avg(x) + "xorl %%ebx, %%ebx \n\t" // ebx: x + "movl %%edi, %%edx \n\t" +//pre "movl prev_row, %%esi \n\t" // esi: Prior(x) +//pre "subl bpp, %%edx \n\t" // (bpp is preloaded into ecx) + "subl %%ecx, %%edx \n\t" // edx: Raw(x-bpp) + + "xorl %%eax,%%eax \n\t" + + // Compute the Raw value for the first bpp bytes + // Raw(x) = Avg(x) + (Prior(x)/2) + "avg_rlp: \n\t" + "movb (%%esi,%%ebx,),%%al \n\t" // load al with Prior(x) + "incl %%ebx \n\t" + "shrb %%al \n\t" // divide by 2 + "addb -1(%%edi,%%ebx,),%%al \n\t" // add Avg(x); -1 to offset inc ebx +//pre "cmpl bpp, %%ebx \n\t" // (bpp is preloaded into ecx) + "cmpl %%ecx, %%ebx \n\t" + "movb %%al,-1(%%edi,%%ebx,) \n\t" // write Raw(x); -1 to offset inc ebx + "jb avg_rlp \n\t" // mov does not affect flags + + // get # of bytes to alignment + "movl %%edi, _dif \n\t" // take start of row + "addl %%ebx, _dif \n\t" // add bpp + "addl $0xf, _dif \n\t" // add 7+8 to incr past alignment bdry + "andl $0xfffffff8, _dif \n\t" // mask to alignment boundary + "subl %%edi, _dif \n\t" // subtract from start => value ebx at + "jz avg_go \n\t" // alignment + + // fix alignment + // Compute the Raw value for the bytes up to the alignment boundary + // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2) + "xorl %%ecx, %%ecx \n\t" + + "avg_lp1: \n\t" + "xorl %%eax, %%eax \n\t" + "movb (%%esi,%%ebx,), %%cl \n\t" // load cl with Prior(x) + "movb (%%edx,%%ebx,), %%al \n\t" // load al with Raw(x-bpp) + "addw %%cx, %%ax \n\t" + "incl %%ebx \n\t" + "shrw %%ax \n\t" // divide by 2 + "addb -1(%%edi,%%ebx,), %%al \n\t" // add Avg(x); -1 to offset inc ebx + "cmpl _dif, %%ebx \n\t" // check if at alignment boundary + "movb %%al, -1(%%edi,%%ebx,) \n\t" // write Raw(x); -1 to offset inc ebx + "jb avg_lp1 \n\t" // repeat until at alignment boundary + + "avg_go: \n\t" + "movl _FullLength, %%eax \n\t" + "movl %%eax, %%ecx \n\t" + "subl %%ebx, %%eax \n\t" // subtract alignment fix + "andl $0x00000007, %%eax \n\t" // calc bytes over mult of 8 + "subl %%eax, %%ecx \n\t" // drop over bytes from original length + "movl %%ecx, _MMXLength \n\t" +#ifdef __PIC__ + "popl %%ebx \n\t" // restore index to Global Offset Table +#endif + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "0" (bpp), // ecx // input regs + "1" (prev_row), // esi + "2" (row) // edi + + : "%eax", "%edx" // clobber list +#ifndef __PIC__ + , "%ebx" +#endif + // GRR: INCLUDE "memory" as clobbered? (_dif, _MMXLength) + // (seems to work fine without...) + ); + + // now do the math for the rest of the row + switch (bpp) + { + case 3: + { + _ActiveMask.use = 0x0000000000ffffffLL; + _ShiftBpp.use = 24; // == 3 * 8 + _ShiftRem.use = 40; // == 64 - 24 + + __asm__ __volatile__ ( + // re-init address pointers and offset + "movq _ActiveMask, %%mm7 \n\t" + "movl _dif, %%ecx \n\t" // ecx: x = offset to + "movq _LBCarryMask, %%mm5 \n\t" // alignment boundary +// preload "movl row, %%edi \n\t" // edi: Avg(x) + "movq _HBClearMask, %%mm4 \n\t" +// preload "movl prev_row, %%esi \n\t" // esi: Prior(x) + + // prime the pump: load the first Raw(x-bpp) data set + "movq -8(%%edi,%%ecx,), %%mm2 \n\t" // load previous aligned 8 bytes + // (correct pos. in loop below) + "avg_3lp: \n\t" + "movq (%%edi,%%ecx,), %%mm0 \n\t" // load mm0 with Avg(x) + "movq %%mm5, %%mm3 \n\t" + "psrlq _ShiftRem, %%mm2 \n\t" // correct position Raw(x-bpp) + // data + "movq (%%esi,%%ecx,), %%mm1 \n\t" // load mm1 with Prior(x) + "movq %%mm7, %%mm6 \n\t" + "pand %%mm1, %%mm3 \n\t" // get lsb for each prev_row byte + "psrlq $1, %%mm1 \n\t" // divide prev_row bytes by 2 + "pand %%mm4, %%mm1 \n\t" // clear invalid bit 7 of each + // byte + "paddb %%mm1, %%mm0 \n\t" // add (Prev_row/2) to Avg for + // each byte + // add 1st active group (Raw(x-bpp)/2) to average with LBCarry + "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting + // LBCarrys + "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte + // where both + // lsb's were == 1 (only valid for active group) + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each + // byte + "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2) + // for each byte + "pand %%mm6, %%mm2 \n\t" // leave only Active Group 1 + // bytes to add to Avg + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to + // Avg for each Active + // byte + // add 2nd active group (Raw(x-bpp)/2) to average with _LBCarry + "psllq _ShiftBpp, %%mm6 \n\t" // shift the mm6 mask to cover + // bytes 3-5 + "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2 + "psllq _ShiftBpp, %%mm2 \n\t" // shift data to pos. correctly + "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting + // LBCarrys + "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte + // where both + // lsb's were == 1 (only valid for active group) + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each + // byte + "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2) + // for each byte + "pand %%mm6, %%mm2 \n\t" // leave only Active Group 2 + // bytes to add to Avg + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to + // Avg for each Active + // byte + + // add 3rd active group (Raw(x-bpp)/2) to average with _LBCarry + "psllq _ShiftBpp, %%mm6 \n\t" // shift mm6 mask to cover last + // two + // bytes + "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2 + "psllq _ShiftBpp, %%mm2 \n\t" // shift data to pos. correctly + // Data only needs to be shifted once here to + // get the correct x-bpp offset. + "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting + // LBCarrys + "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte + // where both + // lsb's were == 1 (only valid for active group) + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each + // byte + "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2) + // for each byte + "pand %%mm6, %%mm2 \n\t" // leave only Active Group 2 + // bytes to add to Avg + "addl $8, %%ecx \n\t" + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to + // Avg for each Active + // byte + // now ready to write back to memory + "movq %%mm0, -8(%%edi,%%ecx,) \n\t" + // move updated Raw(x) to use as Raw(x-bpp) for next loop + "cmpl _MMXLength, %%ecx \n\t" + "movq %%mm0, %%mm2 \n\t" // mov updated Raw(x) to mm2 + "jb avg_3lp \n\t" + + : "=S" (dummy_value_S), // output regs (dummy) + "=D" (dummy_value_D) + + : "0" (prev_row), // esi // input regs + "1" (row) // edi + + : "%ecx" // clobber list +#if 0 /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm2", "%mm3" + , "%mm4", "%mm5", "%mm6", "%mm7" +#endif + ); + } + break; // end 3 bpp + + case 6: + case 4: + //case 7: // who wrote this? PNG doesn't support 5 or 7 bytes/pixel + //case 5: // GRR BOGUS + { + _ActiveMask.use = 0xffffffffffffffffLL; // use shift below to clear + // appropriate inactive bytes + _ShiftBpp.use = bpp << 3; + _ShiftRem.use = 64 - _ShiftBpp.use; + + __asm__ __volatile__ ( + "movq _HBClearMask, %%mm4 \n\t" + + // re-init address pointers and offset + "movl _dif, %%ecx \n\t" // ecx: x = offset to + // alignment boundary + + // load _ActiveMask and clear all bytes except for 1st active group + "movq _ActiveMask, %%mm7 \n\t" +// preload "movl row, %%edi \n\t" // edi: Avg(x) + "psrlq _ShiftRem, %%mm7 \n\t" +// preload "movl prev_row, %%esi \n\t" // esi: Prior(x) + "movq %%mm7, %%mm6 \n\t" + "movq _LBCarryMask, %%mm5 \n\t" + "psllq _ShiftBpp, %%mm6 \n\t" // create mask for 2nd active + // group + + // prime the pump: load the first Raw(x-bpp) data set + "movq -8(%%edi,%%ecx,), %%mm2 \n\t" // load previous aligned 8 bytes + // (we correct pos. in loop below) + "avg_4lp: \n\t" + "movq (%%edi,%%ecx,), %%mm0 \n\t" + "psrlq _ShiftRem, %%mm2 \n\t" // shift data to pos. correctly + "movq (%%esi,%%ecx,), %%mm1 \n\t" + // add (Prev_row/2) to average + "movq %%mm5, %%mm3 \n\t" + "pand %%mm1, %%mm3 \n\t" // get lsb for each prev_row byte + "psrlq $1, %%mm1 \n\t" // divide prev_row bytes by 2 + "pand %%mm4, %%mm1 \n\t" // clear invalid bit 7 of each + // byte + "paddb %%mm1, %%mm0 \n\t" // add (Prev_row/2) to Avg for + // each byte + // add 1st active group (Raw(x-bpp)/2) to average with _LBCarry + "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting + // LBCarrys + "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte + // where both + // lsb's were == 1 (only valid for active group) + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each + // byte + "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2) + // for each byte + "pand %%mm7, %%mm2 \n\t" // leave only Active Group 1 + // bytes to add to Avg + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to Avg + // for each Active + // byte + // add 2nd active group (Raw(x-bpp)/2) to average with _LBCarry + "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2 + "psllq _ShiftBpp, %%mm2 \n\t" // shift data to pos. correctly + "addl $8, %%ecx \n\t" + "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting + // LBCarrys + "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte + // where both + // lsb's were == 1 (only valid for active group) + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each + // byte + "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2) + // for each byte + "pand %%mm6, %%mm2 \n\t" // leave only Active Group 2 + // bytes to add to Avg + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to + // Avg for each Active + // byte + "cmpl _MMXLength, %%ecx \n\t" + // now ready to write back to memory + "movq %%mm0, -8(%%edi,%%ecx,) \n\t" + // prep Raw(x-bpp) for next loop + "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2 + "jb avg_4lp \n\t" + + : "=S" (dummy_value_S), // output regs (dummy) + "=D" (dummy_value_D) + + : "0" (prev_row), // esi // input regs + "1" (row) // edi + + : "%ecx" // clobber list +#if 0 /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm2", "%mm3" + , "%mm4", "%mm5", "%mm6", "%mm7" +#endif + ); + } + break; // end 4,6 bpp + + case 2: + { + _ActiveMask.use = 0x000000000000ffffLL; + _ShiftBpp.use = 16; // == 2 * 8 + _ShiftRem.use = 48; // == 64 - 16 + + __asm__ __volatile__ ( + // load _ActiveMask + "movq _ActiveMask, %%mm7 \n\t" + // re-init address pointers and offset + "movl _dif, %%ecx \n\t" // ecx: x = offset to alignment + // boundary + "movq _LBCarryMask, %%mm5 \n\t" +// preload "movl row, %%edi \n\t" // edi: Avg(x) + "movq _HBClearMask, %%mm4 \n\t" +// preload "movl prev_row, %%esi \n\t" // esi: Prior(x) + + // prime the pump: load the first Raw(x-bpp) data set + "movq -8(%%edi,%%ecx,), %%mm2 \n\t" // load previous aligned 8 bytes + // (we correct pos. in loop below) + "avg_2lp: \n\t" + "movq (%%edi,%%ecx,), %%mm0 \n\t" + "psrlq _ShiftRem, %%mm2 \n\t" // shift data to pos. correctly + "movq (%%esi,%%ecx,), %%mm1 \n\t" // (GRR BUGFIX: was psllq) + // add (Prev_row/2) to average + "movq %%mm5, %%mm3 \n\t" + "pand %%mm1, %%mm3 \n\t" // get lsb for each prev_row byte + "psrlq $1, %%mm1 \n\t" // divide prev_row bytes by 2 + "pand %%mm4, %%mm1 \n\t" // clear invalid bit 7 of each + // byte + "movq %%mm7, %%mm6 \n\t" + "paddb %%mm1, %%mm0 \n\t" // add (Prev_row/2) to Avg for + // each byte + + // add 1st active group (Raw(x-bpp)/2) to average with _LBCarry + "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting + // LBCarrys + "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte + // where both + // lsb's were == 1 (only valid + // for active group) + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each + // byte + "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2) + // for each byte + "pand %%mm6, %%mm2 \n\t" // leave only Active Group 1 + // bytes to add to Avg + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to Avg + // for each Active byte + + // add 2nd active group (Raw(x-bpp)/2) to average with _LBCarry + "psllq _ShiftBpp, %%mm6 \n\t" // shift the mm6 mask to cover + // bytes 2 & 3 + "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2 + "psllq _ShiftBpp, %%mm2 \n\t" // shift data to pos. correctly + "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting + // LBCarrys + "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte + // where both + // lsb's were == 1 (only valid + // for active group) + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each + // byte + "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2) + // for each byte + "pand %%mm6, %%mm2 \n\t" // leave only Active Group 2 + // bytes to add to Avg + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to + // Avg for each Active byte + + // add 3rd active group (Raw(x-bpp)/2) to average with _LBCarry + "psllq _ShiftBpp, %%mm6 \n\t" // shift the mm6 mask to cover + // bytes 4 & 5 + "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2 + "psllq _ShiftBpp, %%mm2 \n\t" // shift data to pos. correctly + "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting + // LBCarrys + "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte + // where both lsb's were == 1 + // (only valid for active group) + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each + // byte + "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2) + // for each byte + "pand %%mm6, %%mm2 \n\t" // leave only Active Group 2 + // bytes to add to Avg + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to + // Avg for each Active byte + + // add 4th active group (Raw(x-bpp)/2) to average with _LBCarry + "psllq _ShiftBpp, %%mm6 \n\t" // shift the mm6 mask to cover + // bytes 6 & 7 + "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2 + "psllq _ShiftBpp, %%mm2 \n\t" // shift data to pos. correctly + "addl $8, %%ecx \n\t" + "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting + // LBCarrys + "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte + // where both + // lsb's were == 1 (only valid + // for active group) + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each + // byte + "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2) + // for each byte + "pand %%mm6, %%mm2 \n\t" // leave only Active Group 2 + // bytes to add to Avg + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to + // Avg for each Active byte + + "cmpl _MMXLength, %%ecx \n\t" + // now ready to write back to memory + "movq %%mm0, -8(%%edi,%%ecx,) \n\t" + // prep Raw(x-bpp) for next loop + "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2 + "jb avg_2lp \n\t" + + : "=S" (dummy_value_S), // output regs (dummy) + "=D" (dummy_value_D) + + : "0" (prev_row), // esi // input regs + "1" (row) // edi + + : "%ecx" // clobber list +#if 0 /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm2", "%mm3" + , "%mm4", "%mm5", "%mm6", "%mm7" +#endif + ); + } + break; // end 2 bpp + + case 1: + { + __asm__ __volatile__ ( + // re-init address pointers and offset +#ifdef __PIC__ + "pushl %%ebx \n\t" // save Global Offset Table index +#endif + "movl _dif, %%ebx \n\t" // ebx: x = offset to alignment + // boundary +// preload "movl row, %%edi \n\t" // edi: Avg(x) + "cmpl _FullLength, %%ebx \n\t" // test if offset at end of array + "jnb avg_1end \n\t" + // do Paeth decode for remaining bytes +// preload "movl prev_row, %%esi \n\t" // esi: Prior(x) + "movl %%edi, %%edx \n\t" +// preload "subl bpp, %%edx \n\t" // (bpp is preloaded into ecx) + "subl %%ecx, %%edx \n\t" // edx: Raw(x-bpp) + "xorl %%ecx, %%ecx \n\t" // zero ecx before using cl & cx + // in loop below + "avg_1lp: \n\t" + // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2) + "xorl %%eax, %%eax \n\t" + "movb (%%esi,%%ebx,), %%cl \n\t" // load cl with Prior(x) + "movb (%%edx,%%ebx,), %%al \n\t" // load al with Raw(x-bpp) + "addw %%cx, %%ax \n\t" + "incl %%ebx \n\t" + "shrw %%ax \n\t" // divide by 2 + "addb -1(%%edi,%%ebx,), %%al \n\t" // add Avg(x); -1 to offset + // inc ebx + "cmpl _FullLength, %%ebx \n\t" // check if at end of array + "movb %%al, -1(%%edi,%%ebx,) \n\t" // write back Raw(x); + // mov does not affect flags; -1 to offset inc ebx + "jb avg_1lp \n\t" + + "avg_1end: \n\t" +#ifdef __PIC__ + "popl %%ebx \n\t" // Global Offset Table index +#endif + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "0" (bpp), // ecx // input regs + "1" (prev_row), // esi + "2" (row) // edi + + : "%eax", "%edx" // clobber list +#ifndef __PIC__ + , "%ebx" +#endif + ); + } + return; // end 1 bpp + + case 8: + { + __asm__ __volatile__ ( + // re-init address pointers and offset + "movl _dif, %%ecx \n\t" // ecx: x == offset to alignment + "movq _LBCarryMask, %%mm5 \n\t" // boundary +// preload "movl row, %%edi \n\t" // edi: Avg(x) + "movq _HBClearMask, %%mm4 \n\t" +// preload "movl prev_row, %%esi \n\t" // esi: Prior(x) + + // prime the pump: load the first Raw(x-bpp) data set + "movq -8(%%edi,%%ecx,), %%mm2 \n\t" // load previous aligned 8 bytes + // (NO NEED to correct pos. in loop below) + + "avg_8lp: \n\t" + "movq (%%edi,%%ecx,), %%mm0 \n\t" + "movq %%mm5, %%mm3 \n\t" + "movq (%%esi,%%ecx,), %%mm1 \n\t" + "addl $8, %%ecx \n\t" + "pand %%mm1, %%mm3 \n\t" // get lsb for each prev_row byte + "psrlq $1, %%mm1 \n\t" // divide prev_row bytes by 2 + "pand %%mm2, %%mm3 \n\t" // get LBCarrys for each byte + // where both lsb's were == 1 + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm1 \n\t" // clear invalid bit 7, each byte + "paddb %%mm3, %%mm0 \n\t" // add LBCarrys to Avg, each byte + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7, each byte + "paddb %%mm1, %%mm0 \n\t" // add (Prev_row/2) to Avg, each + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) to Avg for each + "cmpl _MMXLength, %%ecx \n\t" + "movq %%mm0, -8(%%edi,%%ecx,) \n\t" + "movq %%mm0, %%mm2 \n\t" // reuse as Raw(x-bpp) + "jb avg_8lp \n\t" + + : "=S" (dummy_value_S), // output regs (dummy) + "=D" (dummy_value_D) + + : "0" (prev_row), // esi // input regs + "1" (row) // edi + + : "%ecx" // clobber list +#if 0 /* %mm0, ..., %mm5 not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm2" + , "%mm3", "%mm4", "%mm5" +#endif + ); + } + break; // end 8 bpp + + default: // bpp greater than 8 (!= 1,2,3,4,[5],6,[7],8) + { + +#ifdef PNG_DEBUG + // GRR: PRINT ERROR HERE: SHOULD NEVER BE REACHED + png_debug(1, + "Internal logic error in pnggccrd (png_read_filter_row_mmx_avg())\n"); +#endif + +#if 0 + __asm__ __volatile__ ( + "movq _LBCarryMask, %%mm5 \n\t" + // re-init address pointers and offset + "movl _dif, %%ebx \n\t" // ebx: x = offset to + // alignment boundary + "movl row, %%edi \n\t" // edi: Avg(x) + "movq _HBClearMask, %%mm4 \n\t" + "movl %%edi, %%edx \n\t" + "movl prev_row, %%esi \n\t" // esi: Prior(x) + "subl bpp, %%edx \n\t" // edx: Raw(x-bpp) + "avg_Alp: \n\t" + "movq (%%edi,%%ebx,), %%mm0 \n\t" + "movq %%mm5, %%mm3 \n\t" + "movq (%%esi,%%ebx,), %%mm1 \n\t" + "pand %%mm1, %%mm3 \n\t" // get lsb for each prev_row byte + "movq (%%edx,%%ebx,), %%mm2 \n\t" + "psrlq $1, %%mm1 \n\t" // divide prev_row bytes by 2 + "pand %%mm2, %%mm3 \n\t" // get LBCarrys for each byte + // where both lsb's were == 1 + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm1 \n\t" // clear invalid bit 7 of each + // byte + "paddb %%mm3, %%mm0 \n\t" // add LBCarrys to Avg for each + // byte + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each + // byte + "paddb %%mm1, %%mm0 \n\t" // add (Prev_row/2) to Avg for + // each byte + "addl $8, %%ebx \n\t" + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) to Avg for each + // byte + "cmpl _MMXLength, %%ebx \n\t" + "movq %%mm0, -8(%%edi,%%ebx,) \n\t" + "jb avg_Alp \n\t" + + : // FIXASM: output regs/vars go here, e.g.: "=m" (memory_var) + + : // FIXASM: input regs, e.g.: "c" (count), "S" (src), "D" (dest) + + : "%ebx", "%edx", "%edi", "%esi" // CHECKASM: clobber list + ); +#endif /* 0 - NEVER REACHED */ + } + break; + + } // end switch (bpp) + + __asm__ __volatile__ ( + // MMX acceleration complete; now do clean-up + // check if any remaining bytes left to decode +#ifdef __PIC__ + "pushl %%ebx \n\t" // save index to Global Offset Table +#endif + "movl _MMXLength, %%ebx \n\t" // ebx: x == offset bytes after MMX +//pre "movl row, %%edi \n\t" // edi: Avg(x) + "cmpl _FullLength, %%ebx \n\t" // test if offset at end of array + "jnb avg_end \n\t" + + // do Avg decode for remaining bytes +//pre "movl prev_row, %%esi \n\t" // esi: Prior(x) + "movl %%edi, %%edx \n\t" +//pre "subl bpp, %%edx \n\t" // (bpp is preloaded into ecx) + "subl %%ecx, %%edx \n\t" // edx: Raw(x-bpp) + "xorl %%ecx, %%ecx \n\t" // zero ecx before using cl & cx below + + "avg_lp2: \n\t" + // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2) + "xorl %%eax, %%eax \n\t" + "movb (%%esi,%%ebx,), %%cl \n\t" // load cl with Prior(x) + "movb (%%edx,%%ebx,), %%al \n\t" // load al with Raw(x-bpp) + "addw %%cx, %%ax \n\t" + "incl %%ebx \n\t" + "shrw %%ax \n\t" // divide by 2 + "addb -1(%%edi,%%ebx,), %%al \n\t" // add Avg(x); -1 to offset inc ebx + "cmpl _FullLength, %%ebx \n\t" // check if at end of array + "movb %%al, -1(%%edi,%%ebx,) \n\t" // write back Raw(x) [mov does not + "jb avg_lp2 \n\t" // affect flags; -1 to offset inc ebx] + + "avg_end: \n\t" + "EMMS \n\t" // end MMX; prep for poss. FP instrs. +#ifdef __PIC__ + "popl %%ebx \n\t" // restore index to Global Offset Table +#endif + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "0" (bpp), // ecx // input regs + "1" (prev_row), // esi + "2" (row) // edi + + : "%eax", "%edx" // clobber list +#ifndef __PIC__ + , "%ebx" +#endif + ); + +} /* end png_read_filter_row_mmx_avg() */ +#endif + + + +#ifdef PNG_THREAD_UNSAFE_OK +//===========================================================================// +// // +// P N G _ R E A D _ F I L T E R _ R O W _ M M X _ P A E T H // +// // +//===========================================================================// + +// Optimized code for PNG Paeth filter decoder + +static void /* PRIVATE */ +png_read_filter_row_mmx_paeth(png_row_infop row_info, png_bytep row, + png_bytep prev_row) +{ + int bpp; + int dummy_value_c; // fix 'forbidden register 2 (cx) was spilled' error + int dummy_value_S; + int dummy_value_D; + + bpp = (row_info->pixel_depth + 7) >> 3; // Get # bytes per pixel + _FullLength = row_info->rowbytes; // # of bytes to filter + + __asm__ __volatile__ ( +#ifdef __PIC__ + "pushl %%ebx \n\t" // save index to Global Offset Table +#endif + "xorl %%ebx, %%ebx \n\t" // ebx: x offset +//pre "movl row, %%edi \n\t" + "xorl %%edx, %%edx \n\t" // edx: x-bpp offset +//pre "movl prev_row, %%esi \n\t" + "xorl %%eax, %%eax \n\t" + + // Compute the Raw value for the first bpp bytes + // Note: the formula works out to be always + // Paeth(x) = Raw(x) + Prior(x) where x < bpp + "paeth_rlp: \n\t" + "movb (%%edi,%%ebx,), %%al \n\t" + "addb (%%esi,%%ebx,), %%al \n\t" + "incl %%ebx \n\t" +//pre "cmpl bpp, %%ebx \n\t" (bpp is preloaded into ecx) + "cmpl %%ecx, %%ebx \n\t" + "movb %%al, -1(%%edi,%%ebx,) \n\t" + "jb paeth_rlp \n\t" + // get # of bytes to alignment + "movl %%edi, _dif \n\t" // take start of row + "addl %%ebx, _dif \n\t" // add bpp + "xorl %%ecx, %%ecx \n\t" + "addl $0xf, _dif \n\t" // add 7 + 8 to incr past alignment + // boundary + "andl $0xfffffff8, _dif \n\t" // mask to alignment boundary + "subl %%edi, _dif \n\t" // subtract from start ==> value ebx + // at alignment + "jz paeth_go \n\t" + // fix alignment + + "paeth_lp1: \n\t" + "xorl %%eax, %%eax \n\t" + // pav = p - a = (a + b - c) - a = b - c + "movb (%%esi,%%ebx,), %%al \n\t" // load Prior(x) into al + "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl + "subl %%ecx, %%eax \n\t" // subtract Prior(x-bpp) + "movl %%eax, _patemp \n\t" // Save pav for later use + "xorl %%eax, %%eax \n\t" + // pbv = p - b = (a + b - c) - b = a - c + "movb (%%edi,%%edx,), %%al \n\t" // load Raw(x-bpp) into al + "subl %%ecx, %%eax \n\t" // subtract Prior(x-bpp) + "movl %%eax, %%ecx \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "addl _patemp, %%eax \n\t" // pcv = pav + pbv + // pc = abs(pcv) + "testl $0x80000000, %%eax \n\t" + "jz paeth_pca \n\t" + "negl %%eax \n\t" // reverse sign of neg values + + "paeth_pca: \n\t" + "movl %%eax, _pctemp \n\t" // save pc for later use + // pb = abs(pbv) + "testl $0x80000000, %%ecx \n\t" + "jz paeth_pba \n\t" + "negl %%ecx \n\t" // reverse sign of neg values + + "paeth_pba: \n\t" + "movl %%ecx, _pbtemp \n\t" // save pb for later use + // pa = abs(pav) + "movl _patemp, %%eax \n\t" + "testl $0x80000000, %%eax \n\t" + "jz paeth_paa \n\t" + "negl %%eax \n\t" // reverse sign of neg values + + "paeth_paa: \n\t" + "movl %%eax, _patemp \n\t" // save pa for later use + // test if pa <= pb + "cmpl %%ecx, %%eax \n\t" + "jna paeth_abb \n\t" + // pa > pb; now test if pb <= pc + "cmpl _pctemp, %%ecx \n\t" + "jna paeth_bbc \n\t" + // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp) + "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl + "jmp paeth_paeth \n\t" + + "paeth_bbc: \n\t" + // pb <= pc; Raw(x) = Paeth(x) + Prior(x) + "movb (%%esi,%%ebx,), %%cl \n\t" // load Prior(x) into cl + "jmp paeth_paeth \n\t" + + "paeth_abb: \n\t" + // pa <= pb; now test if pa <= pc + "cmpl _pctemp, %%eax \n\t" + "jna paeth_abc \n\t" + // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp) + "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl + "jmp paeth_paeth \n\t" + + "paeth_abc: \n\t" + // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp) + "movb (%%edi,%%edx,), %%cl \n\t" // load Raw(x-bpp) into cl + + "paeth_paeth: \n\t" + "incl %%ebx \n\t" + "incl %%edx \n\t" + // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256 + "addb %%cl, -1(%%edi,%%ebx,) \n\t" + "cmpl _dif, %%ebx \n\t" + "jb paeth_lp1 \n\t" + + "paeth_go: \n\t" + "movl _FullLength, %%ecx \n\t" + "movl %%ecx, %%eax \n\t" + "subl %%ebx, %%eax \n\t" // subtract alignment fix + "andl $0x00000007, %%eax \n\t" // calc bytes over mult of 8 + "subl %%eax, %%ecx \n\t" // drop over bytes from original length + "movl %%ecx, _MMXLength \n\t" +#ifdef __PIC__ + "popl %%ebx \n\t" // restore index to Global Offset Table +#endif + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "0" (bpp), // ecx // input regs + "1" (prev_row), // esi + "2" (row) // edi + + : "%eax", "%edx" // clobber list +#ifndef __PIC__ + , "%ebx" +#endif + ); + + // now do the math for the rest of the row + switch (bpp) + { + case 3: + { + _ActiveMask.use = 0x0000000000ffffffLL; + _ActiveMaskEnd.use = 0xffff000000000000LL; + _ShiftBpp.use = 24; // == bpp(3) * 8 + _ShiftRem.use = 40; // == 64 - 24 + + __asm__ __volatile__ ( + "movl _dif, %%ecx \n\t" +// preload "movl row, %%edi \n\t" +// preload "movl prev_row, %%esi \n\t" + "pxor %%mm0, %%mm0 \n\t" + // prime the pump: load the first Raw(x-bpp) data set + "movq -8(%%edi,%%ecx,), %%mm1 \n\t" + "paeth_3lp: \n\t" + "psrlq _ShiftRem, %%mm1 \n\t" // shift last 3 bytes to 1st + // 3 bytes + "movq (%%esi,%%ecx,), %%mm2 \n\t" // load b=Prior(x) + "punpcklbw %%mm0, %%mm1 \n\t" // unpack High bytes of a + "movq -8(%%esi,%%ecx,), %%mm3 \n\t" // prep c=Prior(x-bpp) bytes + "punpcklbw %%mm0, %%mm2 \n\t" // unpack High bytes of b + "psrlq _ShiftRem, %%mm3 \n\t" // shift last 3 bytes to 1st + // 3 bytes + // pav = p - a = (a + b - c) - a = b - c + "movq %%mm2, %%mm4 \n\t" + "punpcklbw %%mm0, %%mm3 \n\t" // unpack High bytes of c + // pbv = p - b = (a + b - c) - b = a - c + "movq %%mm1, %%mm5 \n\t" + "psubw %%mm3, %%mm4 \n\t" + "pxor %%mm7, %%mm7 \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "movq %%mm4, %%mm6 \n\t" + "psubw %%mm3, %%mm5 \n\t" + + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + "pcmpgtw %%mm4, %%mm0 \n\t" // create mask pav bytes < 0 + "paddw %%mm5, %%mm6 \n\t" + "pand %%mm4, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "pcmpgtw %%mm5, %%mm7 \n\t" // create mask pbv bytes < 0 + "psubw %%mm0, %%mm4 \n\t" + "pand %%mm5, %%mm7 \n\t" // only pbv bytes < 0 in mm0 + "psubw %%mm0, %%mm4 \n\t" + "psubw %%mm7, %%mm5 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0 + "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "psubw %%mm7, %%mm5 \n\t" + "psubw %%mm0, %%mm6 \n\t" + // test pa <= pb + "movq %%mm4, %%mm7 \n\t" + "psubw %%mm0, %%mm6 \n\t" + "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb? + "movq %%mm7, %%mm0 \n\t" + // use mm7 mask to merge pa & pb + "pand %%mm7, %%mm5 \n\t" + // use mm0 mask copy to merge a & b + "pand %%mm0, %%mm2 \n\t" + "pandn %%mm4, %%mm7 \n\t" + "pandn %%mm1, %%mm0 \n\t" + "paddw %%mm5, %%mm7 \n\t" + "paddw %%mm2, %%mm0 \n\t" + // test ((pa <= pb)? pa:pb) <= pc + "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc? + "pxor %%mm1, %%mm1 \n\t" + "pand %%mm7, %%mm3 \n\t" + "pandn %%mm0, %%mm7 \n\t" + "paddw %%mm3, %%mm7 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "packuswb %%mm1, %%mm7 \n\t" + "movq (%%esi,%%ecx,), %%mm3 \n\t" // load c=Prior(x-bpp) + "pand _ActiveMask, %%mm7 \n\t" + "movq %%mm3, %%mm2 \n\t" // load b=Prior(x) step 1 + "paddb (%%edi,%%ecx,), %%mm7 \n\t" // add Paeth predictor with Raw(x) + "punpcklbw %%mm0, %%mm3 \n\t" // unpack High bytes of c + "movq %%mm7, (%%edi,%%ecx,) \n\t" // write back updated value + "movq %%mm7, %%mm1 \n\t" // now mm1 will be used as + // Raw(x-bpp) + // now do Paeth for 2nd set of bytes (3-5) + "psrlq _ShiftBpp, %%mm2 \n\t" // load b=Prior(x) step 2 + "punpcklbw %%mm0, %%mm1 \n\t" // unpack High bytes of a + "pxor %%mm7, %%mm7 \n\t" + "punpcklbw %%mm0, %%mm2 \n\t" // unpack High bytes of b + // pbv = p - b = (a + b - c) - b = a - c + "movq %%mm1, %%mm5 \n\t" + // pav = p - a = (a + b - c) - a = b - c + "movq %%mm2, %%mm4 \n\t" + "psubw %%mm3, %%mm5 \n\t" + "psubw %%mm3, %%mm4 \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = + // pav + pbv = pbv + pav + "movq %%mm5, %%mm6 \n\t" + "paddw %%mm4, %%mm6 \n\t" + + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + "pcmpgtw %%mm5, %%mm0 \n\t" // create mask pbv bytes < 0 + "pcmpgtw %%mm4, %%mm7 \n\t" // create mask pav bytes < 0 + "pand %%mm5, %%mm0 \n\t" // only pbv bytes < 0 in mm0 + "pand %%mm4, %%mm7 \n\t" // only pav bytes < 0 in mm7 + "psubw %%mm0, %%mm5 \n\t" + "psubw %%mm7, %%mm4 \n\t" + "psubw %%mm0, %%mm5 \n\t" + "psubw %%mm7, %%mm4 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0 + "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "psubw %%mm0, %%mm6 \n\t" + // test pa <= pb + "movq %%mm4, %%mm7 \n\t" + "psubw %%mm0, %%mm6 \n\t" + "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb? + "movq %%mm7, %%mm0 \n\t" + // use mm7 mask to merge pa & pb + "pand %%mm7, %%mm5 \n\t" + // use mm0 mask copy to merge a & b + "pand %%mm0, %%mm2 \n\t" + "pandn %%mm4, %%mm7 \n\t" + "pandn %%mm1, %%mm0 \n\t" + "paddw %%mm5, %%mm7 \n\t" + "paddw %%mm2, %%mm0 \n\t" + // test ((pa <= pb)? pa:pb) <= pc + "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc? + "movq (%%esi,%%ecx,), %%mm2 \n\t" // load b=Prior(x) + "pand %%mm7, %%mm3 \n\t" + "pandn %%mm0, %%mm7 \n\t" + "pxor %%mm1, %%mm1 \n\t" + "paddw %%mm3, %%mm7 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "packuswb %%mm1, %%mm7 \n\t" + "movq %%mm2, %%mm3 \n\t" // load c=Prior(x-bpp) step 1 + "pand _ActiveMask, %%mm7 \n\t" + "punpckhbw %%mm0, %%mm2 \n\t" // unpack High bytes of b + "psllq _ShiftBpp, %%mm7 \n\t" // shift bytes to 2nd group of + // 3 bytes + // pav = p - a = (a + b - c) - a = b - c + "movq %%mm2, %%mm4 \n\t" + "paddb (%%edi,%%ecx,), %%mm7 \n\t" // add Paeth predictor with Raw(x) + "psllq _ShiftBpp, %%mm3 \n\t" // load c=Prior(x-bpp) step 2 + "movq %%mm7, (%%edi,%%ecx,) \n\t" // write back updated value + "movq %%mm7, %%mm1 \n\t" + "punpckhbw %%mm0, %%mm3 \n\t" // unpack High bytes of c + "psllq _ShiftBpp, %%mm1 \n\t" // shift bytes + // now mm1 will be used as Raw(x-bpp) + // now do Paeth for 3rd, and final, set of bytes (6-7) + "pxor %%mm7, %%mm7 \n\t" + "punpckhbw %%mm0, %%mm1 \n\t" // unpack High bytes of a + "psubw %%mm3, %%mm4 \n\t" + // pbv = p - b = (a + b - c) - b = a - c + "movq %%mm1, %%mm5 \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "movq %%mm4, %%mm6 \n\t" + "psubw %%mm3, %%mm5 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "paddw %%mm5, %%mm6 \n\t" + + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + "pcmpgtw %%mm4, %%mm0 \n\t" // create mask pav bytes < 0 + "pcmpgtw %%mm5, %%mm7 \n\t" // create mask pbv bytes < 0 + "pand %%mm4, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "pand %%mm5, %%mm7 \n\t" // only pbv bytes < 0 in mm0 + "psubw %%mm0, %%mm4 \n\t" + "psubw %%mm7, %%mm5 \n\t" + "psubw %%mm0, %%mm4 \n\t" + "psubw %%mm7, %%mm5 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0 + "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "psubw %%mm0, %%mm6 \n\t" + // test pa <= pb + "movq %%mm4, %%mm7 \n\t" + "psubw %%mm0, %%mm6 \n\t" + "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb? + "movq %%mm7, %%mm0 \n\t" + // use mm0 mask copy to merge a & b + "pand %%mm0, %%mm2 \n\t" + // use mm7 mask to merge pa & pb + "pand %%mm7, %%mm5 \n\t" + "pandn %%mm1, %%mm0 \n\t" + "pandn %%mm4, %%mm7 \n\t" + "paddw %%mm2, %%mm0 \n\t" + "paddw %%mm5, %%mm7 \n\t" + // test ((pa <= pb)? pa:pb) <= pc + "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc? + "pand %%mm7, %%mm3 \n\t" + "pandn %%mm0, %%mm7 \n\t" + "paddw %%mm3, %%mm7 \n\t" + "pxor %%mm1, %%mm1 \n\t" + "packuswb %%mm7, %%mm1 \n\t" + // step ecx to next set of 8 bytes and repeat loop til done + "addl $8, %%ecx \n\t" + "pand _ActiveMaskEnd, %%mm1 \n\t" + "paddb -8(%%edi,%%ecx,), %%mm1 \n\t" // add Paeth predictor with + // Raw(x) + + "cmpl _MMXLength, %%ecx \n\t" + "pxor %%mm0, %%mm0 \n\t" // pxor does not affect flags + "movq %%mm1, -8(%%edi,%%ecx,) \n\t" // write back updated value + // mm1 will be used as Raw(x-bpp) next loop + // mm3 ready to be used as Prior(x-bpp) next loop + "jb paeth_3lp \n\t" + + : "=S" (dummy_value_S), // output regs (dummy) + "=D" (dummy_value_D) + + : "0" (prev_row), // esi // input regs + "1" (row) // edi + + : "%ecx" // clobber list +#if 0 /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm2", "%mm3" + , "%mm4", "%mm5", "%mm6", "%mm7" +#endif + ); + } + break; // end 3 bpp + + case 6: + //case 7: // GRR BOGUS + //case 5: // GRR BOGUS + { + _ActiveMask.use = 0x00000000ffffffffLL; + _ActiveMask2.use = 0xffffffff00000000LL; + _ShiftBpp.use = bpp << 3; // == bpp * 8 + _ShiftRem.use = 64 - _ShiftBpp.use; + + __asm__ __volatile__ ( + "movl _dif, %%ecx \n\t" +// preload "movl row, %%edi \n\t" +// preload "movl prev_row, %%esi \n\t" + // prime the pump: load the first Raw(x-bpp) data set + "movq -8(%%edi,%%ecx,), %%mm1 \n\t" + "pxor %%mm0, %%mm0 \n\t" + + "paeth_6lp: \n\t" + // must shift to position Raw(x-bpp) data + "psrlq _ShiftRem, %%mm1 \n\t" + // do first set of 4 bytes + "movq -8(%%esi,%%ecx,), %%mm3 \n\t" // read c=Prior(x-bpp) bytes + "punpcklbw %%mm0, %%mm1 \n\t" // unpack Low bytes of a + "movq (%%esi,%%ecx,), %%mm2 \n\t" // load b=Prior(x) + "punpcklbw %%mm0, %%mm2 \n\t" // unpack Low bytes of b + // must shift to position Prior(x-bpp) data + "psrlq _ShiftRem, %%mm3 \n\t" + // pav = p - a = (a + b - c) - a = b - c + "movq %%mm2, %%mm4 \n\t" + "punpcklbw %%mm0, %%mm3 \n\t" // unpack Low bytes of c + // pbv = p - b = (a + b - c) - b = a - c + "movq %%mm1, %%mm5 \n\t" + "psubw %%mm3, %%mm4 \n\t" + "pxor %%mm7, %%mm7 \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "movq %%mm4, %%mm6 \n\t" + "psubw %%mm3, %%mm5 \n\t" + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + "pcmpgtw %%mm4, %%mm0 \n\t" // create mask pav bytes < 0 + "paddw %%mm5, %%mm6 \n\t" + "pand %%mm4, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "pcmpgtw %%mm5, %%mm7 \n\t" // create mask pbv bytes < 0 + "psubw %%mm0, %%mm4 \n\t" + "pand %%mm5, %%mm7 \n\t" // only pbv bytes < 0 in mm0 + "psubw %%mm0, %%mm4 \n\t" + "psubw %%mm7, %%mm5 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0 + "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "psubw %%mm7, %%mm5 \n\t" + "psubw %%mm0, %%mm6 \n\t" + // test pa <= pb + "movq %%mm4, %%mm7 \n\t" + "psubw %%mm0, %%mm6 \n\t" + "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb? + "movq %%mm7, %%mm0 \n\t" + // use mm7 mask to merge pa & pb + "pand %%mm7, %%mm5 \n\t" + // use mm0 mask copy to merge a & b + "pand %%mm0, %%mm2 \n\t" + "pandn %%mm4, %%mm7 \n\t" + "pandn %%mm1, %%mm0 \n\t" + "paddw %%mm5, %%mm7 \n\t" + "paddw %%mm2, %%mm0 \n\t" + // test ((pa <= pb)? pa:pb) <= pc + "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc? + "pxor %%mm1, %%mm1 \n\t" + "pand %%mm7, %%mm3 \n\t" + "pandn %%mm0, %%mm7 \n\t" + "paddw %%mm3, %%mm7 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "packuswb %%mm1, %%mm7 \n\t" + "movq -8(%%esi,%%ecx,), %%mm3 \n\t" // load c=Prior(x-bpp) + "pand _ActiveMask, %%mm7 \n\t" + "psrlq _ShiftRem, %%mm3 \n\t" + "movq (%%esi,%%ecx,), %%mm2 \n\t" // load b=Prior(x) step 1 + "paddb (%%edi,%%ecx,), %%mm7 \n\t" // add Paeth predictor and Raw(x) + "movq %%mm2, %%mm6 \n\t" + "movq %%mm7, (%%edi,%%ecx,) \n\t" // write back updated value + "movq -8(%%edi,%%ecx,), %%mm1 \n\t" + "psllq _ShiftBpp, %%mm6 \n\t" + "movq %%mm7, %%mm5 \n\t" + "psrlq _ShiftRem, %%mm1 \n\t" + "por %%mm6, %%mm3 \n\t" + "psllq _ShiftBpp, %%mm5 \n\t" + "punpckhbw %%mm0, %%mm3 \n\t" // unpack High bytes of c + "por %%mm5, %%mm1 \n\t" + // do second set of 4 bytes + "punpckhbw %%mm0, %%mm2 \n\t" // unpack High bytes of b + "punpckhbw %%mm0, %%mm1 \n\t" // unpack High bytes of a + // pav = p - a = (a + b - c) - a = b - c + "movq %%mm2, %%mm4 \n\t" + // pbv = p - b = (a + b - c) - b = a - c + "movq %%mm1, %%mm5 \n\t" + "psubw %%mm3, %%mm4 \n\t" + "pxor %%mm7, %%mm7 \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "movq %%mm4, %%mm6 \n\t" + "psubw %%mm3, %%mm5 \n\t" + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + "pcmpgtw %%mm4, %%mm0 \n\t" // create mask pav bytes < 0 + "paddw %%mm5, %%mm6 \n\t" + "pand %%mm4, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "pcmpgtw %%mm5, %%mm7 \n\t" // create mask pbv bytes < 0 + "psubw %%mm0, %%mm4 \n\t" + "pand %%mm5, %%mm7 \n\t" // only pbv bytes < 0 in mm0 + "psubw %%mm0, %%mm4 \n\t" + "psubw %%mm7, %%mm5 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0 + "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "psubw %%mm7, %%mm5 \n\t" + "psubw %%mm0, %%mm6 \n\t" + // test pa <= pb + "movq %%mm4, %%mm7 \n\t" + "psubw %%mm0, %%mm6 \n\t" + "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb? + "movq %%mm7, %%mm0 \n\t" + // use mm7 mask to merge pa & pb + "pand %%mm7, %%mm5 \n\t" + // use mm0 mask copy to merge a & b + "pand %%mm0, %%mm2 \n\t" + "pandn %%mm4, %%mm7 \n\t" + "pandn %%mm1, %%mm0 \n\t" + "paddw %%mm5, %%mm7 \n\t" + "paddw %%mm2, %%mm0 \n\t" + // test ((pa <= pb)? pa:pb) <= pc + "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc? + "pxor %%mm1, %%mm1 \n\t" + "pand %%mm7, %%mm3 \n\t" + "pandn %%mm0, %%mm7 \n\t" + "pxor %%mm1, %%mm1 \n\t" + "paddw %%mm3, %%mm7 \n\t" + "pxor %%mm0, %%mm0 \n\t" + // step ecx to next set of 8 bytes and repeat loop til done + "addl $8, %%ecx \n\t" + "packuswb %%mm7, %%mm1 \n\t" + "paddb -8(%%edi,%%ecx,), %%mm1 \n\t" // add Paeth predictor with Raw(x) + "cmpl _MMXLength, %%ecx \n\t" + "movq %%mm1, -8(%%edi,%%ecx,) \n\t" // write back updated value + // mm1 will be used as Raw(x-bpp) next loop + "jb paeth_6lp \n\t" + + : "=S" (dummy_value_S), // output regs (dummy) + "=D" (dummy_value_D) + + : "0" (prev_row), // esi // input regs + "1" (row) // edi + + : "%ecx" // clobber list +#if 0 /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm2", "%mm3" + , "%mm4", "%mm5", "%mm6", "%mm7" +#endif + ); + } + break; // end 6 bpp + + case 4: + { + _ActiveMask.use = 0x00000000ffffffffLL; + + __asm__ __volatile__ ( + "movl _dif, %%ecx \n\t" +// preload "movl row, %%edi \n\t" +// preload "movl prev_row, %%esi \n\t" + "pxor %%mm0, %%mm0 \n\t" + // prime the pump: load the first Raw(x-bpp) data set + "movq -8(%%edi,%%ecx,), %%mm1 \n\t" // only time should need to read + // a=Raw(x-bpp) bytes + "paeth_4lp: \n\t" + // do first set of 4 bytes + "movq -8(%%esi,%%ecx,), %%mm3 \n\t" // read c=Prior(x-bpp) bytes + "punpckhbw %%mm0, %%mm1 \n\t" // unpack Low bytes of a + "movq (%%esi,%%ecx,), %%mm2 \n\t" // load b=Prior(x) + "punpcklbw %%mm0, %%mm2 \n\t" // unpack High bytes of b + // pav = p - a = (a + b - c) - a = b - c + "movq %%mm2, %%mm4 \n\t" + "punpckhbw %%mm0, %%mm3 \n\t" // unpack High bytes of c + // pbv = p - b = (a + b - c) - b = a - c + "movq %%mm1, %%mm5 \n\t" + "psubw %%mm3, %%mm4 \n\t" + "pxor %%mm7, %%mm7 \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "movq %%mm4, %%mm6 \n\t" + "psubw %%mm3, %%mm5 \n\t" + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + "pcmpgtw %%mm4, %%mm0 \n\t" // create mask pav bytes < 0 + "paddw %%mm5, %%mm6 \n\t" + "pand %%mm4, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "pcmpgtw %%mm5, %%mm7 \n\t" // create mask pbv bytes < 0 + "psubw %%mm0, %%mm4 \n\t" + "pand %%mm5, %%mm7 \n\t" // only pbv bytes < 0 in mm0 + "psubw %%mm0, %%mm4 \n\t" + "psubw %%mm7, %%mm5 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0 + "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "psubw %%mm7, %%mm5 \n\t" + "psubw %%mm0, %%mm6 \n\t" + // test pa <= pb + "movq %%mm4, %%mm7 \n\t" + "psubw %%mm0, %%mm6 \n\t" + "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb? + "movq %%mm7, %%mm0 \n\t" + // use mm7 mask to merge pa & pb + "pand %%mm7, %%mm5 \n\t" + // use mm0 mask copy to merge a & b + "pand %%mm0, %%mm2 \n\t" + "pandn %%mm4, %%mm7 \n\t" + "pandn %%mm1, %%mm0 \n\t" + "paddw %%mm5, %%mm7 \n\t" + "paddw %%mm2, %%mm0 \n\t" + // test ((pa <= pb)? pa:pb) <= pc + "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc? + "pxor %%mm1, %%mm1 \n\t" + "pand %%mm7, %%mm3 \n\t" + "pandn %%mm0, %%mm7 \n\t" + "paddw %%mm3, %%mm7 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "packuswb %%mm1, %%mm7 \n\t" + "movq (%%esi,%%ecx,), %%mm3 \n\t" // load c=Prior(x-bpp) + "pand _ActiveMask, %%mm7 \n\t" + "movq %%mm3, %%mm2 \n\t" // load b=Prior(x) step 1 + "paddb (%%edi,%%ecx,), %%mm7 \n\t" // add Paeth predictor with Raw(x) + "punpcklbw %%mm0, %%mm3 \n\t" // unpack High bytes of c + "movq %%mm7, (%%edi,%%ecx,) \n\t" // write back updated value + "movq %%mm7, %%mm1 \n\t" // now mm1 will be used as Raw(x-bpp) + // do second set of 4 bytes + "punpckhbw %%mm0, %%mm2 \n\t" // unpack Low bytes of b + "punpcklbw %%mm0, %%mm1 \n\t" // unpack Low bytes of a + // pav = p - a = (a + b - c) - a = b - c + "movq %%mm2, %%mm4 \n\t" + // pbv = p - b = (a + b - c) - b = a - c + "movq %%mm1, %%mm5 \n\t" + "psubw %%mm3, %%mm4 \n\t" + "pxor %%mm7, %%mm7 \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "movq %%mm4, %%mm6 \n\t" + "psubw %%mm3, %%mm5 \n\t" + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + "pcmpgtw %%mm4, %%mm0 \n\t" // create mask pav bytes < 0 + "paddw %%mm5, %%mm6 \n\t" + "pand %%mm4, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "pcmpgtw %%mm5, %%mm7 \n\t" // create mask pbv bytes < 0 + "psubw %%mm0, %%mm4 \n\t" + "pand %%mm5, %%mm7 \n\t" // only pbv bytes < 0 in mm0 + "psubw %%mm0, %%mm4 \n\t" + "psubw %%mm7, %%mm5 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0 + "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "psubw %%mm7, %%mm5 \n\t" + "psubw %%mm0, %%mm6 \n\t" + // test pa <= pb + "movq %%mm4, %%mm7 \n\t" + "psubw %%mm0, %%mm6 \n\t" + "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb? + "movq %%mm7, %%mm0 \n\t" + // use mm7 mask to merge pa & pb + "pand %%mm7, %%mm5 \n\t" + // use mm0 mask copy to merge a & b + "pand %%mm0, %%mm2 \n\t" + "pandn %%mm4, %%mm7 \n\t" + "pandn %%mm1, %%mm0 \n\t" + "paddw %%mm5, %%mm7 \n\t" + "paddw %%mm2, %%mm0 \n\t" + // test ((pa <= pb)? pa:pb) <= pc + "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc? + "pxor %%mm1, %%mm1 \n\t" + "pand %%mm7, %%mm3 \n\t" + "pandn %%mm0, %%mm7 \n\t" + "pxor %%mm1, %%mm1 \n\t" + "paddw %%mm3, %%mm7 \n\t" + "pxor %%mm0, %%mm0 \n\t" + // step ecx to next set of 8 bytes and repeat loop til done + "addl $8, %%ecx \n\t" + "packuswb %%mm7, %%mm1 \n\t" + "paddb -8(%%edi,%%ecx,), %%mm1 \n\t" // add predictor with Raw(x) + "cmpl _MMXLength, %%ecx \n\t" + "movq %%mm1, -8(%%edi,%%ecx,) \n\t" // write back updated value + // mm1 will be used as Raw(x-bpp) next loop + "jb paeth_4lp \n\t" + + : "=S" (dummy_value_S), // output regs (dummy) + "=D" (dummy_value_D) + + : "0" (prev_row), // esi // input regs + "1" (row) // edi + + : "%ecx" // clobber list +#if 0 /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm2", "%mm3" + , "%mm4", "%mm5", "%mm6", "%mm7" +#endif + ); + } + break; // end 4 bpp + + case 8: // bpp == 8 + { + _ActiveMask.use = 0x00000000ffffffffLL; + + __asm__ __volatile__ ( + "movl _dif, %%ecx \n\t" +// preload "movl row, %%edi \n\t" +// preload "movl prev_row, %%esi \n\t" + "pxor %%mm0, %%mm0 \n\t" + // prime the pump: load the first Raw(x-bpp) data set + "movq -8(%%edi,%%ecx,), %%mm1 \n\t" // only time should need to read + // a=Raw(x-bpp) bytes + "paeth_8lp: \n\t" + // do first set of 4 bytes + "movq -8(%%esi,%%ecx,), %%mm3 \n\t" // read c=Prior(x-bpp) bytes + "punpcklbw %%mm0, %%mm1 \n\t" // unpack Low bytes of a + "movq (%%esi,%%ecx,), %%mm2 \n\t" // load b=Prior(x) + "punpcklbw %%mm0, %%mm2 \n\t" // unpack Low bytes of b + // pav = p - a = (a + b - c) - a = b - c + "movq %%mm2, %%mm4 \n\t" + "punpcklbw %%mm0, %%mm3 \n\t" // unpack Low bytes of c + // pbv = p - b = (a + b - c) - b = a - c + "movq %%mm1, %%mm5 \n\t" + "psubw %%mm3, %%mm4 \n\t" + "pxor %%mm7, %%mm7 \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "movq %%mm4, %%mm6 \n\t" + "psubw %%mm3, %%mm5 \n\t" + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + "pcmpgtw %%mm4, %%mm0 \n\t" // create mask pav bytes < 0 + "paddw %%mm5, %%mm6 \n\t" + "pand %%mm4, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "pcmpgtw %%mm5, %%mm7 \n\t" // create mask pbv bytes < 0 + "psubw %%mm0, %%mm4 \n\t" + "pand %%mm5, %%mm7 \n\t" // only pbv bytes < 0 in mm0 + "psubw %%mm0, %%mm4 \n\t" + "psubw %%mm7, %%mm5 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0 + "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "psubw %%mm7, %%mm5 \n\t" + "psubw %%mm0, %%mm6 \n\t" + // test pa <= pb + "movq %%mm4, %%mm7 \n\t" + "psubw %%mm0, %%mm6 \n\t" + "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb? + "movq %%mm7, %%mm0 \n\t" + // use mm7 mask to merge pa & pb + "pand %%mm7, %%mm5 \n\t" + // use mm0 mask copy to merge a & b + "pand %%mm0, %%mm2 \n\t" + "pandn %%mm4, %%mm7 \n\t" + "pandn %%mm1, %%mm0 \n\t" + "paddw %%mm5, %%mm7 \n\t" + "paddw %%mm2, %%mm0 \n\t" + // test ((pa <= pb)? pa:pb) <= pc + "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc? + "pxor %%mm1, %%mm1 \n\t" + "pand %%mm7, %%mm3 \n\t" + "pandn %%mm0, %%mm7 \n\t" + "paddw %%mm3, %%mm7 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "packuswb %%mm1, %%mm7 \n\t" + "movq -8(%%esi,%%ecx,), %%mm3 \n\t" // read c=Prior(x-bpp) bytes + "pand _ActiveMask, %%mm7 \n\t" + "movq (%%esi,%%ecx,), %%mm2 \n\t" // load b=Prior(x) + "paddb (%%edi,%%ecx,), %%mm7 \n\t" // add Paeth predictor with Raw(x) + "punpckhbw %%mm0, %%mm3 \n\t" // unpack High bytes of c + "movq %%mm7, (%%edi,%%ecx,) \n\t" // write back updated value + "movq -8(%%edi,%%ecx,), %%mm1 \n\t" // read a=Raw(x-bpp) bytes + + // do second set of 4 bytes + "punpckhbw %%mm0, %%mm2 \n\t" // unpack High bytes of b + "punpckhbw %%mm0, %%mm1 \n\t" // unpack High bytes of a + // pav = p - a = (a + b - c) - a = b - c + "movq %%mm2, %%mm4 \n\t" + // pbv = p - b = (a + b - c) - b = a - c + "movq %%mm1, %%mm5 \n\t" + "psubw %%mm3, %%mm4 \n\t" + "pxor %%mm7, %%mm7 \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "movq %%mm4, %%mm6 \n\t" + "psubw %%mm3, %%mm5 \n\t" + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + "pcmpgtw %%mm4, %%mm0 \n\t" // create mask pav bytes < 0 + "paddw %%mm5, %%mm6 \n\t" + "pand %%mm4, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "pcmpgtw %%mm5, %%mm7 \n\t" // create mask pbv bytes < 0 + "psubw %%mm0, %%mm4 \n\t" + "pand %%mm5, %%mm7 \n\t" // only pbv bytes < 0 in mm0 + "psubw %%mm0, %%mm4 \n\t" + "psubw %%mm7, %%mm5 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0 + "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "psubw %%mm7, %%mm5 \n\t" + "psubw %%mm0, %%mm6 \n\t" + // test pa <= pb + "movq %%mm4, %%mm7 \n\t" + "psubw %%mm0, %%mm6 \n\t" + "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb? + "movq %%mm7, %%mm0 \n\t" + // use mm7 mask to merge pa & pb + "pand %%mm7, %%mm5 \n\t" + // use mm0 mask copy to merge a & b + "pand %%mm0, %%mm2 \n\t" + "pandn %%mm4, %%mm7 \n\t" + "pandn %%mm1, %%mm0 \n\t" + "paddw %%mm5, %%mm7 \n\t" + "paddw %%mm2, %%mm0 \n\t" + // test ((pa <= pb)? pa:pb) <= pc + "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc? + "pxor %%mm1, %%mm1 \n\t" + "pand %%mm7, %%mm3 \n\t" + "pandn %%mm0, %%mm7 \n\t" + "pxor %%mm1, %%mm1 \n\t" + "paddw %%mm3, %%mm7 \n\t" + "pxor %%mm0, %%mm0 \n\t" + // step ecx to next set of 8 bytes and repeat loop til done + "addl $8, %%ecx \n\t" + "packuswb %%mm7, %%mm1 \n\t" + "paddb -8(%%edi,%%ecx,), %%mm1 \n\t" // add Paeth predictor with Raw(x) + "cmpl _MMXLength, %%ecx \n\t" + "movq %%mm1, -8(%%edi,%%ecx,) \n\t" // write back updated value + // mm1 will be used as Raw(x-bpp) next loop + "jb paeth_8lp \n\t" + + : "=S" (dummy_value_S), // output regs (dummy) + "=D" (dummy_value_D) + + : "0" (prev_row), // esi // input regs + "1" (row) // edi + + : "%ecx" // clobber list +#if 0 /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm2", "%mm3" + , "%mm4", "%mm5", "%mm6", "%mm7" +#endif + ); + } + break; // end 8 bpp + + case 1: // bpp = 1 + case 2: // bpp = 2 + default: // bpp > 8 + { + __asm__ __volatile__ ( +#ifdef __PIC__ + "pushl %%ebx \n\t" // save Global Offset Table index +#endif + "movl _dif, %%ebx \n\t" + "cmpl _FullLength, %%ebx \n\t" + "jnb paeth_dend \n\t" + +// preload "movl row, %%edi \n\t" +// preload "movl prev_row, %%esi \n\t" + // do Paeth decode for remaining bytes + "movl %%ebx, %%edx \n\t" +// preload "subl bpp, %%edx \n\t" // (bpp is preloaded into ecx) + "subl %%ecx, %%edx \n\t" // edx = ebx - bpp + "xorl %%ecx, %%ecx \n\t" // zero ecx before using cl & cx + + "paeth_dlp: \n\t" + "xorl %%eax, %%eax \n\t" + // pav = p - a = (a + b - c) - a = b - c + "movb (%%esi,%%ebx,), %%al \n\t" // load Prior(x) into al + "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl + "subl %%ecx, %%eax \n\t" // subtract Prior(x-bpp) + "movl %%eax, _patemp \n\t" // Save pav for later use + "xorl %%eax, %%eax \n\t" + // pbv = p - b = (a + b - c) - b = a - c + "movb (%%edi,%%edx,), %%al \n\t" // load Raw(x-bpp) into al + "subl %%ecx, %%eax \n\t" // subtract Prior(x-bpp) + "movl %%eax, %%ecx \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "addl _patemp, %%eax \n\t" // pcv = pav + pbv + // pc = abs(pcv) + "testl $0x80000000, %%eax \n\t" + "jz paeth_dpca \n\t" + "negl %%eax \n\t" // reverse sign of neg values + + "paeth_dpca: \n\t" + "movl %%eax, _pctemp \n\t" // save pc for later use + // pb = abs(pbv) + "testl $0x80000000, %%ecx \n\t" + "jz paeth_dpba \n\t" + "negl %%ecx \n\t" // reverse sign of neg values + + "paeth_dpba: \n\t" + "movl %%ecx, _pbtemp \n\t" // save pb for later use + // pa = abs(pav) + "movl _patemp, %%eax \n\t" + "testl $0x80000000, %%eax \n\t" + "jz paeth_dpaa \n\t" + "negl %%eax \n\t" // reverse sign of neg values + + "paeth_dpaa: \n\t" + "movl %%eax, _patemp \n\t" // save pa for later use + // test if pa <= pb + "cmpl %%ecx, %%eax \n\t" + "jna paeth_dabb \n\t" + // pa > pb; now test if pb <= pc + "cmpl _pctemp, %%ecx \n\t" + "jna paeth_dbbc \n\t" + // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp) + "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl + "jmp paeth_dpaeth \n\t" + + "paeth_dbbc: \n\t" + // pb <= pc; Raw(x) = Paeth(x) + Prior(x) + "movb (%%esi,%%ebx,), %%cl \n\t" // load Prior(x) into cl + "jmp paeth_dpaeth \n\t" + + "paeth_dabb: \n\t" + // pa <= pb; now test if pa <= pc + "cmpl _pctemp, %%eax \n\t" + "jna paeth_dabc \n\t" + // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp) + "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl + "jmp paeth_dpaeth \n\t" + + "paeth_dabc: \n\t" + // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp) + "movb (%%edi,%%edx,), %%cl \n\t" // load Raw(x-bpp) into cl + + "paeth_dpaeth: \n\t" + "incl %%ebx \n\t" + "incl %%edx \n\t" + // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256 + "addb %%cl, -1(%%edi,%%ebx,) \n\t" + "cmpl _FullLength, %%ebx \n\t" + "jb paeth_dlp \n\t" + + "paeth_dend: \n\t" +#ifdef __PIC__ + "popl %%ebx \n\t" // index to Global Offset Table +#endif + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "0" (bpp), // ecx // input regs + "1" (prev_row), // esi + "2" (row) // edi + + : "%eax", "%edx" // clobber list +#ifndef __PIC__ + , "%ebx" +#endif + ); + } + return; // No need to go further with this one + + } // end switch (bpp) + + __asm__ __volatile__ ( + // MMX acceleration complete; now do clean-up + // check if any remaining bytes left to decode +#ifdef __PIC__ + "pushl %%ebx \n\t" // save index to Global Offset Table +#endif + "movl _MMXLength, %%ebx \n\t" + "cmpl _FullLength, %%ebx \n\t" + "jnb paeth_end \n\t" +//pre "movl row, %%edi \n\t" +//pre "movl prev_row, %%esi \n\t" + // do Paeth decode for remaining bytes + "movl %%ebx, %%edx \n\t" +//pre "subl bpp, %%edx \n\t" // (bpp is preloaded into ecx) + "subl %%ecx, %%edx \n\t" // edx = ebx - bpp + "xorl %%ecx, %%ecx \n\t" // zero ecx before using cl & cx below + + "paeth_lp2: \n\t" + "xorl %%eax, %%eax \n\t" + // pav = p - a = (a + b - c) - a = b - c + "movb (%%esi,%%ebx,), %%al \n\t" // load Prior(x) into al + "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl + "subl %%ecx, %%eax \n\t" // subtract Prior(x-bpp) + "movl %%eax, _patemp \n\t" // Save pav for later use + "xorl %%eax, %%eax \n\t" + // pbv = p - b = (a + b - c) - b = a - c + "movb (%%edi,%%edx,), %%al \n\t" // load Raw(x-bpp) into al + "subl %%ecx, %%eax \n\t" // subtract Prior(x-bpp) + "movl %%eax, %%ecx \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "addl _patemp, %%eax \n\t" // pcv = pav + pbv + // pc = abs(pcv) + "testl $0x80000000, %%eax \n\t" + "jz paeth_pca2 \n\t" + "negl %%eax \n\t" // reverse sign of neg values + + "paeth_pca2: \n\t" + "movl %%eax, _pctemp \n\t" // save pc for later use + // pb = abs(pbv) + "testl $0x80000000, %%ecx \n\t" + "jz paeth_pba2 \n\t" + "negl %%ecx \n\t" // reverse sign of neg values + + "paeth_pba2: \n\t" + "movl %%ecx, _pbtemp \n\t" // save pb for later use + // pa = abs(pav) + "movl _patemp, %%eax \n\t" + "testl $0x80000000, %%eax \n\t" + "jz paeth_paa2 \n\t" + "negl %%eax \n\t" // reverse sign of neg values + + "paeth_paa2: \n\t" + "movl %%eax, _patemp \n\t" // save pa for later use + // test if pa <= pb + "cmpl %%ecx, %%eax \n\t" + "jna paeth_abb2 \n\t" + // pa > pb; now test if pb <= pc + "cmpl _pctemp, %%ecx \n\t" + "jna paeth_bbc2 \n\t" + // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp) + "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl + "jmp paeth_paeth2 \n\t" + + "paeth_bbc2: \n\t" + // pb <= pc; Raw(x) = Paeth(x) + Prior(x) + "movb (%%esi,%%ebx,), %%cl \n\t" // load Prior(x) into cl + "jmp paeth_paeth2 \n\t" + + "paeth_abb2: \n\t" + // pa <= pb; now test if pa <= pc + "cmpl _pctemp, %%eax \n\t" + "jna paeth_abc2 \n\t" + // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp) + "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl + "jmp paeth_paeth2 \n\t" + + "paeth_abc2: \n\t" + // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp) + "movb (%%edi,%%edx,), %%cl \n\t" // load Raw(x-bpp) into cl + + "paeth_paeth2: \n\t" + "incl %%ebx \n\t" + "incl %%edx \n\t" + // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256 + "addb %%cl, -1(%%edi,%%ebx,) \n\t" + "cmpl _FullLength, %%ebx \n\t" + "jb paeth_lp2 \n\t" + + "paeth_end: \n\t" + "EMMS \n\t" // end MMX; prep for poss. FP instrs. +#ifdef __PIC__ + "popl %%ebx \n\t" // restore index to Global Offset Table +#endif + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "0" (bpp), // ecx // input regs + "1" (prev_row), // esi + "2" (row) // edi + + : "%eax", "%edx" // clobber list (no input regs!) +#ifndef __PIC__ + , "%ebx" +#endif + ); + +} /* end png_read_filter_row_mmx_paeth() */ +#endif + + + + +#ifdef PNG_THREAD_UNSAFE_OK +//===========================================================================// +// // +// P N G _ R E A D _ F I L T E R _ R O W _ M M X _ S U B // +// // +//===========================================================================// + +// Optimized code for PNG Sub filter decoder + +static void /* PRIVATE */ +png_read_filter_row_mmx_sub(png_row_infop row_info, png_bytep row) +{ + int bpp; + int dummy_value_a; + int dummy_value_D; + + bpp = (row_info->pixel_depth + 7) >> 3; // calc number of bytes per pixel + _FullLength = row_info->rowbytes - bpp; // number of bytes to filter + + __asm__ __volatile__ ( +//pre "movl row, %%edi \n\t" + "movl %%edi, %%esi \n\t" // lp = row +//pre "movl bpp, %%eax \n\t" + "addl %%eax, %%edi \n\t" // rp = row + bpp +//irr "xorl %%eax, %%eax \n\t" + // get # of bytes to alignment + "movl %%edi, _dif \n\t" // take start of row + "addl $0xf, _dif \n\t" // add 7 + 8 to incr past + // alignment boundary + "xorl %%ecx, %%ecx \n\t" + "andl $0xfffffff8, _dif \n\t" // mask to alignment boundary + "subl %%edi, _dif \n\t" // subtract from start ==> value + "jz sub_go \n\t" // ecx at alignment + + "sub_lp1: \n\t" // fix alignment + "movb (%%esi,%%ecx,), %%al \n\t" + "addb %%al, (%%edi,%%ecx,) \n\t" + "incl %%ecx \n\t" + "cmpl _dif, %%ecx \n\t" + "jb sub_lp1 \n\t" + + "sub_go: \n\t" + "movl _FullLength, %%eax \n\t" + "movl %%eax, %%edx \n\t" + "subl %%ecx, %%edx \n\t" // subtract alignment fix + "andl $0x00000007, %%edx \n\t" // calc bytes over mult of 8 + "subl %%edx, %%eax \n\t" // drop over bytes from length + "movl %%eax, _MMXLength \n\t" + + : "=a" (dummy_value_a), // 0 // output regs (dummy) + "=D" (dummy_value_D) // 1 + + : "0" (bpp), // eax // input regs + "1" (row) // edi + + : "%esi", "%ecx", "%edx" // clobber list + +#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm2", "%mm3" + , "%mm4", "%mm5", "%mm6", "%mm7" +#endif + ); + + // now do the math for the rest of the row + switch (bpp) + { + case 3: + { + _ActiveMask.use = 0x0000ffffff000000LL; + _ShiftBpp.use = 24; // == 3 * 8 + _ShiftRem.use = 40; // == 64 - 24 + + __asm__ __volatile__ ( +// preload "movl row, %%edi \n\t" + "movq _ActiveMask, %%mm7 \n\t" // load _ActiveMask for 2nd + // active byte group + "movl %%edi, %%esi \n\t" // lp = row +// preload "movl bpp, %%eax \n\t" + "addl %%eax, %%edi \n\t" // rp = row + bpp + "movq %%mm7, %%mm6 \n\t" + "movl _dif, %%edx \n\t" + "psllq _ShiftBpp, %%mm6 \n\t" // move mask in mm6 to cover + // 3rd active byte group + // prime the pump: load the first Raw(x-bpp) data set + "movq -8(%%edi,%%edx,), %%mm1 \n\t" + + "sub_3lp: \n\t" // shift data for adding first + "psrlq _ShiftRem, %%mm1 \n\t" // bpp bytes (no need for mask; + // shift clears inactive bytes) + // add 1st active group + "movq (%%edi,%%edx,), %%mm0 \n\t" + "paddb %%mm1, %%mm0 \n\t" + + // add 2nd active group + "movq %%mm0, %%mm1 \n\t" // mov updated Raws to mm1 + "psllq _ShiftBpp, %%mm1 \n\t" // shift data to pos. correctly + "pand %%mm7, %%mm1 \n\t" // mask to use 2nd active group + "paddb %%mm1, %%mm0 \n\t" + + // add 3rd active group + "movq %%mm0, %%mm1 \n\t" // mov updated Raws to mm1 + "psllq _ShiftBpp, %%mm1 \n\t" // shift data to pos. correctly + "pand %%mm6, %%mm1 \n\t" // mask to use 3rd active group + "addl $8, %%edx \n\t" + "paddb %%mm1, %%mm0 \n\t" + + "cmpl _MMXLength, %%edx \n\t" + "movq %%mm0, -8(%%edi,%%edx,) \n\t" // write updated Raws to array + "movq %%mm0, %%mm1 \n\t" // prep 1st add at top of loop + "jb sub_3lp \n\t" + + : "=a" (dummy_value_a), // 0 // output regs (dummy) + "=D" (dummy_value_D) // 1 + + : "0" (bpp), // eax // input regs + "1" (row) // edi + + : "%edx", "%esi" // clobber list +#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm6", "%mm7" +#endif + ); + } + break; + + case 1: + { + __asm__ __volatile__ ( + "movl _dif, %%edx \n\t" +// preload "movl row, %%edi \n\t" + "cmpl _FullLength, %%edx \n\t" + "jnb sub_1end \n\t" + "movl %%edi, %%esi \n\t" // lp = row + "xorl %%eax, %%eax \n\t" +// preload "movl bpp, %%eax \n\t" + "addl %%eax, %%edi \n\t" // rp = row + bpp + + "sub_1lp: \n\t" + "movb (%%esi,%%edx,), %%al \n\t" + "addb %%al, (%%edi,%%edx,) \n\t" + "incl %%edx \n\t" + "cmpl _FullLength, %%edx \n\t" + "jb sub_1lp \n\t" + + "sub_1end: \n\t" + + : "=a" (dummy_value_a), // 0 // output regs (dummy) + "=D" (dummy_value_D) // 1 + + : "0" (bpp), // eax // input regs + "1" (row) // edi + + : "%edx", "%esi" // clobber list + ); + } + return; + + case 6: + case 4: + //case 7: // GRR BOGUS + //case 5: // GRR BOGUS + { + _ShiftBpp.use = bpp << 3; + _ShiftRem.use = 64 - _ShiftBpp.use; + + __asm__ __volatile__ ( +// preload "movl row, %%edi \n\t" + "movl _dif, %%edx \n\t" + "movl %%edi, %%esi \n\t" // lp = row +// preload "movl bpp, %%eax \n\t" + "addl %%eax, %%edi \n\t" // rp = row + bpp + + // prime the pump: load the first Raw(x-bpp) data set + "movq -8(%%edi,%%edx,), %%mm1 \n\t" + + "sub_4lp: \n\t" // shift data for adding first + "psrlq _ShiftRem, %%mm1 \n\t" // bpp bytes (no need for mask; + // shift clears inactive bytes) + "movq (%%edi,%%edx,), %%mm0 \n\t" + "paddb %%mm1, %%mm0 \n\t" + + // add 2nd active group + "movq %%mm0, %%mm1 \n\t" // mov updated Raws to mm1 + "psllq _ShiftBpp, %%mm1 \n\t" // shift data to pos. correctly + "addl $8, %%edx \n\t" + "paddb %%mm1, %%mm0 \n\t" + + "cmpl _MMXLength, %%edx \n\t" + "movq %%mm0, -8(%%edi,%%edx,) \n\t" + "movq %%mm0, %%mm1 \n\t" // prep 1st add at top of loop + "jb sub_4lp \n\t" + + : "=a" (dummy_value_a), // 0 // output regs (dummy) + "=D" (dummy_value_D) // 1 + + : "0" (bpp), // eax // input regs + "1" (row) // edi + + : "%edx", "%esi" // clobber list +#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1" +#endif + ); + } + break; + + case 2: + { + _ActiveMask.use = 0x00000000ffff0000LL; + _ShiftBpp.use = 16; // == 2 * 8 + _ShiftRem.use = 48; // == 64 - 16 + + __asm__ __volatile__ ( + "movq _ActiveMask, %%mm7 \n\t" // load _ActiveMask for 2nd + // active byte group + "movl _dif, %%edx \n\t" + "movq %%mm7, %%mm6 \n\t" +// preload "movl row, %%edi \n\t" + "psllq _ShiftBpp, %%mm6 \n\t" // move mask in mm6 to cover + // 3rd active byte group + "movl %%edi, %%esi \n\t" // lp = row + "movq %%mm6, %%mm5 \n\t" +// preload "movl bpp, %%eax \n\t" + "addl %%eax, %%edi \n\t" // rp = row + bpp + "psllq _ShiftBpp, %%mm5 \n\t" // move mask in mm5 to cover + // 4th active byte group + // prime the pump: load the first Raw(x-bpp) data set + "movq -8(%%edi,%%edx,), %%mm1 \n\t" + + "sub_2lp: \n\t" // shift data for adding first + "psrlq _ShiftRem, %%mm1 \n\t" // bpp bytes (no need for mask; + // shift clears inactive bytes) + // add 1st active group + "movq (%%edi,%%edx,), %%mm0 \n\t" + "paddb %%mm1, %%mm0 \n\t" + + // add 2nd active group + "movq %%mm0, %%mm1 \n\t" // mov updated Raws to mm1 + "psllq _ShiftBpp, %%mm1 \n\t" // shift data to pos. correctly + "pand %%mm7, %%mm1 \n\t" // mask to use 2nd active group + "paddb %%mm1, %%mm0 \n\t" + + // add 3rd active group + "movq %%mm0, %%mm1 \n\t" // mov updated Raws to mm1 + "psllq _ShiftBpp, %%mm1 \n\t" // shift data to pos. correctly + "pand %%mm6, %%mm1 \n\t" // mask to use 3rd active group + "paddb %%mm1, %%mm0 \n\t" + + // add 4th active group + "movq %%mm0, %%mm1 \n\t" // mov updated Raws to mm1 + "psllq _ShiftBpp, %%mm1 \n\t" // shift data to pos. correctly + "pand %%mm5, %%mm1 \n\t" // mask to use 4th active group + "addl $8, %%edx \n\t" + "paddb %%mm1, %%mm0 \n\t" + "cmpl _MMXLength, %%edx \n\t" + "movq %%mm0, -8(%%edi,%%edx,) \n\t" // write updated Raws to array + "movq %%mm0, %%mm1 \n\t" // prep 1st add at top of loop + "jb sub_2lp \n\t" + + : "=a" (dummy_value_a), // 0 // output regs (dummy) + "=D" (dummy_value_D) // 1 + + : "0" (bpp), // eax // input regs + "1" (row) // edi + + : "%edx", "%esi" // clobber list +#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm5", "%mm6", "%mm7" +#endif + ); + } + break; + + case 8: + { + __asm__ __volatile__ ( +// preload "movl row, %%edi \n\t" + "movl _dif, %%edx \n\t" + "movl %%edi, %%esi \n\t" // lp = row +// preload "movl bpp, %%eax \n\t" + "addl %%eax, %%edi \n\t" // rp = row + bpp + "movl _MMXLength, %%ecx \n\t" + + // prime the pump: load the first Raw(x-bpp) data set + "movq -8(%%edi,%%edx,), %%mm7 \n\t" + "andl $0x0000003f, %%ecx \n\t" // calc bytes over mult of 64 + + "sub_8lp: \n\t" + "movq (%%edi,%%edx,), %%mm0 \n\t" // load Sub(x) for 1st 8 bytes + "paddb %%mm7, %%mm0 \n\t" + "movq 8(%%edi,%%edx,), %%mm1 \n\t" // load Sub(x) for 2nd 8 bytes + "movq %%mm0, (%%edi,%%edx,) \n\t" // write Raw(x) for 1st 8 bytes + + // Now mm0 will be used as Raw(x-bpp) for the 2nd group of 8 bytes. + // This will be repeated for each group of 8 bytes with the 8th + // group being used as the Raw(x-bpp) for the 1st group of the + // next loop. + + "paddb %%mm0, %%mm1 \n\t" + "movq 16(%%edi,%%edx,), %%mm2 \n\t" // load Sub(x) for 3rd 8 bytes + "movq %%mm1, 8(%%edi,%%edx,) \n\t" // write Raw(x) for 2nd 8 bytes + "paddb %%mm1, %%mm2 \n\t" + "movq 24(%%edi,%%edx,), %%mm3 \n\t" // load Sub(x) for 4th 8 bytes + "movq %%mm2, 16(%%edi,%%edx,) \n\t" // write Raw(x) for 3rd 8 bytes + "paddb %%mm2, %%mm3 \n\t" + "movq 32(%%edi,%%edx,), %%mm4 \n\t" // load Sub(x) for 5th 8 bytes + "movq %%mm3, 24(%%edi,%%edx,) \n\t" // write Raw(x) for 4th 8 bytes + "paddb %%mm3, %%mm4 \n\t" + "movq 40(%%edi,%%edx,), %%mm5 \n\t" // load Sub(x) for 6th 8 bytes + "movq %%mm4, 32(%%edi,%%edx,) \n\t" // write Raw(x) for 5th 8 bytes + "paddb %%mm4, %%mm5 \n\t" + "movq 48(%%edi,%%edx,), %%mm6 \n\t" // load Sub(x) for 7th 8 bytes + "movq %%mm5, 40(%%edi,%%edx,) \n\t" // write Raw(x) for 6th 8 bytes + "paddb %%mm5, %%mm6 \n\t" + "movq 56(%%edi,%%edx,), %%mm7 \n\t" // load Sub(x) for 8th 8 bytes + "movq %%mm6, 48(%%edi,%%edx,) \n\t" // write Raw(x) for 7th 8 bytes + "addl $64, %%edx \n\t" + "paddb %%mm6, %%mm7 \n\t" + "cmpl %%ecx, %%edx \n\t" + "movq %%mm7, -8(%%edi,%%edx,) \n\t" // write Raw(x) for 8th 8 bytes + "jb sub_8lp \n\t" + + "cmpl _MMXLength, %%edx \n\t" + "jnb sub_8lt8 \n\t" + + "sub_8lpA: \n\t" + "movq (%%edi,%%edx,), %%mm0 \n\t" + "addl $8, %%edx \n\t" + "paddb %%mm7, %%mm0 \n\t" + "cmpl _MMXLength, %%edx \n\t" + "movq %%mm0, -8(%%edi,%%edx,) \n\t" // -8 to offset early addl edx + "movq %%mm0, %%mm7 \n\t" // move calculated Raw(x) data + // to mm1 to be new Raw(x-bpp) + // for next loop + "jb sub_8lpA \n\t" + + "sub_8lt8: \n\t" + + : "=a" (dummy_value_a), // 0 // output regs (dummy) + "=D" (dummy_value_D) // 1 + + : "0" (bpp), // eax // input regs + "1" (row) // edi + + : "%ecx", "%edx", "%esi" // clobber list +#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" +#endif + ); + } + break; + + default: // bpp greater than 8 bytes GRR BOGUS + { + __asm__ __volatile__ ( + "movl _dif, %%edx \n\t" +// preload "movl row, %%edi \n\t" + "movl %%edi, %%esi \n\t" // lp = row +// preload "movl bpp, %%eax \n\t" + "addl %%eax, %%edi \n\t" // rp = row + bpp + + "sub_Alp: \n\t" + "movq (%%edi,%%edx,), %%mm0 \n\t" + "movq (%%esi,%%edx,), %%mm1 \n\t" + "addl $8, %%edx \n\t" + "paddb %%mm1, %%mm0 \n\t" + "cmpl _MMXLength, %%edx \n\t" + "movq %%mm0, -8(%%edi,%%edx,) \n\t" // mov does not affect flags; + // -8 to offset addl edx + "jb sub_Alp \n\t" + + : "=a" (dummy_value_a), // 0 // output regs (dummy) + "=D" (dummy_value_D) // 1 + + : "0" (bpp), // eax // input regs + "1" (row) // edi + + : "%edx", "%esi" // clobber list +#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1" +#endif + ); + } + break; + + } // end switch (bpp) + + __asm__ __volatile__ ( + "movl _MMXLength, %%edx \n\t" +//pre "movl row, %%edi \n\t" + "cmpl _FullLength, %%edx \n\t" + "jnb sub_end \n\t" + + "movl %%edi, %%esi \n\t" // lp = row +//pre "movl bpp, %%eax \n\t" + "addl %%eax, %%edi \n\t" // rp = row + bpp + "xorl %%eax, %%eax \n\t" + + "sub_lp2: \n\t" + "movb (%%esi,%%edx,), %%al \n\t" + "addb %%al, (%%edi,%%edx,) \n\t" + "incl %%edx \n\t" + "cmpl _FullLength, %%edx \n\t" + "jb sub_lp2 \n\t" + + "sub_end: \n\t" + "EMMS \n\t" // end MMX instructions + + : "=a" (dummy_value_a), // 0 // output regs (dummy) + "=D" (dummy_value_D) // 1 + + : "0" (bpp), // eax // input regs + "1" (row) // edi + + : "%edx", "%esi" // clobber list + ); + +} // end of png_read_filter_row_mmx_sub() +#endif + + + + +//===========================================================================// +// // +// P N G _ R E A D _ F I L T E R _ R O W _ M M X _ U P // +// // +//===========================================================================// + +// Optimized code for PNG Up filter decoder + +static void /* PRIVATE */ +png_read_filter_row_mmx_up(png_row_infop row_info, png_bytep row, + png_bytep prev_row) +{ + png_uint_32 len; + int dummy_value_d; // fix 'forbidden register 3 (dx) was spilled' error + int dummy_value_S; + int dummy_value_D; + + len = row_info->rowbytes; // number of bytes to filter + + __asm__ __volatile__ ( +//pre "movl row, %%edi \n\t" + // get # of bytes to alignment +#ifdef __PIC__ + "pushl %%ebx \n\t" +#endif + "movl %%edi, %%ecx \n\t" + "xorl %%ebx, %%ebx \n\t" + "addl $0x7, %%ecx \n\t" + "xorl %%eax, %%eax \n\t" + "andl $0xfffffff8, %%ecx \n\t" +//pre "movl prev_row, %%esi \n\t" + "subl %%edi, %%ecx \n\t" + "jz up_go \n\t" + + "up_lp1: \n\t" // fix alignment + "movb (%%edi,%%ebx,), %%al \n\t" + "addb (%%esi,%%ebx,), %%al \n\t" + "incl %%ebx \n\t" + "cmpl %%ecx, %%ebx \n\t" + "movb %%al, -1(%%edi,%%ebx,) \n\t" // mov does not affect flags; -1 to + "jb up_lp1 \n\t" // offset incl ebx + + "up_go: \n\t" +//pre "movl len, %%edx \n\t" + "movl %%edx, %%ecx \n\t" + "subl %%ebx, %%edx \n\t" // subtract alignment fix + "andl $0x0000003f, %%edx \n\t" // calc bytes over mult of 64 + "subl %%edx, %%ecx \n\t" // drop over bytes from length + + // unrolled loop - use all MMX registers and interleave to reduce + // number of branch instructions (loops) and reduce partial stalls + "up_loop: \n\t" + "movq (%%esi,%%ebx,), %%mm1 \n\t" + "movq (%%edi,%%ebx,), %%mm0 \n\t" + "movq 8(%%esi,%%ebx,), %%mm3 \n\t" + "paddb %%mm1, %%mm0 \n\t" + "movq 8(%%edi,%%ebx,), %%mm2 \n\t" + "movq %%mm0, (%%edi,%%ebx,) \n\t" + "paddb %%mm3, %%mm2 \n\t" + "movq 16(%%esi,%%ebx,), %%mm5 \n\t" + "movq %%mm2, 8(%%edi,%%ebx,) \n\t" + "movq 16(%%edi,%%ebx,), %%mm4 \n\t" + "movq 24(%%esi,%%ebx,), %%mm7 \n\t" + "paddb %%mm5, %%mm4 \n\t" + "movq 24(%%edi,%%ebx,), %%mm6 \n\t" + "movq %%mm4, 16(%%edi,%%ebx,) \n\t" + "paddb %%mm7, %%mm6 \n\t" + "movq 32(%%esi,%%ebx,), %%mm1 \n\t" + "movq %%mm6, 24(%%edi,%%ebx,) \n\t" + "movq 32(%%edi,%%ebx,), %%mm0 \n\t" + "movq 40(%%esi,%%ebx,), %%mm3 \n\t" + "paddb %%mm1, %%mm0 \n\t" + "movq 40(%%edi,%%ebx,), %%mm2 \n\t" + "movq %%mm0, 32(%%edi,%%ebx,) \n\t" + "paddb %%mm3, %%mm2 \n\t" + "movq 48(%%esi,%%ebx,), %%mm5 \n\t" + "movq %%mm2, 40(%%edi,%%ebx,) \n\t" + "movq 48(%%edi,%%ebx,), %%mm4 \n\t" + "movq 56(%%esi,%%ebx,), %%mm7 \n\t" + "paddb %%mm5, %%mm4 \n\t" + "movq 56(%%edi,%%ebx,), %%mm6 \n\t" + "movq %%mm4, 48(%%edi,%%ebx,) \n\t" + "addl $64, %%ebx \n\t" + "paddb %%mm7, %%mm6 \n\t" + "cmpl %%ecx, %%ebx \n\t" + "movq %%mm6, -8(%%edi,%%ebx,) \n\t" // (+56)movq does not affect flags; + "jb up_loop \n\t" // -8 to offset addl ebx + + "cmpl $0, %%edx \n\t" // test for bytes over mult of 64 + "jz up_end \n\t" + + "cmpl $8, %%edx \n\t" // test for less than 8 bytes + "jb up_lt8 \n\t" // [added by lcreeve at netins.net] + + "addl %%edx, %%ecx \n\t" + "andl $0x00000007, %%edx \n\t" // calc bytes over mult of 8 + "subl %%edx, %%ecx \n\t" // drop over bytes from length + "jz up_lt8 \n\t" + + "up_lpA: \n\t" // use MMX regs to update 8 bytes sim. + "movq (%%esi,%%ebx,), %%mm1 \n\t" + "movq (%%edi,%%ebx,), %%mm0 \n\t" + "addl $8, %%ebx \n\t" + "paddb %%mm1, %%mm0 \n\t" + "cmpl %%ecx, %%ebx \n\t" + "movq %%mm0, -8(%%edi,%%ebx,) \n\t" // movq does not affect flags; -8 to + "jb up_lpA \n\t" // offset add ebx + "cmpl $0, %%edx \n\t" // test for bytes over mult of 8 + "jz up_end \n\t" + + "up_lt8: \n\t" + "xorl %%eax, %%eax \n\t" + "addl %%edx, %%ecx \n\t" // move over byte count into counter + + "up_lp2: \n\t" // use x86 regs for remaining bytes + "movb (%%edi,%%ebx,), %%al \n\t" + "addb (%%esi,%%ebx,), %%al \n\t" + "incl %%ebx \n\t" + "cmpl %%ecx, %%ebx \n\t" + "movb %%al, -1(%%edi,%%ebx,) \n\t" // mov does not affect flags; -1 to + "jb up_lp2 \n\t" // offset inc ebx + + "up_end: \n\t" + "EMMS \n\t" // conversion of filtered row complete +#ifdef __PIC__ + "popl %%ebx \n\t" +#endif + + : "=d" (dummy_value_d), // 0 // output regs (dummy) + "=S" (dummy_value_S), // 1 + "=D" (dummy_value_D) // 2 + + : "0" (len), // edx // input regs + "1" (prev_row), // esi + "2" (row) // edi + + : "%eax", "%ecx" // clobber list (no input regs!) +#ifndef __PIC__ + , "%ebx" +#endif + +#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm2", "%mm3" + , "%mm4", "%mm5", "%mm6", "%mm7" +#endif + ); + +} // end of png_read_filter_row_mmx_up() + +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ + + + + +/*===========================================================================*/ +/* */ +/* P N G _ R E A D _ F I L T E R _ R O W */ +/* */ +/*===========================================================================*/ + + +/* Optimized png_read_filter_row routines */ + +void /* PRIVATE */ +png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep + row, png_bytep prev_row, int filter) +{ +#ifdef PNG_DEBUG + char filnm[10]; +#endif + +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) +/* GRR: these are superseded by png_ptr->asm_flags: */ +#define UseMMX_sub 1 // GRR: converted 20000730 +#define UseMMX_up 1 // GRR: converted 20000729 +#define UseMMX_avg 1 // GRR: converted 20000828 (+ 16-bit bugfix 20000916) +#define UseMMX_paeth 1 // GRR: converted 20000828 + + if (_mmx_supported == 2) { + /* this should have happened in png_init_mmx_flags() already */ +#if !defined(PNG_1_0_X) + png_warning(png_ptr, "asm_flags may not have been initialized"); +#endif + png_mmx_support(); + } +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ + +#ifdef PNG_DEBUG + png_debug(1, "in png_read_filter_row (pnggccrd.c)\n"); + switch (filter) + { + case 0: sprintf(filnm, "none"); + break; + case 1: sprintf(filnm, "sub-%s", +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK) +#if !defined(PNG_1_0_X) + (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_SUB)? "MMX" : +#endif +#endif +"x86"); + break; + case 2: sprintf(filnm, "up-%s", +#ifdef PNG_ASSEMBLER_CODE_SUPPORTED +#if !defined(PNG_1_0_X) + (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_UP)? "MMX" : +#endif +#endif + "x86"); + break; + case 3: sprintf(filnm, "avg-%s", +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK) +#if !defined(PNG_1_0_X) + (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_AVG)? "MMX" : +#endif +#endif + "x86"); + break; + case 4: sprintf(filnm, "Paeth-%s", +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK) +#if !defined(PNG_1_0_X) + (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_PAETH)? "MMX": +#endif +#endif +"x86"); + break; + default: sprintf(filnm, "unknw"); + break; + } + png_debug2(0, "row_number=%5ld, %5s, ", png_ptr->row_number, filnm); + png_debug1(0, "row=0x%08lx, ", (unsigned long)row); + png_debug2(0, "pixdepth=%2d, bytes=%d, ", (int)row_info->pixel_depth, + (int)((row_info->pixel_depth + 7) >> 3)); + png_debug1(0,"rowbytes=%8ld\n", row_info->rowbytes); +#endif /* PNG_DEBUG */ + + switch (filter) + { + case PNG_FILTER_VALUE_NONE: + break; + + case PNG_FILTER_VALUE_SUB: +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK) +#if !defined(PNG_1_0_X) + if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_SUB) && + (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) && + (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold)) +#else + if (_mmx_supported) +#endif + { + png_read_filter_row_mmx_sub(row_info, row); + } + else +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ + { + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; + png_bytep rp = row + bpp; + png_bytep lp = row; + + for (i = bpp; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff); + rp++; + } + } /* end !UseMMX_sub */ + break; + + case PNG_FILTER_VALUE_UP: +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) +#if !defined(PNG_1_0_X) + if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_UP) && + (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) && + (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold)) +#else + if (_mmx_supported) +#endif + { + png_read_filter_row_mmx_up(row_info, row, prev_row); + } + else +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ + { + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + png_bytep rp = row; + png_bytep pp = prev_row; + + for (i = 0; i < istop; ++i) + { + *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff); + rp++; + } + } /* end !UseMMX_up */ + break; + + case PNG_FILTER_VALUE_AVG: +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK) +#if !defined(PNG_1_0_X) + if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_AVG) && + (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) && + (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold)) +#else + if (_mmx_supported) +#endif + { + png_read_filter_row_mmx_avg(row_info, row, prev_row); + } + else +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ + { + png_uint_32 i; + png_bytep rp = row; + png_bytep pp = prev_row; + png_bytep lp = row; + png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; + png_uint_32 istop = row_info->rowbytes - bpp; + + for (i = 0; i < bpp; i++) + { + *rp = (png_byte)(((int)(*rp) + + ((int)(*pp++) >> 1)) & 0xff); + rp++; + } + + for (i = 0; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + + ((int)(*pp++ + *lp++) >> 1)) & 0xff); + rp++; + } + } /* end !UseMMX_avg */ + break; + + case PNG_FILTER_VALUE_PAETH: +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK) +#if !defined(PNG_1_0_X) + if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_PAETH) && + (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) && + (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold)) +#else + if (_mmx_supported) +#endif + { + png_read_filter_row_mmx_paeth(row_info, row, prev_row); + } + else +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ + { + png_uint_32 i; + png_bytep rp = row; + png_bytep pp = prev_row; + png_bytep lp = row; + png_bytep cp = prev_row; + png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; + png_uint_32 istop = row_info->rowbytes - bpp; + + for (i = 0; i < bpp; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff); + rp++; + } + + for (i = 0; i < istop; i++) /* use leftover rp,pp */ + { + int a, b, c, pa, pb, pc, p; + + a = *lp++; + b = *pp++; + c = *cp++; + + p = b - c; + pc = a - c; + +#ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +#else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +#endif + + /* + if (pa <= pb && pa <= pc) + p = a; + else if (pb <= pc) + p = b; + else + p = c; + */ + + p = (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c; + + *rp = (png_byte)(((int)(*rp) + p) & 0xff); + rp++; + } + } /* end !UseMMX_paeth */ + break; + + default: + png_warning(png_ptr, "Ignoring bad row-filter type"); + *row=0; + break; + } +} + +#endif /* PNG_HAVE_ASSEMBLER_READ_FILTER_ROW */ + + +/*===========================================================================*/ +/* */ +/* P N G _ M M X _ S U P P O R T */ +/* */ +/*===========================================================================*/ + +/* GRR NOTES: (1) the following code assumes 386 or better (pushfl/popfl) + * (2) all instructions compile with gcc 2.7.2.3 and later + * (3) the function is moved down here to prevent gcc from + * inlining it in multiple places and then barfing be- + * cause the ".NOT_SUPPORTED" label is multiply defined + * [is there a way to signal that a *single* function should + * not be inlined? is there a way to modify the label for + * each inlined instance, e.g., by appending _1, _2, etc.? + * maybe if don't use leading "." in label name? (nope...sigh)] + */ + +int PNGAPI +png_mmx_support(void) +{ +#if defined(PNG_MMX_CODE_SUPPORTED) + __asm__ __volatile__ ( + "pushl %%ebx \n\t" // ebx gets clobbered by CPUID instruction + "pushl %%ecx \n\t" // so does ecx... + "pushl %%edx \n\t" // ...and edx (but ecx & edx safe on Linux) +// ".byte 0x66 \n\t" // convert 16-bit pushf to 32-bit pushfd +// "pushf \n\t" // 16-bit pushf + "pushfl \n\t" // save Eflag to stack + "popl %%eax \n\t" // get Eflag from stack into eax + "movl %%eax, %%ecx \n\t" // make another copy of Eflag in ecx + "xorl $0x200000, %%eax \n\t" // toggle ID bit in Eflag (i.e., bit 21) + "pushl %%eax \n\t" // save modified Eflag back to stack +// ".byte 0x66 \n\t" // convert 16-bit popf to 32-bit popfd +// "popf \n\t" // 16-bit popf + "popfl \n\t" // restore modified value to Eflag reg + "pushfl \n\t" // save Eflag to stack + "popl %%eax \n\t" // get Eflag from stack + "pushl %%ecx \n\t" // save original Eflag to stack + "popfl \n\t" // restore original Eflag + "xorl %%ecx, %%eax \n\t" // compare new Eflag with original Eflag + "jz 0f \n\t" // if same, CPUID instr. is not supported + + "xorl %%eax, %%eax \n\t" // set eax to zero +// ".byte 0x0f, 0xa2 \n\t" // CPUID instruction (two-byte opcode) + "cpuid \n\t" // get the CPU identification info + "cmpl $1, %%eax \n\t" // make sure eax return non-zero value + "jl 0f \n\t" // if eax is zero, MMX is not supported + + "xorl %%eax, %%eax \n\t" // set eax to zero and... + "incl %%eax \n\t" // ...increment eax to 1. This pair is + // faster than the instruction "mov eax, 1" + "cpuid \n\t" // get the CPU identification info again + "andl $0x800000, %%edx \n\t" // mask out all bits but MMX bit (23) + "cmpl $0, %%edx \n\t" // 0 = MMX not supported + "jz 0f \n\t" // non-zero = yes, MMX IS supported + + "movl $1, %%eax \n\t" // set return value to 1 + "jmp 1f \n\t" // DONE: have MMX support + + "0: \n\t" // .NOT_SUPPORTED: target label for jump instructions + "movl $0, %%eax \n\t" // set return value to 0 + "1: \n\t" // .RETURN: target label for jump instructions + "movl %%eax, _mmx_supported \n\t" // save in global static variable, too + "popl %%edx \n\t" // restore edx + "popl %%ecx \n\t" // restore ecx + "popl %%ebx \n\t" // restore ebx + +// "ret \n\t" // DONE: no MMX support + // (fall through to standard C "ret") + + : // output list (none) + + : // any variables used on input (none) + + : "%eax" // clobber list +// , "%ebx", "%ecx", "%edx" // GRR: we handle these manually +// , "memory" // if write to a variable gcc thought was in a reg +// , "cc" // "condition codes" (flag bits) + ); +#else + _mmx_supported = 0; +#endif /* PNG_MMX_CODE_SUPPORTED */ + + return _mmx_supported; +} + + +#endif /* PNG_USE_PNGGCCRD */ diff --git a/syslinux/com32/lib/libpng/pngget.c b/syslinux/com32/lib/libpng/pngget.c new file mode 100644 index 0000000..8eefa77 --- /dev/null +++ b/syslinux/com32/lib/libpng/pngget.c @@ -0,0 +1,934 @@ + +/* pngget.c - retrieval of values from info struct + * + * libpng 1.2.8 - December 3, 2004 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2004 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + */ + +#define PNG_INTERNAL +#include "png.h" + +png_uint_32 PNGAPI +png_get_valid(png_structp png_ptr, png_infop info_ptr, png_uint_32 flag) +{ + if (png_ptr != NULL && info_ptr != NULL) + return(info_ptr->valid & flag); + else + return(0); +} + +png_uint_32 PNGAPI +png_get_rowbytes(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return(info_ptr->rowbytes); + else + return(0); +} + +#if defined(PNG_INFO_IMAGE_SUPPORTED) +png_bytepp PNGAPI +png_get_rows(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return(info_ptr->row_pointers); + else + return(0); +} +#endif + +#ifdef PNG_EASY_ACCESS_SUPPORTED +/* easy access to info, added in libpng-0.99 */ +png_uint_32 PNGAPI +png_get_image_width(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + { + return info_ptr->width; + } + return (0); +} + +png_uint_32 PNGAPI +png_get_image_height(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + { + return info_ptr->height; + } + return (0); +} + +png_byte PNGAPI +png_get_bit_depth(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + { + return info_ptr->bit_depth; + } + return (0); +} + +png_byte PNGAPI +png_get_color_type(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + { + return info_ptr->color_type; + } + return (0); +} + +png_byte PNGAPI +png_get_filter_type(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + { + return info_ptr->filter_type; + } + return (0); +} + +png_byte PNGAPI +png_get_interlace_type(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + { + return info_ptr->interlace_type; + } + return (0); +} + +png_byte PNGAPI +png_get_compression_type(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + { + return info_ptr->compression_type; + } + return (0); +} + +png_uint_32 PNGAPI +png_get_x_pixels_per_meter(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) +#if defined(PNG_pHYs_SUPPORTED) + if (info_ptr->valid & PNG_INFO_pHYs) + { + png_debug1(1, "in %s retrieval function\n", "png_get_x_pixels_per_meter"); + if(info_ptr->phys_unit_type != PNG_RESOLUTION_METER) + return (0); + else return (info_ptr->x_pixels_per_unit); + } +#else + return (0); +#endif + return (0); +} + +png_uint_32 PNGAPI +png_get_y_pixels_per_meter(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) +#if defined(PNG_pHYs_SUPPORTED) + if (info_ptr->valid & PNG_INFO_pHYs) + { + png_debug1(1, "in %s retrieval function\n", "png_get_y_pixels_per_meter"); + if(info_ptr->phys_unit_type != PNG_RESOLUTION_METER) + return (0); + else return (info_ptr->y_pixels_per_unit); + } +#else + return (0); +#endif + return (0); +} + +png_uint_32 PNGAPI +png_get_pixels_per_meter(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) +#if defined(PNG_pHYs_SUPPORTED) + if (info_ptr->valid & PNG_INFO_pHYs) + { + png_debug1(1, "in %s retrieval function\n", "png_get_pixels_per_meter"); + if(info_ptr->phys_unit_type != PNG_RESOLUTION_METER || + info_ptr->x_pixels_per_unit != info_ptr->y_pixels_per_unit) + return (0); + else return (info_ptr->x_pixels_per_unit); + } +#else + return (0); +#endif + return (0); +} + +#ifdef PNG_FLOATING_POINT_SUPPORTED +float PNGAPI +png_get_pixel_aspect_ratio(png_structp png_ptr, png_infop info_ptr) + { + if (png_ptr != NULL && info_ptr != NULL) +#if defined(PNG_pHYs_SUPPORTED) + if (info_ptr->valid & PNG_INFO_pHYs) + { + png_debug1(1, "in %s retrieval function\n", "png_get_aspect_ratio"); + if (info_ptr->x_pixels_per_unit == 0) + return ((float)0.0); + else + return ((float)((float)info_ptr->y_pixels_per_unit + /(float)info_ptr->x_pixels_per_unit)); + } +#else + return (0.0); +#endif + return ((float)0.0); +} +#endif + +png_int_32 PNGAPI +png_get_x_offset_microns(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) +#if defined(PNG_oFFs_SUPPORTED) + if (info_ptr->valid & PNG_INFO_oFFs) + { + png_debug1(1, "in %s retrieval function\n", "png_get_x_offset_microns"); + if(info_ptr->offset_unit_type != PNG_OFFSET_MICROMETER) + return (0); + else return (info_ptr->x_offset); + } +#else + return (0); +#endif + return (0); +} + +png_int_32 PNGAPI +png_get_y_offset_microns(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) +#if defined(PNG_oFFs_SUPPORTED) + if (info_ptr->valid & PNG_INFO_oFFs) + { + png_debug1(1, "in %s retrieval function\n", "png_get_y_offset_microns"); + if(info_ptr->offset_unit_type != PNG_OFFSET_MICROMETER) + return (0); + else return (info_ptr->y_offset); + } +#else + return (0); +#endif + return (0); +} + +png_int_32 PNGAPI +png_get_x_offset_pixels(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) +#if defined(PNG_oFFs_SUPPORTED) + if (info_ptr->valid & PNG_INFO_oFFs) + { + png_debug1(1, "in %s retrieval function\n", "png_get_x_offset_microns"); + if(info_ptr->offset_unit_type != PNG_OFFSET_PIXEL) + return (0); + else return (info_ptr->x_offset); + } +#else + return (0); +#endif + return (0); +} + +png_int_32 PNGAPI +png_get_y_offset_pixels(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) +#if defined(PNG_oFFs_SUPPORTED) + if (info_ptr->valid & PNG_INFO_oFFs) + { + png_debug1(1, "in %s retrieval function\n", "png_get_y_offset_microns"); + if(info_ptr->offset_unit_type != PNG_OFFSET_PIXEL) + return (0); + else return (info_ptr->y_offset); + } +#else + return (0); +#endif + return (0); +} + +#if defined(PNG_INCH_CONVERSIONS) && defined(PNG_FLOATING_POINT_SUPPORTED) +png_uint_32 PNGAPI +png_get_pixels_per_inch(png_structp png_ptr, png_infop info_ptr) +{ + return ((png_uint_32)((float)png_get_pixels_per_meter(png_ptr, info_ptr) + *.0254 +.5)); +} + +png_uint_32 PNGAPI +png_get_x_pixels_per_inch(png_structp png_ptr, png_infop info_ptr) +{ + return ((png_uint_32)((float)png_get_x_pixels_per_meter(png_ptr, info_ptr) + *.0254 +.5)); +} + +png_uint_32 PNGAPI +png_get_y_pixels_per_inch(png_structp png_ptr, png_infop info_ptr) +{ + return ((png_uint_32)((float)png_get_y_pixels_per_meter(png_ptr, info_ptr) + *.0254 +.5)); +} + +float PNGAPI +png_get_x_offset_inches(png_structp png_ptr, png_infop info_ptr) +{ + return ((float)png_get_x_offset_microns(png_ptr, info_ptr) + *.00003937); +} + +float PNGAPI +png_get_y_offset_inches(png_structp png_ptr, png_infop info_ptr) +{ + return ((float)png_get_y_offset_microns(png_ptr, info_ptr) + *.00003937); +} + +#if defined(PNG_pHYs_SUPPORTED) +png_uint_32 PNGAPI +png_get_pHYs_dpi(png_structp png_ptr, png_infop info_ptr, + png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type) +{ + png_uint_32 retval = 0; + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) + { + png_debug1(1, "in %s retrieval function\n", "pHYs"); + if (res_x != NULL) + { + *res_x = info_ptr->x_pixels_per_unit; + retval |= PNG_INFO_pHYs; + } + if (res_y != NULL) + { + *res_y = info_ptr->y_pixels_per_unit; + retval |= PNG_INFO_pHYs; + } + if (unit_type != NULL) + { + *unit_type = (int)info_ptr->phys_unit_type; + retval |= PNG_INFO_pHYs; + if(*unit_type == 1) + { + if (res_x != NULL) *res_x = (png_uint_32)(*res_x * .0254 + .50); + if (res_y != NULL) *res_y = (png_uint_32)(*res_y * .0254 + .50); + } + } + } + return (retval); +} +#endif /* PNG_pHYs_SUPPORTED */ +#endif /* PNG_INCH_CONVERSIONS && PNG_FLOATING_POINT_SUPPORTED */ + +/* png_get_channels really belongs in here, too, but it's been around longer */ + +#endif /* PNG_EASY_ACCESS_SUPPORTED */ + +png_byte PNGAPI +png_get_channels(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return(info_ptr->channels); + else + return (0); +} + +png_bytep PNGAPI +png_get_signature(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return(info_ptr->signature); + else + return (NULL); +} + +#if defined(PNG_bKGD_SUPPORTED) +png_uint_32 PNGAPI +png_get_bKGD(png_structp png_ptr, png_infop info_ptr, + png_color_16p *background) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) + && background != NULL) + { + png_debug1(1, "in %s retrieval function\n", "bKGD"); + *background = &(info_ptr->background); + return (PNG_INFO_bKGD); + } + return (0); +} +#endif + +#if defined(PNG_cHRM_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_cHRM(png_structp png_ptr, png_infop info_ptr, + double *white_x, double *white_y, double *red_x, double *red_y, + double *green_x, double *green_y, double *blue_x, double *blue_y) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)) + { + png_debug1(1, "in %s retrieval function\n", "cHRM"); + if (white_x != NULL) + *white_x = (double)info_ptr->x_white; + if (white_y != NULL) + *white_y = (double)info_ptr->y_white; + if (red_x != NULL) + *red_x = (double)info_ptr->x_red; + if (red_y != NULL) + *red_y = (double)info_ptr->y_red; + if (green_x != NULL) + *green_x = (double)info_ptr->x_green; + if (green_y != NULL) + *green_y = (double)info_ptr->y_green; + if (blue_x != NULL) + *blue_x = (double)info_ptr->x_blue; + if (blue_y != NULL) + *blue_y = (double)info_ptr->y_blue; + return (PNG_INFO_cHRM); + } + return (0); +} +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_cHRM_fixed(png_structp png_ptr, png_infop info_ptr, + png_fixed_point *white_x, png_fixed_point *white_y, png_fixed_point *red_x, + png_fixed_point *red_y, png_fixed_point *green_x, png_fixed_point *green_y, + png_fixed_point *blue_x, png_fixed_point *blue_y) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)) + { + png_debug1(1, "in %s retrieval function\n", "cHRM"); + if (white_x != NULL) + *white_x = info_ptr->int_x_white; + if (white_y != NULL) + *white_y = info_ptr->int_y_white; + if (red_x != NULL) + *red_x = info_ptr->int_x_red; + if (red_y != NULL) + *red_y = info_ptr->int_y_red; + if (green_x != NULL) + *green_x = info_ptr->int_x_green; + if (green_y != NULL) + *green_y = info_ptr->int_y_green; + if (blue_x != NULL) + *blue_x = info_ptr->int_x_blue; + if (blue_y != NULL) + *blue_y = info_ptr->int_y_blue; + return (PNG_INFO_cHRM); + } + return (0); +} +#endif +#endif + +#if defined(PNG_gAMA_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_gAMA(png_structp png_ptr, png_infop info_ptr, double *file_gamma) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA) + && file_gamma != NULL) + { + png_debug1(1, "in %s retrieval function\n", "gAMA"); + *file_gamma = (double)info_ptr->gamma; + return (PNG_INFO_gAMA); + } + return (0); +} +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_gAMA_fixed(png_structp png_ptr, png_infop info_ptr, + png_fixed_point *int_file_gamma) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA) + && int_file_gamma != NULL) + { + png_debug1(1, "in %s retrieval function\n", "gAMA"); + *int_file_gamma = info_ptr->int_gamma; + return (PNG_INFO_gAMA); + } + return (0); +} +#endif +#endif + +#if defined(PNG_sRGB_SUPPORTED) +png_uint_32 PNGAPI +png_get_sRGB(png_structp png_ptr, png_infop info_ptr, int *file_srgb_intent) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB) + && file_srgb_intent != NULL) + { + png_debug1(1, "in %s retrieval function\n", "sRGB"); + *file_srgb_intent = (int)info_ptr->srgb_intent; + return (PNG_INFO_sRGB); + } + return (0); +} +#endif + +#if defined(PNG_iCCP_SUPPORTED) +png_uint_32 PNGAPI +png_get_iCCP(png_structp png_ptr, png_infop info_ptr, + png_charpp name, int *compression_type, + png_charpp profile, png_uint_32 *proflen) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP) + && name != NULL && profile != NULL && proflen != NULL) + { + png_debug1(1, "in %s retrieval function\n", "iCCP"); + *name = info_ptr->iccp_name; + *profile = info_ptr->iccp_profile; + /* compression_type is a dummy so the API won't have to change + if we introduce multiple compression types later. */ + *proflen = (int)info_ptr->iccp_proflen; + *compression_type = (int)info_ptr->iccp_compression; + return (PNG_INFO_iCCP); + } + return (0); +} +#endif + +#if defined(PNG_sPLT_SUPPORTED) +png_uint_32 PNGAPI +png_get_sPLT(png_structp png_ptr, png_infop info_ptr, + png_sPLT_tpp spalettes) +{ + if (png_ptr != NULL && info_ptr != NULL && spalettes != NULL) + *spalettes = info_ptr->splt_palettes; + return ((png_uint_32)info_ptr->splt_palettes_num); +} +#endif + +#if defined(PNG_hIST_SUPPORTED) +png_uint_32 PNGAPI +png_get_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_16p *hist) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) + && hist != NULL) + { + png_debug1(1, "in %s retrieval function\n", "hIST"); + *hist = info_ptr->hist; + return (PNG_INFO_hIST); + } + return (0); +} +#endif + +png_uint_32 PNGAPI +png_get_IHDR(png_structp png_ptr, png_infop info_ptr, + png_uint_32 *width, png_uint_32 *height, int *bit_depth, + int *color_type, int *interlace_type, int *compression_type, + int *filter_type) + +{ + if (png_ptr != NULL && info_ptr != NULL && width != NULL && height != NULL && + bit_depth != NULL && color_type != NULL) + { + png_debug1(1, "in %s retrieval function\n", "IHDR"); + *width = info_ptr->width; + *height = info_ptr->height; + *bit_depth = info_ptr->bit_depth; + if (info_ptr->bit_depth < 1 || info_ptr->bit_depth > 16) + png_error(png_ptr, "Invalid bit depth"); + *color_type = info_ptr->color_type; + if (info_ptr->color_type > 6) + png_error(png_ptr, "Invalid color type"); + if (compression_type != NULL) + *compression_type = info_ptr->compression_type; + if (filter_type != NULL) + *filter_type = info_ptr->filter_type; + if (interlace_type != NULL) + *interlace_type = info_ptr->interlace_type; + + /* check for potential overflow of rowbytes */ + if (*width == 0 || *width > PNG_UINT_31_MAX) + png_error(png_ptr, "Invalid image width"); + if (*height == 0 || *height > PNG_UINT_31_MAX) + png_error(png_ptr, "Invalid image height"); + if (info_ptr->width > (PNG_UINT_32_MAX + >> 3) /* 8-byte RGBA pixels */ + - 64 /* bigrowbuf hack */ + - 1 /* filter byte */ + - 7*8 /* rounding of width to multiple of 8 pixels */ + - 8) /* extra max_pixel_depth pad */ + { + png_warning(png_ptr, + "Width too large for libpng to process image data."); + } + return (1); + } + return (0); +} + +#if defined(PNG_oFFs_SUPPORTED) +png_uint_32 PNGAPI +png_get_oFFs(png_structp png_ptr, png_infop info_ptr, + png_int_32 *offset_x, png_int_32 *offset_y, int *unit_type) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs) + && offset_x != NULL && offset_y != NULL && unit_type != NULL) + { + png_debug1(1, "in %s retrieval function\n", "oFFs"); + *offset_x = info_ptr->x_offset; + *offset_y = info_ptr->y_offset; + *unit_type = (int)info_ptr->offset_unit_type; + return (PNG_INFO_oFFs); + } + return (0); +} +#endif + +#if defined(PNG_pCAL_SUPPORTED) +png_uint_32 PNGAPI +png_get_pCAL(png_structp png_ptr, png_infop info_ptr, + png_charp *purpose, png_int_32 *X0, png_int_32 *X1, int *type, int *nparams, + png_charp *units, png_charpp *params) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL) + && purpose != NULL && X0 != NULL && X1 != NULL && type != NULL && + nparams != NULL && units != NULL && params != NULL) + { + png_debug1(1, "in %s retrieval function\n", "pCAL"); + *purpose = info_ptr->pcal_purpose; + *X0 = info_ptr->pcal_X0; + *X1 = info_ptr->pcal_X1; + *type = (int)info_ptr->pcal_type; + *nparams = (int)info_ptr->pcal_nparams; + *units = info_ptr->pcal_units; + *params = info_ptr->pcal_params; + return (PNG_INFO_pCAL); + } + return (0); +} +#endif + +#if defined(PNG_sCAL_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_sCAL(png_structp png_ptr, png_infop info_ptr, + int *unit, double *width, double *height) +{ + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_sCAL)) + { + *unit = info_ptr->scal_unit; + *width = info_ptr->scal_pixel_width; + *height = info_ptr->scal_pixel_height; + return (PNG_INFO_sCAL); + } + return(0); +} +#else +#ifdef PNG_FIXED_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_sCAL_s(png_structp png_ptr, png_infop info_ptr, + int *unit, png_charpp width, png_charpp height) +{ + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_sCAL)) + { + *unit = info_ptr->scal_unit; + *width = info_ptr->scal_s_width; + *height = info_ptr->scal_s_height; + return (PNG_INFO_sCAL); + } + return(0); +} +#endif +#endif +#endif + +#if defined(PNG_pHYs_SUPPORTED) +png_uint_32 PNGAPI +png_get_pHYs(png_structp png_ptr, png_infop info_ptr, + png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type) +{ + png_uint_32 retval = 0; + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pHYs)) + { + png_debug1(1, "in %s retrieval function\n", "pHYs"); + if (res_x != NULL) + { + *res_x = info_ptr->x_pixels_per_unit; + retval |= PNG_INFO_pHYs; + } + if (res_y != NULL) + { + *res_y = info_ptr->y_pixels_per_unit; + retval |= PNG_INFO_pHYs; + } + if (unit_type != NULL) + { + *unit_type = (int)info_ptr->phys_unit_type; + retval |= PNG_INFO_pHYs; + } + } + return (retval); +} +#endif + +png_uint_32 PNGAPI +png_get_PLTE(png_structp png_ptr, png_infop info_ptr, png_colorp *palette, + int *num_palette) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_PLTE) + && palette != NULL) + { + png_debug1(1, "in %s retrieval function\n", "PLTE"); + *palette = info_ptr->palette; + *num_palette = info_ptr->num_palette; + png_debug1(3, "num_palette = %d\n", *num_palette); + return (PNG_INFO_PLTE); + } + return (0); +} + +#if defined(PNG_sBIT_SUPPORTED) +png_uint_32 PNGAPI +png_get_sBIT(png_structp png_ptr, png_infop info_ptr, png_color_8p *sig_bit) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT) + && sig_bit != NULL) + { + png_debug1(1, "in %s retrieval function\n", "sBIT"); + *sig_bit = &(info_ptr->sig_bit); + return (PNG_INFO_sBIT); + } + return (0); +} +#endif + +#if defined(PNG_TEXT_SUPPORTED) +png_uint_32 PNGAPI +png_get_text(png_structp png_ptr, png_infop info_ptr, png_textp *text_ptr, + int *num_text) +{ + if (png_ptr != NULL && info_ptr != NULL && info_ptr->num_text > 0) + { + png_debug1(1, "in %s retrieval function\n", + (png_ptr->chunk_name[0] == '\0' ? "text" + : (png_const_charp)png_ptr->chunk_name)); + if (text_ptr != NULL) + *text_ptr = info_ptr->text; + if (num_text != NULL) + *num_text = info_ptr->num_text; + return ((png_uint_32)info_ptr->num_text); + } + if (num_text != NULL) + *num_text = 0; + return(0); +} +#endif + +#if defined(PNG_tIME_SUPPORTED) +png_uint_32 PNGAPI +png_get_tIME(png_structp png_ptr, png_infop info_ptr, png_timep *mod_time) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME) + && mod_time != NULL) + { + png_debug1(1, "in %s retrieval function\n", "tIME"); + *mod_time = &(info_ptr->mod_time); + return (PNG_INFO_tIME); + } + return (0); +} +#endif + +#if defined(PNG_tRNS_SUPPORTED) +png_uint_32 PNGAPI +png_get_tRNS(png_structp png_ptr, png_infop info_ptr, + png_bytep *trans, int *num_trans, png_color_16p *trans_values) +{ + png_uint_32 retval = 0; + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) + { + png_debug1(1, "in %s retrieval function\n", "tRNS"); + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (trans != NULL) + { + *trans = info_ptr->trans; + retval |= PNG_INFO_tRNS; + } + if (trans_values != NULL) + *trans_values = &(info_ptr->trans_values); + } + else /* if (info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) */ + { + if (trans_values != NULL) + { + *trans_values = &(info_ptr->trans_values); + retval |= PNG_INFO_tRNS; + } + if(trans != NULL) + *trans = NULL; + } + if(num_trans != NULL) + { + *num_trans = info_ptr->num_trans; + retval |= PNG_INFO_tRNS; + } + } + return (retval); +} +#endif + +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) +png_uint_32 PNGAPI +png_get_unknown_chunks(png_structp png_ptr, png_infop info_ptr, + png_unknown_chunkpp unknowns) +{ + if (png_ptr != NULL && info_ptr != NULL && unknowns != NULL) + *unknowns = info_ptr->unknown_chunks; + return ((png_uint_32)info_ptr->unknown_chunks_num); +} +#endif + +#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) +png_byte PNGAPI +png_get_rgb_to_gray_status (png_structp png_ptr) +{ + return (png_byte)(png_ptr? png_ptr->rgb_to_gray_status : 0); +} +#endif + +#if defined(PNG_USER_CHUNKS_SUPPORTED) +png_voidp PNGAPI +png_get_user_chunk_ptr(png_structp png_ptr) +{ + return (png_ptr? png_ptr->user_chunk_ptr : NULL); +} +#endif + +#ifdef PNG_WRITE_SUPPORTED +png_uint_32 PNGAPI +png_get_compression_buffer_size(png_structp png_ptr) +{ + return (png_uint_32)(png_ptr? png_ptr->zbuf_size : 0L); +} +#endif + +#ifndef PNG_1_0_X +#ifdef PNG_ASSEMBLER_CODE_SUPPORTED +/* this function was added to libpng 1.2.0 and should exist by default */ +png_uint_32 PNGAPI +png_get_asm_flags (png_structp png_ptr) +{ + return (png_uint_32)(png_ptr? png_ptr->asm_flags : 0L); +} + +/* this function was added to libpng 1.2.0 and should exist by default */ +png_uint_32 PNGAPI +png_get_asm_flagmask (int flag_select) +{ + png_uint_32 settable_asm_flags = 0; + + if (flag_select & PNG_SELECT_READ) + settable_asm_flags |= + PNG_ASM_FLAG_MMX_READ_COMBINE_ROW | + PNG_ASM_FLAG_MMX_READ_INTERLACE | + PNG_ASM_FLAG_MMX_READ_FILTER_SUB | + PNG_ASM_FLAG_MMX_READ_FILTER_UP | + PNG_ASM_FLAG_MMX_READ_FILTER_AVG | + PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ; + /* no non-MMX flags yet */ + +#if 0 + /* GRR: no write-flags yet, either, but someday... */ + if (flag_select & PNG_SELECT_WRITE) + settable_asm_flags |= + PNG_ASM_FLAG_MMX_WRITE_ [whatever] ; +#endif /* 0 */ + + return settable_asm_flags; /* _theoretically_ settable capabilities only */ +} +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ + + +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) + /* GRR: could add this: && defined(PNG_MMX_CODE_SUPPORTED) */ +/* this function was added to libpng 1.2.0 */ +png_uint_32 PNGAPI +png_get_mmx_flagmask (int flag_select, int *compilerID) +{ + png_uint_32 settable_mmx_flags = 0; + + if (flag_select & PNG_SELECT_READ) + settable_mmx_flags |= + PNG_ASM_FLAG_MMX_READ_COMBINE_ROW | + PNG_ASM_FLAG_MMX_READ_INTERLACE | + PNG_ASM_FLAG_MMX_READ_FILTER_SUB | + PNG_ASM_FLAG_MMX_READ_FILTER_UP | + PNG_ASM_FLAG_MMX_READ_FILTER_AVG | + PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ; +#if 0 + /* GRR: no MMX write support yet, but someday... */ + if (flag_select & PNG_SELECT_WRITE) + settable_mmx_flags |= + PNG_ASM_FLAG_MMX_WRITE_ [whatever] ; +#endif /* 0 */ + + if (compilerID != NULL) { +#ifdef PNG_USE_PNGVCRD + *compilerID = 1; /* MSVC */ +#else +#ifdef PNG_USE_PNGGCCRD + *compilerID = 2; /* gcc/gas */ +#else + *compilerID = -1; /* unknown (i.e., no asm/MMX code compiled) */ +#endif +#endif + } + + return settable_mmx_flags; /* _theoretically_ settable capabilities only */ +} + +/* this function was added to libpng 1.2.0 */ +png_byte PNGAPI +png_get_mmx_bitdepth_threshold (png_structp png_ptr) +{ + return (png_byte)(png_ptr? png_ptr->mmx_bitdepth_threshold : 0); +} + +/* this function was added to libpng 1.2.0 */ +png_uint_32 PNGAPI +png_get_mmx_rowbytes_threshold (png_structp png_ptr) +{ + return (png_uint_32)(png_ptr? png_ptr->mmx_rowbytes_threshold : 0L); +} +#endif /* ?PNG_ASSEMBLER_CODE_SUPPORTED */ + +#ifdef PNG_SET_USER_LIMITS_SUPPORTED +/* these functions were added to libpng 1.2.6 */ +png_uint_32 PNGAPI +png_get_user_width_max (png_structp png_ptr) +{ + return (png_ptr? png_ptr->user_width_max : 0); +} +png_uint_32 PNGAPI +png_get_user_height_max (png_structp png_ptr) +{ + return (png_ptr? png_ptr->user_height_max : 0); +} +#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */ + +#endif /* ?PNG_1_0_X */ diff --git a/syslinux/com32/lib/libpng/pngmem.c b/syslinux/com32/lib/libpng/pngmem.c new file mode 100644 index 0000000..f1cb693 --- /dev/null +++ b/syslinux/com32/lib/libpng/pngmem.c @@ -0,0 +1,595 @@ + +/* pngmem.c - stub functions for memory allocation + * + * libpng version 1.2.8 - December 3, 2004 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2004 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This file provides a location for all memory allocation. Users who + * need special memory handling are expected to supply replacement + * functions for png_malloc() and png_free(), and to use + * png_create_read_struct_2() and png_create_write_struct_2() to + * identify the replacement functions. + */ + +#define PNG_INTERNAL +#include "png.h" + +/* Borland DOS special memory handler */ +#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__) +/* if you change this, be sure to change the one in png.h also */ + +/* Allocate memory for a png_struct. The malloc and memset can be replaced + by a single call to calloc() if this is thought to improve performance. */ +png_voidp /* PRIVATE */ +png_create_struct(int type) +{ +#ifdef PNG_USER_MEM_SUPPORTED + return (png_create_struct_2(type, png_malloc_ptr_NULL, png_voidp_NULL)); +} + +/* Alternate version of png_create_struct, for use with user-defined malloc. */ +png_voidp /* PRIVATE */ +png_create_struct_2(int type, png_malloc_ptr malloc_fn, png_voidp mem_ptr) +{ +#endif /* PNG_USER_MEM_SUPPORTED */ + png_size_t size; + png_voidp struct_ptr; + + if (type == PNG_STRUCT_INFO) + size = png_sizeof(png_info); + else if (type == PNG_STRUCT_PNG) + size = png_sizeof(png_struct); + else + return (png_get_copyright(NULL)); + +#ifdef PNG_USER_MEM_SUPPORTED + if(malloc_fn != NULL) + { + png_struct dummy_struct; + png_structp png_ptr = &dummy_struct; + png_ptr->mem_ptr=mem_ptr; + struct_ptr = (*(malloc_fn))(png_ptr, (png_uint_32)size); + } + else +#endif /* PNG_USER_MEM_SUPPORTED */ + struct_ptr = (png_voidp)farmalloc(size); + if (struct_ptr != NULL) + png_memset(struct_ptr, 0, size); + return (struct_ptr); +} + +/* Free memory allocated by a png_create_struct() call */ +void /* PRIVATE */ +png_destroy_struct(png_voidp struct_ptr) +{ +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2(struct_ptr, png_free_ptr_NULL, png_voidp_NULL); +} + +/* Free memory allocated by a png_create_struct() call */ +void /* PRIVATE */ +png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn, + png_voidp mem_ptr) +{ +#endif + if (struct_ptr != NULL) + { +#ifdef PNG_USER_MEM_SUPPORTED + if(free_fn != NULL) + { + png_struct dummy_struct; + png_structp png_ptr = &dummy_struct; + png_ptr->mem_ptr=mem_ptr; + (*(free_fn))(png_ptr, struct_ptr); + return; + } +#endif /* PNG_USER_MEM_SUPPORTED */ + farfree (struct_ptr); + } +} + +/* Allocate memory. For reasonable files, size should never exceed + * 64K. However, zlib may allocate more then 64K if you don't tell + * it not to. See zconf.h and png.h for more information. zlib does + * need to allocate exactly 64K, so whatever you call here must + * have the ability to do that. + * + * Borland seems to have a problem in DOS mode for exactly 64K. + * It gives you a segment with an offset of 8 (perhaps to store its + * memory stuff). zlib doesn't like this at all, so we have to + * detect and deal with it. This code should not be needed in + * Windows or OS/2 modes, and only in 16 bit mode. This code has + * been updated by Alexander Lehmann for version 0.89 to waste less + * memory. + * + * Note that we can't use png_size_t for the "size" declaration, + * since on some systems a png_size_t is a 16-bit quantity, and as a + * result, we would be truncating potentially larger memory requests + * (which should cause a fatal error) and introducing major problems. + */ + +png_voidp PNGAPI +png_malloc(png_structp png_ptr, png_uint_32 size) +{ + png_voidp ret; + + if (png_ptr == NULL || size == 0) + return (NULL); + +#ifdef PNG_USER_MEM_SUPPORTED + if(png_ptr->malloc_fn != NULL) + ret = ((png_voidp)(*(png_ptr->malloc_fn))(png_ptr, (png_size_t)size)); + else + ret = (png_malloc_default(png_ptr, size)); + if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) + png_error(png_ptr, "Out of memory!"); + return (ret); +} + +png_voidp PNGAPI +png_malloc_default(png_structp png_ptr, png_uint_32 size) +{ + png_voidp ret; +#endif /* PNG_USER_MEM_SUPPORTED */ + +#ifdef PNG_MAX_MALLOC_64K + if (size > (png_uint_32)65536L) + { + png_warning(png_ptr, "Cannot Allocate > 64K"); + ret = NULL; + } + else +#endif + + if (size != (size_t)size) + ret = NULL; + else if (size == (png_uint_32)65536L) + { + if (png_ptr->offset_table == NULL) + { + /* try to see if we need to do any of this fancy stuff */ + ret = farmalloc(size); + if (ret == NULL || ((png_size_t)ret & 0xffff)) + { + int num_blocks; + png_uint_32 total_size; + png_bytep table; + int i; + png_byte huge * hptr; + + if (ret != NULL) + { + farfree(ret); + ret = NULL; + } + + if(png_ptr->zlib_window_bits > 14) + num_blocks = (int)(1 << (png_ptr->zlib_window_bits - 14)); + else + num_blocks = 1; + if (png_ptr->zlib_mem_level >= 7) + num_blocks += (int)(1 << (png_ptr->zlib_mem_level - 7)); + else + num_blocks++; + + total_size = ((png_uint_32)65536L) * (png_uint_32)num_blocks+16; + + table = farmalloc(total_size); + + if (table == NULL) + { +#ifndef PNG_USER_MEM_SUPPORTED + if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) + png_error(png_ptr, "Out Of Memory."); /* Note "O" and "M" */ + else + png_warning(png_ptr, "Out Of Memory."); +#endif + return (NULL); + } + + if ((png_size_t)table & 0xfff0) + { +#ifndef PNG_USER_MEM_SUPPORTED + if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) + png_error(png_ptr, + "Farmalloc didn't return normalized pointer"); + else + png_warning(png_ptr, + "Farmalloc didn't return normalized pointer"); +#endif + return (NULL); + } + + png_ptr->offset_table = table; + png_ptr->offset_table_ptr = farmalloc(num_blocks * + png_sizeof (png_bytep)); + + if (png_ptr->offset_table_ptr == NULL) + { +#ifndef PNG_USER_MEM_SUPPORTED + if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) + png_error(png_ptr, "Out Of memory."); /* Note "O" and "M" */ + else + png_warning(png_ptr, "Out Of memory."); +#endif + return (NULL); + } + + hptr = (png_byte huge *)table; + if ((png_size_t)hptr & 0xf) + { + hptr = (png_byte huge *)((long)(hptr) & 0xfffffff0L); + hptr = hptr + 16L; /* "hptr += 16L" fails on Turbo C++ 3.0 */ + } + for (i = 0; i < num_blocks; i++) + { + png_ptr->offset_table_ptr[i] = (png_bytep)hptr; + hptr = hptr + (png_uint_32)65536L; /* "+=" fails on TC++3.0 */ + } + + png_ptr->offset_table_number = num_blocks; + png_ptr->offset_table_count = 0; + png_ptr->offset_table_count_free = 0; + } + } + + if (png_ptr->offset_table_count >= png_ptr->offset_table_number) + { +#ifndef PNG_USER_MEM_SUPPORTED + if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) + png_error(png_ptr, "Out of Memory."); /* Note "o" and "M" */ + else + png_warning(png_ptr, "Out of Memory."); +#endif + return (NULL); + } + + ret = png_ptr->offset_table_ptr[png_ptr->offset_table_count++]; + } + else + ret = farmalloc(size); + +#ifndef PNG_USER_MEM_SUPPORTED + if (ret == NULL) + { + if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) + png_error(png_ptr, "Out of memory."); /* Note "o" and "m" */ + else + png_warning(png_ptr, "Out of memory."); /* Note "o" and "m" */ + } +#endif + + return (ret); +} + +/* free a pointer allocated by png_malloc(). In the default + configuration, png_ptr is not used, but is passed in case it + is needed. If ptr is NULL, return without taking any action. */ +void PNGAPI +png_free(png_structp png_ptr, png_voidp ptr) +{ + if (png_ptr == NULL || ptr == NULL) + return; + +#ifdef PNG_USER_MEM_SUPPORTED + if (png_ptr->free_fn != NULL) + { + (*(png_ptr->free_fn))(png_ptr, ptr); + return; + } + else png_free_default(png_ptr, ptr); +} + +void PNGAPI +png_free_default(png_structp png_ptr, png_voidp ptr) +{ +#endif /* PNG_USER_MEM_SUPPORTED */ + + if (png_ptr->offset_table != NULL) + { + int i; + + for (i = 0; i < png_ptr->offset_table_count; i++) + { + if (ptr == png_ptr->offset_table_ptr[i]) + { + ptr = NULL; + png_ptr->offset_table_count_free++; + break; + } + } + if (png_ptr->offset_table_count_free == png_ptr->offset_table_count) + { + farfree(png_ptr->offset_table); + farfree(png_ptr->offset_table_ptr); + png_ptr->offset_table = NULL; + png_ptr->offset_table_ptr = NULL; + } + } + + if (ptr != NULL) + { + farfree(ptr); + } +} + +#else /* Not the Borland DOS special memory handler */ + +/* Allocate memory for a png_struct or a png_info. The malloc and + memset can be replaced by a single call to calloc() if this is thought + to improve performance noticably. */ +png_voidp /* PRIVATE */ +png_create_struct(int type) +{ +#ifdef PNG_USER_MEM_SUPPORTED + return (png_create_struct_2(type, png_malloc_ptr_NULL, png_voidp_NULL)); +} + +/* Allocate memory for a png_struct or a png_info. The malloc and + memset can be replaced by a single call to calloc() if this is thought + to improve performance noticably. */ +png_voidp /* PRIVATE */ +png_create_struct_2(int type, png_malloc_ptr malloc_fn, png_voidp mem_ptr) +{ +#endif /* PNG_USER_MEM_SUPPORTED */ + png_size_t size; + png_voidp struct_ptr; + + if (type == PNG_STRUCT_INFO) + size = png_sizeof(png_info); + else if (type == PNG_STRUCT_PNG) + size = png_sizeof(png_struct); + else + return (NULL); + +#ifdef PNG_USER_MEM_SUPPORTED + if(malloc_fn != NULL) + { + png_struct dummy_struct; + png_structp png_ptr = &dummy_struct; + png_ptr->mem_ptr=mem_ptr; + struct_ptr = (*(malloc_fn))(png_ptr, size); + if (struct_ptr != NULL) + png_memset(struct_ptr, 0, size); + return (struct_ptr); + } +#endif /* PNG_USER_MEM_SUPPORTED */ + +#if defined(__TURBOC__) && !defined(__FLAT__) + struct_ptr = (png_voidp)farmalloc(size); +#else +# if defined(_MSC_VER) && defined(MAXSEG_64K) + struct_ptr = (png_voidp)halloc(size,1); +# else + struct_ptr = (png_voidp)malloc(size); +# endif +#endif + if (struct_ptr != NULL) + png_memset(struct_ptr, 0, size); + + return (struct_ptr); +} + + +/* Free memory allocated by a png_create_struct() call */ +void /* PRIVATE */ +png_destroy_struct(png_voidp struct_ptr) +{ +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2(struct_ptr, png_free_ptr_NULL, png_voidp_NULL); +} + +/* Free memory allocated by a png_create_struct() call */ +void /* PRIVATE */ +png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn, + png_voidp mem_ptr) +{ +#endif /* PNG_USER_MEM_SUPPORTED */ + if (struct_ptr != NULL) + { +#ifdef PNG_USER_MEM_SUPPORTED + if(free_fn != NULL) + { + png_struct dummy_struct; + png_structp png_ptr = &dummy_struct; + png_ptr->mem_ptr=mem_ptr; + (*(free_fn))(png_ptr, struct_ptr); + return; + } +#endif /* PNG_USER_MEM_SUPPORTED */ +#if defined(__TURBOC__) && !defined(__FLAT__) + farfree(struct_ptr); +#else +# if defined(_MSC_VER) && defined(MAXSEG_64K) + hfree(struct_ptr); +# else + free(struct_ptr); +# endif +#endif + } +} + +/* Allocate memory. For reasonable files, size should never exceed + 64K. However, zlib may allocate more then 64K if you don't tell + it not to. See zconf.h and png.h for more information. zlib does + need to allocate exactly 64K, so whatever you call here must + have the ability to do that. */ + +png_voidp PNGAPI +png_malloc(png_structp png_ptr, png_uint_32 size) +{ + png_voidp ret; + +#ifdef PNG_USER_MEM_SUPPORTED + if (png_ptr == NULL || size == 0) + return (NULL); + + if(png_ptr->malloc_fn != NULL) + ret = ((png_voidp)(*(png_ptr->malloc_fn))(png_ptr, (png_size_t)size)); + else + ret = (png_malloc_default(png_ptr, size)); + if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) + png_error(png_ptr, "Out of Memory!"); + return (ret); +} + +png_voidp PNGAPI +png_malloc_default(png_structp png_ptr, png_uint_32 size) +{ + png_voidp ret; +#endif /* PNG_USER_MEM_SUPPORTED */ + + if (png_ptr == NULL || size == 0) + return (NULL); + +#ifdef PNG_MAX_MALLOC_64K + if (size > (png_uint_32)65536L) + { +#ifndef PNG_USER_MEM_SUPPORTED + if(png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) + png_error(png_ptr, "Cannot Allocate > 64K"); + else +#endif + return NULL; + } +#endif + + /* Check for overflow */ +#if defined(__TURBOC__) && !defined(__FLAT__) + if (size != (unsigned long)size) + ret = NULL; + else + ret = farmalloc(size); +#else +# if defined(_MSC_VER) && defined(MAXSEG_64K) + if (size != (unsigned long)size) + ret = NULL; + else + ret = halloc(size, 1); +# else + if (size != (size_t)size) + ret = NULL; + else + ret = malloc((size_t)size); +# endif +#endif + +#ifndef PNG_USER_MEM_SUPPORTED + if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) + png_error(png_ptr, "Out of Memory"); +#endif + + return (ret); +} + +/* Free a pointer allocated by png_malloc(). If ptr is NULL, return + without taking any action. */ +void PNGAPI +png_free(png_structp png_ptr, png_voidp ptr) +{ + if (png_ptr == NULL || ptr == NULL) + return; + +#ifdef PNG_USER_MEM_SUPPORTED + if (png_ptr->free_fn != NULL) + { + (*(png_ptr->free_fn))(png_ptr, ptr); + return; + } + else png_free_default(png_ptr, ptr); +} +void PNGAPI +png_free_default(png_structp png_ptr, png_voidp ptr) +{ + if (png_ptr == NULL || ptr == NULL) + return; + +#endif /* PNG_USER_MEM_SUPPORTED */ + +#if defined(__TURBOC__) && !defined(__FLAT__) + farfree(ptr); +#else +# if defined(_MSC_VER) && defined(MAXSEG_64K) + hfree(ptr); +# else + free(ptr); +# endif +#endif +} + +#endif /* Not Borland DOS special memory handler */ + +#if defined(PNG_1_0_X) +# define png_malloc_warn png_malloc +#else +/* This function was added at libpng version 1.2.3. The png_malloc_warn() + * function will set up png_malloc() to issue a png_warning and return NULL + * instead of issuing a png_error, if it fails to allocate the requested + * memory. + */ +png_voidp PNGAPI +png_malloc_warn(png_structp png_ptr, png_uint_32 size) +{ + png_voidp ptr; + png_uint_32 save_flags=png_ptr->flags; + + png_ptr->flags|=PNG_FLAG_MALLOC_NULL_MEM_OK; + ptr = (png_voidp)png_malloc((png_structp)png_ptr, size); + png_ptr->flags=save_flags; + return(ptr); +} +#endif + +png_voidp PNGAPI +png_memcpy_check (png_structp png_ptr, png_voidp s1, png_voidp s2, + png_uint_32 length) +{ + png_size_t size; + + size = (png_size_t)length; + if ((png_uint_32)size != length) + png_error(png_ptr,"Overflow in png_memcpy_check."); + + return(png_memcpy (s1, s2, size)); +} + +png_voidp PNGAPI +png_memset_check (png_structp png_ptr, png_voidp s1, int value, + png_uint_32 length) +{ + png_size_t size; + + size = (png_size_t)length; + if ((png_uint_32)size != length) + png_error(png_ptr,"Overflow in png_memset_check."); + + return (png_memset (s1, value, size)); + +} + +#ifdef PNG_USER_MEM_SUPPORTED +/* This function is called when the application wants to use another method + * of allocating and freeing memory. + */ +void PNGAPI +png_set_mem_fn(png_structp png_ptr, png_voidp mem_ptr, png_malloc_ptr + malloc_fn, png_free_ptr free_fn) +{ + png_ptr->mem_ptr = mem_ptr; + png_ptr->malloc_fn = malloc_fn; + png_ptr->free_fn = free_fn; +} + +/* This function returns a pointer to the mem_ptr associated with the user + * functions. The application should free any memory associated with this + * pointer before png_write_destroy and png_read_destroy are called. + */ +png_voidp PNGAPI +png_get_mem_ptr(png_structp png_ptr) +{ + return ((png_voidp)png_ptr->mem_ptr); +} +#endif /* PNG_USER_MEM_SUPPORTED */ diff --git a/syslinux/com32/lib/libpng/pngpread.c b/syslinux/com32/lib/libpng/pngpread.c new file mode 100644 index 0000000..8c35faa --- /dev/null +++ b/syslinux/com32/lib/libpng/pngpread.c @@ -0,0 +1,1573 @@ + +/* pngpread.c - read a png file in push mode + * + * libpng version 1.2.8 - December 3, 2004 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2004 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + */ + +#define PNG_INTERNAL +#include "png.h" + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED + +/* push model modes */ +#define PNG_READ_SIG_MODE 0 +#define PNG_READ_CHUNK_MODE 1 +#define PNG_READ_IDAT_MODE 2 +#define PNG_SKIP_MODE 3 +#define PNG_READ_tEXt_MODE 4 +#define PNG_READ_zTXt_MODE 5 +#define PNG_READ_DONE_MODE 6 +#define PNG_READ_iTXt_MODE 7 +#define PNG_ERROR_MODE 8 + +void PNGAPI +png_process_data(png_structp png_ptr, png_infop info_ptr, + png_bytep buffer, png_size_t buffer_size) +{ + png_push_restore_buffer(png_ptr, buffer, buffer_size); + + while (png_ptr->buffer_size) + { + png_process_some_data(png_ptr, info_ptr); + } +} + +/* What we do with the incoming data depends on what we were previously + * doing before we ran out of data... + */ +void /* PRIVATE */ +png_process_some_data(png_structp png_ptr, png_infop info_ptr) +{ + switch (png_ptr->process_mode) + { + case PNG_READ_SIG_MODE: + { + png_push_read_sig(png_ptr, info_ptr); + break; + } + case PNG_READ_CHUNK_MODE: + { + png_push_read_chunk(png_ptr, info_ptr); + break; + } + case PNG_READ_IDAT_MODE: + { + png_push_read_IDAT(png_ptr); + break; + } +#if defined(PNG_READ_tEXt_SUPPORTED) + case PNG_READ_tEXt_MODE: + { + png_push_read_tEXt(png_ptr, info_ptr); + break; + } +#endif +#if defined(PNG_READ_zTXt_SUPPORTED) + case PNG_READ_zTXt_MODE: + { + png_push_read_zTXt(png_ptr, info_ptr); + break; + } +#endif +#if defined(PNG_READ_iTXt_SUPPORTED) + case PNG_READ_iTXt_MODE: + { + png_push_read_iTXt(png_ptr, info_ptr); + break; + } +#endif + case PNG_SKIP_MODE: + { + png_push_crc_finish(png_ptr); + break; + } + default: + { + png_ptr->buffer_size = 0; + break; + } + } +} + +/* Read any remaining signature bytes from the stream and compare them with + * the correct PNG signature. It is possible that this routine is called + * with bytes already read from the signature, either because they have been + * checked by the calling application, or because of multiple calls to this + * routine. + */ +void /* PRIVATE */ +png_push_read_sig(png_structp png_ptr, png_infop info_ptr) +{ + png_size_t num_checked = png_ptr->sig_bytes, + num_to_check = 8 - num_checked; + + if (png_ptr->buffer_size < num_to_check) + { + num_to_check = png_ptr->buffer_size; + } + + png_push_fill_buffer(png_ptr, &(info_ptr->signature[num_checked]), + num_to_check); + png_ptr->sig_bytes = (png_byte)(png_ptr->sig_bytes+num_to_check); + + if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check)) + { + if (num_checked < 4 && + png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4)) + png_error(png_ptr, "Not a PNG file"); + else + png_error(png_ptr, "PNG file corrupted by ASCII conversion"); + } + else + { + if (png_ptr->sig_bytes >= 8) + { + png_ptr->process_mode = PNG_READ_CHUNK_MODE; + } + } +} + +void /* PRIVATE */ +png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_IHDR; + PNG_IDAT; + PNG_IEND; + PNG_PLTE; +#if defined(PNG_READ_bKGD_SUPPORTED) + PNG_bKGD; +#endif +#if defined(PNG_READ_cHRM_SUPPORTED) + PNG_cHRM; +#endif +#if defined(PNG_READ_gAMA_SUPPORTED) + PNG_gAMA; +#endif +#if defined(PNG_READ_hIST_SUPPORTED) + PNG_hIST; +#endif +#if defined(PNG_READ_iCCP_SUPPORTED) + PNG_iCCP; +#endif +#if defined(PNG_READ_iTXt_SUPPORTED) + PNG_iTXt; +#endif +#if defined(PNG_READ_oFFs_SUPPORTED) + PNG_oFFs; +#endif +#if defined(PNG_READ_pCAL_SUPPORTED) + PNG_pCAL; +#endif +#if defined(PNG_READ_pHYs_SUPPORTED) + PNG_pHYs; +#endif +#if defined(PNG_READ_sBIT_SUPPORTED) + PNG_sBIT; +#endif +#if defined(PNG_READ_sCAL_SUPPORTED) + PNG_sCAL; +#endif +#if defined(PNG_READ_sRGB_SUPPORTED) + PNG_sRGB; +#endif +#if defined(PNG_READ_sPLT_SUPPORTED) + PNG_sPLT; +#endif +#if defined(PNG_READ_tEXt_SUPPORTED) + PNG_tEXt; +#endif +#if defined(PNG_READ_tIME_SUPPORTED) + PNG_tIME; +#endif +#if defined(PNG_READ_tRNS_SUPPORTED) + PNG_tRNS; +#endif +#if defined(PNG_READ_zTXt_SUPPORTED) + PNG_zTXt; +#endif +#endif /* PNG_USE_LOCAL_ARRAYS */ + /* First we make sure we have enough data for the 4 byte chunk name + * and the 4 byte chunk length before proceeding with decoding the + * chunk data. To fully decode each of these chunks, we also make + * sure we have enough data in the buffer for the 4 byte CRC at the + * end of every chunk (except IDAT, which is handled separately). + */ + if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER)) + { + png_byte chunk_length[4]; + + if (png_ptr->buffer_size < 8) + { + png_push_save_buffer(png_ptr); + return; + } + + png_push_fill_buffer(png_ptr, chunk_length, 4); + png_ptr->push_length = png_get_uint_31(png_ptr,chunk_length); + png_reset_crc(png_ptr); + png_crc_read(png_ptr, png_ptr->chunk_name, 4); + png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; + } + + if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + png_handle_IHDR(png_ptr, info_ptr, png_ptr->push_length); + } + else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + png_handle_IEND(png_ptr, info_ptr, png_ptr->push_length); + + png_ptr->process_mode = PNG_READ_DONE_MODE; + png_push_have_end(png_ptr, info_ptr); + } +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + else if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) + png_ptr->mode |= PNG_HAVE_IDAT; + png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length); + if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4)) + png_ptr->mode |= PNG_HAVE_PLTE; + else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) + { + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before IDAT"); + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + !(png_ptr->mode & PNG_HAVE_PLTE)) + png_error(png_ptr, "Missing PLTE before IDAT"); + } + } +#endif + else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + png_handle_PLTE(png_ptr, info_ptr, png_ptr->push_length); + } + else if (!png_memcmp(png_ptr->chunk_name, (png_bytep)png_IDAT, 4)) + { + /* If we reach an IDAT chunk, this means we have read all of the + * header chunks, and we can start reading the image (or if this + * is called after the image has been read - we have an error). + */ + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before IDAT"); + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + !(png_ptr->mode & PNG_HAVE_PLTE)) + png_error(png_ptr, "Missing PLTE before IDAT"); + + if (png_ptr->mode & PNG_HAVE_IDAT) + { + if (png_ptr->push_length == 0) + return; + + if (png_ptr->mode & PNG_AFTER_IDAT) + png_error(png_ptr, "Too many IDAT's found"); + } + + png_ptr->idat_size = png_ptr->push_length; + png_ptr->mode |= PNG_HAVE_IDAT; + png_ptr->process_mode = PNG_READ_IDAT_MODE; + png_push_have_info(png_ptr, info_ptr); + png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes; + png_ptr->zstream.next_out = png_ptr->row_buf; + return; + } +#if defined(PNG_READ_gAMA_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + png_handle_gAMA(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_sBIT_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + png_handle_sBIT(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_cHRM_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + png_handle_cHRM(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_sRGB_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_sRGB, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + png_handle_sRGB(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_iCCP_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_iCCP, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + png_handle_iCCP(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_sPLT_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_sPLT, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + png_handle_sPLT(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_tRNS_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + png_handle_tRNS(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_bKGD_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + png_handle_bKGD(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_hIST_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + png_handle_hIST(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_pHYs_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + png_handle_pHYs(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_oFFs_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + png_handle_oFFs(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_pCAL_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + png_handle_pCAL(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_sCAL_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_sCAL, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + png_handle_sCAL(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_tIME_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + png_handle_tIME(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_tEXt_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + png_push_handle_tEXt(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_zTXt_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + png_push_handle_zTXt(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_iTXt_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_iTXt, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + png_push_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length); + } +#endif + else + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + png_push_handle_unknown(png_ptr, info_ptr, png_ptr->push_length); + } + + png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; +} + +void /* PRIVATE */ +png_push_crc_skip(png_structp png_ptr, png_uint_32 skip) +{ + png_ptr->process_mode = PNG_SKIP_MODE; + png_ptr->skip_length = skip; +} + +void /* PRIVATE */ +png_push_crc_finish(png_structp png_ptr) +{ + if (png_ptr->skip_length && png_ptr->save_buffer_size) + { + png_size_t save_size; + + if (png_ptr->skip_length < (png_uint_32)png_ptr->save_buffer_size) + save_size = (png_size_t)png_ptr->skip_length; + else + save_size = png_ptr->save_buffer_size; + + png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size); + + png_ptr->skip_length -= save_size; + png_ptr->buffer_size -= save_size; + png_ptr->save_buffer_size -= save_size; + png_ptr->save_buffer_ptr += save_size; + } + if (png_ptr->skip_length && png_ptr->current_buffer_size) + { + png_size_t save_size; + + if (png_ptr->skip_length < (png_uint_32)png_ptr->current_buffer_size) + save_size = (png_size_t)png_ptr->skip_length; + else + save_size = png_ptr->current_buffer_size; + + png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size); + + png_ptr->skip_length -= save_size; + png_ptr->buffer_size -= save_size; + png_ptr->current_buffer_size -= save_size; + png_ptr->current_buffer_ptr += save_size; + } + if (!png_ptr->skip_length) + { + if (png_ptr->buffer_size < 4) + { + png_push_save_buffer(png_ptr); + return; + } + + png_crc_finish(png_ptr, 0); + png_ptr->process_mode = PNG_READ_CHUNK_MODE; + } +} + +void PNGAPI +png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length) +{ + png_bytep ptr; + + ptr = buffer; + if (png_ptr->save_buffer_size) + { + png_size_t save_size; + + if (length < png_ptr->save_buffer_size) + save_size = length; + else + save_size = png_ptr->save_buffer_size; + + png_memcpy(ptr, png_ptr->save_buffer_ptr, save_size); + length -= save_size; + ptr += save_size; + png_ptr->buffer_size -= save_size; + png_ptr->save_buffer_size -= save_size; + png_ptr->save_buffer_ptr += save_size; + } + if (length && png_ptr->current_buffer_size) + { + png_size_t save_size; + + if (length < png_ptr->current_buffer_size) + save_size = length; + else + save_size = png_ptr->current_buffer_size; + + png_memcpy(ptr, png_ptr->current_buffer_ptr, save_size); + png_ptr->buffer_size -= save_size; + png_ptr->current_buffer_size -= save_size; + png_ptr->current_buffer_ptr += save_size; + } +} + +void /* PRIVATE */ +png_push_save_buffer(png_structp png_ptr) +{ + if (png_ptr->save_buffer_size) + { + if (png_ptr->save_buffer_ptr != png_ptr->save_buffer) + { + png_size_t i,istop; + png_bytep sp; + png_bytep dp; + + istop = png_ptr->save_buffer_size; + for (i = 0, sp = png_ptr->save_buffer_ptr, dp = png_ptr->save_buffer; + i < istop; i++, sp++, dp++) + { + *dp = *sp; + } + } + } + if (png_ptr->save_buffer_size + png_ptr->current_buffer_size > + png_ptr->save_buffer_max) + { + png_size_t new_max; + png_bytep old_buffer; + + if (png_ptr->save_buffer_size > PNG_SIZE_MAX - + (png_ptr->current_buffer_size + 256)) + { + png_error(png_ptr, "Potential overflow of save_buffer"); + } + new_max = png_ptr->save_buffer_size + png_ptr->current_buffer_size + 256; + old_buffer = png_ptr->save_buffer; + png_ptr->save_buffer = (png_bytep)png_malloc(png_ptr, + (png_uint_32)new_max); + png_memcpy(png_ptr->save_buffer, old_buffer, png_ptr->save_buffer_size); + png_free(png_ptr, old_buffer); + png_ptr->save_buffer_max = new_max; + } + if (png_ptr->current_buffer_size) + { + png_memcpy(png_ptr->save_buffer + png_ptr->save_buffer_size, + png_ptr->current_buffer_ptr, png_ptr->current_buffer_size); + png_ptr->save_buffer_size += png_ptr->current_buffer_size; + png_ptr->current_buffer_size = 0; + } + png_ptr->save_buffer_ptr = png_ptr->save_buffer; + png_ptr->buffer_size = 0; +} + +void /* PRIVATE */ +png_push_restore_buffer(png_structp png_ptr, png_bytep buffer, + png_size_t buffer_length) +{ + png_ptr->current_buffer = buffer; + png_ptr->current_buffer_size = buffer_length; + png_ptr->buffer_size = buffer_length + png_ptr->save_buffer_size; + png_ptr->current_buffer_ptr = png_ptr->current_buffer; +} + +void /* PRIVATE */ +png_push_read_IDAT(png_structp png_ptr) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_IDAT; +#endif + if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER)) + { + png_byte chunk_length[4]; + + if (png_ptr->buffer_size < 8) + { + png_push_save_buffer(png_ptr); + return; + } + + png_push_fill_buffer(png_ptr, chunk_length, 4); + png_ptr->push_length = png_get_uint_31(png_ptr,chunk_length); + png_reset_crc(png_ptr); + png_crc_read(png_ptr, png_ptr->chunk_name, 4); + png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; + + if (png_memcmp(png_ptr->chunk_name, (png_bytep)png_IDAT, 4)) + { + png_ptr->process_mode = PNG_READ_CHUNK_MODE; + if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)) + png_error(png_ptr, "Not enough compressed data"); + return; + } + + png_ptr->idat_size = png_ptr->push_length; + } + if (png_ptr->idat_size && png_ptr->save_buffer_size) + { + png_size_t save_size; + + if (png_ptr->idat_size < (png_uint_32)png_ptr->save_buffer_size) + { + save_size = (png_size_t)png_ptr->idat_size; + /* check for overflow */ + if((png_uint_32)save_size != png_ptr->idat_size) + png_error(png_ptr, "save_size overflowed in pngpread"); + } + else + save_size = png_ptr->save_buffer_size; + + png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size); + if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)) + png_process_IDAT_data(png_ptr, png_ptr->save_buffer_ptr, save_size); + png_ptr->idat_size -= save_size; + png_ptr->buffer_size -= save_size; + png_ptr->save_buffer_size -= save_size; + png_ptr->save_buffer_ptr += save_size; + } + if (png_ptr->idat_size && png_ptr->current_buffer_size) + { + png_size_t save_size; + + if (png_ptr->idat_size < (png_uint_32)png_ptr->current_buffer_size) + { + save_size = (png_size_t)png_ptr->idat_size; + /* check for overflow */ + if((png_uint_32)save_size != png_ptr->idat_size) + png_error(png_ptr, "save_size overflowed in pngpread"); + } + else + save_size = png_ptr->current_buffer_size; + + png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size); + if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)) + png_process_IDAT_data(png_ptr, png_ptr->current_buffer_ptr, save_size); + + png_ptr->idat_size -= save_size; + png_ptr->buffer_size -= save_size; + png_ptr->current_buffer_size -= save_size; + png_ptr->current_buffer_ptr += save_size; + } + if (!png_ptr->idat_size) + { + if (png_ptr->buffer_size < 4) + { + png_push_save_buffer(png_ptr); + return; + } + + png_crc_finish(png_ptr, 0); + png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; + png_ptr->mode |= PNG_AFTER_IDAT; + } +} + +void /* PRIVATE */ +png_process_IDAT_data(png_structp png_ptr, png_bytep buffer, + png_size_t buffer_length) +{ + int ret; + + if ((png_ptr->flags & PNG_FLAG_ZLIB_FINISHED) && buffer_length) + png_error(png_ptr, "Extra compression data"); + + png_ptr->zstream.next_in = buffer; + png_ptr->zstream.avail_in = (uInt)buffer_length; + for(;;) + { + ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); + if (ret != Z_OK) + { + if (ret == Z_STREAM_END) + { + if (png_ptr->zstream.avail_in) + png_error(png_ptr, "Extra compressed data"); + if (!(png_ptr->zstream.avail_out)) + { + png_push_process_row(png_ptr); + } + + png_ptr->mode |= PNG_AFTER_IDAT; + png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; + break; + } + else if (ret == Z_BUF_ERROR) + break; + else + png_error(png_ptr, "Decompression Error"); + } + if (!(png_ptr->zstream.avail_out)) + { + if (( +#if defined(PNG_READ_INTERLACING_SUPPORTED) + png_ptr->interlaced && png_ptr->pass > 6) || + (!png_ptr->interlaced && +#endif + png_ptr->row_number == png_ptr->num_rows)) + { + if (png_ptr->zstream.avail_in) + png_warning(png_ptr, "Too much data in IDAT chunks"); + png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; + break; + } + png_push_process_row(png_ptr); + png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes; + png_ptr->zstream.next_out = png_ptr->row_buf; + } + else + break; + } +} + +void /* PRIVATE */ +png_push_process_row(png_structp png_ptr) +{ + png_ptr->row_info.color_type = png_ptr->color_type; + png_ptr->row_info.width = png_ptr->iwidth; + png_ptr->row_info.channels = png_ptr->channels; + png_ptr->row_info.bit_depth = png_ptr->bit_depth; + png_ptr->row_info.pixel_depth = png_ptr->pixel_depth; + + png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth, + png_ptr->row_info.width); + + png_read_filter_row(png_ptr, &(png_ptr->row_info), + png_ptr->row_buf + 1, png_ptr->prev_row + 1, + (int)(png_ptr->row_buf[0])); + + png_memcpy_check(png_ptr, png_ptr->prev_row, png_ptr->row_buf, + png_ptr->rowbytes + 1); + + if (png_ptr->transformations || (png_ptr->flags&PNG_FLAG_STRIP_ALPHA)) + png_do_read_transformations(png_ptr); + +#if defined(PNG_READ_INTERLACING_SUPPORTED) + /* blow up interlaced rows to full size */ + if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) + { + if (png_ptr->pass < 6) +/* old interface (pre-1.0.9): + png_do_read_interlace(&(png_ptr->row_info), + png_ptr->row_buf + 1, png_ptr->pass, png_ptr->transformations); + */ + png_do_read_interlace(png_ptr); + + switch (png_ptr->pass) + { + case 0: + { + int i; + for (i = 0; i < 8 && png_ptr->pass == 0; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); /* updates png_ptr->pass */ + } + if (png_ptr->pass == 2) /* pass 1 might be empty */ + { + for (i = 0; i < 4 && png_ptr->pass == 2; i++) + { + png_push_have_row(png_ptr, png_bytep_NULL); + png_read_push_finish_row(png_ptr); + } + } + if (png_ptr->pass == 4 && png_ptr->height <= 4) + { + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, png_bytep_NULL); + png_read_push_finish_row(png_ptr); + } + } + if (png_ptr->pass == 6 && png_ptr->height <= 4) + { + png_push_have_row(png_ptr, png_bytep_NULL); + png_read_push_finish_row(png_ptr); + } + break; + } + case 1: + { + int i; + for (i = 0; i < 8 && png_ptr->pass == 1; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + if (png_ptr->pass == 2) /* skip top 4 generated rows */ + { + for (i = 0; i < 4 && png_ptr->pass == 2; i++) + { + png_push_have_row(png_ptr, png_bytep_NULL); + png_read_push_finish_row(png_ptr); + } + } + break; + } + case 2: + { + int i; + for (i = 0; i < 4 && png_ptr->pass == 2; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + for (i = 0; i < 4 && png_ptr->pass == 2; i++) + { + png_push_have_row(png_ptr, png_bytep_NULL); + png_read_push_finish_row(png_ptr); + } + if (png_ptr->pass == 4) /* pass 3 might be empty */ + { + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, png_bytep_NULL); + png_read_push_finish_row(png_ptr); + } + } + break; + } + case 3: + { + int i; + for (i = 0; i < 4 && png_ptr->pass == 3; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + if (png_ptr->pass == 4) /* skip top two generated rows */ + { + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, png_bytep_NULL); + png_read_push_finish_row(png_ptr); + } + } + break; + } + case 4: + { + int i; + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, png_bytep_NULL); + png_read_push_finish_row(png_ptr); + } + if (png_ptr->pass == 6) /* pass 5 might be empty */ + { + png_push_have_row(png_ptr, png_bytep_NULL); + png_read_push_finish_row(png_ptr); + } + break; + } + case 5: + { + int i; + for (i = 0; i < 2 && png_ptr->pass == 5; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + if (png_ptr->pass == 6) /* skip top generated row */ + { + png_push_have_row(png_ptr, png_bytep_NULL); + png_read_push_finish_row(png_ptr); + } + break; + } + case 6: + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + if (png_ptr->pass != 6) + break; + png_push_have_row(png_ptr, png_bytep_NULL); + png_read_push_finish_row(png_ptr); + } + } + } + else +#endif + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } +} + +void /* PRIVATE */ +png_read_push_finish_row(png_structp png_ptr) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* start of interlace block */ + const int FARDATA png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; + + /* offset to next interlace block */ + const int FARDATA png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; + + /* start of interlace block in the y direction */ + const int FARDATA png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1}; + + /* offset to next interlace block in the y direction */ + const int FARDATA png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2}; + + /* Width of interlace block. This is not currently used - if you need + * it, uncomment it here and in png.h + const int FARDATA png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; + */ + + /* Height of interlace block. This is not currently used - if you need + * it, uncomment it here and in png.h + const int FARDATA png_pass_height[] = {8, 8, 4, 4, 2, 2, 1}; + */ +#endif + + png_ptr->row_number++; + if (png_ptr->row_number < png_ptr->num_rows) + return; + + if (png_ptr->interlaced) + { + png_ptr->row_number = 0; + png_memset_check(png_ptr, png_ptr->prev_row, 0, + png_ptr->rowbytes + 1); + do + { + png_ptr->pass++; + if ((png_ptr->pass == 1 && png_ptr->width < 5) || + (png_ptr->pass == 3 && png_ptr->width < 3) || + (png_ptr->pass == 5 && png_ptr->width < 2)) + png_ptr->pass++; + + if (png_ptr->pass > 7) + png_ptr->pass--; + if (png_ptr->pass >= 7) + break; + + png_ptr->iwidth = (png_ptr->width + + png_pass_inc[png_ptr->pass] - 1 - + png_pass_start[png_ptr->pass]) / + png_pass_inc[png_ptr->pass]; + + png_ptr->irowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, + png_ptr->iwidth) + 1; + + if (png_ptr->transformations & PNG_INTERLACE) + break; + + png_ptr->num_rows = (png_ptr->height + + png_pass_yinc[png_ptr->pass] - 1 - + png_pass_ystart[png_ptr->pass]) / + png_pass_yinc[png_ptr->pass]; + + } while (png_ptr->iwidth == 0 || png_ptr->num_rows == 0); + } +} + +#if defined(PNG_READ_tEXt_SUPPORTED) +void /* PRIVATE */ +png_push_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 + length) +{ + if (!(png_ptr->mode & PNG_HAVE_IHDR) || (png_ptr->mode & PNG_HAVE_IEND)) + { + png_error(png_ptr, "Out of place tEXt"); + /* to quiet some compiler warnings */ + if(info_ptr == NULL) return; + } + +#ifdef PNG_MAX_MALLOC_64K + png_ptr->skip_length = 0; /* This may not be necessary */ + + if (length > (png_uint_32)65535L) /* Can't hold entire string in memory */ + { + png_warning(png_ptr, "tEXt chunk too large to fit in memory"); + png_ptr->skip_length = length - (png_uint_32)65535L; + length = (png_uint_32)65535L; + } +#endif + + png_ptr->current_text = (png_charp)png_malloc(png_ptr, + (png_uint_32)(length+1)); + png_ptr->current_text[length] = '\0'; + png_ptr->current_text_ptr = png_ptr->current_text; + png_ptr->current_text_size = (png_size_t)length; + png_ptr->current_text_left = (png_size_t)length; + png_ptr->process_mode = PNG_READ_tEXt_MODE; +} + +void /* PRIVATE */ +png_push_read_tEXt(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr->buffer_size && png_ptr->current_text_left) + { + png_size_t text_size; + + if (png_ptr->buffer_size < png_ptr->current_text_left) + text_size = png_ptr->buffer_size; + else + text_size = png_ptr->current_text_left; + png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size); + png_ptr->current_text_left -= text_size; + png_ptr->current_text_ptr += text_size; + } + if (!(png_ptr->current_text_left)) + { + png_textp text_ptr; + png_charp text; + png_charp key; + int ret; + + if (png_ptr->buffer_size < 4) + { + png_push_save_buffer(png_ptr); + return; + } + + png_push_crc_finish(png_ptr); + +#if defined(PNG_MAX_MALLOC_64K) + if (png_ptr->skip_length) + return; +#endif + + key = png_ptr->current_text; + + for (text = key; *text; text++) + /* empty loop */ ; + + if (text != key + png_ptr->current_text_size) + text++; + + text_ptr = (png_textp)png_malloc(png_ptr, + (png_uint_32)png_sizeof(png_text)); + text_ptr->compression = PNG_TEXT_COMPRESSION_NONE; + text_ptr->key = key; +#ifdef PNG_iTXt_SUPPORTED + text_ptr->lang = NULL; + text_ptr->lang_key = NULL; +#endif + text_ptr->text = text; + + ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); + + png_free(png_ptr, key); + png_free(png_ptr, text_ptr); + png_ptr->current_text = NULL; + + if (ret) + png_warning(png_ptr, "Insufficient memory to store text chunk."); + } +} +#endif + +#if defined(PNG_READ_zTXt_SUPPORTED) +void /* PRIVATE */ +png_push_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 + length) +{ + if (!(png_ptr->mode & PNG_HAVE_IHDR) || (png_ptr->mode & PNG_HAVE_IEND)) + { + png_error(png_ptr, "Out of place zTXt"); + /* to quiet some compiler warnings */ + if(info_ptr == NULL) return; + } + +#ifdef PNG_MAX_MALLOC_64K + /* We can't handle zTXt chunks > 64K, since we don't have enough space + * to be able to store the uncompressed data. Actually, the threshold + * is probably around 32K, but it isn't as definite as 64K is. + */ + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr, "zTXt chunk too large to fit in memory"); + png_push_crc_skip(png_ptr, length); + return; + } +#endif + + png_ptr->current_text = (png_charp)png_malloc(png_ptr, + (png_uint_32)(length+1)); + png_ptr->current_text[length] = '\0'; + png_ptr->current_text_ptr = png_ptr->current_text; + png_ptr->current_text_size = (png_size_t)length; + png_ptr->current_text_left = (png_size_t)length; + png_ptr->process_mode = PNG_READ_zTXt_MODE; +} + +void /* PRIVATE */ +png_push_read_zTXt(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr->buffer_size && png_ptr->current_text_left) + { + png_size_t text_size; + + if (png_ptr->buffer_size < (png_uint_32)png_ptr->current_text_left) + text_size = png_ptr->buffer_size; + else + text_size = png_ptr->current_text_left; + png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size); + png_ptr->current_text_left -= text_size; + png_ptr->current_text_ptr += text_size; + } + if (!(png_ptr->current_text_left)) + { + png_textp text_ptr; + png_charp text; + png_charp key; + int ret; + png_size_t text_size, key_size; + + if (png_ptr->buffer_size < 4) + { + png_push_save_buffer(png_ptr); + return; + } + + png_push_crc_finish(png_ptr); + + key = png_ptr->current_text; + + for (text = key; *text; text++) + /* empty loop */ ; + + /* zTXt can't have zero text */ + if (text == key + png_ptr->current_text_size) + { + png_ptr->current_text = NULL; + png_free(png_ptr, key); + return; + } + + text++; + + if (*text != PNG_TEXT_COMPRESSION_zTXt) /* check compression byte */ + { + png_ptr->current_text = NULL; + png_free(png_ptr, key); + return; + } + + text++; + + png_ptr->zstream.next_in = (png_bytep )text; + png_ptr->zstream.avail_in = (uInt)(png_ptr->current_text_size - + (text - key)); + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + + key_size = text - key; + text_size = 0; + text = NULL; + ret = Z_STREAM_END; + + while (png_ptr->zstream.avail_in) + { + ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); + if (ret != Z_OK && ret != Z_STREAM_END) + { + inflateReset(&png_ptr->zstream); + png_ptr->zstream.avail_in = 0; + png_ptr->current_text = NULL; + png_free(png_ptr, key); + png_free(png_ptr, text); + return; + } + if (!(png_ptr->zstream.avail_out) || ret == Z_STREAM_END) + { + if (text == NULL) + { + text = (png_charp)png_malloc(png_ptr, + (png_uint_32)(png_ptr->zbuf_size - png_ptr->zstream.avail_out + + key_size + 1)); + png_memcpy(text + key_size, png_ptr->zbuf, + png_ptr->zbuf_size - png_ptr->zstream.avail_out); + png_memcpy(text, key, key_size); + text_size = key_size + png_ptr->zbuf_size - + png_ptr->zstream.avail_out; + *(text + text_size) = '\0'; + } + else + { + png_charp tmp; + + tmp = text; + text = (png_charp)png_malloc(png_ptr, text_size + + (png_uint_32)(png_ptr->zbuf_size - png_ptr->zstream.avail_out + + 1)); + png_memcpy(text, tmp, text_size); + png_free(png_ptr, tmp); + png_memcpy(text + text_size, png_ptr->zbuf, + png_ptr->zbuf_size - png_ptr->zstream.avail_out); + text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out; + *(text + text_size) = '\0'; + } + if (ret != Z_STREAM_END) + { + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + } + } + else + { + break; + } + + if (ret == Z_STREAM_END) + break; + } + + inflateReset(&png_ptr->zstream); + png_ptr->zstream.avail_in = 0; + + if (ret != Z_STREAM_END) + { + png_ptr->current_text = NULL; + png_free(png_ptr, key); + png_free(png_ptr, text); + return; + } + + png_ptr->current_text = NULL; + png_free(png_ptr, key); + key = text; + text += key_size; + + text_ptr = (png_textp)png_malloc(png_ptr, + (png_uint_32)png_sizeof(png_text)); + text_ptr->compression = PNG_TEXT_COMPRESSION_zTXt; + text_ptr->key = key; +#ifdef PNG_iTXt_SUPPORTED + text_ptr->lang = NULL; + text_ptr->lang_key = NULL; +#endif + text_ptr->text = text; + + ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); + + png_free(png_ptr, key); + png_free(png_ptr, text_ptr); + + if (ret) + png_warning(png_ptr, "Insufficient memory to store text chunk."); + } +} +#endif + +#if defined(PNG_READ_iTXt_SUPPORTED) +void /* PRIVATE */ +png_push_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 + length) +{ + if (!(png_ptr->mode & PNG_HAVE_IHDR) || (png_ptr->mode & PNG_HAVE_IEND)) + { + png_error(png_ptr, "Out of place iTXt"); + /* to quiet some compiler warnings */ + if(info_ptr == NULL) return; + } + +#ifdef PNG_MAX_MALLOC_64K + png_ptr->skip_length = 0; /* This may not be necessary */ + + if (length > (png_uint_32)65535L) /* Can't hold entire string in memory */ + { + png_warning(png_ptr, "iTXt chunk too large to fit in memory"); + png_ptr->skip_length = length - (png_uint_32)65535L; + length = (png_uint_32)65535L; + } +#endif + + png_ptr->current_text = (png_charp)png_malloc(png_ptr, + (png_uint_32)(length+1)); + png_ptr->current_text[length] = '\0'; + png_ptr->current_text_ptr = png_ptr->current_text; + png_ptr->current_text_size = (png_size_t)length; + png_ptr->current_text_left = (png_size_t)length; + png_ptr->process_mode = PNG_READ_iTXt_MODE; +} + +void /* PRIVATE */ +png_push_read_iTXt(png_structp png_ptr, png_infop info_ptr) +{ + + if (png_ptr->buffer_size && png_ptr->current_text_left) + { + png_size_t text_size; + + if (png_ptr->buffer_size < png_ptr->current_text_left) + text_size = png_ptr->buffer_size; + else + text_size = png_ptr->current_text_left; + png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size); + png_ptr->current_text_left -= text_size; + png_ptr->current_text_ptr += text_size; + } + if (!(png_ptr->current_text_left)) + { + png_textp text_ptr; + png_charp key; + int comp_flag; + png_charp lang; + png_charp lang_key; + png_charp text; + int ret; + + if (png_ptr->buffer_size < 4) + { + png_push_save_buffer(png_ptr); + return; + } + + png_push_crc_finish(png_ptr); + +#if defined(PNG_MAX_MALLOC_64K) + if (png_ptr->skip_length) + return; +#endif + + key = png_ptr->current_text; + + for (lang = key; *lang; lang++) + /* empty loop */ ; + + if (lang != key + png_ptr->current_text_size) + lang++; + + comp_flag = *lang++; + lang++; /* skip comp_type, always zero */ + + for (lang_key = lang; *lang_key; lang_key++) + /* empty loop */ ; + lang_key++; /* skip NUL separator */ + + for (text = lang_key; *text; text++) + /* empty loop */ ; + + if (text != key + png_ptr->current_text_size) + text++; + + text_ptr = (png_textp)png_malloc(png_ptr, + (png_uint_32)png_sizeof(png_text)); + text_ptr->compression = comp_flag + 2; + text_ptr->key = key; + text_ptr->lang = lang; + text_ptr->lang_key = lang_key; + text_ptr->text = text; + text_ptr->text_length = 0; + text_ptr->itxt_length = png_strlen(text); + + ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); + + png_ptr->current_text = NULL; + + png_free(png_ptr, text_ptr); + if (ret) + png_warning(png_ptr, "Insufficient memory to store iTXt chunk."); + } +} +#endif + +/* This function is called when we haven't found a handler for this + * chunk. If there isn't a problem with the chunk itself (ie a bad chunk + * name or a critical chunk), the chunk is (currently) silently ignored. + */ +void /* PRIVATE */ +png_push_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 + length) +{ + png_uint_32 skip=0; + png_check_chunk_name(png_ptr, png_ptr->chunk_name); + + if (!(png_ptr->chunk_name[0] & 0x20)) + { +#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) + if(png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != + PNG_HANDLE_CHUNK_ALWAYS +#if defined(PNG_READ_USER_CHUNKS_SUPPORTED) + && png_ptr->read_user_chunk_fn == NULL +#endif + ) +#endif + png_chunk_error(png_ptr, "unknown critical chunk"); + + /* to quiet compiler warnings about unused info_ptr */ + if (info_ptr == NULL) + return; + } + +#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) + if (png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS) + { + png_unknown_chunk chunk; + +#ifdef PNG_MAX_MALLOC_64K + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr, "unknown chunk too large to fit in memory"); + skip = length - (png_uint_32)65535L; + length = (png_uint_32)65535L; + } +#endif + + png_strcpy((png_charp)chunk.name, (png_charp)png_ptr->chunk_name); + chunk.data = (png_bytep)png_malloc(png_ptr, length); + png_crc_read(png_ptr, chunk.data, length); + chunk.size = length; +#if defined(PNG_READ_USER_CHUNKS_SUPPORTED) + if(png_ptr->read_user_chunk_fn != NULL) + { + /* callback to user unknown chunk handler */ + if ((*(png_ptr->read_user_chunk_fn)) (png_ptr, &chunk) <= 0) + { + if (!(png_ptr->chunk_name[0] & 0x20)) + if(png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != + PNG_HANDLE_CHUNK_ALWAYS) + png_chunk_error(png_ptr, "unknown critical chunk"); + } + png_set_unknown_chunks(png_ptr, info_ptr, &chunk, 1); + } + else +#endif + png_set_unknown_chunks(png_ptr, info_ptr, &chunk, 1); + png_free(png_ptr, chunk.data); + } + else +#endif + skip=length; + png_push_crc_skip(png_ptr, skip); +} + +void /* PRIVATE */ +png_push_have_info(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr->info_fn != NULL) + (*(png_ptr->info_fn))(png_ptr, info_ptr); +} + +void /* PRIVATE */ +png_push_have_end(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr->end_fn != NULL) + (*(png_ptr->end_fn))(png_ptr, info_ptr); +} + +void /* PRIVATE */ +png_push_have_row(png_structp png_ptr, png_bytep row) +{ + if (png_ptr->row_fn != NULL) + (*(png_ptr->row_fn))(png_ptr, row, png_ptr->row_number, + (int)png_ptr->pass); +} + +void PNGAPI +png_progressive_combine_row (png_structp png_ptr, + png_bytep old_row, png_bytep new_row) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + const int FARDATA png_pass_dsp_mask[7] = + {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff}; +#endif + if (new_row != NULL) /* new_row must == png_ptr->row_buf here. */ + png_combine_row(png_ptr, old_row, png_pass_dsp_mask[png_ptr->pass]); +} + +void PNGAPI +png_set_progressive_read_fn(png_structp png_ptr, png_voidp progressive_ptr, + png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn, + png_progressive_end_ptr end_fn) +{ + png_ptr->info_fn = info_fn; + png_ptr->row_fn = row_fn; + png_ptr->end_fn = end_fn; + + png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer); +} + +png_voidp PNGAPI +png_get_progressive_ptr(png_structp png_ptr) +{ + return png_ptr->io_ptr; +} +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ diff --git a/syslinux/com32/lib/libpng/pngread.c b/syslinux/com32/lib/libpng/pngread.c new file mode 100644 index 0000000..7030807 --- /dev/null +++ b/syslinux/com32/lib/libpng/pngread.c @@ -0,0 +1,1456 @@ + +/* pngread.c - read a PNG file + * + * libpng 1.2.8 - December 3, 2004 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2004 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This file contains routines that an application calls directly to + * read a PNG file or stream. + */ + +#define PNG_INTERNAL +#include "png.h" + +/* Create a PNG structure for reading, and allocate any memory needed. */ +png_structp PNGAPI +png_create_read_struct(png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn) +{ + +#ifdef PNG_USER_MEM_SUPPORTED + return (png_create_read_struct_2(user_png_ver, error_ptr, error_fn, + warn_fn, png_voidp_NULL, png_malloc_ptr_NULL, png_free_ptr_NULL)); +} + +/* Alternate create PNG structure for reading, and allocate any memory needed. */ +png_structp PNGAPI +png_create_read_struct_2(png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn) +{ +#endif /* PNG_USER_MEM_SUPPORTED */ + + volatile png_structp png_ptr; + +#ifdef PNG_SETJMP_SUPPORTED +#ifdef USE_FAR_KEYWORD + jmp_buf jmpbuf; +#endif +#endif + + int i; + + png_debug(1, "in png_create_read_struct\n"); +#ifdef PNG_USER_MEM_SUPPORTED + png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG, + (png_malloc_ptr)malloc_fn, (png_voidp)mem_ptr); +#else + png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG); +#endif + if (png_ptr == NULL) + return (NULL); + +#if !defined(PNG_1_0_X) +#ifdef PNG_ASSEMBLER_CODE_SUPPORTED + png_init_mmx_flags(png_ptr); /* 1.2.0 addition */ +#endif +#endif /* PNG_1_0_X */ + + /* added at libpng-1.2.6 */ +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + png_ptr->user_width_max=PNG_USER_WIDTH_MAX; + png_ptr->user_height_max=PNG_USER_HEIGHT_MAX; +#endif + +#ifdef PNG_SETJMP_SUPPORTED +#ifdef USE_FAR_KEYWORD + if (setjmp(jmpbuf)) +#else + if (setjmp(png_ptr->jmpbuf)) +#endif + { + png_free(png_ptr, png_ptr->zbuf); + png_ptr->zbuf=NULL; +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2((png_voidp)png_ptr, + (png_free_ptr)free_fn, (png_voidp)mem_ptr); +#else + png_destroy_struct((png_voidp)png_ptr); +#endif + return (NULL); + } +#ifdef USE_FAR_KEYWORD + png_memcpy(png_ptr->jmpbuf,jmpbuf,png_sizeof(jmp_buf)); +#endif +#endif + +#ifdef PNG_USER_MEM_SUPPORTED + png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn); +#endif + + png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn); + + i=0; + do + { + if(user_png_ver[i] != png_libpng_ver[i]) + png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; + } while (png_libpng_ver[i++]); + + if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) + { + /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so + * we must recompile any applications that use any older library version. + * For versions after libpng 1.0, we will be compatible, so we need + * only check the first digit. + */ + if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] || + (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) || + (user_png_ver[0] == '0' && user_png_ver[2] < '9')) + { +#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) + char msg[80]; + if (user_png_ver) + { + sprintf(msg, "Application was compiled with png.h from libpng-%.20s", + user_png_ver); + png_warning(png_ptr, msg); + } + sprintf(msg, "Application is running with png.c from libpng-%.20s", + png_libpng_ver); + png_warning(png_ptr, msg); +#endif +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + png_ptr->flags=0; +#endif + png_error(png_ptr, + "Incompatible libpng version in application and library"); + } + } + + /* initialize zbuf - compression buffer */ + png_ptr->zbuf_size = PNG_ZBUF_SIZE; + png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, + (png_uint_32)png_ptr->zbuf_size); + png_ptr->zstream.zalloc = png_zalloc; + png_ptr->zstream.zfree = png_zfree; + png_ptr->zstream.opaque = (voidpf)png_ptr; + + switch (inflateInit(&png_ptr->zstream)) + { + case Z_OK: /* Do nothing */ break; + case Z_MEM_ERROR: + case Z_STREAM_ERROR: png_error(png_ptr, "zlib memory error"); break; + case Z_VERSION_ERROR: png_error(png_ptr, "zlib version error"); break; + default: png_error(png_ptr, "Unknown zlib error"); + } + + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + + png_set_read_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL); + +#ifdef PNG_SETJMP_SUPPORTED +/* Applications that neglect to set up their own setjmp() and then encounter + a png_error() will longjmp here. Since the jmpbuf is then meaningless we + abort instead of returning. */ +#ifdef USE_FAR_KEYWORD + if (setjmp(jmpbuf)) + PNG_ABORT(); + png_memcpy(png_ptr->jmpbuf,jmpbuf,png_sizeof(jmp_buf)); +#else + if (setjmp(png_ptr->jmpbuf)) + PNG_ABORT(); +#endif +#endif + return (png_ptr); +} + +/* Initialize PNG structure for reading, and allocate any memory needed. + This interface is deprecated in favour of the png_create_read_struct(), + and it will eventually disappear. */ +#if defined(PNG_1_0_X) || defined (PNG_1_2_X) +#undef png_read_init +void PNGAPI +png_read_init(png_structp png_ptr) +{ + /* We only come here via pre-1.0.7-compiled applications */ + png_read_init_2(png_ptr, "1.0.6 or earlier", 0, 0); +} +#endif + +void PNGAPI +png_read_init_2(png_structp png_ptr, png_const_charp user_png_ver, + png_size_t png_struct_size, png_size_t png_info_size) +{ + /* We only come here via pre-1.0.12-compiled applications */ +#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) + if(png_sizeof(png_struct) > png_struct_size || + png_sizeof(png_info) > png_info_size) + { + char msg[80]; + png_ptr->warning_fn=NULL; + if (user_png_ver) + { + sprintf(msg, "Application was compiled with png.h from libpng-%.20s", + user_png_ver); + png_warning(png_ptr, msg); + } + sprintf(msg, "Application is running with png.c from libpng-%.20s", + png_libpng_ver); + png_warning(png_ptr, msg); + } +#endif + if(png_sizeof(png_struct) > png_struct_size) + { + png_ptr->error_fn=NULL; +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + png_ptr->flags=0; +#endif + png_error(png_ptr, + "The png struct allocated by the application for reading is too small."); + } + if(png_sizeof(png_info) > png_info_size) + { + png_ptr->error_fn=NULL; +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + png_ptr->flags=0; +#endif + png_error(png_ptr, + "The info struct allocated by application for reading is too small."); + } + png_read_init_3(&png_ptr, user_png_ver, png_struct_size); +} + +void PNGAPI +png_read_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver, + png_size_t png_struct_size) +{ +#ifdef PNG_SETJMP_SUPPORTED + jmp_buf tmp_jmp; /* to save current jump buffer */ +#endif + + int i=0; + + png_structp png_ptr=*ptr_ptr; + + do + { + if(user_png_ver[i] != png_libpng_ver[i]) + { +#ifdef PNG_LEGACY_SUPPORTED + png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; +#else + png_ptr->warning_fn=NULL; + png_warning(png_ptr, + "Application uses deprecated png_read_init() and should be recompiled."); + break; +#endif + } + } while (png_libpng_ver[i++]); + + png_debug(1, "in png_read_init_3\n"); + +#ifdef PNG_SETJMP_SUPPORTED + /* save jump buffer and error functions */ + png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof (jmp_buf)); +#endif + + if(png_sizeof(png_struct) > png_struct_size) + { + png_destroy_struct(png_ptr); + *ptr_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG); + png_ptr = *ptr_ptr; + } + + /* reset all variables to 0 */ + png_memset(png_ptr, 0, png_sizeof (png_struct)); + +#ifdef PNG_SETJMP_SUPPORTED + /* restore jump buffer */ + png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof (jmp_buf)); +#endif + + /* added at libpng-1.2.6 */ +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + png_ptr->user_width_max=PNG_USER_WIDTH_MAX; + png_ptr->user_height_max=PNG_USER_HEIGHT_MAX; +#endif + + /* initialize zbuf - compression buffer */ + png_ptr->zbuf_size = PNG_ZBUF_SIZE; + png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, + (png_uint_32)png_ptr->zbuf_size); + png_ptr->zstream.zalloc = png_zalloc; + png_ptr->zstream.zfree = png_zfree; + png_ptr->zstream.opaque = (voidpf)png_ptr; + + switch (inflateInit(&png_ptr->zstream)) + { + case Z_OK: /* Do nothing */ break; + case Z_MEM_ERROR: + case Z_STREAM_ERROR: png_error(png_ptr, "zlib memory"); break; + case Z_VERSION_ERROR: png_error(png_ptr, "zlib version"); break; + default: png_error(png_ptr, "Unknown zlib error"); + } + + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + + png_set_read_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL); +} + +#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED +/* Read the information before the actual image data. This has been + * changed in v0.90 to allow reading a file that already has the magic + * bytes read from the stream. You can tell libpng how many bytes have + * been read from the beginning of the stream (up to the maximum of 8) + * via png_set_sig_bytes(), and we will only check the remaining bytes + * here. The application can then have access to the signature bytes we + * read if it is determined that this isn't a valid PNG file. + */ +void PNGAPI +png_read_info(png_structp png_ptr, png_infop info_ptr) +{ + png_debug(1, "in png_read_info\n"); + /* If we haven't checked all of the PNG signature bytes, do so now. */ + if (png_ptr->sig_bytes < 8) + { + png_size_t num_checked = png_ptr->sig_bytes, + num_to_check = 8 - num_checked; + + png_read_data(png_ptr, &(info_ptr->signature[num_checked]), num_to_check); + png_ptr->sig_bytes = 8; + + if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check)) + { + if (num_checked < 4 && + png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4)) + png_error(png_ptr, "Not a PNG file"); + else + png_error(png_ptr, "PNG file corrupted by ASCII conversion"); + } + if (num_checked < 3) + png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE; + } + + for(;;) + { +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_IHDR; + PNG_IDAT; + PNG_IEND; + PNG_PLTE; +#if defined(PNG_READ_bKGD_SUPPORTED) + PNG_bKGD; +#endif +#if defined(PNG_READ_cHRM_SUPPORTED) + PNG_cHRM; +#endif +#if defined(PNG_READ_gAMA_SUPPORTED) + PNG_gAMA; +#endif +#if defined(PNG_READ_hIST_SUPPORTED) + PNG_hIST; +#endif +#if defined(PNG_READ_iCCP_SUPPORTED) + PNG_iCCP; +#endif +#if defined(PNG_READ_iTXt_SUPPORTED) + PNG_iTXt; +#endif +#if defined(PNG_READ_oFFs_SUPPORTED) + PNG_oFFs; +#endif +#if defined(PNG_READ_pCAL_SUPPORTED) + PNG_pCAL; +#endif +#if defined(PNG_READ_pHYs_SUPPORTED) + PNG_pHYs; +#endif +#if defined(PNG_READ_sBIT_SUPPORTED) + PNG_sBIT; +#endif +#if defined(PNG_READ_sCAL_SUPPORTED) + PNG_sCAL; +#endif +#if defined(PNG_READ_sPLT_SUPPORTED) + PNG_sPLT; +#endif +#if defined(PNG_READ_sRGB_SUPPORTED) + PNG_sRGB; +#endif +#if defined(PNG_READ_tEXt_SUPPORTED) + PNG_tEXt; +#endif +#if defined(PNG_READ_tIME_SUPPORTED) + PNG_tIME; +#endif +#if defined(PNG_READ_tRNS_SUPPORTED) + PNG_tRNS; +#endif +#if defined(PNG_READ_zTXt_SUPPORTED) + PNG_zTXt; +#endif +#endif /* PNG_USE_LOCAL_ARRAYS */ + png_byte chunk_length[4]; + png_uint_32 length; + + png_read_data(png_ptr, chunk_length, 4); + length = png_get_uint_31(png_ptr,chunk_length); + + png_reset_crc(png_ptr); + png_crc_read(png_ptr, png_ptr->chunk_name, 4); + + png_debug2(0, "Reading %s chunk, length=%lu.\n", png_ptr->chunk_name, + length); + + /* This should be a binary subdivision search or a hash for + * matching the chunk name rather than a linear search. + */ + if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4)) + png_handle_IHDR(png_ptr, info_ptr, length); + else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4)) + png_handle_IEND(png_ptr, info_ptr, length); +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + else if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name)) + { + if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) + png_ptr->mode |= PNG_HAVE_IDAT; + png_handle_unknown(png_ptr, info_ptr, length); + if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4)) + png_ptr->mode |= PNG_HAVE_PLTE; + else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) + { + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before IDAT"); + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + !(png_ptr->mode & PNG_HAVE_PLTE)) + png_error(png_ptr, "Missing PLTE before IDAT"); + break; + } + } +#endif + else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4)) + png_handle_PLTE(png_ptr, info_ptr, length); + else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) + { + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before IDAT"); + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + !(png_ptr->mode & PNG_HAVE_PLTE)) + png_error(png_ptr, "Missing PLTE before IDAT"); + + png_ptr->idat_size = length; + png_ptr->mode |= PNG_HAVE_IDAT; + break; + } +#if defined(PNG_READ_bKGD_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4)) + png_handle_bKGD(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_cHRM_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4)) + png_handle_cHRM(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_gAMA_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4)) + png_handle_gAMA(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_hIST_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4)) + png_handle_hIST(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_oFFs_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4)) + png_handle_oFFs(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_pCAL_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4)) + png_handle_pCAL(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_sCAL_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_sCAL, 4)) + png_handle_sCAL(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_pHYs_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4)) + png_handle_pHYs(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_sBIT_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4)) + png_handle_sBIT(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_sRGB_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_sRGB, 4)) + png_handle_sRGB(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_iCCP_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_iCCP, 4)) + png_handle_iCCP(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_sPLT_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_sPLT, 4)) + png_handle_sPLT(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_tEXt_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4)) + png_handle_tEXt(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_tIME_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4)) + png_handle_tIME(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_tRNS_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4)) + png_handle_tRNS(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_zTXt_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4)) + png_handle_zTXt(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_iTXt_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_iTXt, 4)) + png_handle_iTXt(png_ptr, info_ptr, length); +#endif + else + png_handle_unknown(png_ptr, info_ptr, length); + } +} +#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */ + +/* optional call to update the users info_ptr structure */ +void PNGAPI +png_read_update_info(png_structp png_ptr, png_infop info_ptr) +{ + png_debug(1, "in png_read_update_info\n"); + if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) + png_read_start_row(png_ptr); + else + png_warning(png_ptr, + "Ignoring extra png_read_update_info() call; row buffer not reallocated"); + png_read_transform_info(png_ptr, info_ptr); +} + +#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED +/* Initialize palette, background, etc, after transformations + * are set, but before any reading takes place. This allows + * the user to obtain a gamma-corrected palette, for example. + * If the user doesn't call this, we will do it ourselves. + */ +void PNGAPI +png_start_read_image(png_structp png_ptr) +{ + png_debug(1, "in png_start_read_image\n"); + if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) + png_read_start_row(png_ptr); +} +#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */ + +#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED +void PNGAPI +png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_IDAT; + const int png_pass_dsp_mask[7] = {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff}; + const int png_pass_mask[7] = {0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff}; +#endif + int ret; + png_debug2(1, "in png_read_row (row %lu, pass %d)\n", + png_ptr->row_number, png_ptr->pass); + if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) + png_read_start_row(png_ptr); + if (png_ptr->row_number == 0 && png_ptr->pass == 0) + { + /* check for transforms that have been set but were defined out */ +#if defined(PNG_WRITE_INVERT_SUPPORTED) && !defined(PNG_READ_INVERT_SUPPORTED) + if (png_ptr->transformations & PNG_INVERT_MONO) + png_warning(png_ptr, "PNG_READ_INVERT_SUPPORTED is not defined."); +#endif +#if defined(PNG_WRITE_FILLER_SUPPORTED) && !defined(PNG_READ_FILLER_SUPPORTED) + if (png_ptr->transformations & PNG_FILLER) + png_warning(png_ptr, "PNG_READ_FILLER_SUPPORTED is not defined."); +#endif +#if defined(PNG_WRITE_PACKSWAP_SUPPORTED) && !defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + png_warning(png_ptr, "PNG_READ_PACKSWAP_SUPPORTED is not defined."); +#endif +#if defined(PNG_WRITE_PACK_SUPPORTED) && !defined(PNG_READ_PACK_SUPPORTED) + if (png_ptr->transformations & PNG_PACK) + png_warning(png_ptr, "PNG_READ_PACK_SUPPORTED is not defined."); +#endif +#if defined(PNG_WRITE_SHIFT_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) + if (png_ptr->transformations & PNG_SHIFT) + png_warning(png_ptr, "PNG_READ_SHIFT_SUPPORTED is not defined."); +#endif +#if defined(PNG_WRITE_BGR_SUPPORTED) && !defined(PNG_READ_BGR_SUPPORTED) + if (png_ptr->transformations & PNG_BGR) + png_warning(png_ptr, "PNG_READ_BGR_SUPPORTED is not defined."); +#endif +#if defined(PNG_WRITE_SWAP_SUPPORTED) && !defined(PNG_READ_SWAP_SUPPORTED) + if (png_ptr->transformations & PNG_SWAP_BYTES) + png_warning(png_ptr, "PNG_READ_SWAP_SUPPORTED is not defined."); +#endif + } + +#if defined(PNG_READ_INTERLACING_SUPPORTED) + /* if interlaced and we do not need a new row, combine row and return */ + if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) + { + switch (png_ptr->pass) + { + case 0: + if (png_ptr->row_number & 0x07) + { + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, + png_pass_dsp_mask[png_ptr->pass]); + png_read_finish_row(png_ptr); + return; + } + break; + case 1: + if ((png_ptr->row_number & 0x07) || png_ptr->width < 5) + { + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, + png_pass_dsp_mask[png_ptr->pass]); + png_read_finish_row(png_ptr); + return; + } + break; + case 2: + if ((png_ptr->row_number & 0x07) != 4) + { + if (dsp_row != NULL && (png_ptr->row_number & 4)) + png_combine_row(png_ptr, dsp_row, + png_pass_dsp_mask[png_ptr->pass]); + png_read_finish_row(png_ptr); + return; + } + break; + case 3: + if ((png_ptr->row_number & 3) || png_ptr->width < 3) + { + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, + png_pass_dsp_mask[png_ptr->pass]); + png_read_finish_row(png_ptr); + return; + } + break; + case 4: + if ((png_ptr->row_number & 3) != 2) + { + if (dsp_row != NULL && (png_ptr->row_number & 2)) + png_combine_row(png_ptr, dsp_row, + png_pass_dsp_mask[png_ptr->pass]); + png_read_finish_row(png_ptr); + return; + } + break; + case 5: + if ((png_ptr->row_number & 1) || png_ptr->width < 2) + { + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, + png_pass_dsp_mask[png_ptr->pass]); + png_read_finish_row(png_ptr); + return; + } + break; + case 6: + if (!(png_ptr->row_number & 1)) + { + png_read_finish_row(png_ptr); + return; + } + break; + } + } +#endif + + if (!(png_ptr->mode & PNG_HAVE_IDAT)) + png_error(png_ptr, "Invalid attempt to read row data"); + + png_ptr->zstream.next_out = png_ptr->row_buf; + png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes; + do + { + if (!(png_ptr->zstream.avail_in)) + { + while (!png_ptr->idat_size) + { + png_byte chunk_length[4]; + + png_crc_finish(png_ptr, 0); + + png_read_data(png_ptr, chunk_length, 4); + png_ptr->idat_size = png_get_uint_31(png_ptr,chunk_length); + + png_reset_crc(png_ptr); + png_crc_read(png_ptr, png_ptr->chunk_name, 4); + if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) + png_error(png_ptr, "Not enough image data"); + } + png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size; + png_ptr->zstream.next_in = png_ptr->zbuf; + if (png_ptr->zbuf_size > png_ptr->idat_size) + png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size; + png_crc_read(png_ptr, png_ptr->zbuf, + (png_size_t)png_ptr->zstream.avail_in); + png_ptr->idat_size -= png_ptr->zstream.avail_in; + } + ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); + if (ret == Z_STREAM_END) + { + if (png_ptr->zstream.avail_out || png_ptr->zstream.avail_in || + png_ptr->idat_size) + png_error(png_ptr, "Extra compressed data"); + png_ptr->mode |= PNG_AFTER_IDAT; + png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; + break; + } + if (ret != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg : + "Decompression error"); + + } while (png_ptr->zstream.avail_out); + + png_ptr->row_info.color_type = png_ptr->color_type; + png_ptr->row_info.width = png_ptr->iwidth; + png_ptr->row_info.channels = png_ptr->channels; + png_ptr->row_info.bit_depth = png_ptr->bit_depth; + png_ptr->row_info.pixel_depth = png_ptr->pixel_depth; + png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth, + png_ptr->row_info.width); + + if(png_ptr->row_buf[0]) + png_read_filter_row(png_ptr, &(png_ptr->row_info), + png_ptr->row_buf + 1, png_ptr->prev_row + 1, + (int)(png_ptr->row_buf[0])); + + png_memcpy_check(png_ptr, png_ptr->prev_row, png_ptr->row_buf, + png_ptr->rowbytes + 1); + +#if defined(PNG_MNG_FEATURES_SUPPORTED) + if((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && + (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) + { + /* Intrapixel differencing */ + png_do_read_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1); + } +#endif + + + if (png_ptr->transformations || (png_ptr->flags&PNG_FLAG_STRIP_ALPHA)) + png_do_read_transformations(png_ptr); + +#if defined(PNG_READ_INTERLACING_SUPPORTED) + /* blow up interlaced rows to full size */ + if (png_ptr->interlaced && + (png_ptr->transformations & PNG_INTERLACE)) + { + if (png_ptr->pass < 6) +/* old interface (pre-1.0.9): + png_do_read_interlace(&(png_ptr->row_info), + png_ptr->row_buf + 1, png_ptr->pass, png_ptr->transformations); + */ + png_do_read_interlace(png_ptr); + + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, + png_pass_dsp_mask[png_ptr->pass]); + if (row != NULL) + png_combine_row(png_ptr, row, + png_pass_mask[png_ptr->pass]); + } + else +#endif + { + if (row != NULL) + png_combine_row(png_ptr, row, 0xff); + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, 0xff); + } + png_read_finish_row(png_ptr); + + if (png_ptr->read_row_fn != NULL) + (*(png_ptr->read_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); +} +#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */ + +#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED +/* Read one or more rows of image data. If the image is interlaced, + * and png_set_interlace_handling() has been called, the rows need to + * contain the contents of the rows from the previous pass. If the + * image has alpha or transparency, and png_handle_alpha()[*] has been + * called, the rows contents must be initialized to the contents of the + * screen. + * + * "row" holds the actual image, and pixels are placed in it + * as they arrive. If the image is displayed after each pass, it will + * appear to "sparkle" in. "display_row" can be used to display a + * "chunky" progressive image, with finer detail added as it becomes + * available. If you do not want this "chunky" display, you may pass + * NULL for display_row. If you do not want the sparkle display, and + * you have not called png_handle_alpha(), you may pass NULL for rows. + * If you have called png_handle_alpha(), and the image has either an + * alpha channel or a transparency chunk, you must provide a buffer for + * rows. In this case, you do not have to provide a display_row buffer + * also, but you may. If the image is not interlaced, or if you have + * not called png_set_interlace_handling(), the display_row buffer will + * be ignored, so pass NULL to it. + * + * [*] png_handle_alpha() does not exist yet, as of libpng version 1.2.8 + */ + +void PNGAPI +png_read_rows(png_structp png_ptr, png_bytepp row, + png_bytepp display_row, png_uint_32 num_rows) +{ + png_uint_32 i; + png_bytepp rp; + png_bytepp dp; + + png_debug(1, "in png_read_rows\n"); + rp = row; + dp = display_row; + if (rp != NULL && dp != NULL) + for (i = 0; i < num_rows; i++) + { + png_bytep rptr = *rp++; + png_bytep dptr = *dp++; + + png_read_row(png_ptr, rptr, dptr); + } + else if(rp != NULL) + for (i = 0; i < num_rows; i++) + { + png_bytep rptr = *rp; + png_read_row(png_ptr, rptr, png_bytep_NULL); + rp++; + } + else if(dp != NULL) + for (i = 0; i < num_rows; i++) + { + png_bytep dptr = *dp; + png_read_row(png_ptr, png_bytep_NULL, dptr); + dp++; + } +} +#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */ + +#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED +/* Read the entire image. If the image has an alpha channel or a tRNS + * chunk, and you have called png_handle_alpha()[*], you will need to + * initialize the image to the current image that PNG will be overlaying. + * We set the num_rows again here, in case it was incorrectly set in + * png_read_start_row() by a call to png_read_update_info() or + * png_start_read_image() if png_set_interlace_handling() wasn't called + * prior to either of these functions like it should have been. You can + * only call this function once. If you desire to have an image for + * each pass of a interlaced image, use png_read_rows() instead. + * + * [*] png_handle_alpha() does not exist yet, as of libpng version 1.2.8 + */ +void PNGAPI +png_read_image(png_structp png_ptr, png_bytepp image) +{ + png_uint_32 i,image_height; + int pass, j; + png_bytepp rp; + + png_debug(1, "in png_read_image\n"); + +#ifdef PNG_READ_INTERLACING_SUPPORTED + pass = png_set_interlace_handling(png_ptr); +#else + if (png_ptr->interlaced) + png_error(png_ptr, + "Cannot read interlaced image -- interlace handler disabled."); + pass = 1; +#endif + + + image_height=png_ptr->height; + png_ptr->num_rows = image_height; /* Make sure this is set correctly */ + + for (j = 0; j < pass; j++) + { + rp = image; + for (i = 0; i < image_height; i++) + { + png_read_row(png_ptr, *rp, png_bytep_NULL); + rp++; + } + } +} +#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */ + +#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED +/* Read the end of the PNG file. Will not read past the end of the + * file, will verify the end is accurate, and will read any comments + * or time information at the end of the file, if info is not NULL. + */ +void PNGAPI +png_read_end(png_structp png_ptr, png_infop info_ptr) +{ + png_byte chunk_length[4]; + png_uint_32 length; + + png_debug(1, "in png_read_end\n"); + png_crc_finish(png_ptr, 0); /* Finish off CRC from last IDAT chunk */ + + do + { +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_IHDR; + PNG_IDAT; + PNG_IEND; + PNG_PLTE; +#if defined(PNG_READ_bKGD_SUPPORTED) + PNG_bKGD; +#endif +#if defined(PNG_READ_cHRM_SUPPORTED) + PNG_cHRM; +#endif +#if defined(PNG_READ_gAMA_SUPPORTED) + PNG_gAMA; +#endif +#if defined(PNG_READ_hIST_SUPPORTED) + PNG_hIST; +#endif +#if defined(PNG_READ_iCCP_SUPPORTED) + PNG_iCCP; +#endif +#if defined(PNG_READ_iTXt_SUPPORTED) + PNG_iTXt; +#endif +#if defined(PNG_READ_oFFs_SUPPORTED) + PNG_oFFs; +#endif +#if defined(PNG_READ_pCAL_SUPPORTED) + PNG_pCAL; +#endif +#if defined(PNG_READ_pHYs_SUPPORTED) + PNG_pHYs; +#endif +#if defined(PNG_READ_sBIT_SUPPORTED) + PNG_sBIT; +#endif +#if defined(PNG_READ_sCAL_SUPPORTED) + PNG_sCAL; +#endif +#if defined(PNG_READ_sPLT_SUPPORTED) + PNG_sPLT; +#endif +#if defined(PNG_READ_sRGB_SUPPORTED) + PNG_sRGB; +#endif +#if defined(PNG_READ_tEXt_SUPPORTED) + PNG_tEXt; +#endif +#if defined(PNG_READ_tIME_SUPPORTED) + PNG_tIME; +#endif +#if defined(PNG_READ_tRNS_SUPPORTED) + PNG_tRNS; +#endif +#if defined(PNG_READ_zTXt_SUPPORTED) + PNG_zTXt; +#endif +#endif /* PNG_USE_LOCAL_ARRAYS */ + + png_read_data(png_ptr, chunk_length, 4); + length = png_get_uint_31(png_ptr,chunk_length); + + png_reset_crc(png_ptr); + png_crc_read(png_ptr, png_ptr->chunk_name, 4); + + png_debug1(0, "Reading %s chunk.\n", png_ptr->chunk_name); + + if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4)) + png_handle_IHDR(png_ptr, info_ptr, length); + else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4)) + png_handle_IEND(png_ptr, info_ptr, length); +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + else if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name)) + { + if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) + { + if (length > 0 || png_ptr->mode & PNG_AFTER_IDAT) + png_error(png_ptr, "Too many IDAT's found"); + } + else + png_ptr->mode |= PNG_AFTER_IDAT; + png_handle_unknown(png_ptr, info_ptr, length); + if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4)) + png_ptr->mode |= PNG_HAVE_PLTE; + } +#endif + else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) + { + /* Zero length IDATs are legal after the last IDAT has been + * read, but not after other chunks have been read. + */ + if (length > 0 || png_ptr->mode & PNG_AFTER_IDAT) + png_error(png_ptr, "Too many IDAT's found"); + png_crc_finish(png_ptr, length); + } + else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4)) + png_handle_PLTE(png_ptr, info_ptr, length); +#if defined(PNG_READ_bKGD_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4)) + png_handle_bKGD(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_cHRM_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4)) + png_handle_cHRM(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_gAMA_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4)) + png_handle_gAMA(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_hIST_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4)) + png_handle_hIST(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_oFFs_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4)) + png_handle_oFFs(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_pCAL_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4)) + png_handle_pCAL(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_sCAL_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_sCAL, 4)) + png_handle_sCAL(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_pHYs_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4)) + png_handle_pHYs(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_sBIT_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4)) + png_handle_sBIT(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_sRGB_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_sRGB, 4)) + png_handle_sRGB(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_iCCP_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_iCCP, 4)) + png_handle_iCCP(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_sPLT_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_sPLT, 4)) + png_handle_sPLT(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_tEXt_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4)) + png_handle_tEXt(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_tIME_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4)) + png_handle_tIME(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_tRNS_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4)) + png_handle_tRNS(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_zTXt_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4)) + png_handle_zTXt(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_iTXt_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_iTXt, 4)) + png_handle_iTXt(png_ptr, info_ptr, length); +#endif + else + png_handle_unknown(png_ptr, info_ptr, length); + } while (!(png_ptr->mode & PNG_HAVE_IEND)); +} +#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */ + +/* free all memory used by the read */ +void PNGAPI +png_destroy_read_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr, + png_infopp end_info_ptr_ptr) +{ + png_structp png_ptr = NULL; + png_infop info_ptr = NULL, end_info_ptr = NULL; +#ifdef PNG_USER_MEM_SUPPORTED + png_free_ptr free_fn; + png_voidp mem_ptr; +#endif + + png_debug(1, "in png_destroy_read_struct\n"); + if (png_ptr_ptr != NULL) + png_ptr = *png_ptr_ptr; + + if (info_ptr_ptr != NULL) + info_ptr = *info_ptr_ptr; + + if (end_info_ptr_ptr != NULL) + end_info_ptr = *end_info_ptr_ptr; + +#ifdef PNG_USER_MEM_SUPPORTED + free_fn = png_ptr->free_fn; + mem_ptr = png_ptr->mem_ptr; +#endif + + png_read_destroy(png_ptr, info_ptr, end_info_ptr); + + if (info_ptr != NULL) + { +#if defined(PNG_TEXT_SUPPORTED) + png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, -1); +#endif + +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn, + (png_voidp)mem_ptr); +#else + png_destroy_struct((png_voidp)info_ptr); +#endif + *info_ptr_ptr = NULL; + } + + if (end_info_ptr != NULL) + { +#if defined(PNG_READ_TEXT_SUPPORTED) + png_free_data(png_ptr, end_info_ptr, PNG_FREE_TEXT, -1); +#endif +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2((png_voidp)end_info_ptr, (png_free_ptr)free_fn, + (png_voidp)mem_ptr); +#else + png_destroy_struct((png_voidp)end_info_ptr); +#endif + *end_info_ptr_ptr = NULL; + } + + if (png_ptr != NULL) + { +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn, + (png_voidp)mem_ptr); +#else + png_destroy_struct((png_voidp)png_ptr); +#endif + *png_ptr_ptr = NULL; + } +} + +/* free all memory used by the read (old method) */ +void /* PRIVATE */ +png_read_destroy(png_structp png_ptr, png_infop info_ptr, png_infop end_info_ptr) +{ +#ifdef PNG_SETJMP_SUPPORTED + jmp_buf tmp_jmp; +#endif + png_error_ptr error_fn; + png_error_ptr warning_fn; + png_voidp error_ptr; +#ifdef PNG_USER_MEM_SUPPORTED + png_free_ptr free_fn; +#endif + + png_debug(1, "in png_read_destroy\n"); + if (info_ptr != NULL) + png_info_destroy(png_ptr, info_ptr); + + if (end_info_ptr != NULL) + png_info_destroy(png_ptr, end_info_ptr); + + png_free(png_ptr, png_ptr->zbuf); + png_free(png_ptr, png_ptr->big_row_buf); + png_free(png_ptr, png_ptr->prev_row); +#if defined(PNG_READ_DITHER_SUPPORTED) + png_free(png_ptr, png_ptr->palette_lookup); + png_free(png_ptr, png_ptr->dither_index); +#endif +#if defined(PNG_READ_GAMMA_SUPPORTED) + png_free(png_ptr, png_ptr->gamma_table); +#endif +#if defined(PNG_READ_BACKGROUND_SUPPORTED) + png_free(png_ptr, png_ptr->gamma_from_1); + png_free(png_ptr, png_ptr->gamma_to_1); +#endif +#ifdef PNG_FREE_ME_SUPPORTED + if (png_ptr->free_me & PNG_FREE_PLTE) + png_zfree(png_ptr, png_ptr->palette); + png_ptr->free_me &= ~PNG_FREE_PLTE; +#else + if (png_ptr->flags & PNG_FLAG_FREE_PLTE) + png_zfree(png_ptr, png_ptr->palette); + png_ptr->flags &= ~PNG_FLAG_FREE_PLTE; +#endif +#if defined(PNG_tRNS_SUPPORTED) || \ + defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) +#ifdef PNG_FREE_ME_SUPPORTED + if (png_ptr->free_me & PNG_FREE_TRNS) + png_free(png_ptr, png_ptr->trans); + png_ptr->free_me &= ~PNG_FREE_TRNS; +#else + if (png_ptr->flags & PNG_FLAG_FREE_TRNS) + png_free(png_ptr, png_ptr->trans); + png_ptr->flags &= ~PNG_FLAG_FREE_TRNS; +#endif +#endif +#if defined(PNG_READ_hIST_SUPPORTED) +#ifdef PNG_FREE_ME_SUPPORTED + if (png_ptr->free_me & PNG_FREE_HIST) + png_free(png_ptr, png_ptr->hist); + png_ptr->free_me &= ~PNG_FREE_HIST; +#else + if (png_ptr->flags & PNG_FLAG_FREE_HIST) + png_free(png_ptr, png_ptr->hist); + png_ptr->flags &= ~PNG_FLAG_FREE_HIST; +#endif +#endif +#if defined(PNG_READ_GAMMA_SUPPORTED) + if (png_ptr->gamma_16_table != NULL) + { + int i; + int istop = (1 << (8 - png_ptr->gamma_shift)); + for (i = 0; i < istop; i++) + { + png_free(png_ptr, png_ptr->gamma_16_table[i]); + } + png_free(png_ptr, png_ptr->gamma_16_table); + } +#if defined(PNG_READ_BACKGROUND_SUPPORTED) + if (png_ptr->gamma_16_from_1 != NULL) + { + int i; + int istop = (1 << (8 - png_ptr->gamma_shift)); + for (i = 0; i < istop; i++) + { + png_free(png_ptr, png_ptr->gamma_16_from_1[i]); + } + png_free(png_ptr, png_ptr->gamma_16_from_1); + } + if (png_ptr->gamma_16_to_1 != NULL) + { + int i; + int istop = (1 << (8 - png_ptr->gamma_shift)); + for (i = 0; i < istop; i++) + { + png_free(png_ptr, png_ptr->gamma_16_to_1[i]); + } + png_free(png_ptr, png_ptr->gamma_16_to_1); + } +#endif +#endif +#if defined(PNG_TIME_RFC1123_SUPPORTED) + png_free(png_ptr, png_ptr->time_buffer); +#endif + + inflateEnd(&png_ptr->zstream); +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED + png_free(png_ptr, png_ptr->save_buffer); +#endif + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +#ifdef PNG_TEXT_SUPPORTED + png_free(png_ptr, png_ptr->current_text); +#endif /* PNG_TEXT_SUPPORTED */ +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ + + /* Save the important info out of the png_struct, in case it is + * being used again. + */ +#ifdef PNG_SETJMP_SUPPORTED + png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof (jmp_buf)); +#endif + + error_fn = png_ptr->error_fn; + warning_fn = png_ptr->warning_fn; + error_ptr = png_ptr->error_ptr; +#ifdef PNG_USER_MEM_SUPPORTED + free_fn = png_ptr->free_fn; +#endif + + png_memset(png_ptr, 0, png_sizeof (png_struct)); + + png_ptr->error_fn = error_fn; + png_ptr->warning_fn = warning_fn; + png_ptr->error_ptr = error_ptr; +#ifdef PNG_USER_MEM_SUPPORTED + png_ptr->free_fn = free_fn; +#endif + +#ifdef PNG_SETJMP_SUPPORTED + png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof (jmp_buf)); +#endif + +} + +void PNGAPI +png_set_read_status_fn(png_structp png_ptr, png_read_status_ptr read_row_fn) +{ + png_ptr->read_row_fn = read_row_fn; +} + + +#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED +#if defined(PNG_INFO_IMAGE_SUPPORTED) +void PNGAPI +png_read_png(png_structp png_ptr, png_infop info_ptr, + int transforms, + voidp params) +{ + int row; + +#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) + /* invert the alpha channel from opacity to transparency + */ + if (transforms & PNG_TRANSFORM_INVERT_ALPHA) + png_set_invert_alpha(png_ptr); +#endif + + /* png_read_info() gives us all of the information from the + * PNG file before the first IDAT (image data chunk). + */ + png_read_info(png_ptr, info_ptr); + if (info_ptr->height > PNG_UINT_32_MAX/png_sizeof(png_bytep)) + png_error(png_ptr,"Image is too high to process with png_read_png()"); + + /* -------------- image transformations start here ------------------- */ + +#if defined(PNG_READ_16_TO_8_SUPPORTED) + /* tell libpng to strip 16 bit/color files down to 8 bits per color + */ + if (transforms & PNG_TRANSFORM_STRIP_16) + png_set_strip_16(png_ptr); +#endif + +#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED) + /* Strip alpha bytes from the input data without combining with + * the background (not recommended). + */ + if (transforms & PNG_TRANSFORM_STRIP_ALPHA) + png_set_strip_alpha(png_ptr); +#endif + +#if defined(PNG_READ_PACK_SUPPORTED) && !defined(PNG_READ_EXPAND_SUPPORTED) + /* Extract multiple pixels with bit depths of 1, 2, or 4 from a single + * byte into separate bytes (useful for paletted and grayscale images). + */ + if (transforms & PNG_TRANSFORM_PACKING) + png_set_packing(png_ptr); +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + /* Change the order of packed pixels to least significant bit first + * (not useful if you are using png_set_packing). + */ + if (transforms & PNG_TRANSFORM_PACKSWAP) + png_set_packswap(png_ptr); +#endif + +#if defined(PNG_READ_EXPAND_SUPPORTED) + /* Expand paletted colors into true RGB triplets + * Expand grayscale images to full 8 bits from 1, 2, or 4 bits/pixel + * Expand paletted or RGB images with transparency to full alpha + * channels so the data will be available as RGBA quartets. + */ + if (transforms & PNG_TRANSFORM_EXPAND) + if ((png_ptr->bit_depth < 8) || + (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) || + (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))) + png_set_expand(png_ptr); +#endif + + /* We don't handle background color or gamma transformation or dithering. + */ + +#if defined(PNG_READ_INVERT_SUPPORTED) + /* invert monochrome files to have 0 as white and 1 as black + */ + if (transforms & PNG_TRANSFORM_INVERT_MONO) + png_set_invert_mono(png_ptr); +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) + /* If you want to shift the pixel values from the range [0,255] or + * [0,65535] to the original [0,7] or [0,31], or whatever range the + * colors were originally in: + */ + if ((transforms & PNG_TRANSFORM_SHIFT) + && png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT)) + { + png_color_8p sig_bit; + + png_get_sBIT(png_ptr, info_ptr, &sig_bit); + png_set_shift(png_ptr, sig_bit); + } +#endif + +#if defined(PNG_READ_BGR_SUPPORTED) + /* flip the RGB pixels to BGR (or RGBA to BGRA) + */ + if (transforms & PNG_TRANSFORM_BGR) + png_set_bgr(png_ptr); +#endif + +#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) + /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) + */ + if (transforms & PNG_TRANSFORM_SWAP_ALPHA) + png_set_swap_alpha(png_ptr); +#endif + +#if defined(PNG_READ_SWAP_SUPPORTED) + /* swap bytes of 16 bit files to least significant byte first + */ + if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) + png_set_swap(png_ptr); +#endif + + /* We don't handle adding filler bytes */ + + /* Optional call to gamma correct and add the background to the palette + * and update info structure. REQUIRED if you are expecting libpng to + * update the palette for you (i.e., you selected such a transform above). + */ + png_read_update_info(png_ptr, info_ptr); + + /* -------------- image transformations end here ------------------- */ + +#ifdef PNG_FREE_ME_SUPPORTED + png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); +#endif + if(info_ptr->row_pointers == NULL) + { + info_ptr->row_pointers = (png_bytepp)png_malloc(png_ptr, + info_ptr->height * png_sizeof(png_bytep)); +#ifdef PNG_FREE_ME_SUPPORTED + info_ptr->free_me |= PNG_FREE_ROWS; +#endif + for (row = 0; row < (int)info_ptr->height; row++) + { + info_ptr->row_pointers[row] = (png_bytep)png_malloc(png_ptr, + png_get_rowbytes(png_ptr, info_ptr)); + } + } + + png_read_image(png_ptr, info_ptr->row_pointers); + info_ptr->valid |= PNG_INFO_IDAT; + + /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ + png_read_end(png_ptr, info_ptr); + + if(transforms == 0 || params == NULL) + /* quiet compiler warnings */ return; + +} +#endif +#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */ diff --git a/syslinux/com32/lib/libpng/pngrio.c b/syslinux/com32/lib/libpng/pngrio.c new file mode 100644 index 0000000..cae501a --- /dev/null +++ b/syslinux/com32/lib/libpng/pngrio.c @@ -0,0 +1,161 @@ + +/* pngrio.c - functions for data input + * + * libpng 1.2.8 - December 3, 2004 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2004 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This file provides a location for all input. Users who need + * special handling are expected to write a function that has the same + * arguments as this and performs a similar function, but that possibly + * has a different input method. Note that you shouldn't change this + * function, but rather write a replacement function and then make + * libpng use it at run time with png_set_read_fn(...). + */ + +#define PNG_INTERNAL +#include "png.h" + +/* Read the data from whatever input you are using. The default routine + reads from a file pointer. Note that this routine sometimes gets called + with very small lengths, so you should implement some kind of simple + buffering if you are using unbuffered reads. This should never be asked + to read more then 64K on a 16 bit machine. */ +void /* PRIVATE */ +png_read_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_debug1(4,"reading %d bytes\n", (int)length); + if (png_ptr->read_data_fn != NULL) + (*(png_ptr->read_data_fn))(png_ptr, data, length); + else + png_error(png_ptr, "Call to NULL read function"); +} + +#if !defined(PNG_NO_STDIO) +/* This is the function that does the actual reading of data. If you are + not reading from a standard C stream, you should create a replacement + read_data function and use it at run time with png_set_read_fn(), rather + than changing the library. */ +#ifndef USE_FAR_KEYWORD +void PNGAPI +png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_size_t check; + + /* fread() returns 0 on error, so it is OK to store this in a png_size_t + * instead of an int, which is what fread() actually returns. + */ +#if defined(_WIN32_WCE) + if ( !ReadFile((HANDLE)(png_ptr->io_ptr), data, length, &check, NULL) ) + check = 0; +#else + check = (png_size_t)fread(data, (png_size_t)1, length, + (png_FILE_p)png_ptr->io_ptr); +#endif + + if (check != length) + png_error(png_ptr, "Read Error"); +} +#else +/* this is the model-independent version. Since the standard I/O library + can't handle far buffers in the medium and small models, we have to copy + the data. +*/ + +#define NEAR_BUF_SIZE 1024 +#define MIN(a,b) (a <= b ? a : b) + +static void /* PRIVATE */ +png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + int check; + png_byte *n_data; + png_FILE_p io_ptr; + + /* Check if data really is near. If so, use usual code. */ + n_data = (png_byte *)CVT_PTR_NOCHECK(data); + io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr); + if ((png_bytep)n_data == data) + { +#if defined(_WIN32_WCE) + if ( !ReadFile((HANDLE)(png_ptr->io_ptr), data, length, &check, NULL) ) + check = 0; +#else + check = fread(n_data, 1, length, io_ptr); +#endif + } + else + { + png_byte buf[NEAR_BUF_SIZE]; + png_size_t read, remaining, err; + check = 0; + remaining = length; + do + { + read = MIN(NEAR_BUF_SIZE, remaining); +#if defined(_WIN32_WCE) + if ( !ReadFile((HANDLE)(io_ptr), buf, read, &err, NULL) ) + err = 0; +#else + err = fread(buf, (png_size_t)1, read, io_ptr); +#endif + png_memcpy(data, buf, read); /* copy far buffer to near buffer */ + if(err != read) + break; + else + check += err; + data += read; + remaining -= read; + } + while (remaining != 0); + } + if ((png_uint_32)check != (png_uint_32)length) + png_error(png_ptr, "read Error"); +} +#endif +#endif + +/* This function allows the application to supply a new input function + for libpng if standard C streams aren't being used. + + This function takes as its arguments: + png_ptr - pointer to a png input data structure + io_ptr - pointer to user supplied structure containing info about + the input functions. May be NULL. + read_data_fn - pointer to a new input function that takes as its + arguments a pointer to a png_struct, a pointer to + a location where input data can be stored, and a 32-bit + unsigned int that is the number of bytes to be read. + To exit and output any fatal error messages the new write + function should call png_error(png_ptr, "Error msg"). */ +void PNGAPI +png_set_read_fn(png_structp png_ptr, png_voidp io_ptr, + png_rw_ptr read_data_fn) +{ + png_ptr->io_ptr = io_ptr; + +#if !defined(PNG_NO_STDIO) + if (read_data_fn != NULL) + png_ptr->read_data_fn = read_data_fn; + else + png_ptr->read_data_fn = png_default_read_data; +#else + png_ptr->read_data_fn = read_data_fn; +#endif + + /* It is an error to write to a read device */ + if (png_ptr->write_data_fn != NULL) + { + png_ptr->write_data_fn = NULL; + png_warning(png_ptr, + "It's an error to set both read_data_fn and write_data_fn in the "); + png_warning(png_ptr, + "same structure. Resetting write_data_fn to NULL."); + } + +#if defined(PNG_WRITE_FLUSH_SUPPORTED) + png_ptr->output_flush_fn = NULL; +#endif +} diff --git a/syslinux/com32/lib/libpng/pngrtran.c b/syslinux/com32/lib/libpng/pngrtran.c new file mode 100644 index 0000000..e1d6e3c --- /dev/null +++ b/syslinux/com32/lib/libpng/pngrtran.c @@ -0,0 +1,4177 @@ + +/* pngrtran.c - transforms the data in a row for PNG readers + * + * libpng version 1.2.8 - December 3, 2004 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2004 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This file contains functions optionally called by an application + * in order to tell libpng how to handle data when reading a PNG. + * Transformations that are used in both reading and writing are + * in pngtrans.c. + */ + +#define PNG_INTERNAL +#include "png.h" + +/* Set the action on getting a CRC error for an ancillary or critical chunk. */ +void PNGAPI +png_set_crc_action(png_structp png_ptr, int crit_action, int ancil_action) +{ + png_debug(1, "in png_set_crc_action\n"); + /* Tell libpng how we react to CRC errors in critical chunks */ + switch (crit_action) + { + case PNG_CRC_NO_CHANGE: /* leave setting as is */ + break; + case PNG_CRC_WARN_USE: /* warn/use data */ + png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; + png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE; + break; + case PNG_CRC_QUIET_USE: /* quiet/use data */ + png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; + png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE | + PNG_FLAG_CRC_CRITICAL_IGNORE; + break; + case PNG_CRC_WARN_DISCARD: /* not a valid action for critical data */ + png_warning(png_ptr, "Can't discard critical data on CRC error."); + case PNG_CRC_ERROR_QUIT: /* error/quit */ + case PNG_CRC_DEFAULT: + default: + png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; + break; + } + + switch (ancil_action) + { + case PNG_CRC_NO_CHANGE: /* leave setting as is */ + break; + case PNG_CRC_WARN_USE: /* warn/use data */ + png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; + png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE; + break; + case PNG_CRC_QUIET_USE: /* quiet/use data */ + png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; + png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE | + PNG_FLAG_CRC_ANCILLARY_NOWARN; + break; + case PNG_CRC_ERROR_QUIT: /* error/quit */ + png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; + png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_NOWARN; + break; + case PNG_CRC_WARN_DISCARD: /* warn/discard data */ + case PNG_CRC_DEFAULT: + default: + png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; + break; + } +} + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \ + defined(PNG_FLOATING_POINT_SUPPORTED) +/* handle alpha and tRNS via a background color */ +void PNGAPI +png_set_background(png_structp png_ptr, + png_color_16p background_color, int background_gamma_code, + int need_expand, double background_gamma) +{ + png_debug(1, "in png_set_background\n"); + if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN) + { + png_warning(png_ptr, "Application must supply a known background gamma"); + return; + } + + png_ptr->transformations |= PNG_BACKGROUND; + png_memcpy(&(png_ptr->background), background_color, + png_sizeof(png_color_16)); + png_ptr->background_gamma = (float)background_gamma; + png_ptr->background_gamma_type = (png_byte)(background_gamma_code); + png_ptr->transformations |= (need_expand ? PNG_BACKGROUND_EXPAND : 0); + + /* Note: if need_expand is set and color_type is either RGB or RGB_ALPHA + * (in which case need_expand is superfluous anyway), the background color + * might actually be gray yet not be flagged as such. This is not a problem + * for the current code, which uses PNG_BACKGROUND_IS_GRAY only to + * decide when to do the png_do_gray_to_rgb() transformation. + */ + if ((need_expand && !(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) || + (!need_expand && background_color->red == background_color->green && + background_color->red == background_color->blue)) + png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; +} +#endif + +#if defined(PNG_READ_16_TO_8_SUPPORTED) +/* strip 16 bit depth files to 8 bit depth */ +void PNGAPI +png_set_strip_16(png_structp png_ptr) +{ + png_debug(1, "in png_set_strip_16\n"); + png_ptr->transformations |= PNG_16_TO_8; +} +#endif + +#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED) +void PNGAPI +png_set_strip_alpha(png_structp png_ptr) +{ + png_debug(1, "in png_set_strip_alpha\n"); + png_ptr->flags |= PNG_FLAG_STRIP_ALPHA; +} +#endif + +#if defined(PNG_READ_DITHER_SUPPORTED) +/* Dither file to 8 bit. Supply a palette, the current number + * of elements in the palette, the maximum number of elements + * allowed, and a histogram if possible. If the current number + * of colors is greater then the maximum number, the palette will be + * modified to fit in the maximum number. "full_dither" indicates + * whether we need a dithering cube set up for RGB images, or if we + * simply are reducing the number of colors in a paletted image. + */ + +typedef struct png_dsort_struct +{ + struct png_dsort_struct FAR * next; + png_byte left; + png_byte right; +} png_dsort; +typedef png_dsort FAR * png_dsortp; +typedef png_dsort FAR * FAR * png_dsortpp; + +void PNGAPI +png_set_dither(png_structp png_ptr, png_colorp palette, + int num_palette, int maximum_colors, png_uint_16p histogram, + int full_dither) +{ + png_debug(1, "in png_set_dither\n"); + png_ptr->transformations |= PNG_DITHER; + + if (!full_dither) + { + int i; + + png_ptr->dither_index = (png_bytep)png_malloc(png_ptr, + (png_uint_32)(num_palette * png_sizeof (png_byte))); + for (i = 0; i < num_palette; i++) + png_ptr->dither_index[i] = (png_byte)i; + } + + if (num_palette > maximum_colors) + { + if (histogram != NULL) + { + /* This is easy enough, just throw out the least used colors. + Perhaps not the best solution, but good enough. */ + + int i; + + /* initialize an array to sort colors */ + png_ptr->dither_sort = (png_bytep)png_malloc(png_ptr, + (png_uint_32)(num_palette * png_sizeof (png_byte))); + + /* initialize the dither_sort array */ + for (i = 0; i < num_palette; i++) + png_ptr->dither_sort[i] = (png_byte)i; + + /* Find the least used palette entries by starting a + bubble sort, and running it until we have sorted + out enough colors. Note that we don't care about + sorting all the colors, just finding which are + least used. */ + + for (i = num_palette - 1; i >= maximum_colors; i--) + { + int done; /* to stop early if the list is pre-sorted */ + int j; + + done = 1; + for (j = 0; j < i; j++) + { + if (histogram[png_ptr->dither_sort[j]] + < histogram[png_ptr->dither_sort[j + 1]]) + { + png_byte t; + + t = png_ptr->dither_sort[j]; + png_ptr->dither_sort[j] = png_ptr->dither_sort[j + 1]; + png_ptr->dither_sort[j + 1] = t; + done = 0; + } + } + if (done) + break; + } + + /* swap the palette around, and set up a table, if necessary */ + if (full_dither) + { + int j = num_palette; + + /* put all the useful colors within the max, but don't + move the others */ + for (i = 0; i < maximum_colors; i++) + { + if ((int)png_ptr->dither_sort[i] >= maximum_colors) + { + do + j--; + while ((int)png_ptr->dither_sort[j] >= maximum_colors); + palette[i] = palette[j]; + } + } + } + else + { + int j = num_palette; + + /* move all the used colors inside the max limit, and + develop a translation table */ + for (i = 0; i < maximum_colors; i++) + { + /* only move the colors we need to */ + if ((int)png_ptr->dither_sort[i] >= maximum_colors) + { + png_color tmp_color; + + do + j--; + while ((int)png_ptr->dither_sort[j] >= maximum_colors); + + tmp_color = palette[j]; + palette[j] = palette[i]; + palette[i] = tmp_color; + /* indicate where the color went */ + png_ptr->dither_index[j] = (png_byte)i; + png_ptr->dither_index[i] = (png_byte)j; + } + } + + /* find closest color for those colors we are not using */ + for (i = 0; i < num_palette; i++) + { + if ((int)png_ptr->dither_index[i] >= maximum_colors) + { + int min_d, k, min_k, d_index; + + /* find the closest color to one we threw out */ + d_index = png_ptr->dither_index[i]; + min_d = PNG_COLOR_DIST(palette[d_index], palette[0]); + for (k = 1, min_k = 0; k < maximum_colors; k++) + { + int d; + + d = PNG_COLOR_DIST(palette[d_index], palette[k]); + + if (d < min_d) + { + min_d = d; + min_k = k; + } + } + /* point to closest color */ + png_ptr->dither_index[i] = (png_byte)min_k; + } + } + } + png_free(png_ptr, png_ptr->dither_sort); + png_ptr->dither_sort=NULL; + } + else + { + /* This is much harder to do simply (and quickly). Perhaps + we need to go through a median cut routine, but those + don't always behave themselves with only a few colors + as input. So we will just find the closest two colors, + and throw out one of them (chosen somewhat randomly). + [We don't understand this at all, so if someone wants to + work on improving it, be our guest - AED, GRP] + */ + int i; + int max_d; + int num_new_palette; + png_dsortp t; + png_dsortpp hash; + + t=NULL; + + /* initialize palette index arrays */ + png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr, + (png_uint_32)(num_palette * png_sizeof (png_byte))); + png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr, + (png_uint_32)(num_palette * png_sizeof (png_byte))); + + /* initialize the sort array */ + for (i = 0; i < num_palette; i++) + { + png_ptr->index_to_palette[i] = (png_byte)i; + png_ptr->palette_to_index[i] = (png_byte)i; + } + + hash = (png_dsortpp)png_malloc(png_ptr, (png_uint_32)(769 * + png_sizeof (png_dsortp))); + for (i = 0; i < 769; i++) + hash[i] = NULL; +/* png_memset(hash, 0, 769 * png_sizeof (png_dsortp)); */ + + num_new_palette = num_palette; + + /* initial wild guess at how far apart the farthest pixel + pair we will be eliminating will be. Larger + numbers mean more areas will be allocated, Smaller + numbers run the risk of not saving enough data, and + having to do this all over again. + + I have not done extensive checking on this number. + */ + max_d = 96; + + while (num_new_palette > maximum_colors) + { + for (i = 0; i < num_new_palette - 1; i++) + { + int j; + + for (j = i + 1; j < num_new_palette; j++) + { + int d; + + d = PNG_COLOR_DIST(palette[i], palette[j]); + + if (d <= max_d) + { + + t = (png_dsortp)png_malloc_warn(png_ptr, + (png_uint_32)(png_sizeof(png_dsort))); + if (t == NULL) + break; + t->next = hash[d]; + t->left = (png_byte)i; + t->right = (png_byte)j; + hash[d] = t; + } + } + if (t == NULL) + break; + } + + if (t != NULL) + for (i = 0; i <= max_d; i++) + { + if (hash[i] != NULL) + { + png_dsortp p; + + for (p = hash[i]; p; p = p->next) + { + if ((int)png_ptr->index_to_palette[p->left] + < num_new_palette && + (int)png_ptr->index_to_palette[p->right] + < num_new_palette) + { + int j, next_j; + + if (num_new_palette & 0x01) + { + j = p->left; + next_j = p->right; + } + else + { + j = p->right; + next_j = p->left; + } + + num_new_palette--; + palette[png_ptr->index_to_palette[j]] + = palette[num_new_palette]; + if (!full_dither) + { + int k; + + for (k = 0; k < num_palette; k++) + { + if (png_ptr->dither_index[k] == + png_ptr->index_to_palette[j]) + png_ptr->dither_index[k] = + png_ptr->index_to_palette[next_j]; + if ((int)png_ptr->dither_index[k] == + num_new_palette) + png_ptr->dither_index[k] = + png_ptr->index_to_palette[j]; + } + } + + png_ptr->index_to_palette[png_ptr->palette_to_index + [num_new_palette]] = png_ptr->index_to_palette[j]; + png_ptr->palette_to_index[png_ptr->index_to_palette[j]] + = png_ptr->palette_to_index[num_new_palette]; + + png_ptr->index_to_palette[j] = (png_byte)num_new_palette; + png_ptr->palette_to_index[num_new_palette] = (png_byte)j; + } + if (num_new_palette <= maximum_colors) + break; + } + if (num_new_palette <= maximum_colors) + break; + } + } + + for (i = 0; i < 769; i++) + { + if (hash[i] != NULL) + { + png_dsortp p = hash[i]; + while (p) + { + t = p->next; + png_free(png_ptr, p); + p = t; + } + } + hash[i] = 0; + } + max_d += 96; + } + png_free(png_ptr, hash); + png_free(png_ptr, png_ptr->palette_to_index); + png_free(png_ptr, png_ptr->index_to_palette); + png_ptr->palette_to_index=NULL; + png_ptr->index_to_palette=NULL; + } + num_palette = maximum_colors; + } + if (png_ptr->palette == NULL) + { + png_ptr->palette = palette; + } + png_ptr->num_palette = (png_uint_16)num_palette; + + if (full_dither) + { + int i; + png_bytep distance; + int total_bits = PNG_DITHER_RED_BITS + PNG_DITHER_GREEN_BITS + + PNG_DITHER_BLUE_BITS; + int num_red = (1 << PNG_DITHER_RED_BITS); + int num_green = (1 << PNG_DITHER_GREEN_BITS); + int num_blue = (1 << PNG_DITHER_BLUE_BITS); + png_size_t num_entries = ((png_size_t)1 << total_bits); + + png_ptr->palette_lookup = (png_bytep )png_malloc(png_ptr, + (png_uint_32)(num_entries * png_sizeof (png_byte))); + + png_memset(png_ptr->palette_lookup, 0, num_entries * + png_sizeof (png_byte)); + + distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_entries * + png_sizeof(png_byte))); + + png_memset(distance, 0xff, num_entries * png_sizeof(png_byte)); + + for (i = 0; i < num_palette; i++) + { + int ir, ig, ib; + int r = (palette[i].red >> (8 - PNG_DITHER_RED_BITS)); + int g = (palette[i].green >> (8 - PNG_DITHER_GREEN_BITS)); + int b = (palette[i].blue >> (8 - PNG_DITHER_BLUE_BITS)); + + for (ir = 0; ir < num_red; ir++) + { + /* int dr = abs(ir - r); */ + int dr = ((ir > r) ? ir - r : r - ir); + int index_r = (ir << (PNG_DITHER_BLUE_BITS + PNG_DITHER_GREEN_BITS)); + + for (ig = 0; ig < num_green; ig++) + { + /* int dg = abs(ig - g); */ + int dg = ((ig > g) ? ig - g : g - ig); + int dt = dr + dg; + int dm = ((dr > dg) ? dr : dg); + int index_g = index_r | (ig << PNG_DITHER_BLUE_BITS); + + for (ib = 0; ib < num_blue; ib++) + { + int d_index = index_g | ib; + /* int db = abs(ib - b); */ + int db = ((ib > b) ? ib - b : b - ib); + int dmax = ((dm > db) ? dm : db); + int d = dmax + dt + db; + + if (d < (int)distance[d_index]) + { + distance[d_index] = (png_byte)d; + png_ptr->palette_lookup[d_index] = (png_byte)i; + } + } + } + } + } + + png_free(png_ptr, distance); + } +} +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED) +/* Transform the image from the file_gamma to the screen_gamma. We + * only do transformations on images where the file_gamma and screen_gamma + * are not close reciprocals, otherwise it slows things down slightly, and + * also needlessly introduces small errors. + * + * We will turn off gamma transformation later if no semitransparent entries + * are present in the tRNS array for palette images. We can't do it here + * because we don't necessarily have the tRNS chunk yet. + */ +void PNGAPI +png_set_gamma(png_structp png_ptr, double scrn_gamma, double file_gamma) +{ + png_debug(1, "in png_set_gamma\n"); + if ((fabs(scrn_gamma * file_gamma - 1.0) > PNG_GAMMA_THRESHOLD) || + (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) || + (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)) + png_ptr->transformations |= PNG_GAMMA; + png_ptr->gamma = (float)file_gamma; + png_ptr->screen_gamma = (float)scrn_gamma; +} +#endif + +#if defined(PNG_READ_EXPAND_SUPPORTED) +/* Expand paletted images to RGB, expand grayscale images of + * less than 8-bit depth to 8-bit depth, and expand tRNS chunks + * to alpha channels. + */ +void PNGAPI +png_set_expand(png_structp png_ptr) +{ + png_debug(1, "in png_set_expand\n"); + png_ptr->transformations |= PNG_EXPAND; +} + +/* GRR 19990627: the following three functions currently are identical + * to png_set_expand(). However, it is entirely reasonable that someone + * might wish to expand an indexed image to RGB but *not* expand a single, + * fully transparent palette entry to a full alpha channel--perhaps instead + * convert tRNS to the grayscale/RGB format (16-bit RGB value), or replace + * the transparent color with a particular RGB value, or drop tRNS entirely. + * IOW, a future version of the library may make the transformations flag + * a bit more fine-grained, with separate bits for each of these three + * functions. + * + * More to the point, these functions make it obvious what libpng will be + * doing, whereas "expand" can (and does) mean any number of things. + */ + +/* Expand paletted images to RGB. */ +void PNGAPI +png_set_palette_to_rgb(png_structp png_ptr) +{ + png_debug(1, "in png_set_expand\n"); + png_ptr->transformations |= PNG_EXPAND; +} + +/* Expand grayscale images of less than 8-bit depth to 8 bits. */ +void PNGAPI +png_set_gray_1_2_4_to_8(png_structp png_ptr) +{ + png_debug(1, "in png_set_expand\n"); + png_ptr->transformations |= PNG_EXPAND; +} + +/* Expand tRNS chunks to alpha channels. */ +void PNGAPI +png_set_tRNS_to_alpha(png_structp png_ptr) +{ + png_debug(1, "in png_set_expand\n"); + png_ptr->transformations |= PNG_EXPAND; +} +#endif /* defined(PNG_READ_EXPAND_SUPPORTED) */ + +#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) +void PNGAPI +png_set_gray_to_rgb(png_structp png_ptr) +{ + png_debug(1, "in png_set_gray_to_rgb\n"); + png_ptr->transformations |= PNG_GRAY_TO_RGB; +} +#endif + +#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) +#if defined(PNG_FLOATING_POINT_SUPPORTED) +/* Convert a RGB image to a grayscale of the same width. This allows us, + * for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image. + */ + +void PNGAPI +png_set_rgb_to_gray(png_structp png_ptr, int error_action, double red, + double green) +{ + int red_fixed = (int)((float)red*100000.0 + 0.5); + int green_fixed = (int)((float)green*100000.0 + 0.5); + png_set_rgb_to_gray_fixed(png_ptr, error_action, red_fixed, green_fixed); +} +#endif + +void PNGAPI +png_set_rgb_to_gray_fixed(png_structp png_ptr, int error_action, + png_fixed_point red, png_fixed_point green) +{ + png_debug(1, "in png_set_rgb_to_gray\n"); + switch(error_action) + { + case 1: png_ptr->transformations |= PNG_RGB_TO_GRAY; + break; + case 2: png_ptr->transformations |= PNG_RGB_TO_GRAY_WARN; + break; + case 3: png_ptr->transformations |= PNG_RGB_TO_GRAY_ERR; + } + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) +#if defined(PNG_READ_EXPAND_SUPPORTED) + png_ptr->transformations |= PNG_EXPAND; +#else + { + png_warning(png_ptr, "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED."); + png_ptr->transformations &= ~PNG_RGB_TO_GRAY; + } +#endif + { + png_uint_16 red_int, green_int; + if(red < 0 || green < 0) + { + red_int = 6968; /* .212671 * 32768 + .5 */ + green_int = 23434; /* .715160 * 32768 + .5 */ + } + else if(red + green < 100000L) + { + red_int = (png_uint_16)(((png_uint_32)red*32768L)/100000L); + green_int = (png_uint_16)(((png_uint_32)green*32768L)/100000L); + } + else + { + png_warning(png_ptr, "ignoring out of range rgb_to_gray coefficients"); + red_int = 6968; + green_int = 23434; + } + png_ptr->rgb_to_gray_red_coeff = red_int; + png_ptr->rgb_to_gray_green_coeff = green_int; + png_ptr->rgb_to_gray_blue_coeff = (png_uint_16)(32768-red_int-green_int); + } +} +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_LEGACY_SUPPORTED) +void PNGAPI +png_set_read_user_transform_fn(png_structp png_ptr, png_user_transform_ptr + read_user_transform_fn) +{ + png_debug(1, "in png_set_read_user_transform_fn\n"); +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) + png_ptr->transformations |= PNG_USER_TRANSFORM; + png_ptr->read_user_transform_fn = read_user_transform_fn; +#endif +#ifdef PNG_LEGACY_SUPPORTED + if(read_user_transform_fn) + png_warning(png_ptr, + "This version of libpng does not support user transforms"); +#endif +} +#endif + +/* Initialize everything needed for the read. This includes modifying + * the palette. + */ +void /* PRIVATE */ +png_init_read_transformations(png_structp png_ptr) +{ + png_debug(1, "in png_init_read_transformations\n"); +#if defined(PNG_USELESS_TESTS_SUPPORTED) + if(png_ptr != NULL) +#endif + { +#if defined(PNG_READ_BACKGROUND_SUPPORTED) || defined(PNG_READ_SHIFT_SUPPORTED) \ + || defined(PNG_READ_GAMMA_SUPPORTED) + int color_type = png_ptr->color_type; +#endif + +#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED) + if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) && + (png_ptr->transformations & PNG_EXPAND)) + { + if (!(color_type & PNG_COLOR_MASK_COLOR)) /* i.e., GRAY or GRAY_ALPHA */ + { + /* expand background chunk. */ + switch (png_ptr->bit_depth) + { + case 1: + png_ptr->background.gray *= (png_uint_16)0xff; + png_ptr->background.red = png_ptr->background.green + = png_ptr->background.blue = png_ptr->background.gray; + break; + case 2: + png_ptr->background.gray *= (png_uint_16)0x55; + png_ptr->background.red = png_ptr->background.green + = png_ptr->background.blue = png_ptr->background.gray; + break; + case 4: + png_ptr->background.gray *= (png_uint_16)0x11; + png_ptr->background.red = png_ptr->background.green + = png_ptr->background.blue = png_ptr->background.gray; + break; + case 8: + case 16: + png_ptr->background.red = png_ptr->background.green + = png_ptr->background.blue = png_ptr->background.gray; + break; + } + } + else if (color_type == PNG_COLOR_TYPE_PALETTE) + { + png_ptr->background.red = + png_ptr->palette[png_ptr->background.index].red; + png_ptr->background.green = + png_ptr->palette[png_ptr->background.index].green; + png_ptr->background.blue = + png_ptr->palette[png_ptr->background.index].blue; + +#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) + if (png_ptr->transformations & PNG_INVERT_ALPHA) + { +#if defined(PNG_READ_EXPAND_SUPPORTED) + if (!(png_ptr->transformations & PNG_EXPAND)) +#endif + { + /* invert the alpha channel (in tRNS) unless the pixels are + going to be expanded, in which case leave it for later */ + int i,istop; + istop=(int)png_ptr->num_trans; + for (i=0; i<istop; i++) + png_ptr->trans[i] = (png_byte)(255 - png_ptr->trans[i]); + } + } +#endif + + } + } +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED) + png_ptr->background_1 = png_ptr->background; +#endif +#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED) + + if ((color_type == PNG_COLOR_TYPE_PALETTE && png_ptr->num_trans != 0) + && (fabs(png_ptr->screen_gamma * png_ptr->gamma - 1.0) + < PNG_GAMMA_THRESHOLD)) + { + int i,k; + k=0; + for (i=0; i<png_ptr->num_trans; i++) + { + if (png_ptr->trans[i] != 0 && png_ptr->trans[i] != 0xff) + k=1; /* partial transparency is present */ + } + if (k == 0) + png_ptr->transformations &= (~PNG_GAMMA); + } + + if (png_ptr->transformations & (PNG_GAMMA | PNG_RGB_TO_GRAY)) + { + png_build_gamma_table(png_ptr); +#if defined(PNG_READ_BACKGROUND_SUPPORTED) + if (png_ptr->transformations & PNG_BACKGROUND) + { + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + /* could skip if no transparency and + */ + png_color back, back_1; + png_colorp palette = png_ptr->palette; + int num_palette = png_ptr->num_palette; + int i; + if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE) + { + back.red = png_ptr->gamma_table[png_ptr->background.red]; + back.green = png_ptr->gamma_table[png_ptr->background.green]; + back.blue = png_ptr->gamma_table[png_ptr->background.blue]; + + back_1.red = png_ptr->gamma_to_1[png_ptr->background.red]; + back_1.green = png_ptr->gamma_to_1[png_ptr->background.green]; + back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue]; + } + else + { + double g, gs; + + switch (png_ptr->background_gamma_type) + { + case PNG_BACKGROUND_GAMMA_SCREEN: + g = (png_ptr->screen_gamma); + gs = 1.0; + break; + case PNG_BACKGROUND_GAMMA_FILE: + g = 1.0 / (png_ptr->gamma); + gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma); + break; + case PNG_BACKGROUND_GAMMA_UNIQUE: + g = 1.0 / (png_ptr->background_gamma); + gs = 1.0 / (png_ptr->background_gamma * + png_ptr->screen_gamma); + break; + default: + g = 1.0; /* back_1 */ + gs = 1.0; /* back */ + } + + if ( fabs(gs - 1.0) < PNG_GAMMA_THRESHOLD) + { + back.red = (png_byte)png_ptr->background.red; + back.green = (png_byte)png_ptr->background.green; + back.blue = (png_byte)png_ptr->background.blue; + } + else + { + back.red = (png_byte)(pow( + (double)png_ptr->background.red/255, gs) * 255.0 + .5); + back.green = (png_byte)(pow( + (double)png_ptr->background.green/255, gs) * 255.0 + .5); + back.blue = (png_byte)(pow( + (double)png_ptr->background.blue/255, gs) * 255.0 + .5); + } + + back_1.red = (png_byte)(pow( + (double)png_ptr->background.red/255, g) * 255.0 + .5); + back_1.green = (png_byte)(pow( + (double)png_ptr->background.green/255, g) * 255.0 + .5); + back_1.blue = (png_byte)(pow( + (double)png_ptr->background.blue/255, g) * 255.0 + .5); + } + for (i = 0; i < num_palette; i++) + { + if (i < (int)png_ptr->num_trans && png_ptr->trans[i] != 0xff) + { + if (png_ptr->trans[i] == 0) + { + palette[i] = back; + } + else /* if (png_ptr->trans[i] != 0xff) */ + { + png_byte v, w; + + v = png_ptr->gamma_to_1[palette[i].red]; + png_composite(w, v, png_ptr->trans[i], back_1.red); + palette[i].red = png_ptr->gamma_from_1[w]; + + v = png_ptr->gamma_to_1[palette[i].green]; + png_composite(w, v, png_ptr->trans[i], back_1.green); + palette[i].green = png_ptr->gamma_from_1[w]; + + v = png_ptr->gamma_to_1[palette[i].blue]; + png_composite(w, v, png_ptr->trans[i], back_1.blue); + palette[i].blue = png_ptr->gamma_from_1[w]; + } + } + else + { + palette[i].red = png_ptr->gamma_table[palette[i].red]; + palette[i].green = png_ptr->gamma_table[palette[i].green]; + palette[i].blue = png_ptr->gamma_table[palette[i].blue]; + } + } + } + /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN) */ + else + /* color_type != PNG_COLOR_TYPE_PALETTE */ + { + double m = (double)(((png_uint_32)1 << png_ptr->bit_depth) - 1); + double g = 1.0; + double gs = 1.0; + + switch (png_ptr->background_gamma_type) + { + case PNG_BACKGROUND_GAMMA_SCREEN: + g = (png_ptr->screen_gamma); + gs = 1.0; + break; + case PNG_BACKGROUND_GAMMA_FILE: + g = 1.0 / (png_ptr->gamma); + gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma); + break; + case PNG_BACKGROUND_GAMMA_UNIQUE: + g = 1.0 / (png_ptr->background_gamma); + gs = 1.0 / (png_ptr->background_gamma * + png_ptr->screen_gamma); + break; + } + + png_ptr->background_1.gray = (png_uint_16)(pow( + (double)png_ptr->background.gray / m, g) * m + .5); + png_ptr->background.gray = (png_uint_16)(pow( + (double)png_ptr->background.gray / m, gs) * m + .5); + + if ((png_ptr->background.red != png_ptr->background.green) || + (png_ptr->background.red != png_ptr->background.blue) || + (png_ptr->background.red != png_ptr->background.gray)) + { + /* RGB or RGBA with color background */ + png_ptr->background_1.red = (png_uint_16)(pow( + (double)png_ptr->background.red / m, g) * m + .5); + png_ptr->background_1.green = (png_uint_16)(pow( + (double)png_ptr->background.green / m, g) * m + .5); + png_ptr->background_1.blue = (png_uint_16)(pow( + (double)png_ptr->background.blue / m, g) * m + .5); + png_ptr->background.red = (png_uint_16)(pow( + (double)png_ptr->background.red / m, gs) * m + .5); + png_ptr->background.green = (png_uint_16)(pow( + (double)png_ptr->background.green / m, gs) * m + .5); + png_ptr->background.blue = (png_uint_16)(pow( + (double)png_ptr->background.blue / m, gs) * m + .5); + } + else + { + /* GRAY, GRAY ALPHA, RGB, or RGBA with gray background */ + png_ptr->background_1.red = png_ptr->background_1.green + = png_ptr->background_1.blue = png_ptr->background_1.gray; + png_ptr->background.red = png_ptr->background.green + = png_ptr->background.blue = png_ptr->background.gray; + } + } + } + else + /* transformation does not include PNG_BACKGROUND */ +#endif /* PNG_READ_BACKGROUND_SUPPORTED */ + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + png_colorp palette = png_ptr->palette; + int num_palette = png_ptr->num_palette; + int i; + + for (i = 0; i < num_palette; i++) + { + palette[i].red = png_ptr->gamma_table[palette[i].red]; + palette[i].green = png_ptr->gamma_table[palette[i].green]; + palette[i].blue = png_ptr->gamma_table[palette[i].blue]; + } + } + } +#if defined(PNG_READ_BACKGROUND_SUPPORTED) + else +#endif +#endif /* PNG_READ_GAMMA_SUPPORTED && PNG_FLOATING_POINT_SUPPORTED */ +#if defined(PNG_READ_BACKGROUND_SUPPORTED) + /* No GAMMA transformation */ + if ((png_ptr->transformations & PNG_BACKGROUND) && + (color_type == PNG_COLOR_TYPE_PALETTE)) + { + int i; + int istop = (int)png_ptr->num_trans; + png_color back; + png_colorp palette = png_ptr->palette; + + back.red = (png_byte)png_ptr->background.red; + back.green = (png_byte)png_ptr->background.green; + back.blue = (png_byte)png_ptr->background.blue; + + for (i = 0; i < istop; i++) + { + if (png_ptr->trans[i] == 0) + { + palette[i] = back; + } + else if (png_ptr->trans[i] != 0xff) + { + /* The png_composite() macro is defined in png.h */ + png_composite(palette[i].red, palette[i].red, + png_ptr->trans[i], back.red); + png_composite(palette[i].green, palette[i].green, + png_ptr->trans[i], back.green); + png_composite(palette[i].blue, palette[i].blue, + png_ptr->trans[i], back.blue); + } + } + } +#endif /* PNG_READ_BACKGROUND_SUPPORTED */ + +#if defined(PNG_READ_SHIFT_SUPPORTED) + if ((png_ptr->transformations & PNG_SHIFT) && + (color_type == PNG_COLOR_TYPE_PALETTE)) + { + png_uint_16 i; + png_uint_16 istop = png_ptr->num_palette; + int sr = 8 - png_ptr->sig_bit.red; + int sg = 8 - png_ptr->sig_bit.green; + int sb = 8 - png_ptr->sig_bit.blue; + + if (sr < 0 || sr > 8) + sr = 0; + if (sg < 0 || sg > 8) + sg = 0; + if (sb < 0 || sb > 8) + sb = 0; + for (i = 0; i < istop; i++) + { + png_ptr->palette[i].red >>= sr; + png_ptr->palette[i].green >>= sg; + png_ptr->palette[i].blue >>= sb; + } + } +#endif /* PNG_READ_SHIFT_SUPPORTED */ + } +#if !defined(PNG_READ_GAMMA_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) \ + && !defined(PNG_READ_BACKGROUND_SUPPORTED) + if(png_ptr) + return; +#endif +} + +/* Modify the info structure to reflect the transformations. The + * info should be updated so a PNG file could be written with it, + * assuming the transformations result in valid PNG data. + */ +void /* PRIVATE */ +png_read_transform_info(png_structp png_ptr, png_infop info_ptr) +{ + png_debug(1, "in png_read_transform_info\n"); +#if defined(PNG_READ_EXPAND_SUPPORTED) + if (png_ptr->transformations & PNG_EXPAND) + { + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (png_ptr->num_trans) + info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA; + else + info_ptr->color_type = PNG_COLOR_TYPE_RGB; + info_ptr->bit_depth = 8; + info_ptr->num_trans = 0; + } + else + { + if (png_ptr->num_trans) + info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; + if (info_ptr->bit_depth < 8) + info_ptr->bit_depth = 8; + info_ptr->num_trans = 0; + } + } +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) + if (png_ptr->transformations & PNG_BACKGROUND) + { + info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA; + info_ptr->num_trans = 0; + info_ptr->background = png_ptr->background; + } +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) + if (png_ptr->transformations & PNG_GAMMA) + { +#ifdef PNG_FLOATING_POINT_SUPPORTED + info_ptr->gamma = png_ptr->gamma; +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + info_ptr->int_gamma = png_ptr->int_gamma; +#endif + } +#endif + +#if defined(PNG_READ_16_TO_8_SUPPORTED) + if ((png_ptr->transformations & PNG_16_TO_8) && (info_ptr->bit_depth == 16)) + info_ptr->bit_depth = 8; +#endif + +#if defined(PNG_READ_DITHER_SUPPORTED) + if (png_ptr->transformations & PNG_DITHER) + { + if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) || + (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) && + png_ptr->palette_lookup && info_ptr->bit_depth == 8) + { + info_ptr->color_type = PNG_COLOR_TYPE_PALETTE; + } + } +#endif + +#if defined(PNG_READ_PACK_SUPPORTED) + if ((png_ptr->transformations & PNG_PACK) && (info_ptr->bit_depth < 8)) + info_ptr->bit_depth = 8; +#endif + +#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) + if (png_ptr->transformations & PNG_GRAY_TO_RGB) + info_ptr->color_type |= PNG_COLOR_MASK_COLOR; +#endif + +#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + if (png_ptr->transformations & PNG_RGB_TO_GRAY) + info_ptr->color_type &= ~PNG_COLOR_MASK_COLOR; +#endif + + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + info_ptr->channels = 1; + else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) + info_ptr->channels = 3; + else + info_ptr->channels = 1; + +#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED) + if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA) + info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA; +#endif + + if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) + info_ptr->channels++; + +#if defined(PNG_READ_FILLER_SUPPORTED) + /* STRIP_ALPHA and FILLER allowed: MASK_ALPHA bit stripped above */ + if ((png_ptr->transformations & PNG_FILLER) && + ((info_ptr->color_type == PNG_COLOR_TYPE_RGB) || + (info_ptr->color_type == PNG_COLOR_TYPE_GRAY))) + { + info_ptr->channels++; + /* if adding a true alpha channel not just filler */ +#if !defined(PNG_1_0_X) + if (png_ptr->transformations & PNG_ADD_ALPHA) + info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; +#endif + } +#endif + +#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \ +defined(PNG_READ_USER_TRANSFORM_SUPPORTED) + if(png_ptr->transformations & PNG_USER_TRANSFORM) + { + if(info_ptr->bit_depth < png_ptr->user_transform_depth) + info_ptr->bit_depth = png_ptr->user_transform_depth; + if(info_ptr->channels < png_ptr->user_transform_channels) + info_ptr->channels = png_ptr->user_transform_channels; + } +#endif + + info_ptr->pixel_depth = (png_byte)(info_ptr->channels * + info_ptr->bit_depth); + + info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth,info_ptr->width); + +#if !defined(PNG_READ_EXPAND_SUPPORTED) + if(png_ptr) + return; +#endif +} + +/* Transform the row. The order of transformations is significant, + * and is very touchy. If you add a transformation, take care to + * decide how it fits in with the other transformations here. + */ +void /* PRIVATE */ +png_do_read_transformations(png_structp png_ptr) +{ + png_debug(1, "in png_do_read_transformations\n"); +#if !defined(PNG_USELESS_TESTS_SUPPORTED) + if (png_ptr->row_buf == NULL) + { +#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) + char msg[50]; + + sprintf(msg, "NULL row buffer for row %ld, pass %d", png_ptr->row_number, + png_ptr->pass); + png_error(png_ptr, msg); +#else + png_error(png_ptr, "NULL row buffer"); +#endif + } +#endif + +#if defined(PNG_READ_EXPAND_SUPPORTED) + if (png_ptr->transformations & PNG_EXPAND) + { + if (png_ptr->row_info.color_type == PNG_COLOR_TYPE_PALETTE) + { + png_do_expand_palette(&(png_ptr->row_info), png_ptr->row_buf + 1, + png_ptr->palette, png_ptr->trans, png_ptr->num_trans); + } + else + { + if (png_ptr->num_trans) + png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1, + &(png_ptr->trans_values)); + else + png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1, + NULL); + } + } +#endif + +#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED) + if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA) + png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1, + PNG_FLAG_FILLER_AFTER | (png_ptr->flags & PNG_FLAG_STRIP_ALPHA)); +#endif + +#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + if (png_ptr->transformations & PNG_RGB_TO_GRAY) + { + int rgb_error = + png_do_rgb_to_gray(png_ptr, &(png_ptr->row_info), png_ptr->row_buf + 1); + if(rgb_error) + { + png_ptr->rgb_to_gray_status=1; + if(png_ptr->transformations == PNG_RGB_TO_GRAY_WARN) + png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel"); + if(png_ptr->transformations == PNG_RGB_TO_GRAY_ERR) + png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel"); + } + } +#endif + +/* +From Andreas Dilger e-mail to png-implement, 26 March 1998: + + In most cases, the "simple transparency" should be done prior to doing + gray-to-RGB, or you will have to test 3x as many bytes to check if a + pixel is transparent. You would also need to make sure that the + transparency information is upgraded to RGB. + + To summarize, the current flow is: + - Gray + simple transparency -> compare 1 or 2 gray bytes and composite + with background "in place" if transparent, + convert to RGB if necessary + - Gray + alpha -> composite with gray background and remove alpha bytes, + convert to RGB if necessary + + To support RGB backgrounds for gray images we need: + - Gray + simple transparency -> convert to RGB + simple transparency, compare + 3 or 6 bytes and composite with background + "in place" if transparent (3x compare/pixel + compared to doing composite with gray bkgrnd) + - Gray + alpha -> convert to RGB + alpha, composite with background and + remove alpha bytes (3x float operations/pixel + compared with composite on gray background) + + Greg's change will do this. The reason it wasn't done before is for + performance, as this increases the per-pixel operations. If we would check + in advance if the background was gray or RGB, and position the gray-to-RGB + transform appropriately, then it would save a lot of work/time. + */ + +#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) + /* if gray -> RGB, do so now only if background is non-gray; else do later + * for performance reasons */ + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) && + !(png_ptr->mode & PNG_BACKGROUND_IS_GRAY)) + png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) + if ((png_ptr->transformations & PNG_BACKGROUND) && + ((png_ptr->num_trans != 0 ) || + (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) + png_do_background(&(png_ptr->row_info), png_ptr->row_buf + 1, + &(png_ptr->trans_values), &(png_ptr->background) +#if defined(PNG_READ_GAMMA_SUPPORTED) + , &(png_ptr->background_1), + png_ptr->gamma_table, png_ptr->gamma_from_1, + png_ptr->gamma_to_1, png_ptr->gamma_16_table, + png_ptr->gamma_16_from_1, png_ptr->gamma_16_to_1, + png_ptr->gamma_shift +#endif +); +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) + if ((png_ptr->transformations & PNG_GAMMA) && +#if defined(PNG_READ_BACKGROUND_SUPPORTED) + !((png_ptr->transformations & PNG_BACKGROUND) && + ((png_ptr->num_trans != 0) || + (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) && +#endif + (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)) + png_do_gamma(&(png_ptr->row_info), png_ptr->row_buf + 1, + png_ptr->gamma_table, png_ptr->gamma_16_table, + png_ptr->gamma_shift); +#endif + +#if defined(PNG_READ_16_TO_8_SUPPORTED) + if (png_ptr->transformations & PNG_16_TO_8) + png_do_chop(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#if defined(PNG_READ_DITHER_SUPPORTED) + if (png_ptr->transformations & PNG_DITHER) + { + png_do_dither((png_row_infop)&(png_ptr->row_info), png_ptr->row_buf + 1, + png_ptr->palette_lookup, png_ptr->dither_index); + if(png_ptr->row_info.rowbytes == (png_uint_32)0) + png_error(png_ptr, "png_do_dither returned rowbytes=0"); + } +#endif + +#if defined(PNG_READ_INVERT_SUPPORTED) + if (png_ptr->transformations & PNG_INVERT_MONO) + png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) + if (png_ptr->transformations & PNG_SHIFT) + png_do_unshift(&(png_ptr->row_info), png_ptr->row_buf + 1, + &(png_ptr->shift)); +#endif + +#if defined(PNG_READ_PACK_SUPPORTED) + if (png_ptr->transformations & PNG_PACK) + png_do_unpack(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#if defined(PNG_READ_BGR_SUPPORTED) + if (png_ptr->transformations & PNG_BGR) + png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) + /* if gray -> RGB, do so now only if we did not do so above */ + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) && + (png_ptr->mode & PNG_BACKGROUND_IS_GRAY)) + png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#if defined(PNG_READ_FILLER_SUPPORTED) + if (png_ptr->transformations & PNG_FILLER) + png_do_read_filler(&(png_ptr->row_info), png_ptr->row_buf + 1, + (png_uint_32)png_ptr->filler, png_ptr->flags); +#endif + +#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) + if (png_ptr->transformations & PNG_INVERT_ALPHA) + png_do_read_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) + if (png_ptr->transformations & PNG_SWAP_ALPHA) + png_do_read_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#if defined(PNG_READ_SWAP_SUPPORTED) + if (png_ptr->transformations & PNG_SWAP_BYTES) + png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) + if (png_ptr->transformations & PNG_USER_TRANSFORM) + { + if(png_ptr->read_user_transform_fn != NULL) + (*(png_ptr->read_user_transform_fn)) /* user read transform function */ + (png_ptr, /* png_ptr */ + &(png_ptr->row_info), /* row_info: */ + /* png_uint_32 width; width of row */ + /* png_uint_32 rowbytes; number of bytes in row */ + /* png_byte color_type; color type of pixels */ + /* png_byte bit_depth; bit depth of samples */ + /* png_byte channels; number of channels (1-4) */ + /* png_byte pixel_depth; bits per pixel (depth*channels) */ + png_ptr->row_buf + 1); /* start of pixel data for row */ +#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) + if(png_ptr->user_transform_depth) + png_ptr->row_info.bit_depth = png_ptr->user_transform_depth; + if(png_ptr->user_transform_channels) + png_ptr->row_info.channels = png_ptr->user_transform_channels; +#endif + png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth * + png_ptr->row_info.channels); + png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth, + png_ptr->row_info.width); + } +#endif + +} + +#if defined(PNG_READ_PACK_SUPPORTED) +/* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel, + * without changing the actual values. Thus, if you had a row with + * a bit depth of 1, you would end up with bytes that only contained + * the numbers 0 or 1. If you would rather they contain 0 and 255, use + * png_do_shift() after this. + */ +void /* PRIVATE */ +png_do_unpack(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_unpack\n"); +#if defined(PNG_USELESS_TESTS_SUPPORTED) + if (row != NULL && row_info != NULL && row_info->bit_depth < 8) +#else + if (row_info->bit_depth < 8) +#endif + { + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + switch (row_info->bit_depth) + { + case 1: + { + png_bytep sp = row + (png_size_t)((row_width - 1) >> 3); + png_bytep dp = row + (png_size_t)row_width - 1; + png_uint_32 shift = 7 - (int)((row_width + 7) & 0x07); + for (i = 0; i < row_width; i++) + { + *dp = (png_byte)((*sp >> shift) & 0x01); + if (shift == 7) + { + shift = 0; + sp--; + } + else + shift++; + + dp--; + } + break; + } + case 2: + { + + png_bytep sp = row + (png_size_t)((row_width - 1) >> 2); + png_bytep dp = row + (png_size_t)row_width - 1; + png_uint_32 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); + for (i = 0; i < row_width; i++) + { + *dp = (png_byte)((*sp >> shift) & 0x03); + if (shift == 6) + { + shift = 0; + sp--; + } + else + shift += 2; + + dp--; + } + break; + } + case 4: + { + png_bytep sp = row + (png_size_t)((row_width - 1) >> 1); + png_bytep dp = row + (png_size_t)row_width - 1; + png_uint_32 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2); + for (i = 0; i < row_width; i++) + { + *dp = (png_byte)((*sp >> shift) & 0x0f); + if (shift == 4) + { + shift = 0; + sp--; + } + else + shift = 4; + + dp--; + } + break; + } + } + row_info->bit_depth = 8; + row_info->pixel_depth = (png_byte)(8 * row_info->channels); + row_info->rowbytes = row_width * row_info->channels; + } +} +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) +/* Reverse the effects of png_do_shift. This routine merely shifts the + * pixels back to their significant bits values. Thus, if you have + * a row of bit depth 8, but only 5 are significant, this will shift + * the values back to 0 through 31. + */ +void /* PRIVATE */ +png_do_unshift(png_row_infop row_info, png_bytep row, png_color_8p sig_bits) +{ + png_debug(1, "in png_do_unshift\n"); + if ( +#if defined(PNG_USELESS_TESTS_SUPPORTED) + row != NULL && row_info != NULL && sig_bits != NULL && +#endif + row_info->color_type != PNG_COLOR_TYPE_PALETTE) + { + int shift[4]; + int channels = 0; + int c; + png_uint_16 value = 0; + png_uint_32 row_width = row_info->width; + + if (row_info->color_type & PNG_COLOR_MASK_COLOR) + { + shift[channels++] = row_info->bit_depth - sig_bits->red; + shift[channels++] = row_info->bit_depth - sig_bits->green; + shift[channels++] = row_info->bit_depth - sig_bits->blue; + } + else + { + shift[channels++] = row_info->bit_depth - sig_bits->gray; + } + if (row_info->color_type & PNG_COLOR_MASK_ALPHA) + { + shift[channels++] = row_info->bit_depth - sig_bits->alpha; + } + + for (c = 0; c < channels; c++) + { + if (shift[c] <= 0) + shift[c] = 0; + else + value = 1; + } + + if (!value) + return; + + switch (row_info->bit_depth) + { + case 2: + { + png_bytep bp; + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + + for (bp = row, i = 0; i < istop; i++) + { + *bp >>= 1; + *bp++ &= 0x55; + } + break; + } + case 4: + { + png_bytep bp = row; + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + png_byte mask = (png_byte)((((int)0xf0 >> shift[0]) & (int)0xf0) | + (png_byte)((int)0xf >> shift[0])); + + for (i = 0; i < istop; i++) + { + *bp >>= shift[0]; + *bp++ &= mask; + } + break; + } + case 8: + { + png_bytep bp = row; + png_uint_32 i; + png_uint_32 istop = row_width * channels; + + for (i = 0; i < istop; i++) + { + *bp++ >>= shift[i%channels]; + } + break; + } + case 16: + { + png_bytep bp = row; + png_uint_32 i; + png_uint_32 istop = channels * row_width; + + for (i = 0; i < istop; i++) + { + value = (png_uint_16)((*bp << 8) + *(bp + 1)); + value >>= shift[i%channels]; + *bp++ = (png_byte)(value >> 8); + *bp++ = (png_byte)(value & 0xff); + } + break; + } + } + } +} +#endif + +#if defined(PNG_READ_16_TO_8_SUPPORTED) +/* chop rows of bit depth 16 down to 8 */ +void /* PRIVATE */ +png_do_chop(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_chop\n"); +#if defined(PNG_USELESS_TESTS_SUPPORTED) + if (row != NULL && row_info != NULL && row_info->bit_depth == 16) +#else + if (row_info->bit_depth == 16) +#endif + { + png_bytep sp = row; + png_bytep dp = row; + png_uint_32 i; + png_uint_32 istop = row_info->width * row_info->channels; + + for (i = 0; i<istop; i++, sp += 2, dp++) + { +#if defined(PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED) + /* This does a more accurate scaling of the 16-bit color + * value, rather than a simple low-byte truncation. + * + * What the ideal calculation should be: + * *dp = (((((png_uint_32)(*sp) << 8) | + * (png_uint_32)(*(sp + 1))) * 255 + 127) / (png_uint_32)65535L; + * + * GRR: no, I think this is what it really should be: + * *dp = (((((png_uint_32)(*sp) << 8) | + * (png_uint_32)(*(sp + 1))) + 128L) / (png_uint_32)257L; + * + * GRR: here's the exact calculation with shifts: + * temp = (((png_uint_32)(*sp) << 8) | (png_uint_32)(*(sp + 1))) + 128L; + * *dp = (temp - (temp >> 8)) >> 8; + * + * Approximate calculation with shift/add instead of multiply/divide: + * *dp = ((((png_uint_32)(*sp) << 8) | + * (png_uint_32)((int)(*(sp + 1)) - *sp)) + 128) >> 8; + * + * What we actually do to avoid extra shifting and conversion: + */ + + *dp = *sp + ((((int)(*(sp + 1)) - *sp) > 128) ? 1 : 0); +#else + /* Simply discard the low order byte */ + *dp = *sp; +#endif + } + row_info->bit_depth = 8; + row_info->pixel_depth = (png_byte)(8 * row_info->channels); + row_info->rowbytes = row_info->width * row_info->channels; + } +} +#endif + +#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) +void /* PRIVATE */ +png_do_read_swap_alpha(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_read_swap_alpha\n"); +#if defined(PNG_USELESS_TESTS_SUPPORTED) + if (row != NULL && row_info != NULL) +#endif + { + png_uint_32 row_width = row_info->width; + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + /* This converts from RGBA to ARGB */ + if (row_info->bit_depth == 8) + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_byte save; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + save = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = save; + } + } + /* This converts from RRGGBBAA to AARRGGBB */ + else + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_byte save[2]; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + save[0] = *(--sp); + save[1] = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = save[0]; + *(--dp) = save[1]; + } + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + /* This converts from GA to AG */ + if (row_info->bit_depth == 8) + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_byte save; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + save = *(--sp); + *(--dp) = *(--sp); + *(--dp) = save; + } + } + /* This converts from GGAA to AAGG */ + else + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_byte save[2]; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + save[0] = *(--sp); + save[1] = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = save[0]; + *(--dp) = save[1]; + } + } + } + } +} +#endif + +#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) +void /* PRIVATE */ +png_do_read_invert_alpha(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_read_invert_alpha\n"); +#if defined(PNG_USELESS_TESTS_SUPPORTED) + if (row != NULL && row_info != NULL) +#endif + { + png_uint_32 row_width = row_info->width; + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + /* This inverts the alpha channel in RGBA */ + if (row_info->bit_depth == 8) + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + *(--dp) = (png_byte)(255 - *(--sp)); + +/* This does nothing: + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + We can replace it with: +*/ + sp-=3; + dp=sp; + } + } + /* This inverts the alpha channel in RRGGBBAA */ + else + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + *(--dp) = (png_byte)(255 - *(--sp)); + *(--dp) = (png_byte)(255 - *(--sp)); + +/* This does nothing: + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + We can replace it with: +*/ + sp-=6; + dp=sp; + } + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + /* This inverts the alpha channel in GA */ + if (row_info->bit_depth == 8) + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + *(--dp) = (png_byte)(255 - *(--sp)); + *(--dp) = *(--sp); + } + } + /* This inverts the alpha channel in GGAA */ + else + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + *(--dp) = (png_byte)(255 - *(--sp)); + *(--dp) = (png_byte)(255 - *(--sp)); +/* + *(--dp) = *(--sp); + *(--dp) = *(--sp); +*/ + sp-=2; + dp=sp; + } + } + } + } +} +#endif + +#if defined(PNG_READ_FILLER_SUPPORTED) +/* Add filler channel if we have RGB color */ +void /* PRIVATE */ +png_do_read_filler(png_row_infop row_info, png_bytep row, + png_uint_32 filler, png_uint_32 flags) +{ + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + png_byte hi_filler = (png_byte)((filler>>8) & 0xff); + png_byte lo_filler = (png_byte)(filler & 0xff); + + png_debug(1, "in png_do_read_filler\n"); + if ( +#if defined(PNG_USELESS_TESTS_SUPPORTED) + row != NULL && row_info != NULL && +#endif + row_info->color_type == PNG_COLOR_TYPE_GRAY) + { + if(row_info->bit_depth == 8) + { + /* This changes the data from G to GX */ + if (flags & PNG_FLAG_FILLER_AFTER) + { + png_bytep sp = row + (png_size_t)row_width; + png_bytep dp = sp + (png_size_t)row_width; + for (i = 1; i < row_width; i++) + { + *(--dp) = lo_filler; + *(--dp) = *(--sp); + } + *(--dp) = lo_filler; + row_info->channels = 2; + row_info->pixel_depth = 16; + row_info->rowbytes = row_width * 2; + } + /* This changes the data from G to XG */ + else + { + png_bytep sp = row + (png_size_t)row_width; + png_bytep dp = sp + (png_size_t)row_width; + for (i = 0; i < row_width; i++) + { + *(--dp) = *(--sp); + *(--dp) = lo_filler; + } + row_info->channels = 2; + row_info->pixel_depth = 16; + row_info->rowbytes = row_width * 2; + } + } + else if(row_info->bit_depth == 16) + { + /* This changes the data from GG to GGXX */ + if (flags & PNG_FLAG_FILLER_AFTER) + { + png_bytep sp = row + (png_size_t)row_width * 2; + png_bytep dp = sp + (png_size_t)row_width * 2; + for (i = 1; i < row_width; i++) + { + *(--dp) = hi_filler; + *(--dp) = lo_filler; + *(--dp) = *(--sp); + *(--dp) = *(--sp); + } + *(--dp) = hi_filler; + *(--dp) = lo_filler; + row_info->channels = 2; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + } + /* This changes the data from GG to XXGG */ + else + { + png_bytep sp = row + (png_size_t)row_width * 2; + png_bytep dp = sp + (png_size_t)row_width * 2; + for (i = 0; i < row_width; i++) + { + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = hi_filler; + *(--dp) = lo_filler; + } + row_info->channels = 2; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + } + } + } /* COLOR_TYPE == GRAY */ + else if (row_info->color_type == PNG_COLOR_TYPE_RGB) + { + if(row_info->bit_depth == 8) + { + /* This changes the data from RGB to RGBX */ + if (flags & PNG_FLAG_FILLER_AFTER) + { + png_bytep sp = row + (png_size_t)row_width * 3; + png_bytep dp = sp + (png_size_t)row_width; + for (i = 1; i < row_width; i++) + { + *(--dp) = lo_filler; + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + } + *(--dp) = lo_filler; + row_info->channels = 4; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + } + /* This changes the data from RGB to XRGB */ + else + { + png_bytep sp = row + (png_size_t)row_width * 3; + png_bytep dp = sp + (png_size_t)row_width; + for (i = 0; i < row_width; i++) + { + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = lo_filler; + } + row_info->channels = 4; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + } + } + else if(row_info->bit_depth == 16) + { + /* This changes the data from RRGGBB to RRGGBBXX */ + if (flags & PNG_FLAG_FILLER_AFTER) + { + png_bytep sp = row + (png_size_t)row_width * 6; + png_bytep dp = sp + (png_size_t)row_width * 2; + for (i = 1; i < row_width; i++) + { + *(--dp) = hi_filler; + *(--dp) = lo_filler; + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + } + *(--dp) = hi_filler; + *(--dp) = lo_filler; + row_info->channels = 4; + row_info->pixel_depth = 64; + row_info->rowbytes = row_width * 8; + } + /* This changes the data from RRGGBB to XXRRGGBB */ + else + { + png_bytep sp = row + (png_size_t)row_width * 6; + png_bytep dp = sp + (png_size_t)row_width * 2; + for (i = 0; i < row_width; i++) + { + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = hi_filler; + *(--dp) = lo_filler; + } + row_info->channels = 4; + row_info->pixel_depth = 64; + row_info->rowbytes = row_width * 8; + } + } + } /* COLOR_TYPE == RGB */ +} +#endif + +#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) +/* expand grayscale files to RGB, with or without alpha */ +void /* PRIVATE */ +png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) +{ + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + png_debug(1, "in png_do_gray_to_rgb\n"); + if (row_info->bit_depth >= 8 && +#if defined(PNG_USELESS_TESTS_SUPPORTED) + row != NULL && row_info != NULL && +#endif + !(row_info->color_type & PNG_COLOR_MASK_COLOR)) + { + if (row_info->color_type == PNG_COLOR_TYPE_GRAY) + { + if (row_info->bit_depth == 8) + { + png_bytep sp = row + (png_size_t)row_width - 1; + png_bytep dp = sp + (png_size_t)row_width * 2; + for (i = 0; i < row_width; i++) + { + *(dp--) = *sp; + *(dp--) = *sp; + *(dp--) = *(sp--); + } + } + else + { + png_bytep sp = row + (png_size_t)row_width * 2 - 1; + png_bytep dp = sp + (png_size_t)row_width * 4; + for (i = 0; i < row_width; i++) + { + *(dp--) = *sp; + *(dp--) = *(sp - 1); + *(dp--) = *sp; + *(dp--) = *(sp - 1); + *(dp--) = *(sp--); + *(dp--) = *(sp--); + } + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + if (row_info->bit_depth == 8) + { + png_bytep sp = row + (png_size_t)row_width * 2 - 1; + png_bytep dp = sp + (png_size_t)row_width * 2; + for (i = 0; i < row_width; i++) + { + *(dp--) = *(sp--); + *(dp--) = *sp; + *(dp--) = *sp; + *(dp--) = *(sp--); + } + } + else + { + png_bytep sp = row + (png_size_t)row_width * 4 - 1; + png_bytep dp = sp + (png_size_t)row_width * 4; + for (i = 0; i < row_width; i++) + { + *(dp--) = *(sp--); + *(dp--) = *(sp--); + *(dp--) = *sp; + *(dp--) = *(sp - 1); + *(dp--) = *sp; + *(dp--) = *(sp - 1); + *(dp--) = *(sp--); + *(dp--) = *(sp--); + } + } + } + row_info->channels += (png_byte)2; + row_info->color_type |= PNG_COLOR_MASK_COLOR; + row_info->pixel_depth = (png_byte)(row_info->channels * + row_info->bit_depth); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,row_width); + } +} +#endif + +#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) +/* reduce RGB files to grayscale, with or without alpha + * using the equation given in Poynton's ColorFAQ at + * <http://www.inforamp.net/~poynton/> + * Copyright (c) 1998-01-04 Charles Poynton poynton at inforamp.net + * + * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B + * + * We approximate this with + * + * Y = 0.21268 * R + 0.7151 * G + 0.07217 * B + * + * which can be expressed with integers as + * + * Y = (6969 * R + 23434 * G + 2365 * B)/32768 + * + * The calculation is to be done in a linear colorspace. + * + * Other integer coefficents can be used via png_set_rgb_to_gray(). + */ +int /* PRIVATE */ +png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row) + +{ + png_uint_32 i; + + png_uint_32 row_width = row_info->width; + int rgb_error = 0; + + png_debug(1, "in png_do_rgb_to_gray\n"); + if ( +#if defined(PNG_USELESS_TESTS_SUPPORTED) + row != NULL && row_info != NULL && +#endif + (row_info->color_type & PNG_COLOR_MASK_COLOR)) + { + png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff; + png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff; + png_uint_32 bc = png_ptr->rgb_to_gray_blue_coeff; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + { + if (row_info->bit_depth == 8) + { +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL) + { + png_bytep sp = row; + png_bytep dp = row; + + for (i = 0; i < row_width; i++) + { + png_byte red = png_ptr->gamma_to_1[*(sp++)]; + png_byte green = png_ptr->gamma_to_1[*(sp++)]; + png_byte blue = png_ptr->gamma_to_1[*(sp++)]; + if(red != green || red != blue) + { + rgb_error |= 1; + *(dp++) = png_ptr->gamma_from_1[ + (rc*red+gc*green+bc*blue)>>15]; + } + else + *(dp++) = *(sp-1); + } + } + else +#endif + { + png_bytep sp = row; + png_bytep dp = row; + for (i = 0; i < row_width; i++) + { + png_byte red = *(sp++); + png_byte green = *(sp++); + png_byte blue = *(sp++); + if(red != green || red != blue) + { + rgb_error |= 1; + *(dp++) = (png_byte)((rc*red+gc*green+bc*blue)>>15); + } + else + *(dp++) = *(sp-1); + } + } + } + + else /* RGB bit_depth == 16 */ + { +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + if (png_ptr->gamma_16_to_1 != NULL && + png_ptr->gamma_16_from_1 != NULL) + { + png_bytep sp = row; + png_bytep dp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 red, green, blue, w; + + red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + + if(red == green && red == blue) + w = red; + else + { + png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >> + png_ptr->gamma_shift][red>>8]; + png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >> + png_ptr->gamma_shift][green>>8]; + png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >> + png_ptr->gamma_shift][blue>>8]; + png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1 + + bc*blue_1)>>15); + w = png_ptr->gamma_16_from_1[(gray16&0xff) >> + png_ptr->gamma_shift][gray16 >> 8]; + rgb_error |= 1; + } + + *(dp++) = (png_byte)((w>>8) & 0xff); + *(dp++) = (png_byte)(w & 0xff); + } + } + else +#endif + { + png_bytep sp = row; + png_bytep dp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 red, green, blue, gray16; + + red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + + if(red != green || red != blue) + rgb_error |= 1; + gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15); + *(dp++) = (png_byte)((gray16>>8) & 0xff); + *(dp++) = (png_byte)(gray16 & 0xff); + } + } + } + } + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + if (row_info->bit_depth == 8) + { +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL) + { + png_bytep sp = row; + png_bytep dp = row; + for (i = 0; i < row_width; i++) + { + png_byte red = png_ptr->gamma_to_1[*(sp++)]; + png_byte green = png_ptr->gamma_to_1[*(sp++)]; + png_byte blue = png_ptr->gamma_to_1[*(sp++)]; + if(red != green || red != blue) + rgb_error |= 1; + *(dp++) = png_ptr->gamma_from_1 + [(rc*red + gc*green + bc*blue)>>15]; + *(dp++) = *(sp++); /* alpha */ + } + } + else +#endif + { + png_bytep sp = row; + png_bytep dp = row; + for (i = 0; i < row_width; i++) + { + png_byte red = *(sp++); + png_byte green = *(sp++); + png_byte blue = *(sp++); + if(red != green || red != blue) + rgb_error |= 1; + *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15); + *(dp++) = *(sp++); /* alpha */ + } + } + } + else /* RGBA bit_depth == 16 */ + { +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + if (png_ptr->gamma_16_to_1 != NULL && + png_ptr->gamma_16_from_1 != NULL) + { + png_bytep sp = row; + png_bytep dp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 red, green, blue, w; + + red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + + if(red == green && red == blue) + w = red; + else + { + png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >> + png_ptr->gamma_shift][red>>8]; + png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >> + png_ptr->gamma_shift][green>>8]; + png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >> + png_ptr->gamma_shift][blue>>8]; + png_uint_16 gray16 = (png_uint_16)((rc * red_1 + + gc * green_1 + bc * blue_1)>>15); + w = png_ptr->gamma_16_from_1[(gray16&0xff) >> + png_ptr->gamma_shift][gray16 >> 8]; + rgb_error |= 1; + } + + *(dp++) = (png_byte)((w>>8) & 0xff); + *(dp++) = (png_byte)(w & 0xff); + *(dp++) = *(sp++); /* alpha */ + *(dp++) = *(sp++); + } + } + else +#endif + { + png_bytep sp = row; + png_bytep dp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 red, green, blue, gray16; + red = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2; + green = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2; + blue = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2; + if(red != green || red != blue) + rgb_error |= 1; + gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15); + *(dp++) = (png_byte)((gray16>>8) & 0xff); + *(dp++) = (png_byte)(gray16 & 0xff); + *(dp++) = *(sp++); /* alpha */ + *(dp++) = *(sp++); + } + } + } + } + row_info->channels -= (png_byte)2; + row_info->color_type &= ~PNG_COLOR_MASK_COLOR; + row_info->pixel_depth = (png_byte)(row_info->channels * + row_info->bit_depth); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,row_width); + } + return rgb_error; +} +#endif + +/* Build a grayscale palette. Palette is assumed to be 1 << bit_depth + * large of png_color. This lets grayscale images be treated as + * paletted. Most useful for gamma correction and simplification + * of code. + */ +void PNGAPI +png_build_grayscale_palette(int bit_depth, png_colorp palette) +{ + int num_palette; + int color_inc; + int i; + int v; + + png_debug(1, "in png_do_build_grayscale_palette\n"); + if (palette == NULL) + return; + + switch (bit_depth) + { + case 1: + num_palette = 2; + color_inc = 0xff; + break; + case 2: + num_palette = 4; + color_inc = 0x55; + break; + case 4: + num_palette = 16; + color_inc = 0x11; + break; + case 8: + num_palette = 256; + color_inc = 1; + break; + default: + num_palette = 0; + color_inc = 0; + break; + } + + for (i = 0, v = 0; i < num_palette; i++, v += color_inc) + { + palette[i].red = (png_byte)v; + palette[i].green = (png_byte)v; + palette[i].blue = (png_byte)v; + } +} + +/* This function is currently unused. Do we really need it? */ +#if defined(PNG_READ_DITHER_SUPPORTED) && defined(PNG_CORRECT_PALETTE_SUPPORTED) +void /* PRIVATE */ +png_correct_palette(png_structp png_ptr, png_colorp palette, + int num_palette) +{ + png_debug(1, "in png_correct_palette\n"); +#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \ + defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED) + if (png_ptr->transformations & (PNG_GAMMA | PNG_BACKGROUND)) + { + png_color back, back_1; + + if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE) + { + back.red = png_ptr->gamma_table[png_ptr->background.red]; + back.green = png_ptr->gamma_table[png_ptr->background.green]; + back.blue = png_ptr->gamma_table[png_ptr->background.blue]; + + back_1.red = png_ptr->gamma_to_1[png_ptr->background.red]; + back_1.green = png_ptr->gamma_to_1[png_ptr->background.green]; + back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue]; + } + else + { + double g; + + g = 1.0 / (png_ptr->background_gamma * png_ptr->screen_gamma); + + if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_SCREEN || + fabs(g - 1.0) < PNG_GAMMA_THRESHOLD) + { + back.red = png_ptr->background.red; + back.green = png_ptr->background.green; + back.blue = png_ptr->background.blue; + } + else + { + back.red = + (png_byte)(pow((double)png_ptr->background.red/255, g) * + 255.0 + 0.5); + back.green = + (png_byte)(pow((double)png_ptr->background.green/255, g) * + 255.0 + 0.5); + back.blue = + (png_byte)(pow((double)png_ptr->background.blue/255, g) * + 255.0 + 0.5); + } + + g = 1.0 / png_ptr->background_gamma; + + back_1.red = + (png_byte)(pow((double)png_ptr->background.red/255, g) * + 255.0 + 0.5); + back_1.green = + (png_byte)(pow((double)png_ptr->background.green/255, g) * + 255.0 + 0.5); + back_1.blue = + (png_byte)(pow((double)png_ptr->background.blue/255, g) * + 255.0 + 0.5); + } + + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + png_uint_32 i; + + for (i = 0; i < (png_uint_32)num_palette; i++) + { + if (i < png_ptr->num_trans && png_ptr->trans[i] == 0) + { + palette[i] = back; + } + else if (i < png_ptr->num_trans && png_ptr->trans[i] != 0xff) + { + png_byte v, w; + + v = png_ptr->gamma_to_1[png_ptr->palette[i].red]; + png_composite(w, v, png_ptr->trans[i], back_1.red); + palette[i].red = png_ptr->gamma_from_1[w]; + + v = png_ptr->gamma_to_1[png_ptr->palette[i].green]; + png_composite(w, v, png_ptr->trans[i], back_1.green); + palette[i].green = png_ptr->gamma_from_1[w]; + + v = png_ptr->gamma_to_1[png_ptr->palette[i].blue]; + png_composite(w, v, png_ptr->trans[i], back_1.blue); + palette[i].blue = png_ptr->gamma_from_1[w]; + } + else + { + palette[i].red = png_ptr->gamma_table[palette[i].red]; + palette[i].green = png_ptr->gamma_table[palette[i].green]; + palette[i].blue = png_ptr->gamma_table[palette[i].blue]; + } + } + } + else + { + int i; + + for (i = 0; i < num_palette; i++) + { + if (palette[i].red == (png_byte)png_ptr->trans_values.gray) + { + palette[i] = back; + } + else + { + palette[i].red = png_ptr->gamma_table[palette[i].red]; + palette[i].green = png_ptr->gamma_table[palette[i].green]; + palette[i].blue = png_ptr->gamma_table[palette[i].blue]; + } + } + } + } + else +#endif +#if defined(PNG_READ_GAMMA_SUPPORTED) + if (png_ptr->transformations & PNG_GAMMA) + { + int i; + + for (i = 0; i < num_palette; i++) + { + palette[i].red = png_ptr->gamma_table[palette[i].red]; + palette[i].green = png_ptr->gamma_table[palette[i].green]; + palette[i].blue = png_ptr->gamma_table[palette[i].blue]; + } + } +#if defined(PNG_READ_BACKGROUND_SUPPORTED) + else +#endif +#endif +#if defined(PNG_READ_BACKGROUND_SUPPORTED) + if (png_ptr->transformations & PNG_BACKGROUND) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + png_color back; + + back.red = (png_byte)png_ptr->background.red; + back.green = (png_byte)png_ptr->background.green; + back.blue = (png_byte)png_ptr->background.blue; + + for (i = 0; i < (int)png_ptr->num_trans; i++) + { + if (png_ptr->trans[i] == 0) + { + palette[i].red = back.red; + palette[i].green = back.green; + palette[i].blue = back.blue; + } + else if (png_ptr->trans[i] != 0xff) + { + png_composite(palette[i].red, png_ptr->palette[i].red, + png_ptr->trans[i], back.red); + png_composite(palette[i].green, png_ptr->palette[i].green, + png_ptr->trans[i], back.green); + png_composite(palette[i].blue, png_ptr->palette[i].blue, + png_ptr->trans[i], back.blue); + } + } + } + else /* assume grayscale palette (what else could it be?) */ + { + int i; + + for (i = 0; i < num_palette; i++) + { + if (i == (png_byte)png_ptr->trans_values.gray) + { + palette[i].red = (png_byte)png_ptr->background.red; + palette[i].green = (png_byte)png_ptr->background.green; + palette[i].blue = (png_byte)png_ptr->background.blue; + } + } + } + } +#endif +} +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) +/* Replace any alpha or transparency with the supplied background color. + * "background" is already in the screen gamma, while "background_1" is + * at a gamma of 1.0. Paletted files have already been taken care of. + */ +void /* PRIVATE */ +png_do_background(png_row_infop row_info, png_bytep row, + png_color_16p trans_values, png_color_16p background +#if defined(PNG_READ_GAMMA_SUPPORTED) + , png_color_16p background_1, + png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1, + png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1, + png_uint_16pp gamma_16_to_1, int gamma_shift +#endif + ) +{ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width=row_info->width; + int shift; + + png_debug(1, "in png_do_background\n"); + if (background != NULL && +#if defined(PNG_USELESS_TESTS_SUPPORTED) + row != NULL && row_info != NULL && +#endif + (!(row_info->color_type & PNG_COLOR_MASK_ALPHA) || + (row_info->color_type != PNG_COLOR_TYPE_PALETTE && trans_values))) + { + switch (row_info->color_type) + { + case PNG_COLOR_TYPE_GRAY: + { + switch (row_info->bit_depth) + { + case 1: + { + sp = row; + shift = 7; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x01) + == trans_values->gray) + { + *sp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff); + *sp |= (png_byte)(background->gray << shift); + } + if (!shift) + { + shift = 7; + sp++; + } + else + shift--; + } + break; + } + case 2: + { +#if defined(PNG_READ_GAMMA_SUPPORTED) + if (gamma_table != NULL) + { + sp = row; + shift = 6; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x03) + == trans_values->gray) + { + *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); + *sp |= (png_byte)(background->gray << shift); + } + else + { + png_byte p = (png_byte)((*sp >> shift) & 0x03); + png_byte g = (png_byte)((gamma_table [p | (p << 2) | + (p << 4) | (p << 6)] >> 6) & 0x03); + *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); + *sp |= (png_byte)(g << shift); + } + if (!shift) + { + shift = 6; + sp++; + } + else + shift -= 2; + } + } + else +#endif + { + sp = row; + shift = 6; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x03) + == trans_values->gray) + { + *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); + *sp |= (png_byte)(background->gray << shift); + } + if (!shift) + { + shift = 6; + sp++; + } + else + shift -= 2; + } + } + break; + } + case 4: + { +#if defined(PNG_READ_GAMMA_SUPPORTED) + if (gamma_table != NULL) + { + sp = row; + shift = 4; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x0f) + == trans_values->gray) + { + *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); + *sp |= (png_byte)(background->gray << shift); + } + else + { + png_byte p = (png_byte)((*sp >> shift) & 0x0f); + png_byte g = (png_byte)((gamma_table[p | + (p << 4)] >> 4) & 0x0f); + *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); + *sp |= (png_byte)(g << shift); + } + if (!shift) + { + shift = 4; + sp++; + } + else + shift -= 4; + } + } + else +#endif + { + sp = row; + shift = 4; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x0f) + == trans_values->gray) + { + *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); + *sp |= (png_byte)(background->gray << shift); + } + if (!shift) + { + shift = 4; + sp++; + } + else + shift -= 4; + } + } + break; + } + case 8: + { +#if defined(PNG_READ_GAMMA_SUPPORTED) + if (gamma_table != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp++) + { + if (*sp == trans_values->gray) + { + *sp = (png_byte)background->gray; + } + else + { + *sp = gamma_table[*sp]; + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp++) + { + if (*sp == trans_values->gray) + { + *sp = (png_byte)background->gray; + } + } + } + break; + } + case 16: + { +#if defined(PNG_READ_GAMMA_SUPPORTED) + if (gamma_16 != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 2) + { + png_uint_16 v; + + v = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + if (v == trans_values->gray) + { + /* background is already in screen gamma */ + *sp = (png_byte)((background->gray >> 8) & 0xff); + *(sp + 1) = (png_byte)(background->gray & 0xff); + } + else + { + v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 2) + { + png_uint_16 v; + + v = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + if (v == trans_values->gray) + { + *sp = (png_byte)((background->gray >> 8) & 0xff); + *(sp + 1) = (png_byte)(background->gray & 0xff); + } + } + } + break; + } + } + break; + } + case PNG_COLOR_TYPE_RGB: + { + if (row_info->bit_depth == 8) + { +#if defined(PNG_READ_GAMMA_SUPPORTED) + if (gamma_table != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 3) + { + if (*sp == trans_values->red && + *(sp + 1) == trans_values->green && + *(sp + 2) == trans_values->blue) + { + *sp = (png_byte)background->red; + *(sp + 1) = (png_byte)background->green; + *(sp + 2) = (png_byte)background->blue; + } + else + { + *sp = gamma_table[*sp]; + *(sp + 1) = gamma_table[*(sp + 1)]; + *(sp + 2) = gamma_table[*(sp + 2)]; + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 3) + { + if (*sp == trans_values->red && + *(sp + 1) == trans_values->green && + *(sp + 2) == trans_values->blue) + { + *sp = (png_byte)background->red; + *(sp + 1) = (png_byte)background->green; + *(sp + 2) = (png_byte)background->blue; + } + } + } + } + else /* if (row_info->bit_depth == 16) */ + { +#if defined(PNG_READ_GAMMA_SUPPORTED) + if (gamma_16 != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 6) + { + png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3)); + png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5)); + if (r == trans_values->red && g == trans_values->green && + b == trans_values->blue) + { + /* background is already in screen gamma */ + *sp = (png_byte)((background->red >> 8) & 0xff); + *(sp + 1) = (png_byte)(background->red & 0xff); + *(sp + 2) = (png_byte)((background->green >> 8) & 0xff); + *(sp + 3) = (png_byte)(background->green & 0xff); + *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff); + *(sp + 5) = (png_byte)(background->blue & 0xff); + } + else + { + png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)]; + *(sp + 2) = (png_byte)((v >> 8) & 0xff); + *(sp + 3) = (png_byte)(v & 0xff); + v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)]; + *(sp + 4) = (png_byte)((v >> 8) & 0xff); + *(sp + 5) = (png_byte)(v & 0xff); + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 6) + { + png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp+1)); + png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3)); + png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5)); + + if (r == trans_values->red && g == trans_values->green && + b == trans_values->blue) + { + *sp = (png_byte)((background->red >> 8) & 0xff); + *(sp + 1) = (png_byte)(background->red & 0xff); + *(sp + 2) = (png_byte)((background->green >> 8) & 0xff); + *(sp + 3) = (png_byte)(background->green & 0xff); + *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff); + *(sp + 5) = (png_byte)(background->blue & 0xff); + } + } + } + } + break; + } + case PNG_COLOR_TYPE_GRAY_ALPHA: + { + if (row_info->bit_depth == 8) + { +#if defined(PNG_READ_GAMMA_SUPPORTED) + if (gamma_to_1 != NULL && gamma_from_1 != NULL && + gamma_table != NULL) + { + sp = row; + dp = row; + for (i = 0; i < row_width; i++, sp += 2, dp++) + { + png_uint_16 a = *(sp + 1); + + if (a == 0xff) + { + *dp = gamma_table[*sp]; + } + else if (a == 0) + { + /* background is already in screen gamma */ + *dp = (png_byte)background->gray; + } + else + { + png_byte v, w; + + v = gamma_to_1[*sp]; + png_composite(w, v, a, background_1->gray); + *dp = gamma_from_1[w]; + } + } + } + else +#endif + { + sp = row; + dp = row; + for (i = 0; i < row_width; i++, sp += 2, dp++) + { + png_byte a = *(sp + 1); + + if (a == 0xff) + { + *dp = *sp; + } +#if defined(PNG_READ_GAMMA_SUPPORTED) + else if (a == 0) + { + *dp = (png_byte)background->gray; + } + else + { + png_composite(*dp, *sp, a, background_1->gray); + } +#else + *dp = (png_byte)background->gray; +#endif + } + } + } + else /* if (png_ptr->bit_depth == 16) */ + { +#if defined(PNG_READ_GAMMA_SUPPORTED) + if (gamma_16 != NULL && gamma_16_from_1 != NULL && + gamma_16_to_1 != NULL) + { + sp = row; + dp = row; + for (i = 0; i < row_width; i++, sp += 4, dp += 2) + { + png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3)); + + if (a == (png_uint_16)0xffff) + { + png_uint_16 v; + + v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; + *dp = (png_byte)((v >> 8) & 0xff); + *(dp + 1) = (png_byte)(v & 0xff); + } +#if defined(PNG_READ_GAMMA_SUPPORTED) + else if (a == 0) +#else + else +#endif + { + /* background is already in screen gamma */ + *dp = (png_byte)((background->gray >> 8) & 0xff); + *(dp + 1) = (png_byte)(background->gray & 0xff); + } +#if defined(PNG_READ_GAMMA_SUPPORTED) + else + { + png_uint_16 g, v, w; + + g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; + png_composite_16(v, g, a, background_1->gray); + w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8]; + *dp = (png_byte)((w >> 8) & 0xff); + *(dp + 1) = (png_byte)(w & 0xff); + } +#endif + } + } + else +#endif + { + sp = row; + dp = row; + for (i = 0; i < row_width; i++, sp += 4, dp += 2) + { + png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3)); + if (a == (png_uint_16)0xffff) + { + png_memcpy(dp, sp, 2); + } +#if defined(PNG_READ_GAMMA_SUPPORTED) + else if (a == 0) +#else + else +#endif + { + *dp = (png_byte)((background->gray >> 8) & 0xff); + *(dp + 1) = (png_byte)(background->gray & 0xff); + } +#if defined(PNG_READ_GAMMA_SUPPORTED) + else + { + png_uint_16 g, v; + + g = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + png_composite_16(v, g, a, background_1->gray); + *dp = (png_byte)((v >> 8) & 0xff); + *(dp + 1) = (png_byte)(v & 0xff); + } +#endif + } + } + } + break; + } + case PNG_COLOR_TYPE_RGB_ALPHA: + { + if (row_info->bit_depth == 8) + { +#if defined(PNG_READ_GAMMA_SUPPORTED) + if (gamma_to_1 != NULL && gamma_from_1 != NULL && + gamma_table != NULL) + { + sp = row; + dp = row; + for (i = 0; i < row_width; i++, sp += 4, dp += 3) + { + png_byte a = *(sp + 3); + + if (a == 0xff) + { + *dp = gamma_table[*sp]; + *(dp + 1) = gamma_table[*(sp + 1)]; + *(dp + 2) = gamma_table[*(sp + 2)]; + } + else if (a == 0) + { + /* background is already in screen gamma */ + *dp = (png_byte)background->red; + *(dp + 1) = (png_byte)background->green; + *(dp + 2) = (png_byte)background->blue; + } + else + { + png_byte v, w; + + v = gamma_to_1[*sp]; + png_composite(w, v, a, background_1->red); + *dp = gamma_from_1[w]; + v = gamma_to_1[*(sp + 1)]; + png_composite(w, v, a, background_1->green); + *(dp + 1) = gamma_from_1[w]; + v = gamma_to_1[*(sp + 2)]; + png_composite(w, v, a, background_1->blue); + *(dp + 2) = gamma_from_1[w]; + } + } + } + else +#endif + { + sp = row; + dp = row; + for (i = 0; i < row_width; i++, sp += 4, dp += 3) + { + png_byte a = *(sp + 3); + + if (a == 0xff) + { + *dp = *sp; + *(dp + 1) = *(sp + 1); + *(dp + 2) = *(sp + 2); + } + else if (a == 0) + { + *dp = (png_byte)background->red; + *(dp + 1) = (png_byte)background->green; + *(dp + 2) = (png_byte)background->blue; + } + else + { + png_composite(*dp, *sp, a, background->red); + png_composite(*(dp + 1), *(sp + 1), a, + background->green); + png_composite(*(dp + 2), *(sp + 2), a, + background->blue); + } + } + } + } + else /* if (row_info->bit_depth == 16) */ + { +#if defined(PNG_READ_GAMMA_SUPPORTED) + if (gamma_16 != NULL && gamma_16_from_1 != NULL && + gamma_16_to_1 != NULL) + { + sp = row; + dp = row; + for (i = 0; i < row_width; i++, sp += 8, dp += 6) + { + png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6)) + << 8) + (png_uint_16)(*(sp + 7))); + if (a == (png_uint_16)0xffff) + { + png_uint_16 v; + + v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; + *dp = (png_byte)((v >> 8) & 0xff); + *(dp + 1) = (png_byte)(v & 0xff); + v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)]; + *(dp + 2) = (png_byte)((v >> 8) & 0xff); + *(dp + 3) = (png_byte)(v & 0xff); + v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)]; + *(dp + 4) = (png_byte)((v >> 8) & 0xff); + *(dp + 5) = (png_byte)(v & 0xff); + } + else if (a == 0) + { + /* background is already in screen gamma */ + *dp = (png_byte)((background->red >> 8) & 0xff); + *(dp + 1) = (png_byte)(background->red & 0xff); + *(dp + 2) = (png_byte)((background->green >> 8) & 0xff); + *(dp + 3) = (png_byte)(background->green & 0xff); + *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff); + *(dp + 5) = (png_byte)(background->blue & 0xff); + } + else + { + png_uint_16 v, w, x; + + v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; + png_composite_16(w, v, a, background_1->red); + x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8]; + *dp = (png_byte)((x >> 8) & 0xff); + *(dp + 1) = (png_byte)(x & 0xff); + v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)]; + png_composite_16(w, v, a, background_1->green); + x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8]; + *(dp + 2) = (png_byte)((x >> 8) & 0xff); + *(dp + 3) = (png_byte)(x & 0xff); + v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)]; + png_composite_16(w, v, a, background_1->blue); + x = gamma_16_from_1[(w & 0xff) >> gamma_shift][w >> 8]; + *(dp + 4) = (png_byte)((x >> 8) & 0xff); + *(dp + 5) = (png_byte)(x & 0xff); + } + } + } + else +#endif + { + sp = row; + dp = row; + for (i = 0; i < row_width; i++, sp += 8, dp += 6) + { + png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6)) + << 8) + (png_uint_16)(*(sp + 7))); + if (a == (png_uint_16)0xffff) + { + png_memcpy(dp, sp, 6); + } + else if (a == 0) + { + *dp = (png_byte)((background->red >> 8) & 0xff); + *(dp + 1) = (png_byte)(background->red & 0xff); + *(dp + 2) = (png_byte)((background->green >> 8) & 0xff); + *(dp + 3) = (png_byte)(background->green & 0xff); + *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff); + *(dp + 5) = (png_byte)(background->blue & 0xff); + } + else + { + png_uint_16 v; + + png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8) + + *(sp + 3)); + png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8) + + *(sp + 5)); + + png_composite_16(v, r, a, background->red); + *dp = (png_byte)((v >> 8) & 0xff); + *(dp + 1) = (png_byte)(v & 0xff); + png_composite_16(v, g, a, background->green); + *(dp + 2) = (png_byte)((v >> 8) & 0xff); + *(dp + 3) = (png_byte)(v & 0xff); + png_composite_16(v, b, a, background->blue); + *(dp + 4) = (png_byte)((v >> 8) & 0xff); + *(dp + 5) = (png_byte)(v & 0xff); + } + } + } + } + break; + } + } + + if (row_info->color_type & PNG_COLOR_MASK_ALPHA) + { + row_info->color_type &= ~PNG_COLOR_MASK_ALPHA; + row_info->channels--; + row_info->pixel_depth = (png_byte)(row_info->channels * + row_info->bit_depth); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,row_width); + } + } +} +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) +/* Gamma correct the image, avoiding the alpha channel. Make sure + * you do this after you deal with the transparency issue on grayscale + * or RGB images. If your bit depth is 8, use gamma_table, if it + * is 16, use gamma_16_table and gamma_shift. Build these with + * build_gamma_table(). + */ +void /* PRIVATE */ +png_do_gamma(png_row_infop row_info, png_bytep row, + png_bytep gamma_table, png_uint_16pp gamma_16_table, + int gamma_shift) +{ + png_bytep sp; + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + png_debug(1, "in png_do_gamma\n"); + if ( +#if defined(PNG_USELESS_TESTS_SUPPORTED) + row != NULL && row_info != NULL && +#endif + ((row_info->bit_depth <= 8 && gamma_table != NULL) || + (row_info->bit_depth == 16 && gamma_16_table != NULL))) + { + switch (row_info->color_type) + { + case PNG_COLOR_TYPE_RGB: + { + if (row_info->bit_depth == 8) + { + sp = row; + for (i = 0; i < row_width; i++) + { + *sp = gamma_table[*sp]; + sp++; + *sp = gamma_table[*sp]; + sp++; + *sp = gamma_table[*sp]; + sp++; + } + } + else /* if (row_info->bit_depth == 16) */ + { + sp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 v; + + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + } + } + break; + } + case PNG_COLOR_TYPE_RGB_ALPHA: + { + if (row_info->bit_depth == 8) + { + sp = row; + for (i = 0; i < row_width; i++) + { + *sp = gamma_table[*sp]; + sp++; + *sp = gamma_table[*sp]; + sp++; + *sp = gamma_table[*sp]; + sp++; + sp++; + } + } + else /* if (row_info->bit_depth == 16) */ + { + sp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 4; + } + } + break; + } + case PNG_COLOR_TYPE_GRAY_ALPHA: + { + if (row_info->bit_depth == 8) + { + sp = row; + for (i = 0; i < row_width; i++) + { + *sp = gamma_table[*sp]; + sp += 2; + } + } + else /* if (row_info->bit_depth == 16) */ + { + sp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 4; + } + } + break; + } + case PNG_COLOR_TYPE_GRAY: + { + if (row_info->bit_depth == 2) + { + sp = row; + for (i = 0; i < row_width; i += 4) + { + int a = *sp & 0xc0; + int b = *sp & 0x30; + int c = *sp & 0x0c; + int d = *sp & 0x03; + + *sp = (png_byte)( + ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)]) ) & 0xc0)| + ((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)| + ((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)| + ((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) )); + sp++; + } + } + if (row_info->bit_depth == 4) + { + sp = row; + for (i = 0; i < row_width; i += 2) + { + int msb = *sp & 0xf0; + int lsb = *sp & 0x0f; + + *sp = (png_byte)((((int)gamma_table[msb | (msb >> 4)]) & 0xf0) + | (((int)gamma_table[(lsb << 4) | lsb]) >> 4)); + sp++; + } + } + else if (row_info->bit_depth == 8) + { + sp = row; + for (i = 0; i < row_width; i++) + { + *sp = gamma_table[*sp]; + sp++; + } + } + else if (row_info->bit_depth == 16) + { + sp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + } + } + break; + } + } + } +} +#endif + +#if defined(PNG_READ_EXPAND_SUPPORTED) +/* Expands a palette row to an RGB or RGBA row depending + * upon whether you supply trans and num_trans. + */ +void /* PRIVATE */ +png_do_expand_palette(png_row_infop row_info, png_bytep row, + png_colorp palette, png_bytep trans, int num_trans) +{ + int shift, value; + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + png_debug(1, "in png_do_expand_palette\n"); + if ( +#if defined(PNG_USELESS_TESTS_SUPPORTED) + row != NULL && row_info != NULL && +#endif + row_info->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (row_info->bit_depth < 8) + { + switch (row_info->bit_depth) + { + case 1: + { + sp = row + (png_size_t)((row_width - 1) >> 3); + dp = row + (png_size_t)row_width - 1; + shift = 7 - (int)((row_width + 7) & 0x07); + for (i = 0; i < row_width; i++) + { + if ((*sp >> shift) & 0x01) + *dp = 1; + else + *dp = 0; + if (shift == 7) + { + shift = 0; + sp--; + } + else + shift++; + + dp--; + } + break; + } + case 2: + { + sp = row + (png_size_t)((row_width - 1) >> 2); + dp = row + (png_size_t)row_width - 1; + shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); + for (i = 0; i < row_width; i++) + { + value = (*sp >> shift) & 0x03; + *dp = (png_byte)value; + if (shift == 6) + { + shift = 0; + sp--; + } + else + shift += 2; + + dp--; + } + break; + } + case 4: + { + sp = row + (png_size_t)((row_width - 1) >> 1); + dp = row + (png_size_t)row_width - 1; + shift = (int)((row_width & 0x01) << 2); + for (i = 0; i < row_width; i++) + { + value = (*sp >> shift) & 0x0f; + *dp = (png_byte)value; + if (shift == 4) + { + shift = 0; + sp--; + } + else + shift += 4; + + dp--; + } + break; + } + } + row_info->bit_depth = 8; + row_info->pixel_depth = 8; + row_info->rowbytes = row_width; + } + switch (row_info->bit_depth) + { + case 8: + { + if (trans != NULL) + { + sp = row + (png_size_t)row_width - 1; + dp = row + (png_size_t)(row_width << 2) - 1; + + for (i = 0; i < row_width; i++) + { + if ((int)(*sp) >= num_trans) + *dp-- = 0xff; + else + *dp-- = trans[*sp]; + *dp-- = palette[*sp].blue; + *dp-- = palette[*sp].green; + *dp-- = palette[*sp].red; + sp--; + } + row_info->bit_depth = 8; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + row_info->color_type = 6; + row_info->channels = 4; + } + else + { + sp = row + (png_size_t)row_width - 1; + dp = row + (png_size_t)(row_width * 3) - 1; + + for (i = 0; i < row_width; i++) + { + *dp-- = palette[*sp].blue; + *dp-- = palette[*sp].green; + *dp-- = palette[*sp].red; + sp--; + } + row_info->bit_depth = 8; + row_info->pixel_depth = 24; + row_info->rowbytes = row_width * 3; + row_info->color_type = 2; + row_info->channels = 3; + } + break; + } + } + } +} + +/* If the bit depth < 8, it is expanded to 8. Also, if the + * transparency value is supplied, an alpha channel is built. + */ +void /* PRIVATE */ +png_do_expand(png_row_infop row_info, png_bytep row, + png_color_16p trans_value) +{ + int shift, value; + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + png_debug(1, "in png_do_expand\n"); +#if defined(PNG_USELESS_TESTS_SUPPORTED) + if (row != NULL && row_info != NULL) +#endif + { + if (row_info->color_type == PNG_COLOR_TYPE_GRAY) + { + png_uint_16 gray = (png_uint_16)(trans_value ? trans_value->gray : 0); + + if (row_info->bit_depth < 8) + { + switch (row_info->bit_depth) + { + case 1: + { + gray = (png_uint_16)(gray*0xff); + sp = row + (png_size_t)((row_width - 1) >> 3); + dp = row + (png_size_t)row_width - 1; + shift = 7 - (int)((row_width + 7) & 0x07); + for (i = 0; i < row_width; i++) + { + if ((*sp >> shift) & 0x01) + *dp = 0xff; + else + *dp = 0; + if (shift == 7) + { + shift = 0; + sp--; + } + else + shift++; + + dp--; + } + break; + } + case 2: + { + gray = (png_uint_16)(gray*0x55); + sp = row + (png_size_t)((row_width - 1) >> 2); + dp = row + (png_size_t)row_width - 1; + shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); + for (i = 0; i < row_width; i++) + { + value = (*sp >> shift) & 0x03; + *dp = (png_byte)(value | (value << 2) | (value << 4) | + (value << 6)); + if (shift == 6) + { + shift = 0; + sp--; + } + else + shift += 2; + + dp--; + } + break; + } + case 4: + { + gray = (png_uint_16)(gray*0x11); + sp = row + (png_size_t)((row_width - 1) >> 1); + dp = row + (png_size_t)row_width - 1; + shift = (int)((1 - ((row_width + 1) & 0x01)) << 2); + for (i = 0; i < row_width; i++) + { + value = (*sp >> shift) & 0x0f; + *dp = (png_byte)(value | (value << 4)); + if (shift == 4) + { + shift = 0; + sp--; + } + else + shift = 4; + + dp--; + } + break; + } + } + row_info->bit_depth = 8; + row_info->pixel_depth = 8; + row_info->rowbytes = row_width; + } + + if (trans_value != NULL) + { + if (row_info->bit_depth == 8) + { + sp = row + (png_size_t)row_width - 1; + dp = row + (png_size_t)(row_width << 1) - 1; + for (i = 0; i < row_width; i++) + { + if (*sp == gray) + *dp-- = 0; + else + *dp-- = 0xff; + *dp-- = *sp--; + } + } + else if (row_info->bit_depth == 16) + { + sp = row + row_info->rowbytes - 1; + dp = row + (row_info->rowbytes << 1) - 1; + for (i = 0; i < row_width; i++) + { + if (((png_uint_16)*(sp) | + ((png_uint_16)*(sp - 1) << 8)) == gray) + { + *dp-- = 0; + *dp-- = 0; + } + else + { + *dp-- = 0xff; + *dp-- = 0xff; + } + *dp-- = *sp--; + *dp-- = *sp--; + } + } + row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA; + row_info->channels = 2; + row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, + row_width); + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_value) + { + if (row_info->bit_depth == 8) + { + sp = row + (png_size_t)row_info->rowbytes - 1; + dp = row + (png_size_t)(row_width << 2) - 1; + for (i = 0; i < row_width; i++) + { + if (*(sp - 2) == trans_value->red && + *(sp - 1) == trans_value->green && + *(sp - 0) == trans_value->blue) + *dp-- = 0; + else + *dp-- = 0xff; + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + } + } + else if (row_info->bit_depth == 16) + { + sp = row + row_info->rowbytes - 1; + dp = row + (png_size_t)(row_width << 3) - 1; + for (i = 0; i < row_width; i++) + { + if ((((png_uint_16)*(sp - 4) | + ((png_uint_16)*(sp - 5) << 8)) == trans_value->red) && + (((png_uint_16)*(sp - 2) | + ((png_uint_16)*(sp - 3) << 8)) == trans_value->green) && + (((png_uint_16)*(sp - 0) | + ((png_uint_16)*(sp - 1) << 8)) == trans_value->blue)) + { + *dp-- = 0; + *dp-- = 0; + } + else + { + *dp-- = 0xff; + *dp-- = 0xff; + } + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + } + } + row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA; + row_info->channels = 4; + row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,row_width); + } + } +} +#endif + +#if defined(PNG_READ_DITHER_SUPPORTED) +void /* PRIVATE */ +png_do_dither(png_row_infop row_info, png_bytep row, + png_bytep palette_lookup, png_bytep dither_lookup) +{ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + png_debug(1, "in png_do_dither\n"); +#if defined(PNG_USELESS_TESTS_SUPPORTED) + if (row != NULL && row_info != NULL) +#endif + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB && + palette_lookup && row_info->bit_depth == 8) + { + int r, g, b, p; + sp = row; + dp = row; + for (i = 0; i < row_width; i++) + { + r = *sp++; + g = *sp++; + b = *sp++; + + /* this looks real messy, but the compiler will reduce + it down to a reasonable formula. For example, with + 5 bits per color, we get: + p = (((r >> 3) & 0x1f) << 10) | + (((g >> 3) & 0x1f) << 5) | + ((b >> 3) & 0x1f); + */ + p = (((r >> (8 - PNG_DITHER_RED_BITS)) & + ((1 << PNG_DITHER_RED_BITS) - 1)) << + (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) | + (((g >> (8 - PNG_DITHER_GREEN_BITS)) & + ((1 << PNG_DITHER_GREEN_BITS) - 1)) << + (PNG_DITHER_BLUE_BITS)) | + ((b >> (8 - PNG_DITHER_BLUE_BITS)) & + ((1 << PNG_DITHER_BLUE_BITS) - 1)); + + *dp++ = palette_lookup[p]; + } + row_info->color_type = PNG_COLOR_TYPE_PALETTE; + row_info->channels = 1; + row_info->pixel_depth = row_info->bit_depth; + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,row_width); + } + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA && + palette_lookup != NULL && row_info->bit_depth == 8) + { + int r, g, b, p; + sp = row; + dp = row; + for (i = 0; i < row_width; i++) + { + r = *sp++; + g = *sp++; + b = *sp++; + sp++; + + p = (((r >> (8 - PNG_DITHER_RED_BITS)) & + ((1 << PNG_DITHER_RED_BITS) - 1)) << + (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) | + (((g >> (8 - PNG_DITHER_GREEN_BITS)) & + ((1 << PNG_DITHER_GREEN_BITS) - 1)) << + (PNG_DITHER_BLUE_BITS)) | + ((b >> (8 - PNG_DITHER_BLUE_BITS)) & + ((1 << PNG_DITHER_BLUE_BITS) - 1)); + + *dp++ = palette_lookup[p]; + } + row_info->color_type = PNG_COLOR_TYPE_PALETTE; + row_info->channels = 1; + row_info->pixel_depth = row_info->bit_depth; + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,row_width); + } + else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE && + dither_lookup && row_info->bit_depth == 8) + { + sp = row; + for (i = 0; i < row_width; i++, sp++) + { + *sp = dither_lookup[*sp]; + } + } + } +} +#endif + +#ifdef PNG_FLOATING_POINT_SUPPORTED +#if defined(PNG_READ_GAMMA_SUPPORTED) +static int png_gamma_shift[] = + {0x10, 0x21, 0x42, 0x84, 0x110, 0x248, 0x550, 0xff0}; + +/* We build the 8- or 16-bit gamma tables here. Note that for 16-bit + * tables, we don't make a full table if we are reducing to 8-bit in + * the future. Note also how the gamma_16 tables are segmented so that + * we don't need to allocate > 64K chunks for a full 16-bit table. + */ +void /* PRIVATE */ +png_build_gamma_table(png_structp png_ptr) +{ + png_debug(1, "in png_build_gamma_table\n"); + if(png_ptr->gamma != 0.0) + { + if (png_ptr->bit_depth <= 8) + { + int i; + double g; + + if (png_ptr->screen_gamma > .000001) + g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma); + else + g = 1.0; + + png_ptr->gamma_table = (png_bytep)png_malloc(png_ptr, + (png_uint_32)256); + + for (i = 0; i < 256; i++) + { + png_ptr->gamma_table[i] = (png_byte)(pow((double)i / 255.0, + g) * 255.0 + .5); + } + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + if (png_ptr->transformations & ((PNG_BACKGROUND) | PNG_RGB_TO_GRAY)) + { + + g = 1.0 / (png_ptr->gamma); + + png_ptr->gamma_to_1 = (png_bytep)png_malloc(png_ptr, + (png_uint_32)256); + + for (i = 0; i < 256; i++) + { + png_ptr->gamma_to_1[i] = (png_byte)(pow((double)i / 255.0, + g) * 255.0 + .5); + } + + + png_ptr->gamma_from_1 = (png_bytep)png_malloc(png_ptr, + (png_uint_32)256); + + if(png_ptr->screen_gamma > 0.000001) + g = 1.0 / png_ptr->screen_gamma; + else + g = png_ptr->gamma; /* probably doing rgb_to_gray */ + + for (i = 0; i < 256; i++) + { + png_ptr->gamma_from_1[i] = (png_byte)(pow((double)i / 255.0, + g) * 255.0 + .5); + + } + } +#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */ + } + else + { + double g; + int i, j, shift, num; + int sig_bit; + png_uint_32 ig; + + if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) + { + sig_bit = (int)png_ptr->sig_bit.red; + if ((int)png_ptr->sig_bit.green > sig_bit) + sig_bit = png_ptr->sig_bit.green; + if ((int)png_ptr->sig_bit.blue > sig_bit) + sig_bit = png_ptr->sig_bit.blue; + } + else + { + sig_bit = (int)png_ptr->sig_bit.gray; + } + + if (sig_bit > 0) + shift = 16 - sig_bit; + else + shift = 0; + + if (png_ptr->transformations & PNG_16_TO_8) + { + if (shift < (16 - PNG_MAX_GAMMA_8)) + shift = (16 - PNG_MAX_GAMMA_8); + } + + if (shift > 8) + shift = 8; + if (shift < 0) + shift = 0; + + png_ptr->gamma_shift = (png_byte)shift; + + num = (1 << (8 - shift)); + + if (png_ptr->screen_gamma > .000001) + g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma); + else + g = 1.0; + + png_ptr->gamma_16_table = (png_uint_16pp)png_malloc(png_ptr, + (png_uint_32)(num * png_sizeof (png_uint_16p))); + + if (png_ptr->transformations & (PNG_16_TO_8 | PNG_BACKGROUND)) + { + double fin, fout; + png_uint_32 last, max; + + for (i = 0; i < num; i++) + { + png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(256 * png_sizeof (png_uint_16))); + } + + g = 1.0 / g; + last = 0; + for (i = 0; i < 256; i++) + { + fout = ((double)i + 0.5) / 256.0; + fin = pow(fout, g); + max = (png_uint_32)(fin * (double)((png_uint_32)num << 8)); + while (last <= max) + { + png_ptr->gamma_16_table[(int)(last & (0xff >> shift))] + [(int)(last >> (8 - shift))] = (png_uint_16)( + (png_uint_16)i | ((png_uint_16)i << 8)); + last++; + } + } + while (last < ((png_uint_32)num << 8)) + { + png_ptr->gamma_16_table[(int)(last & (0xff >> shift))] + [(int)(last >> (8 - shift))] = (png_uint_16)65535L; + last++; + } + } + else + { + for (i = 0; i < num; i++) + { + png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(256 * png_sizeof (png_uint_16))); + + ig = (((png_uint_32)i * (png_uint_32)png_gamma_shift[shift]) >> 4); + for (j = 0; j < 256; j++) + { + png_ptr->gamma_16_table[i][j] = + (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) / + 65535.0, g) * 65535.0 + .5); + } + } + } + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + if (png_ptr->transformations & (PNG_BACKGROUND | PNG_RGB_TO_GRAY)) + { + + g = 1.0 / (png_ptr->gamma); + + png_ptr->gamma_16_to_1 = (png_uint_16pp)png_malloc(png_ptr, + (png_uint_32)(num * png_sizeof (png_uint_16p ))); + + for (i = 0; i < num; i++) + { + png_ptr->gamma_16_to_1[i] = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(256 * png_sizeof (png_uint_16))); + + ig = (((png_uint_32)i * + (png_uint_32)png_gamma_shift[shift]) >> 4); + for (j = 0; j < 256; j++) + { + png_ptr->gamma_16_to_1[i][j] = + (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) / + 65535.0, g) * 65535.0 + .5); + } + } + + if(png_ptr->screen_gamma > 0.000001) + g = 1.0 / png_ptr->screen_gamma; + else + g = png_ptr->gamma; /* probably doing rgb_to_gray */ + + png_ptr->gamma_16_from_1 = (png_uint_16pp)png_malloc(png_ptr, + (png_uint_32)(num * png_sizeof (png_uint_16p))); + + for (i = 0; i < num; i++) + { + png_ptr->gamma_16_from_1[i] = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(256 * png_sizeof (png_uint_16))); + + ig = (((png_uint_32)i * + (png_uint_32)png_gamma_shift[shift]) >> 4); + for (j = 0; j < 256; j++) + { + png_ptr->gamma_16_from_1[i][j] = + (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) / + 65535.0, g) * 65535.0 + .5); + } + } + } +#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */ + } + } +} +#endif +/* To do: install integer version of png_build_gamma_table here */ +#endif + +#if defined(PNG_MNG_FEATURES_SUPPORTED) +/* undoes intrapixel differencing */ +void /* PRIVATE */ +png_do_read_intrapixel(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_read_intrapixel\n"); + if ( +#if defined(PNG_USELESS_TESTS_SUPPORTED) + row != NULL && row_info != NULL && +#endif + (row_info->color_type & PNG_COLOR_MASK_COLOR)) + { + int bytes_per_pixel; + png_uint_32 row_width = row_info->width; + if (row_info->bit_depth == 8) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 3; + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 4; + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + *(rp) = (png_byte)((256 + *rp + *(rp+1))&0xff); + *(rp+2) = (png_byte)((256 + *(rp+2) + *(rp+1))&0xff); + } + } + else if (row_info->bit_depth == 16) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 6; + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 8; + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + png_uint_32 s0 = (*(rp ) << 8) | *(rp+1); + png_uint_32 s1 = (*(rp+2) << 8) | *(rp+3); + png_uint_32 s2 = (*(rp+4) << 8) | *(rp+5); + png_uint_32 red = (png_uint_32)((s0+s1+65536L) & 0xffffL); + png_uint_32 blue = (png_uint_32)((s2+s1+65536L) & 0xffffL); + *(rp ) = (png_byte)((red >> 8) & 0xff); + *(rp+1) = (png_byte)(red & 0xff); + *(rp+4) = (png_byte)((blue >> 8) & 0xff); + *(rp+5) = (png_byte)(blue & 0xff); + } + } + } +} +#endif /* PNG_MNG_FEATURES_SUPPORTED */ diff --git a/syslinux/com32/lib/libpng/pngrutil.c b/syslinux/com32/lib/libpng/pngrutil.c new file mode 100644 index 0000000..99e466f --- /dev/null +++ b/syslinux/com32/lib/libpng/pngrutil.c @@ -0,0 +1,3124 @@ +/* pngrutil.c - utilities to read a PNG file + * + * libpng version 1.2.8 - December 3, 2004 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2004 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This file contains routines that are only called from within + * libpng itself during the course of reading an image. + */ + +#define PNG_INTERNAL +#include "png.h" + +#if defined(_WIN32_WCE) +/* strtod() function is not supported on WindowsCE */ +# ifdef PNG_FLOATING_POINT_SUPPORTED +__inline double strtod(const char *nptr, char **endptr) +{ + double result = 0; + int len; + wchar_t *str, *end; + + len = MultiByteToWideChar(CP_ACP, 0, nptr, -1, NULL, 0); + str = (wchar_t *)malloc(len * sizeof(wchar_t)); + if ( NULL != str ) + { + MultiByteToWideChar(CP_ACP, 0, nptr, -1, str, len); + result = wcstod(str, &end); + len = WideCharToMultiByte(CP_ACP, 0, end, -1, NULL, 0, NULL, NULL); + *endptr = (char *)nptr + (png_strlen(nptr) - len + 1); + free(str); + } + return result; +} +# endif +#endif + +png_uint_32 /* PRIVATE */ +png_get_uint_31(png_structp png_ptr, png_bytep buf) +{ + png_uint_32 i = png_get_uint_32(buf); + if (i > PNG_UINT_31_MAX) + png_error(png_ptr, "PNG unsigned integer out of range.\n"); + return (i); +} +#ifndef PNG_READ_BIG_ENDIAN_SUPPORTED +/* Grab an unsigned 32-bit integer from a buffer in big-endian format. */ +png_uint_32 /* PRIVATE */ +png_get_uint_32(png_bytep buf) +{ + png_uint_32 i = ((png_uint_32)(*buf) << 24) + + ((png_uint_32)(*(buf + 1)) << 16) + + ((png_uint_32)(*(buf + 2)) << 8) + + (png_uint_32)(*(buf + 3)); + + return (i); +} + +#if defined(PNG_READ_pCAL_SUPPORTED) || defined(PNG_READ_oFFs_SUPPORTED) +/* Grab a signed 32-bit integer from a buffer in big-endian format. The + * data is stored in the PNG file in two's complement format, and it is + * assumed that the machine format for signed integers is the same. */ +png_int_32 /* PRIVATE */ +png_get_int_32(png_bytep buf) +{ + png_int_32 i = ((png_int_32)(*buf) << 24) + + ((png_int_32)(*(buf + 1)) << 16) + + ((png_int_32)(*(buf + 2)) << 8) + + (png_int_32)(*(buf + 3)); + + return (i); +} +#endif /* PNG_READ_pCAL_SUPPORTED */ + +/* Grab an unsigned 16-bit integer from a buffer in big-endian format. */ +png_uint_16 /* PRIVATE */ +png_get_uint_16(png_bytep buf) +{ + png_uint_16 i = (png_uint_16)(((png_uint_16)(*buf) << 8) + + (png_uint_16)(*(buf + 1))); + + return (i); +} +#endif /* PNG_READ_BIG_ENDIAN_SUPPORTED */ + +/* Read data, and (optionally) run it through the CRC. */ +void /* PRIVATE */ +png_crc_read(png_structp png_ptr, png_bytep buf, png_size_t length) +{ + png_read_data(png_ptr, buf, length); + png_calculate_crc(png_ptr, buf, length); +} + +/* Optionally skip data and then check the CRC. Depending on whether we + are reading a ancillary or critical chunk, and how the program has set + things up, we may calculate the CRC on the data and print a message. + Returns '1' if there was a CRC error, '0' otherwise. */ +int /* PRIVATE */ +png_crc_finish(png_structp png_ptr, png_uint_32 skip) +{ + png_size_t i; + png_size_t istop = png_ptr->zbuf_size; + + for (i = (png_size_t)skip; i > istop; i -= istop) + { + png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); + } + if (i) + { + png_crc_read(png_ptr, png_ptr->zbuf, i); + } + + if (png_crc_error(png_ptr)) + { + if (((png_ptr->chunk_name[0] & 0x20) && /* Ancillary */ + !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) || + (!(png_ptr->chunk_name[0] & 0x20) && /* Critical */ + (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE))) + { + png_chunk_warning(png_ptr, "CRC error"); + } + else + { + png_chunk_error(png_ptr, "CRC error"); + } + return (1); + } + + return (0); +} + +/* Compare the CRC stored in the PNG file with that calculated by libpng from + the data it has read thus far. */ +int /* PRIVATE */ +png_crc_error(png_structp png_ptr) +{ + png_byte crc_bytes[4]; + png_uint_32 crc; + int need_crc = 1; + + if (png_ptr->chunk_name[0] & 0x20) /* ancillary */ + { + if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == + (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) + need_crc = 0; + } + else /* critical */ + { + if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) + need_crc = 0; + } + + png_read_data(png_ptr, crc_bytes, 4); + + if (need_crc) + { + crc = png_get_uint_32(crc_bytes); + return ((int)(crc != png_ptr->crc)); + } + else + return (0); +} + +#if defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) || \ + defined(PNG_READ_iCCP_SUPPORTED) +/* + * Decompress trailing data in a chunk. The assumption is that chunkdata + * points at an allocated area holding the contents of a chunk with a + * trailing compressed part. What we get back is an allocated area + * holding the original prefix part and an uncompressed version of the + * trailing part (the malloc area passed in is freed). + */ +png_charp /* PRIVATE */ +png_decompress_chunk(png_structp png_ptr, int comp_type, + png_charp chunkdata, png_size_t chunklength, + png_size_t prefix_size, png_size_t *newlength) +{ + static char msg[] = "Error decoding compressed text"; + png_charp text; + png_size_t text_size; + + if (comp_type == PNG_COMPRESSION_TYPE_BASE) + { + int ret = Z_OK; + png_ptr->zstream.next_in = (png_bytep)(chunkdata + prefix_size); + png_ptr->zstream.avail_in = (uInt)(chunklength - prefix_size); + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + + text_size = 0; + text = NULL; + + while (png_ptr->zstream.avail_in) + { + ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); + if (ret != Z_OK && ret != Z_STREAM_END) + { + if (png_ptr->zstream.msg != NULL) + png_warning(png_ptr, png_ptr->zstream.msg); + else + png_warning(png_ptr, msg); + inflateReset(&png_ptr->zstream); + png_ptr->zstream.avail_in = 0; + + if (text == NULL) + { + text_size = prefix_size + png_sizeof(msg) + 1; + text = (png_charp)png_malloc_warn(png_ptr, text_size); + if (text == NULL) + { + png_free(png_ptr,chunkdata); + png_error(png_ptr,"Not enough memory to decompress chunk"); + } + png_memcpy(text, chunkdata, prefix_size); + } + + text[text_size - 1] = 0x00; + + /* Copy what we can of the error message into the text chunk */ + text_size = (png_size_t)(chunklength - (text - chunkdata) - 1); + text_size = png_sizeof(msg) > text_size ? text_size : + png_sizeof(msg); + png_memcpy(text + prefix_size, msg, text_size + 1); + break; + } + if (!png_ptr->zstream.avail_out || ret == Z_STREAM_END) + { + if (text == NULL) + { + text_size = prefix_size + + png_ptr->zbuf_size - png_ptr->zstream.avail_out; + text = (png_charp)png_malloc_warn(png_ptr, text_size + 1); + if (text == NULL) + { + png_free(png_ptr,chunkdata); + png_error(png_ptr,"Not enough memory to decompress chunk."); + } + png_memcpy(text + prefix_size, png_ptr->zbuf, + text_size - prefix_size); + png_memcpy(text, chunkdata, prefix_size); + *(text + text_size) = 0x00; + } + else + { + png_charp tmp; + + tmp = text; + text = (png_charp)png_malloc_warn(png_ptr, + (png_uint_32)(text_size + + png_ptr->zbuf_size - png_ptr->zstream.avail_out + 1)); + if (text == NULL) + { + png_free(png_ptr, tmp); + png_free(png_ptr, chunkdata); + png_error(png_ptr,"Not enough memory to decompress chunk.."); + } + png_memcpy(text, tmp, text_size); + png_free(png_ptr, tmp); + png_memcpy(text + text_size, png_ptr->zbuf, + (png_ptr->zbuf_size - png_ptr->zstream.avail_out)); + text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out; + *(text + text_size) = 0x00; + } + if (ret == Z_STREAM_END) + break; + else + { + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + } + } + } + if (ret != Z_STREAM_END) + { +#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) + char umsg[50]; + + if (ret == Z_BUF_ERROR) + sprintf(umsg,"Buffer error in compressed datastream in %s chunk", + png_ptr->chunk_name); + else if (ret == Z_DATA_ERROR) + sprintf(umsg,"Data error in compressed datastream in %s chunk", + png_ptr->chunk_name); + else + sprintf(umsg,"Incomplete compressed datastream in %s chunk", + png_ptr->chunk_name); + png_warning(png_ptr, umsg); +#else + png_warning(png_ptr, + "Incomplete compressed datastream in chunk other than IDAT"); +#endif + text_size=prefix_size; + if (text == NULL) + { + text = (png_charp)png_malloc_warn(png_ptr, text_size+1); + if (text == NULL) + { + png_free(png_ptr, chunkdata); + png_error(png_ptr,"Not enough memory for text."); + } + png_memcpy(text, chunkdata, prefix_size); + } + *(text + text_size) = 0x00; + } + + inflateReset(&png_ptr->zstream); + png_ptr->zstream.avail_in = 0; + + png_free(png_ptr, chunkdata); + chunkdata = text; + *newlength=text_size; + } + else /* if (comp_type != PNG_COMPRESSION_TYPE_BASE) */ + { +#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) + char umsg[50]; + + sprintf(umsg, "Unknown zTXt compression type %d", comp_type); + png_warning(png_ptr, umsg); +#else + png_warning(png_ptr, "Unknown zTXt compression type"); +#endif + + *(chunkdata + prefix_size) = 0x00; + *newlength=prefix_size; + } + + return chunkdata; +} +#endif + +/* read and check the IDHR chunk */ +void /* PRIVATE */ +png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_byte buf[13]; + png_uint_32 width, height; + int bit_depth, color_type, compression_type, filter_type; + int interlace_type; + + png_debug(1, "in png_handle_IHDR\n"); + + if (png_ptr->mode & PNG_HAVE_IHDR) + png_error(png_ptr, "Out of place IHDR"); + + /* check the length */ + if (length != 13) + png_error(png_ptr, "Invalid IHDR chunk"); + + png_ptr->mode |= PNG_HAVE_IHDR; + + png_crc_read(png_ptr, buf, 13); + png_crc_finish(png_ptr, 0); + + width = png_get_uint_31(png_ptr, buf); + height = png_get_uint_31(png_ptr, buf + 4); + bit_depth = buf[8]; + color_type = buf[9]; + compression_type = buf[10]; + filter_type = buf[11]; + interlace_type = buf[12]; + + /* set internal variables */ + png_ptr->width = width; + png_ptr->height = height; + png_ptr->bit_depth = (png_byte)bit_depth; + png_ptr->interlaced = (png_byte)interlace_type; + png_ptr->color_type = (png_byte)color_type; +#if defined(PNG_MNG_FEATURES_SUPPORTED) + png_ptr->filter_type = (png_byte)filter_type; +#endif + png_ptr->compression_type = (png_byte)compression_type; + + /* find number of channels */ + switch (png_ptr->color_type) + { + case PNG_COLOR_TYPE_GRAY: + case PNG_COLOR_TYPE_PALETTE: + png_ptr->channels = 1; + break; + case PNG_COLOR_TYPE_RGB: + png_ptr->channels = 3; + break; + case PNG_COLOR_TYPE_GRAY_ALPHA: + png_ptr->channels = 2; + break; + case PNG_COLOR_TYPE_RGB_ALPHA: + png_ptr->channels = 4; + break; + } + + /* set up other useful info */ + png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth * + png_ptr->channels); + png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->width); + png_debug1(3,"bit_depth = %d\n", png_ptr->bit_depth); + png_debug1(3,"channels = %d\n", png_ptr->channels); + png_debug1(3,"rowbytes = %lu\n", png_ptr->rowbytes); + png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, + color_type, interlace_type, compression_type, filter_type); +} + +/* read and check the palette */ +void /* PRIVATE */ +png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_color palette[PNG_MAX_PALETTE_LENGTH]; + int num, i; +#ifndef PNG_NO_POINTER_INDEXING + png_colorp pal_ptr; +#endif + + png_debug(1, "in png_handle_PLTE\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before PLTE"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid PLTE after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (png_ptr->mode & PNG_HAVE_PLTE) + png_error(png_ptr, "Duplicate PLTE chunk"); + + png_ptr->mode |= PNG_HAVE_PLTE; + + if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR)) + { + png_warning(png_ptr, + "Ignoring PLTE chunk in grayscale PNG"); + png_crc_finish(png_ptr, length); + return; + } +#if !defined(PNG_READ_OPT_PLTE_SUPPORTED) + if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE) + { + png_crc_finish(png_ptr, length); + return; + } +#endif + + if (length > 3*PNG_MAX_PALETTE_LENGTH || length % 3) + { + if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE) + { + png_warning(png_ptr, "Invalid palette chunk"); + png_crc_finish(png_ptr, length); + return; + } + else + { + png_error(png_ptr, "Invalid palette chunk"); + } + } + + num = (int)length / 3; + +#ifndef PNG_NO_POINTER_INDEXING + for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++) + { + png_byte buf[3]; + + png_crc_read(png_ptr, buf, 3); + pal_ptr->red = buf[0]; + pal_ptr->green = buf[1]; + pal_ptr->blue = buf[2]; + } +#else + for (i = 0; i < num; i++) + { + png_byte buf[3]; + + png_crc_read(png_ptr, buf, 3); + /* don't depend upon png_color being any order */ + palette[i].red = buf[0]; + palette[i].green = buf[1]; + palette[i].blue = buf[2]; + } +#endif + + /* If we actually NEED the PLTE chunk (ie for a paletted image), we do + whatever the normal CRC configuration tells us. However, if we + have an RGB image, the PLTE can be considered ancillary, so + we will act as though it is. */ +#if !defined(PNG_READ_OPT_PLTE_SUPPORTED) + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) +#endif + { + png_crc_finish(png_ptr, 0); + } +#if !defined(PNG_READ_OPT_PLTE_SUPPORTED) + else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */ + { + /* If we don't want to use the data from an ancillary chunk, + we have two options: an error abort, or a warning and we + ignore the data in this chunk (which should be OK, since + it's considered ancillary for a RGB or RGBA image). */ + if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE)) + { + if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) + { + png_chunk_error(png_ptr, "CRC error"); + } + else + { + png_chunk_warning(png_ptr, "CRC error"); + return; + } + } + /* Otherwise, we (optionally) emit a warning and use the chunk. */ + else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) + { + png_chunk_warning(png_ptr, "CRC error"); + } + } +#endif + + png_set_PLTE(png_ptr, info_ptr, palette, num); + +#if defined(PNG_READ_tRNS_SUPPORTED) + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) + { + if (png_ptr->num_trans > (png_uint_16)num) + { + png_warning(png_ptr, "Truncating incorrect tRNS chunk length"); + png_ptr->num_trans = (png_uint_16)num; + } + if (info_ptr->num_trans > (png_uint_16)num) + { + png_warning(png_ptr, "Truncating incorrect info tRNS chunk length"); + info_ptr->num_trans = (png_uint_16)num; + } + } + } +#endif + +} + +void /* PRIVATE */ +png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_debug(1, "in png_handle_IEND\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT)) + { + png_error(png_ptr, "No image in file"); + } + + png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND); + + if (length != 0) + { + png_warning(png_ptr, "Incorrect IEND chunk length"); + } + png_crc_finish(png_ptr, length); + + if (&info_ptr == NULL) /* quiet compiler warnings about unused info_ptr */ + return; +} + +#if defined(PNG_READ_gAMA_SUPPORTED) +void /* PRIVATE */ +png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_fixed_point igamma; +#ifdef PNG_FLOATING_POINT_SUPPORTED + float file_gamma; +#endif + png_byte buf[4]; + + png_debug(1, "in png_handle_gAMA\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before gAMA"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid gAMA after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (png_ptr->mode & PNG_HAVE_PLTE) + /* Should be an error, but we can cope with it */ + png_warning(png_ptr, "Out of place gAMA chunk"); + + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA) +#if defined(PNG_READ_sRGB_SUPPORTED) + && !(info_ptr->valid & PNG_INFO_sRGB) +#endif + ) + { + png_warning(png_ptr, "Duplicate gAMA chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (length != 4) + { + png_warning(png_ptr, "Incorrect gAMA chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, 4); + if (png_crc_finish(png_ptr, 0)) + return; + + igamma = (png_fixed_point)png_get_uint_32(buf); + /* check for zero gamma */ + if (igamma == 0) + { + png_warning(png_ptr, + "Ignoring gAMA chunk with gamma=0"); + return; + } + +#if defined(PNG_READ_sRGB_SUPPORTED) + if (info_ptr->valid & PNG_INFO_sRGB) + if (PNG_OUT_OF_RANGE(igamma, 45500L, 500)) + { + png_warning(png_ptr, + "Ignoring incorrect gAMA value when sRGB is also present"); +#ifndef PNG_NO_CONSOLE_IO + fprintf(stderr, "gamma = (%d/100000)\n", (int)igamma); +#endif + return; + } +#endif /* PNG_READ_sRGB_SUPPORTED */ + +#ifdef PNG_FLOATING_POINT_SUPPORTED + file_gamma = (float)igamma / (float)100000.0; +# ifdef PNG_READ_GAMMA_SUPPORTED + png_ptr->gamma = file_gamma; +# endif + png_set_gAMA(png_ptr, info_ptr, file_gamma); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + png_set_gAMA_fixed(png_ptr, info_ptr, igamma); +#endif +} +#endif + +#if defined(PNG_READ_sBIT_SUPPORTED) +void /* PRIVATE */ +png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_size_t truelen; + png_byte buf[4]; + + png_debug(1, "in png_handle_sBIT\n"); + + buf[0] = buf[1] = buf[2] = buf[3] = 0; + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before sBIT"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid sBIT after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (png_ptr->mode & PNG_HAVE_PLTE) + { + /* Should be an error, but we can cope with it */ + png_warning(png_ptr, "Out of place sBIT chunk"); + } + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT)) + { + png_warning(png_ptr, "Duplicate sBIT chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + truelen = 3; + else + truelen = (png_size_t)png_ptr->channels; + + if (length != truelen || length > 4) + { + png_warning(png_ptr, "Incorrect sBIT chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, truelen); + if (png_crc_finish(png_ptr, 0)) + return; + + if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) + { + png_ptr->sig_bit.red = buf[0]; + png_ptr->sig_bit.green = buf[1]; + png_ptr->sig_bit.blue = buf[2]; + png_ptr->sig_bit.alpha = buf[3]; + } + else + { + png_ptr->sig_bit.gray = buf[0]; + png_ptr->sig_bit.red = buf[0]; + png_ptr->sig_bit.green = buf[0]; + png_ptr->sig_bit.blue = buf[0]; + png_ptr->sig_bit.alpha = buf[1]; + } + png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit)); +} +#endif + +#if defined(PNG_READ_cHRM_SUPPORTED) +void /* PRIVATE */ +png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_byte buf[4]; +#ifdef PNG_FLOATING_POINT_SUPPORTED + float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y; +#endif + png_fixed_point int_x_white, int_y_white, int_x_red, int_y_red, int_x_green, + int_y_green, int_x_blue, int_y_blue; + + png_uint_32 uint_x, uint_y; + + png_debug(1, "in png_handle_cHRM\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before cHRM"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid cHRM after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (png_ptr->mode & PNG_HAVE_PLTE) + /* Should be an error, but we can cope with it */ + png_warning(png_ptr, "Missing PLTE before cHRM"); + + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM) +#if defined(PNG_READ_sRGB_SUPPORTED) + && !(info_ptr->valid & PNG_INFO_sRGB) +#endif + ) + { + png_warning(png_ptr, "Duplicate cHRM chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (length != 32) + { + png_warning(png_ptr, "Incorrect cHRM chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, 4); + uint_x = png_get_uint_32(buf); + + png_crc_read(png_ptr, buf, 4); + uint_y = png_get_uint_32(buf); + + if (uint_x > 80000L || uint_y > 80000L || + uint_x + uint_y > 100000L) + { + png_warning(png_ptr, "Invalid cHRM white point"); + png_crc_finish(png_ptr, 24); + return; + } + int_x_white = (png_fixed_point)uint_x; + int_y_white = (png_fixed_point)uint_y; + + png_crc_read(png_ptr, buf, 4); + uint_x = png_get_uint_32(buf); + + png_crc_read(png_ptr, buf, 4); + uint_y = png_get_uint_32(buf); + + if (uint_x > 80000L || uint_y > 80000L || + uint_x + uint_y > 100000L) + { + png_warning(png_ptr, "Invalid cHRM red point"); + png_crc_finish(png_ptr, 16); + return; + } + int_x_red = (png_fixed_point)uint_x; + int_y_red = (png_fixed_point)uint_y; + + png_crc_read(png_ptr, buf, 4); + uint_x = png_get_uint_32(buf); + + png_crc_read(png_ptr, buf, 4); + uint_y = png_get_uint_32(buf); + + if (uint_x > 80000L || uint_y > 80000L || + uint_x + uint_y > 100000L) + { + png_warning(png_ptr, "Invalid cHRM green point"); + png_crc_finish(png_ptr, 8); + return; + } + int_x_green = (png_fixed_point)uint_x; + int_y_green = (png_fixed_point)uint_y; + + png_crc_read(png_ptr, buf, 4); + uint_x = png_get_uint_32(buf); + + png_crc_read(png_ptr, buf, 4); + uint_y = png_get_uint_32(buf); + + if (uint_x > 80000L || uint_y > 80000L || + uint_x + uint_y > 100000L) + { + png_warning(png_ptr, "Invalid cHRM blue point"); + png_crc_finish(png_ptr, 0); + return; + } + int_x_blue = (png_fixed_point)uint_x; + int_y_blue = (png_fixed_point)uint_y; + +#ifdef PNG_FLOATING_POINT_SUPPORTED + white_x = (float)int_x_white / (float)100000.0; + white_y = (float)int_y_white / (float)100000.0; + red_x = (float)int_x_red / (float)100000.0; + red_y = (float)int_y_red / (float)100000.0; + green_x = (float)int_x_green / (float)100000.0; + green_y = (float)int_y_green / (float)100000.0; + blue_x = (float)int_x_blue / (float)100000.0; + blue_y = (float)int_y_blue / (float)100000.0; +#endif + +#if defined(PNG_READ_sRGB_SUPPORTED) + if (info_ptr->valid & PNG_INFO_sRGB) + { + if (PNG_OUT_OF_RANGE(int_x_white, 31270, 1000) || + PNG_OUT_OF_RANGE(int_y_white, 32900, 1000) || + PNG_OUT_OF_RANGE(int_x_red, 64000L, 1000) || + PNG_OUT_OF_RANGE(int_y_red, 33000, 1000) || + PNG_OUT_OF_RANGE(int_x_green, 30000, 1000) || + PNG_OUT_OF_RANGE(int_y_green, 60000L, 1000) || + PNG_OUT_OF_RANGE(int_x_blue, 15000, 1000) || + PNG_OUT_OF_RANGE(int_y_blue, 6000, 1000)) + { + + png_warning(png_ptr, + "Ignoring incorrect cHRM value when sRGB is also present"); +#ifndef PNG_NO_CONSOLE_IO +#ifdef PNG_FLOATING_POINT_SUPPORTED + fprintf(stderr,"wx=%f, wy=%f, rx=%f, ry=%f\n", + white_x, white_y, red_x, red_y); + fprintf(stderr,"gx=%f, gy=%f, bx=%f, by=%f\n", + green_x, green_y, blue_x, blue_y); +#else + fprintf(stderr,"wx=%ld, wy=%ld, rx=%ld, ry=%ld\n", + int_x_white, int_y_white, int_x_red, int_y_red); + fprintf(stderr,"gx=%ld, gy=%ld, bx=%ld, by=%ld\n", + int_x_green, int_y_green, int_x_blue, int_y_blue); +#endif +#endif /* PNG_NO_CONSOLE_IO */ + } + png_crc_finish(png_ptr, 0); + return; + } +#endif /* PNG_READ_sRGB_SUPPORTED */ + +#ifdef PNG_FLOATING_POINT_SUPPORTED + png_set_cHRM(png_ptr, info_ptr, + white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + png_set_cHRM_fixed(png_ptr, info_ptr, + int_x_white, int_y_white, int_x_red, int_y_red, int_x_green, + int_y_green, int_x_blue, int_y_blue); +#endif + if (png_crc_finish(png_ptr, 0)) + return; +} +#endif + +#if defined(PNG_READ_sRGB_SUPPORTED) +void /* PRIVATE */ +png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + int intent; + png_byte buf[1]; + + png_debug(1, "in png_handle_sRGB\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before sRGB"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid sRGB after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (png_ptr->mode & PNG_HAVE_PLTE) + /* Should be an error, but we can cope with it */ + png_warning(png_ptr, "Out of place sRGB chunk"); + + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB)) + { + png_warning(png_ptr, "Duplicate sRGB chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (length != 1) + { + png_warning(png_ptr, "Incorrect sRGB chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, 1); + if (png_crc_finish(png_ptr, 0)) + return; + + intent = buf[0]; + /* check for bad intent */ + if (intent >= PNG_sRGB_INTENT_LAST) + { + png_warning(png_ptr, "Unknown sRGB intent"); + return; + } + +#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED) + if ((info_ptr->valid & PNG_INFO_gAMA)) + { + png_fixed_point igamma; +#ifdef PNG_FIXED_POINT_SUPPORTED + igamma=info_ptr->int_gamma; +#else +# ifdef PNG_FLOATING_POINT_SUPPORTED + igamma=(png_fixed_point)(info_ptr->gamma * 100000.); +# endif +#endif + if (PNG_OUT_OF_RANGE(igamma, 45500L, 500)) + { + png_warning(png_ptr, + "Ignoring incorrect gAMA value when sRGB is also present"); +#ifndef PNG_NO_CONSOLE_IO +# ifdef PNG_FIXED_POINT_SUPPORTED + fprintf(stderr,"incorrect gamma=(%d/100000)\n",(int)png_ptr->int_gamma); +# else +# ifdef PNG_FLOATING_POINT_SUPPORTED + fprintf(stderr,"incorrect gamma=%f\n",png_ptr->gamma); +# endif +# endif +#endif + } + } +#endif /* PNG_READ_gAMA_SUPPORTED */ + +#ifdef PNG_READ_cHRM_SUPPORTED +#ifdef PNG_FIXED_POINT_SUPPORTED + if (info_ptr->valid & PNG_INFO_cHRM) + if (PNG_OUT_OF_RANGE(info_ptr->int_x_white, 31270, 1000) || + PNG_OUT_OF_RANGE(info_ptr->int_y_white, 32900, 1000) || + PNG_OUT_OF_RANGE(info_ptr->int_x_red, 64000L, 1000) || + PNG_OUT_OF_RANGE(info_ptr->int_y_red, 33000, 1000) || + PNG_OUT_OF_RANGE(info_ptr->int_x_green, 30000, 1000) || + PNG_OUT_OF_RANGE(info_ptr->int_y_green, 60000L, 1000) || + PNG_OUT_OF_RANGE(info_ptr->int_x_blue, 15000, 1000) || + PNG_OUT_OF_RANGE(info_ptr->int_y_blue, 6000, 1000)) + { + png_warning(png_ptr, + "Ignoring incorrect cHRM value when sRGB is also present"); + } +#endif /* PNG_FIXED_POINT_SUPPORTED */ +#endif /* PNG_READ_cHRM_SUPPORTED */ + + png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, intent); +} +#endif /* PNG_READ_sRGB_SUPPORTED */ + +#if defined(PNG_READ_iCCP_SUPPORTED) +void /* PRIVATE */ +png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +/* Note: this does not properly handle chunks that are > 64K under DOS */ +{ + png_charp chunkdata; + png_byte compression_type; + png_bytep pC; + png_charp profile; + png_uint_32 skip = 0; + png_uint_32 profile_size, profile_length; + png_size_t slength, prefix_length, data_length; + + png_debug(1, "in png_handle_iCCP\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before iCCP"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid iCCP after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (png_ptr->mode & PNG_HAVE_PLTE) + /* Should be an error, but we can cope with it */ + png_warning(png_ptr, "Out of place iCCP chunk"); + + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP)) + { + png_warning(png_ptr, "Duplicate iCCP chunk"); + png_crc_finish(png_ptr, length); + return; + } + +#ifdef PNG_MAX_MALLOC_64K + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr, "iCCP chunk too large to fit in memory"); + skip = length - (png_uint_32)65535L; + length = (png_uint_32)65535L; + } +#endif + + chunkdata = (png_charp)png_malloc(png_ptr, length + 1); + slength = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)chunkdata, slength); + + if (png_crc_finish(png_ptr, skip)) + { + png_free(png_ptr, chunkdata); + return; + } + + chunkdata[slength] = 0x00; + + for (profile = chunkdata; *profile; profile++) + /* empty loop to find end of name */ ; + + ++profile; + + /* there should be at least one zero (the compression type byte) + following the separator, and we should be on it */ + if ( profile >= chunkdata + slength) + { + png_free(png_ptr, chunkdata); + png_warning(png_ptr, "Malformed iCCP chunk"); + return; + } + + /* compression_type should always be zero */ + compression_type = *profile++; + if (compression_type) + { + png_warning(png_ptr, "Ignoring nonzero compression type in iCCP chunk"); + compression_type=0x00; /* Reset it to zero (libpng-1.0.6 through 1.0.8 + wrote nonzero) */ + } + + prefix_length = profile - chunkdata; + chunkdata = png_decompress_chunk(png_ptr, compression_type, chunkdata, + slength, prefix_length, &data_length); + + profile_length = data_length - prefix_length; + + if ( prefix_length > data_length || profile_length < 4) + { + png_free(png_ptr, chunkdata); + png_warning(png_ptr, "Profile size field missing from iCCP chunk"); + return; + } + + /* Check the profile_size recorded in the first 32 bits of the ICC profile */ + pC = (png_bytep)(chunkdata+prefix_length); + profile_size = ((*(pC ))<<24) | + ((*(pC+1))<<16) | + ((*(pC+2))<< 8) | + ((*(pC+3)) ); + + if(profile_size < profile_length) + profile_length = profile_size; + + if(profile_size > profile_length) + { + png_free(png_ptr, chunkdata); + png_warning(png_ptr, "Ignoring truncated iCCP profile.\n"); + return; + } + + png_set_iCCP(png_ptr, info_ptr, chunkdata, compression_type, + chunkdata + prefix_length, profile_length); + png_free(png_ptr, chunkdata); +} +#endif /* PNG_READ_iCCP_SUPPORTED */ + +#if defined(PNG_READ_sPLT_SUPPORTED) +void /* PRIVATE */ +png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +/* Note: this does not properly handle chunks that are > 64K under DOS */ +{ + png_bytep chunkdata; + png_bytep entry_start; + png_sPLT_t new_palette; +#ifdef PNG_NO_POINTER_INDEXING + png_sPLT_entryp pp; +#endif + int data_length, entry_size, i; + png_uint_32 skip = 0; + png_size_t slength; + + png_debug(1, "in png_handle_sPLT\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before sPLT"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid sPLT after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + +#ifdef PNG_MAX_MALLOC_64K + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr, "sPLT chunk too large to fit in memory"); + skip = length - (png_uint_32)65535L; + length = (png_uint_32)65535L; + } +#endif + + chunkdata = (png_bytep)png_malloc(png_ptr, length + 1); + slength = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)chunkdata, slength); + + if (png_crc_finish(png_ptr, skip)) + { + png_free(png_ptr, chunkdata); + return; + } + + chunkdata[slength] = 0x00; + + for (entry_start = chunkdata; *entry_start; entry_start++) + /* empty loop to find end of name */ ; + ++entry_start; + + /* a sample depth should follow the separator, and we should be on it */ + if (entry_start > chunkdata + slength) + { + png_free(png_ptr, chunkdata); + png_warning(png_ptr, "malformed sPLT chunk"); + return; + } + + new_palette.depth = *entry_start++; + entry_size = (new_palette.depth == 8 ? 6 : 10); + data_length = (slength - (entry_start - chunkdata)); + + /* integrity-check the data length */ + if (data_length % entry_size) + { + png_free(png_ptr, chunkdata); + png_warning(png_ptr, "sPLT chunk has bad length"); + return; + } + + new_palette.nentries = (png_uint_32) (data_length / entry_size); + if ((png_uint_32) new_palette.nentries > (png_uint_32) (PNG_SIZE_MAX / + png_sizeof(png_sPLT_entry))) + { + png_warning(png_ptr, "sPLT chunk too long"); + return; + } + new_palette.entries = (png_sPLT_entryp)png_malloc_warn( + png_ptr, new_palette.nentries * png_sizeof(png_sPLT_entry)); + if (new_palette.entries == NULL) + { + png_warning(png_ptr, "sPLT chunk requires too much memory"); + return; + } + +#ifndef PNG_NO_POINTER_INDEXING + for (i = 0; i < new_palette.nentries; i++) + { + png_sPLT_entryp pp = new_palette.entries + i; + + if (new_palette.depth == 8) + { + pp->red = *entry_start++; + pp->green = *entry_start++; + pp->blue = *entry_start++; + pp->alpha = *entry_start++; + } + else + { + pp->red = png_get_uint_16(entry_start); entry_start += 2; + pp->green = png_get_uint_16(entry_start); entry_start += 2; + pp->blue = png_get_uint_16(entry_start); entry_start += 2; + pp->alpha = png_get_uint_16(entry_start); entry_start += 2; + } + pp->frequency = png_get_uint_16(entry_start); entry_start += 2; + } +#else + pp = new_palette.entries; + for (i = 0; i < new_palette.nentries; i++) + { + + if (new_palette.depth == 8) + { + pp[i].red = *entry_start++; + pp[i].green = *entry_start++; + pp[i].blue = *entry_start++; + pp[i].alpha = *entry_start++; + } + else + { + pp[i].red = png_get_uint_16(entry_start); entry_start += 2; + pp[i].green = png_get_uint_16(entry_start); entry_start += 2; + pp[i].blue = png_get_uint_16(entry_start); entry_start += 2; + pp[i].alpha = png_get_uint_16(entry_start); entry_start += 2; + } + pp->frequency = png_get_uint_16(entry_start); entry_start += 2; + } +#endif + + /* discard all chunk data except the name and stash that */ + new_palette.name = (png_charp)chunkdata; + + png_set_sPLT(png_ptr, info_ptr, &new_palette, 1); + + png_free(png_ptr, chunkdata); + png_free(png_ptr, new_palette.entries); +} +#endif /* PNG_READ_sPLT_SUPPORTED */ + +#if defined(PNG_READ_tRNS_SUPPORTED) +void /* PRIVATE */ +png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_byte readbuf[PNG_MAX_PALETTE_LENGTH]; + + png_debug(1, "in png_handle_tRNS\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before tRNS"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid tRNS after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) + { + png_warning(png_ptr, "Duplicate tRNS chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) + { + png_byte buf[2]; + + if (length != 2) + { + png_warning(png_ptr, "Incorrect tRNS chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, 2); + png_ptr->num_trans = 1; + png_ptr->trans_values.gray = png_get_uint_16(buf); + } + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) + { + png_byte buf[6]; + + if (length != 6) + { + png_warning(png_ptr, "Incorrect tRNS chunk length"); + png_crc_finish(png_ptr, length); + return; + } + png_crc_read(png_ptr, buf, (png_size_t)length); + png_ptr->num_trans = 1; + png_ptr->trans_values.red = png_get_uint_16(buf); + png_ptr->trans_values.green = png_get_uint_16(buf + 2); + png_ptr->trans_values.blue = png_get_uint_16(buf + 4); + } + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (!(png_ptr->mode & PNG_HAVE_PLTE)) + { + /* Should be an error, but we can cope with it. */ + png_warning(png_ptr, "Missing PLTE before tRNS"); + } + if (length > (png_uint_32)png_ptr->num_palette || + length > PNG_MAX_PALETTE_LENGTH) + { + png_warning(png_ptr, "Incorrect tRNS chunk length"); + png_crc_finish(png_ptr, length); + return; + } + if (length == 0) + { + png_warning(png_ptr, "Zero length tRNS chunk"); + png_crc_finish(png_ptr, length); + return; + } + png_crc_read(png_ptr, readbuf, (png_size_t)length); + png_ptr->num_trans = (png_uint_16)length; + } + else + { + png_warning(png_ptr, "tRNS chunk not allowed with alpha channel"); + png_crc_finish(png_ptr, length); + return; + } + + if (png_crc_finish(png_ptr, 0)) + return; + + png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans, + &(png_ptr->trans_values)); +} +#endif + +#if defined(PNG_READ_bKGD_SUPPORTED) +void /* PRIVATE */ +png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_size_t truelen; + png_byte buf[6]; + + png_debug(1, "in png_handle_bKGD\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before bKGD"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid bKGD after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + !(png_ptr->mode & PNG_HAVE_PLTE)) + { + png_warning(png_ptr, "Missing PLTE before bKGD"); + png_crc_finish(png_ptr, length); + return; + } + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD)) + { + png_warning(png_ptr, "Duplicate bKGD chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + truelen = 1; + else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) + truelen = 6; + else + truelen = 2; + + if (length != truelen) + { + png_warning(png_ptr, "Incorrect bKGD chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, truelen); + if (png_crc_finish(png_ptr, 0)) + return; + + /* We convert the index value into RGB components so that we can allow + * arbitrary RGB values for background when we have transparency, and + * so it is easy to determine the RGB values of the background color + * from the info_ptr struct. */ + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + png_ptr->background.index = buf[0]; + if(info_ptr->num_palette) + { + if(buf[0] > info_ptr->num_palette) + { + png_warning(png_ptr, "Incorrect bKGD chunk index value"); + return; + } + png_ptr->background.red = + (png_uint_16)png_ptr->palette[buf[0]].red; + png_ptr->background.green = + (png_uint_16)png_ptr->palette[buf[0]].green; + png_ptr->background.blue = + (png_uint_16)png_ptr->palette[buf[0]].blue; + } + } + else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */ + { + png_ptr->background.red = + png_ptr->background.green = + png_ptr->background.blue = + png_ptr->background.gray = png_get_uint_16(buf); + } + else + { + png_ptr->background.red = png_get_uint_16(buf); + png_ptr->background.green = png_get_uint_16(buf + 2); + png_ptr->background.blue = png_get_uint_16(buf + 4); + } + + png_set_bKGD(png_ptr, info_ptr, &(png_ptr->background)); +} +#endif + +#if defined(PNG_READ_hIST_SUPPORTED) +void /* PRIVATE */ +png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + unsigned int num, i; + png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH]; + + png_debug(1, "in png_handle_hIST\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before hIST"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid hIST after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (!(png_ptr->mode & PNG_HAVE_PLTE)) + { + png_warning(png_ptr, "Missing PLTE before hIST"); + png_crc_finish(png_ptr, length); + return; + } + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST)) + { + png_warning(png_ptr, "Duplicate hIST chunk"); + png_crc_finish(png_ptr, length); + return; + } + + num = length / 2 ; + if (num != (unsigned int) png_ptr->num_palette || num > + (unsigned int) PNG_MAX_PALETTE_LENGTH) + { + png_warning(png_ptr, "Incorrect hIST chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + for (i = 0; i < num; i++) + { + png_byte buf[2]; + + png_crc_read(png_ptr, buf, 2); + readbuf[i] = png_get_uint_16(buf); + } + + if (png_crc_finish(png_ptr, 0)) + return; + + png_set_hIST(png_ptr, info_ptr, readbuf); +} +#endif + +#if defined(PNG_READ_pHYs_SUPPORTED) +void /* PRIVATE */ +png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_byte buf[9]; + png_uint_32 res_x, res_y; + int unit_type; + + png_debug(1, "in png_handle_pHYs\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before pHYs"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid pHYs after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) + { + png_warning(png_ptr, "Duplicate pHYs chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (length != 9) + { + png_warning(png_ptr, "Incorrect pHYs chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, 9); + if (png_crc_finish(png_ptr, 0)) + return; + + res_x = png_get_uint_32(buf); + res_y = png_get_uint_32(buf + 4); + unit_type = buf[8]; + png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type); +} +#endif + +#if defined(PNG_READ_oFFs_SUPPORTED) +void /* PRIVATE */ +png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_byte buf[9]; + png_int_32 offset_x, offset_y; + int unit_type; + + png_debug(1, "in png_handle_oFFs\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before oFFs"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid oFFs after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)) + { + png_warning(png_ptr, "Duplicate oFFs chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (length != 9) + { + png_warning(png_ptr, "Incorrect oFFs chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, 9); + if (png_crc_finish(png_ptr, 0)) + return; + + offset_x = png_get_int_32(buf); + offset_y = png_get_int_32(buf + 4); + unit_type = buf[8]; + png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type); +} +#endif + +#if defined(PNG_READ_pCAL_SUPPORTED) +/* read the pCAL chunk (described in the PNG Extensions document) */ +void /* PRIVATE */ +png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_charp purpose; + png_int_32 X0, X1; + png_byte type, nparams; + png_charp buf, units, endptr; + png_charpp params; + png_size_t slength; + int i; + + png_debug(1, "in png_handle_pCAL\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before pCAL"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid pCAL after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL)) + { + png_warning(png_ptr, "Duplicate pCAL chunk"); + png_crc_finish(png_ptr, length); + return; + } + + png_debug1(2, "Allocating and reading pCAL chunk data (%lu bytes)\n", + length + 1); + purpose = (png_charp)png_malloc_warn(png_ptr, length + 1); + if (purpose == NULL) + { + png_warning(png_ptr, "No memory for pCAL purpose."); + return; + } + slength = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)purpose, slength); + + if (png_crc_finish(png_ptr, 0)) + { + png_free(png_ptr, purpose); + return; + } + + purpose[slength] = 0x00; /* null terminate the last string */ + + png_debug(3, "Finding end of pCAL purpose string\n"); + for (buf = purpose; *buf; buf++) + /* empty loop */ ; + + endptr = purpose + slength; + + /* We need to have at least 12 bytes after the purpose string + in order to get the parameter information. */ + if (endptr <= buf + 12) + { + png_warning(png_ptr, "Invalid pCAL data"); + png_free(png_ptr, purpose); + return; + } + + png_debug(3, "Reading pCAL X0, X1, type, nparams, and units\n"); + X0 = png_get_int_32((png_bytep)buf+1); + X1 = png_get_int_32((png_bytep)buf+5); + type = buf[9]; + nparams = buf[10]; + units = buf + 11; + + png_debug(3, "Checking pCAL equation type and number of parameters\n"); + /* Check that we have the right number of parameters for known + equation types. */ + if ((type == PNG_EQUATION_LINEAR && nparams != 2) || + (type == PNG_EQUATION_BASE_E && nparams != 3) || + (type == PNG_EQUATION_ARBITRARY && nparams != 3) || + (type == PNG_EQUATION_HYPERBOLIC && nparams != 4)) + { + png_warning(png_ptr, "Invalid pCAL parameters for equation type"); + png_free(png_ptr, purpose); + return; + } + else if (type >= PNG_EQUATION_LAST) + { + png_warning(png_ptr, "Unrecognized equation type for pCAL chunk"); + } + + for (buf = units; *buf; buf++) + /* Empty loop to move past the units string. */ ; + + png_debug(3, "Allocating pCAL parameters array\n"); + params = (png_charpp)png_malloc_warn(png_ptr, (png_uint_32)(nparams + *png_sizeof(png_charp))) ; + if (params == NULL) + { + png_free(png_ptr, purpose); + png_warning(png_ptr, "No memory for pCAL params."); + return; + } + + /* Get pointers to the start of each parameter string. */ + for (i = 0; i < (int)nparams; i++) + { + buf++; /* Skip the null string terminator from previous parameter. */ + + png_debug1(3, "Reading pCAL parameter %d\n", i); + for (params[i] = buf; *buf != 0x00 && buf <= endptr; buf++) + /* Empty loop to move past each parameter string */ ; + + /* Make sure we haven't run out of data yet */ + if (buf > endptr) + { + png_warning(png_ptr, "Invalid pCAL data"); + png_free(png_ptr, purpose); + png_free(png_ptr, params); + return; + } + } + + png_set_pCAL(png_ptr, info_ptr, purpose, X0, X1, type, nparams, + units, params); + + png_free(png_ptr, purpose); + png_free(png_ptr, params); +} +#endif + +#if defined(PNG_READ_sCAL_SUPPORTED) +/* read the sCAL chunk */ +void /* PRIVATE */ +png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_charp buffer, ep; +#ifdef PNG_FLOATING_POINT_SUPPORTED + double width, height; + png_charp vp; +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + png_charp swidth, sheight; +#endif +#endif + png_size_t slength; + + png_debug(1, "in png_handle_sCAL\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before sCAL"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid sCAL after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL)) + { + png_warning(png_ptr, "Duplicate sCAL chunk"); + png_crc_finish(png_ptr, length); + return; + } + + png_debug1(2, "Allocating and reading sCAL chunk data (%lu bytes)\n", + length + 1); + buffer = (png_charp)png_malloc_warn(png_ptr, length + 1); + if (buffer == NULL) + { + png_warning(png_ptr, "Out of memory while processing sCAL chunk"); + return; + } + slength = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)buffer, slength); + + if (png_crc_finish(png_ptr, 0)) + { + png_free(png_ptr, buffer); + return; + } + + buffer[slength] = 0x00; /* null terminate the last string */ + + ep = buffer + 1; /* skip unit byte */ + +#ifdef PNG_FLOATING_POINT_SUPPORTED + width = strtod(ep, &vp); + if (*vp) + { + png_warning(png_ptr, "malformed width string in sCAL chunk"); + return; + } +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + swidth = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1); + if (swidth == NULL) + { + png_warning(png_ptr, "Out of memory while processing sCAL chunk width"); + return; + } + png_memcpy(swidth, ep, (png_size_t)png_strlen(ep)); +#endif +#endif + + for (ep = buffer; *ep; ep++) + /* empty loop */ ; + ep++; + +#ifdef PNG_FLOATING_POINT_SUPPORTED + height = strtod(ep, &vp); + if (*vp) + { + png_warning(png_ptr, "malformed height string in sCAL chunk"); + return; + } +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + sheight = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1); + if (swidth == NULL) + { + png_warning(png_ptr, "Out of memory while processing sCAL chunk height"); + return; + } + png_memcpy(sheight, ep, (png_size_t)png_strlen(ep)); +#endif +#endif + + if (buffer + slength < ep +#ifdef PNG_FLOATING_POINT_SUPPORTED + || width <= 0. || height <= 0. +#endif + ) + { + png_warning(png_ptr, "Invalid sCAL data"); + png_free(png_ptr, buffer); +#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED) + png_free(png_ptr, swidth); + png_free(png_ptr, sheight); +#endif + return; + } + + +#ifdef PNG_FLOATING_POINT_SUPPORTED + png_set_sCAL(png_ptr, info_ptr, buffer[0], width, height); +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + png_set_sCAL_s(png_ptr, info_ptr, buffer[0], swidth, sheight); +#endif +#endif + + png_free(png_ptr, buffer); +#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED) + png_free(png_ptr, swidth); + png_free(png_ptr, sheight); +#endif +} +#endif + +#if defined(PNG_READ_tIME_SUPPORTED) +void /* PRIVATE */ +png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_byte buf[7]; + png_time mod_time; + + png_debug(1, "in png_handle_tIME\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Out of place tIME chunk"); + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME)) + { + png_warning(png_ptr, "Duplicate tIME chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (png_ptr->mode & PNG_HAVE_IDAT) + png_ptr->mode |= PNG_AFTER_IDAT; + + if (length != 7) + { + png_warning(png_ptr, "Incorrect tIME chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, 7); + if (png_crc_finish(png_ptr, 0)) + return; + + mod_time.second = buf[6]; + mod_time.minute = buf[5]; + mod_time.hour = buf[4]; + mod_time.day = buf[3]; + mod_time.month = buf[2]; + mod_time.year = png_get_uint_16(buf); + + png_set_tIME(png_ptr, info_ptr, &mod_time); +} +#endif + +#if defined(PNG_READ_tEXt_SUPPORTED) +/* Note: this does not properly handle chunks that are > 64K under DOS */ +void /* PRIVATE */ +png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_textp text_ptr; + png_charp key; + png_charp text; + png_uint_32 skip = 0; + png_size_t slength; + int ret; + + png_debug(1, "in png_handle_tEXt\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before tEXt"); + + if (png_ptr->mode & PNG_HAVE_IDAT) + png_ptr->mode |= PNG_AFTER_IDAT; + +#ifdef PNG_MAX_MALLOC_64K + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr, "tEXt chunk too large to fit in memory"); + skip = length - (png_uint_32)65535L; + length = (png_uint_32)65535L; + } +#endif + + key = (png_charp)png_malloc_warn(png_ptr, length + 1); + if (key == NULL) + { + png_warning(png_ptr, "No memory to process text chunk."); + return; + } + slength = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)key, slength); + + if (png_crc_finish(png_ptr, skip)) + { + png_free(png_ptr, key); + return; + } + + key[slength] = 0x00; + + for (text = key; *text; text++) + /* empty loop to find end of key */ ; + + if (text != key + slength) + text++; + + text_ptr = (png_textp)png_malloc_warn(png_ptr, + (png_uint_32)png_sizeof(png_text)); + if (text_ptr == NULL) + { + png_warning(png_ptr, "Not enough memory to process text chunk."); + png_free(png_ptr, key); + return; + } + text_ptr->compression = PNG_TEXT_COMPRESSION_NONE; + text_ptr->key = key; +#ifdef PNG_iTXt_SUPPORTED + text_ptr->lang = NULL; + text_ptr->lang_key = NULL; + text_ptr->itxt_length = 0; +#endif + text_ptr->text = text; + text_ptr->text_length = png_strlen(text); + + ret=png_set_text_2(png_ptr, info_ptr, text_ptr, 1); + + png_free(png_ptr, key); + png_free(png_ptr, text_ptr); + if (ret) + png_warning(png_ptr, "Insufficient memory to process text chunk."); +} +#endif + +#if defined(PNG_READ_zTXt_SUPPORTED) +/* note: this does not correctly handle chunks that are > 64K under DOS */ +void /* PRIVATE */ +png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_textp text_ptr; + png_charp chunkdata; + png_charp text; + int comp_type; + int ret; + png_size_t slength, prefix_len, data_len; + + png_debug(1, "in png_handle_zTXt\n"); + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before zTXt"); + + if (png_ptr->mode & PNG_HAVE_IDAT) + png_ptr->mode |= PNG_AFTER_IDAT; + +#ifdef PNG_MAX_MALLOC_64K + /* We will no doubt have problems with chunks even half this size, but + there is no hard and fast rule to tell us where to stop. */ + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr,"zTXt chunk too large to fit in memory"); + png_crc_finish(png_ptr, length); + return; + } +#endif + + chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); + if (chunkdata == NULL) + { + png_warning(png_ptr,"Out of memory processing zTXt chunk."); + return; + } + slength = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)chunkdata, slength); + if (png_crc_finish(png_ptr, 0)) + { + png_free(png_ptr, chunkdata); + return; + } + + chunkdata[slength] = 0x00; + + for (text = chunkdata; *text; text++) + /* empty loop */ ; + + /* zTXt must have some text after the chunkdataword */ + if (text == chunkdata + slength) + { + comp_type = PNG_TEXT_COMPRESSION_NONE; + png_warning(png_ptr, "Zero length zTXt chunk"); + } + else + { + comp_type = *(++text); + if (comp_type != PNG_TEXT_COMPRESSION_zTXt) + { + png_warning(png_ptr, "Unknown compression type in zTXt chunk"); + comp_type = PNG_TEXT_COMPRESSION_zTXt; + } + text++; /* skip the compression_method byte */ + } + prefix_len = text - chunkdata; + + chunkdata = (png_charp)png_decompress_chunk(png_ptr, comp_type, chunkdata, + (png_size_t)length, prefix_len, &data_len); + + text_ptr = (png_textp)png_malloc_warn(png_ptr, + (png_uint_32)png_sizeof(png_text)); + if (text_ptr == NULL) + { + png_warning(png_ptr,"Not enough memory to process zTXt chunk."); + png_free(png_ptr, chunkdata); + return; + } + text_ptr->compression = comp_type; + text_ptr->key = chunkdata; +#ifdef PNG_iTXt_SUPPORTED + text_ptr->lang = NULL; + text_ptr->lang_key = NULL; + text_ptr->itxt_length = 0; +#endif + text_ptr->text = chunkdata + prefix_len; + text_ptr->text_length = data_len; + + ret=png_set_text_2(png_ptr, info_ptr, text_ptr, 1); + + png_free(png_ptr, text_ptr); + png_free(png_ptr, chunkdata); + if (ret) + png_error(png_ptr, "Insufficient memory to store zTXt chunk."); +} +#endif + +#if defined(PNG_READ_iTXt_SUPPORTED) +/* note: this does not correctly handle chunks that are > 64K under DOS */ +void /* PRIVATE */ +png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_textp text_ptr; + png_charp chunkdata; + png_charp key, lang, text, lang_key; + int comp_flag; + int comp_type = 0; + int ret; + png_size_t slength, prefix_len, data_len; + + png_debug(1, "in png_handle_iTXt\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before iTXt"); + + if (png_ptr->mode & PNG_HAVE_IDAT) + png_ptr->mode |= PNG_AFTER_IDAT; + +#ifdef PNG_MAX_MALLOC_64K + /* We will no doubt have problems with chunks even half this size, but + there is no hard and fast rule to tell us where to stop. */ + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr,"iTXt chunk too large to fit in memory"); + png_crc_finish(png_ptr, length); + return; + } +#endif + + chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); + if (chunkdata == NULL) + { + png_warning(png_ptr, "No memory to process iTXt chunk."); + return; + } + slength = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)chunkdata, slength); + if (png_crc_finish(png_ptr, 0)) + { + png_free(png_ptr, chunkdata); + return; + } + + chunkdata[slength] = 0x00; + + for (lang = chunkdata; *lang; lang++) + /* empty loop */ ; + lang++; /* skip NUL separator */ + + /* iTXt must have a language tag (possibly empty), two compression bytes, + translated keyword (possibly empty), and possibly some text after the + keyword */ + + if (lang >= chunkdata + slength) + { + comp_flag = PNG_TEXT_COMPRESSION_NONE; + png_warning(png_ptr, "Zero length iTXt chunk"); + } + else + { + comp_flag = *lang++; + comp_type = *lang++; + } + + for (lang_key = lang; *lang_key; lang_key++) + /* empty loop */ ; + lang_key++; /* skip NUL separator */ + + for (text = lang_key; *text; text++) + /* empty loop */ ; + text++; /* skip NUL separator */ + + prefix_len = text - chunkdata; + + key=chunkdata; + if (comp_flag) + chunkdata = png_decompress_chunk(png_ptr, comp_type, chunkdata, + (size_t)length, prefix_len, &data_len); + else + data_len=png_strlen(chunkdata + prefix_len); + text_ptr = (png_textp)png_malloc_warn(png_ptr, + (png_uint_32)png_sizeof(png_text)); + if (text_ptr == NULL) + { + png_warning(png_ptr,"Not enough memory to process iTXt chunk."); + png_free(png_ptr, chunkdata); + return; + } + text_ptr->compression = (int)comp_flag + 1; + text_ptr->lang_key = chunkdata+(lang_key-key); + text_ptr->lang = chunkdata+(lang-key); + text_ptr->itxt_length = data_len; + text_ptr->text_length = 0; + text_ptr->key = chunkdata; + text_ptr->text = chunkdata + prefix_len; + + ret=png_set_text_2(png_ptr, info_ptr, text_ptr, 1); + + png_free(png_ptr, text_ptr); + png_free(png_ptr, chunkdata); + if (ret) + png_error(png_ptr, "Insufficient memory to store iTXt chunk."); +} +#endif + +/* This function is called when we haven't found a handler for a + chunk. If there isn't a problem with the chunk itself (ie bad + chunk name, CRC, or a critical chunk), the chunk is silently ignored + -- unless the PNG_FLAG_UNKNOWN_CHUNKS_SUPPORTED flag is on in which + case it will be saved away to be written out later. */ +void /* PRIVATE */ +png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_uint_32 skip = 0; + + png_debug(1, "in png_handle_unknown\n"); + + if (png_ptr->mode & PNG_HAVE_IDAT) + { +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_IDAT; +#endif + if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) /* not an IDAT */ + png_ptr->mode |= PNG_AFTER_IDAT; + } + + png_check_chunk_name(png_ptr, png_ptr->chunk_name); + + if (!(png_ptr->chunk_name[0] & 0x20)) + { +#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) + if(png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != + PNG_HANDLE_CHUNK_ALWAYS +#if defined(PNG_READ_USER_CHUNKS_SUPPORTED) + && png_ptr->read_user_chunk_fn == NULL +#endif + ) +#endif + png_chunk_error(png_ptr, "unknown critical chunk"); + } + +#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) + if (png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS) + { + png_unknown_chunk chunk; + +#ifdef PNG_MAX_MALLOC_64K + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr, "unknown chunk too large to fit in memory"); + skip = length - (png_uint_32)65535L; + length = (png_uint_32)65535L; + } +#endif + png_strcpy((png_charp)chunk.name, (png_charp)png_ptr->chunk_name); + chunk.data = (png_bytep)png_malloc(png_ptr, length); + chunk.size = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)chunk.data, length); +#if defined(PNG_READ_USER_CHUNKS_SUPPORTED) + if(png_ptr->read_user_chunk_fn != NULL) + { + /* callback to user unknown chunk handler */ + if ((*(png_ptr->read_user_chunk_fn)) (png_ptr, &chunk) <= 0) + { + if (!(png_ptr->chunk_name[0] & 0x20)) + if(png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != + PNG_HANDLE_CHUNK_ALWAYS) + { + png_free(png_ptr, chunk.data); + png_chunk_error(png_ptr, "unknown critical chunk"); + } + png_set_unknown_chunks(png_ptr, info_ptr, &chunk, 1); + } + } + else +#endif + png_set_unknown_chunks(png_ptr, info_ptr, &chunk, 1); + png_free(png_ptr, chunk.data); + } + else +#endif + skip = length; + + png_crc_finish(png_ptr, skip); + +#if !defined(PNG_READ_USER_CHUNKS_SUPPORTED) + if (&info_ptr == NULL) /* quiet compiler warnings about unused info_ptr */ + return; +#endif +} + +/* This function is called to verify that a chunk name is valid. + This function can't have the "critical chunk check" incorporated + into it, since in the future we will need to be able to call user + functions to handle unknown critical chunks after we check that + the chunk name itself is valid. */ + +#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97)) + +void /* PRIVATE */ +png_check_chunk_name(png_structp png_ptr, png_bytep chunk_name) +{ + png_debug(1, "in png_check_chunk_name\n"); + if (isnonalpha(chunk_name[0]) || isnonalpha(chunk_name[1]) || + isnonalpha(chunk_name[2]) || isnonalpha(chunk_name[3])) + { + png_chunk_error(png_ptr, "invalid chunk type"); + } +} + +/* Combines the row recently read in with the existing pixels in the + row. This routine takes care of alpha and transparency if requested. + This routine also handles the two methods of progressive display + of interlaced images, depending on the mask value. + The mask value describes which pixels are to be combined with + the row. The pattern always repeats every 8 pixels, so just 8 + bits are needed. A one indicates the pixel is to be combined, + a zero indicates the pixel is to be skipped. This is in addition + to any alpha or transparency value associated with the pixel. If + you want all pixels to be combined, pass 0xff (255) in mask. */ +#ifndef PNG_HAVE_ASSEMBLER_COMBINE_ROW +void /* PRIVATE */ +png_combine_row(png_structp png_ptr, png_bytep row, int mask) +{ + png_debug(1,"in png_combine_row\n"); + if (mask == 0xff) + { + png_memcpy(row, png_ptr->row_buf + 1, + PNG_ROWBYTES(png_ptr->row_info.pixel_depth, png_ptr->width)); + } + else + { + switch (png_ptr->row_info.pixel_depth) + { + case 1: + { + png_bytep sp = png_ptr->row_buf + 1; + png_bytep dp = row; + int s_inc, s_start, s_end; + int m = 0x80; + int shift; + png_uint_32 i; + png_uint_32 row_width = png_ptr->width; + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + { + s_start = 0; + s_end = 7; + s_inc = 1; + } + else +#endif + { + s_start = 7; + s_end = 0; + s_inc = -1; + } + + shift = s_start; + + for (i = 0; i < row_width; i++) + { + if (m & mask) + { + int value; + + value = (*sp >> shift) & 0x01; + *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff); + *dp |= (png_byte)(value << shift); + } + + if (shift == s_end) + { + shift = s_start; + sp++; + dp++; + } + else + shift += s_inc; + + if (m == 1) + m = 0x80; + else + m >>= 1; + } + break; + } + case 2: + { + png_bytep sp = png_ptr->row_buf + 1; + png_bytep dp = row; + int s_start, s_end, s_inc; + int m = 0x80; + int shift; + png_uint_32 i; + png_uint_32 row_width = png_ptr->width; + int value; + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + { + s_start = 0; + s_end = 6; + s_inc = 2; + } + else +#endif + { + s_start = 6; + s_end = 0; + s_inc = -2; + } + + shift = s_start; + + for (i = 0; i < row_width; i++) + { + if (m & mask) + { + value = (*sp >> shift) & 0x03; + *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); + *dp |= (png_byte)(value << shift); + } + + if (shift == s_end) + { + shift = s_start; + sp++; + dp++; + } + else + shift += s_inc; + if (m == 1) + m = 0x80; + else + m >>= 1; + } + break; + } + case 4: + { + png_bytep sp = png_ptr->row_buf + 1; + png_bytep dp = row; + int s_start, s_end, s_inc; + int m = 0x80; + int shift; + png_uint_32 i; + png_uint_32 row_width = png_ptr->width; + int value; + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + { + s_start = 0; + s_end = 4; + s_inc = 4; + } + else +#endif + { + s_start = 4; + s_end = 0; + s_inc = -4; + } + shift = s_start; + + for (i = 0; i < row_width; i++) + { + if (m & mask) + { + value = (*sp >> shift) & 0xf; + *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); + *dp |= (png_byte)(value << shift); + } + + if (shift == s_end) + { + shift = s_start; + sp++; + dp++; + } + else + shift += s_inc; + if (m == 1) + m = 0x80; + else + m >>= 1; + } + break; + } + default: + { + png_bytep sp = png_ptr->row_buf + 1; + png_bytep dp = row; + png_size_t pixel_bytes = (png_ptr->row_info.pixel_depth >> 3); + png_uint_32 i; + png_uint_32 row_width = png_ptr->width; + png_byte m = 0x80; + + + for (i = 0; i < row_width; i++) + { + if (m & mask) + { + png_memcpy(dp, sp, pixel_bytes); + } + + sp += pixel_bytes; + dp += pixel_bytes; + + if (m == 1) + m = 0x80; + else + m >>= 1; + } + break; + } + } + } +} +#endif /* !PNG_HAVE_ASSEMBLER_COMBINE_ROW */ + +#ifdef PNG_READ_INTERLACING_SUPPORTED +#ifndef PNG_HAVE_ASSEMBLER_READ_INTERLACE /* else in pngvcrd.c, pnggccrd.c */ +/* OLD pre-1.0.9 interface: +void png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, + png_uint_32 transformations) + */ +void /* PRIVATE */ +png_do_read_interlace(png_structp png_ptr) +{ + png_row_infop row_info = &(png_ptr->row_info); + png_bytep row = png_ptr->row_buf + 1; + int pass = png_ptr->pass; + png_uint_32 transformations = png_ptr->transformations; +#ifdef PNG_USE_LOCAL_ARRAYS + /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + /* offset to next interlace block */ + const int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; +#endif + + png_debug(1,"in png_do_read_interlace (stock C version)\n"); + if (row != NULL && row_info != NULL) + { + png_uint_32 final_width; + + final_width = row_info->width * png_pass_inc[pass]; + + switch (row_info->pixel_depth) + { + case 1: + { + png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 3); + png_bytep dp = row + (png_size_t)((final_width - 1) >> 3); + int sshift, dshift; + int s_start, s_end, s_inc; + int jstop = png_pass_inc[pass]; + png_byte v; + png_uint_32 i; + int j; + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (transformations & PNG_PACKSWAP) + { + sshift = (int)((row_info->width + 7) & 0x07); + dshift = (int)((final_width + 7) & 0x07); + s_start = 7; + s_end = 0; + s_inc = -1; + } + else +#endif + { + sshift = 7 - (int)((row_info->width + 7) & 0x07); + dshift = 7 - (int)((final_width + 7) & 0x07); + s_start = 0; + s_end = 7; + s_inc = 1; + } + + for (i = 0; i < row_info->width; i++) + { + v = (png_byte)((*sp >> sshift) & 0x01); + for (j = 0; j < jstop; j++) + { + *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff); + *dp |= (png_byte)(v << dshift); + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + else + dshift += s_inc; + } + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + else + sshift += s_inc; + } + break; + } + case 2: + { + png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2); + png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2); + int sshift, dshift; + int s_start, s_end, s_inc; + int jstop = png_pass_inc[pass]; + png_uint_32 i; + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (transformations & PNG_PACKSWAP) + { + sshift = (int)(((row_info->width + 3) & 0x03) << 1); + dshift = (int)(((final_width + 3) & 0x03) << 1); + s_start = 6; + s_end = 0; + s_inc = -2; + } + else +#endif + { + sshift = (int)((3 - ((row_info->width + 3) & 0x03)) << 1); + dshift = (int)((3 - ((final_width + 3) & 0x03)) << 1); + s_start = 0; + s_end = 6; + s_inc = 2; + } + + for (i = 0; i < row_info->width; i++) + { + png_byte v; + int j; + + v = (png_byte)((*sp >> sshift) & 0x03); + for (j = 0; j < jstop; j++) + { + *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff); + *dp |= (png_byte)(v << dshift); + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + else + dshift += s_inc; + } + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + else + sshift += s_inc; + } + break; + } + case 4: + { + png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 1); + png_bytep dp = row + (png_size_t)((final_width - 1) >> 1); + int sshift, dshift; + int s_start, s_end, s_inc; + png_uint_32 i; + int jstop = png_pass_inc[pass]; + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (transformations & PNG_PACKSWAP) + { + sshift = (int)(((row_info->width + 1) & 0x01) << 2); + dshift = (int)(((final_width + 1) & 0x01) << 2); + s_start = 4; + s_end = 0; + s_inc = -4; + } + else +#endif + { + sshift = (int)((1 - ((row_info->width + 1) & 0x01)) << 2); + dshift = (int)((1 - ((final_width + 1) & 0x01)) << 2); + s_start = 0; + s_end = 4; + s_inc = 4; + } + + for (i = 0; i < row_info->width; i++) + { + png_byte v = (png_byte)((*sp >> sshift) & 0xf); + int j; + + for (j = 0; j < jstop; j++) + { + *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff); + *dp |= (png_byte)(v << dshift); + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + else + dshift += s_inc; + } + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + else + sshift += s_inc; + } + break; + } + default: + { + png_size_t pixel_bytes = (row_info->pixel_depth >> 3); + png_bytep sp = row + (png_size_t)(row_info->width - 1) * pixel_bytes; + png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes; + + int jstop = png_pass_inc[pass]; + png_uint_32 i; + + for (i = 0; i < row_info->width; i++) + { + png_byte v[8]; + int j; + + png_memcpy(v, sp, pixel_bytes); + for (j = 0; j < jstop; j++) + { + png_memcpy(dp, v, pixel_bytes); + dp -= pixel_bytes; + } + sp -= pixel_bytes; + } + break; + } + } + row_info->width = final_width; + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,final_width); + } +#if !defined(PNG_READ_PACKSWAP_SUPPORTED) + if (&transformations == NULL) /* silence compiler warning */ + return; +#endif +} +#endif /* !PNG_HAVE_ASSEMBLER_READ_INTERLACE */ +#endif /* PNG_READ_INTERLACING_SUPPORTED */ + +#ifndef PNG_HAVE_ASSEMBLER_READ_FILTER_ROW +void /* PRIVATE */ +png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row, + png_bytep prev_row, int filter) +{ + png_debug(1, "in png_read_filter_row\n"); + png_debug2(2,"row = %lu, filter = %d\n", png_ptr->row_number, filter); + switch (filter) + { + case PNG_FILTER_VALUE_NONE: + break; + case PNG_FILTER_VALUE_SUB: + { + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; + png_bytep rp = row + bpp; + png_bytep lp = row; + + for (i = bpp; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff); + rp++; + } + break; + } + case PNG_FILTER_VALUE_UP: + { + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + png_bytep rp = row; + png_bytep pp = prev_row; + + for (i = 0; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff); + rp++; + } + break; + } + case PNG_FILTER_VALUE_AVG: + { + png_uint_32 i; + png_bytep rp = row; + png_bytep pp = prev_row; + png_bytep lp = row; + png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; + png_uint_32 istop = row_info->rowbytes - bpp; + + for (i = 0; i < bpp; i++) + { + *rp = (png_byte)(((int)(*rp) + + ((int)(*pp++) / 2 )) & 0xff); + rp++; + } + + for (i = 0; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + + (int)(*pp++ + *lp++) / 2 ) & 0xff); + rp++; + } + break; + } + case PNG_FILTER_VALUE_PAETH: + { + png_uint_32 i; + png_bytep rp = row; + png_bytep pp = prev_row; + png_bytep lp = row; + png_bytep cp = prev_row; + png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; + png_uint_32 istop=row_info->rowbytes - bpp; + + for (i = 0; i < bpp; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff); + rp++; + } + + for (i = 0; i < istop; i++) /* use leftover rp,pp */ + { + int a, b, c, pa, pb, pc, p; + + a = *lp++; + b = *pp++; + c = *cp++; + + p = b - c; + pc = a - c; + +#ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +#else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +#endif + + /* + if (pa <= pb && pa <= pc) + p = a; + else if (pb <= pc) + p = b; + else + p = c; + */ + + p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; + + *rp = (png_byte)(((int)(*rp) + p) & 0xff); + rp++; + } + break; + } + default: + png_warning(png_ptr, "Ignoring bad adaptive filter type"); + *row=0; + break; + } +} +#endif /* !PNG_HAVE_ASSEMBLER_READ_FILTER_ROW */ + +void /* PRIVATE */ +png_read_finish_row(png_structp png_ptr) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* start of interlace block */ + const int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* offset to next interlace block */ + const int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + /* start of interlace block in the y direction */ + const int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + + /* offset to next interlace block in the y direction */ + const int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; +#endif + + png_debug(1, "in png_read_finish_row\n"); + png_ptr->row_number++; + if (png_ptr->row_number < png_ptr->num_rows) + return; + + if (png_ptr->interlaced) + { + png_ptr->row_number = 0; + png_memset_check(png_ptr, png_ptr->prev_row, 0, png_ptr->rowbytes + 1); + do + { + png_ptr->pass++; + if (png_ptr->pass >= 7) + break; + png_ptr->iwidth = (png_ptr->width + + png_pass_inc[png_ptr->pass] - 1 - + png_pass_start[png_ptr->pass]) / + png_pass_inc[png_ptr->pass]; + + png_ptr->irowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, + png_ptr->iwidth) + 1; + + if (!(png_ptr->transformations & PNG_INTERLACE)) + { + png_ptr->num_rows = (png_ptr->height + + png_pass_yinc[png_ptr->pass] - 1 - + png_pass_ystart[png_ptr->pass]) / + png_pass_yinc[png_ptr->pass]; + if (!(png_ptr->num_rows)) + continue; + } + else /* if (png_ptr->transformations & PNG_INTERLACE) */ + break; + } while (png_ptr->iwidth == 0); + + if (png_ptr->pass < 7) + return; + } + + if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)) + { +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_IDAT; +#endif + char extra; + int ret; + + png_ptr->zstream.next_out = (Byte *)&extra; + png_ptr->zstream.avail_out = (uInt)1; + for(;;) + { + if (!(png_ptr->zstream.avail_in)) + { + while (!png_ptr->idat_size) + { + png_byte chunk_length[4]; + + png_crc_finish(png_ptr, 0); + + png_read_data(png_ptr, chunk_length, 4); + png_ptr->idat_size = png_get_uint_31(png_ptr, chunk_length); + png_reset_crc(png_ptr); + png_crc_read(png_ptr, png_ptr->chunk_name, 4); + if (png_memcmp(png_ptr->chunk_name, (png_bytep)png_IDAT, 4)) + png_error(png_ptr, "Not enough image data"); + + } + png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size; + png_ptr->zstream.next_in = png_ptr->zbuf; + if (png_ptr->zbuf_size > png_ptr->idat_size) + png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size; + png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream.avail_in); + png_ptr->idat_size -= png_ptr->zstream.avail_in; + } + ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); + if (ret == Z_STREAM_END) + { + if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in || + png_ptr->idat_size) + png_warning(png_ptr, "Extra compressed data"); + png_ptr->mode |= PNG_AFTER_IDAT; + png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; + break; + } + if (ret != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg : + "Decompression Error"); + + if (!(png_ptr->zstream.avail_out)) + { + png_warning(png_ptr, "Extra compressed data."); + png_ptr->mode |= PNG_AFTER_IDAT; + png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; + break; + } + + } + png_ptr->zstream.avail_out = 0; + } + + if (png_ptr->idat_size || png_ptr->zstream.avail_in) + png_warning(png_ptr, "Extra compression data"); + + inflateReset(&png_ptr->zstream); + + png_ptr->mode |= PNG_AFTER_IDAT; +} + +void /* PRIVATE */ +png_read_start_row(png_structp png_ptr) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* start of interlace block */ + const int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* offset to next interlace block */ + const int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + /* start of interlace block in the y direction */ + const int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + + /* offset to next interlace block in the y direction */ + const int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; +#endif + + int max_pixel_depth; + png_uint_32 row_bytes; + + png_debug(1, "in png_read_start_row\n"); + png_ptr->zstream.avail_in = 0; + png_init_read_transformations(png_ptr); + if (png_ptr->interlaced) + { + if (!(png_ptr->transformations & PNG_INTERLACE)) + png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - + png_pass_ystart[0]) / png_pass_yinc[0]; + else + png_ptr->num_rows = png_ptr->height; + + png_ptr->iwidth = (png_ptr->width + + png_pass_inc[png_ptr->pass] - 1 - + png_pass_start[png_ptr->pass]) / + png_pass_inc[png_ptr->pass]; + + row_bytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->iwidth) + 1; + + png_ptr->irowbytes = (png_size_t)row_bytes; + if((png_uint_32)png_ptr->irowbytes != row_bytes) + png_error(png_ptr, "Rowbytes overflow in png_read_start_row"); + } + else + { + png_ptr->num_rows = png_ptr->height; + png_ptr->iwidth = png_ptr->width; + png_ptr->irowbytes = png_ptr->rowbytes + 1; + } + max_pixel_depth = png_ptr->pixel_depth; + +#if defined(PNG_READ_PACK_SUPPORTED) + if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8) + max_pixel_depth = 8; +#endif + +#if defined(PNG_READ_EXPAND_SUPPORTED) + if (png_ptr->transformations & PNG_EXPAND) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (png_ptr->num_trans) + max_pixel_depth = 32; + else + max_pixel_depth = 24; + } + else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) + { + if (max_pixel_depth < 8) + max_pixel_depth = 8; + if (png_ptr->num_trans) + max_pixel_depth *= 2; + } + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) + { + if (png_ptr->num_trans) + { + max_pixel_depth *= 4; + max_pixel_depth /= 3; + } + } + } +#endif + +#if defined(PNG_READ_FILLER_SUPPORTED) + if (png_ptr->transformations & (PNG_FILLER)) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + max_pixel_depth = 32; + else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) + { + if (max_pixel_depth <= 8) + max_pixel_depth = 16; + else + max_pixel_depth = 32; + } + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) + { + if (max_pixel_depth <= 32) + max_pixel_depth = 32; + else + max_pixel_depth = 64; + } + } +#endif + +#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) + if (png_ptr->transformations & PNG_GRAY_TO_RGB) + { + if ( +#if defined(PNG_READ_EXPAND_SUPPORTED) + (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) || +#endif +#if defined(PNG_READ_FILLER_SUPPORTED) + (png_ptr->transformations & (PNG_FILLER)) || +#endif + png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + if (max_pixel_depth <= 16) + max_pixel_depth = 32; + else + max_pixel_depth = 64; + } + else + { + if (max_pixel_depth <= 8) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + max_pixel_depth = 32; + else + max_pixel_depth = 24; + } + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + max_pixel_depth = 64; + else + max_pixel_depth = 48; + } + } +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \ +defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) + if(png_ptr->transformations & PNG_USER_TRANSFORM) + { + int user_pixel_depth=png_ptr->user_transform_depth* + png_ptr->user_transform_channels; + if(user_pixel_depth > max_pixel_depth) + max_pixel_depth=user_pixel_depth; + } +#endif + + /* align the width on the next larger 8 pixels. Mainly used + for interlacing */ + row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7)); + /* calculate the maximum bytes needed, adding a byte and a pixel + for safety's sake */ + row_bytes = PNG_ROWBYTES(max_pixel_depth,row_bytes) + + 1 + ((max_pixel_depth + 7) >> 3); +#ifdef PNG_MAX_MALLOC_64K + if (row_bytes > (png_uint_32)65536L) + png_error(png_ptr, "This image requires a row greater than 64KB"); +#endif + png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, row_bytes+64); + png_ptr->row_buf = png_ptr->big_row_buf+32; +#if defined(PNG_DEBUG) && defined(PNG_USE_PNGGCCRD) + png_ptr->row_buf_size = row_bytes; +#endif + +#ifdef PNG_MAX_MALLOC_64K + if ((png_uint_32)png_ptr->rowbytes + 1 > (png_uint_32)65536L) + png_error(png_ptr, "This image requires a row greater than 64KB"); +#endif + if ((png_uint_32)png_ptr->rowbytes > PNG_SIZE_MAX - 1) + png_error(png_ptr, "Row has too many bytes to allocate in memory."); + png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)( + png_ptr->rowbytes + 1)); + + png_memset_check(png_ptr, png_ptr->prev_row, 0, png_ptr->rowbytes + 1); + + png_debug1(3, "width = %lu,\n", png_ptr->width); + png_debug1(3, "height = %lu,\n", png_ptr->height); + png_debug1(3, "iwidth = %lu,\n", png_ptr->iwidth); + png_debug1(3, "num_rows = %lu\n", png_ptr->num_rows); + png_debug1(3, "rowbytes = %lu,\n", png_ptr->rowbytes); + png_debug1(3, "irowbytes = %lu,\n", png_ptr->irowbytes); + + png_ptr->flags |= PNG_FLAG_ROW_INIT; +} diff --git a/syslinux/com32/lib/libpng/pngset.c b/syslinux/com32/lib/libpng/pngset.c new file mode 100644 index 0000000..5922cad --- /dev/null +++ b/syslinux/com32/lib/libpng/pngset.c @@ -0,0 +1,1219 @@ + +/* pngset.c - storage of image information into info struct + * + * libpng 1.2.8 - December 3, 2004 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2004 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * The functions here are used during reads to store data from the file + * into the info struct, and during writes to store application data + * into the info struct for writing into the file. This abstracts the + * info struct and allows us to change the structure in the future. + */ + +#define PNG_INTERNAL +#include "png.h" + +#if defined(PNG_bKGD_SUPPORTED) +void PNGAPI +png_set_bKGD(png_structp png_ptr, png_infop info_ptr, png_color_16p background) +{ + png_debug1(1, "in %s storage function\n", "bKGD"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + png_memcpy(&(info_ptr->background), background, png_sizeof(png_color_16)); + info_ptr->valid |= PNG_INFO_bKGD; +} +#endif + +#if defined(PNG_cHRM_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_cHRM(png_structp png_ptr, png_infop info_ptr, + double white_x, double white_y, double red_x, double red_y, + double green_x, double green_y, double blue_x, double blue_y) +{ + png_debug1(1, "in %s storage function\n", "cHRM"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + if (white_x < 0.0 || white_y < 0.0 || + red_x < 0.0 || red_y < 0.0 || + green_x < 0.0 || green_y < 0.0 || + blue_x < 0.0 || blue_y < 0.0) + { + png_warning(png_ptr, + "Ignoring attempt to set negative chromaticity value"); + return; + } + if (white_x > 21474.83 || white_y > 21474.83 || + red_x > 21474.83 || red_y > 21474.83 || + green_x > 21474.83 || green_y > 21474.83 || + blue_x > 21474.83 || blue_y > 21474.83) + { + png_warning(png_ptr, + "Ignoring attempt to set chromaticity value exceeding 21474.83"); + return; + } + + info_ptr->x_white = (float)white_x; + info_ptr->y_white = (float)white_y; + info_ptr->x_red = (float)red_x; + info_ptr->y_red = (float)red_y; + info_ptr->x_green = (float)green_x; + info_ptr->y_green = (float)green_y; + info_ptr->x_blue = (float)blue_x; + info_ptr->y_blue = (float)blue_y; +#ifdef PNG_FIXED_POINT_SUPPORTED + info_ptr->int_x_white = (png_fixed_point)(white_x*100000.+0.5); + info_ptr->int_y_white = (png_fixed_point)(white_y*100000.+0.5); + info_ptr->int_x_red = (png_fixed_point)( red_x*100000.+0.5); + info_ptr->int_y_red = (png_fixed_point)( red_y*100000.+0.5); + info_ptr->int_x_green = (png_fixed_point)(green_x*100000.+0.5); + info_ptr->int_y_green = (png_fixed_point)(green_y*100000.+0.5); + info_ptr->int_x_blue = (png_fixed_point)( blue_x*100000.+0.5); + info_ptr->int_y_blue = (png_fixed_point)( blue_y*100000.+0.5); +#endif + info_ptr->valid |= PNG_INFO_cHRM; +} +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +void PNGAPI +png_set_cHRM_fixed(png_structp png_ptr, png_infop info_ptr, + png_fixed_point white_x, png_fixed_point white_y, png_fixed_point red_x, + png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y, + png_fixed_point blue_x, png_fixed_point blue_y) +{ + png_debug1(1, "in %s storage function\n", "cHRM"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + if (white_x < 0 || white_y < 0 || + red_x < 0 || red_y < 0 || + green_x < 0 || green_y < 0 || + blue_x < 0 || blue_y < 0) + { + png_warning(png_ptr, + "Ignoring attempt to set negative chromaticity value"); + return; + } + if (white_x > (double) PNG_UINT_31_MAX || + white_y > (double) PNG_UINT_31_MAX || + red_x > (double) PNG_UINT_31_MAX || + red_y > (double) PNG_UINT_31_MAX || + green_x > (double) PNG_UINT_31_MAX || + green_y > (double) PNG_UINT_31_MAX || + blue_x > (double) PNG_UINT_31_MAX || + blue_y > (double) PNG_UINT_31_MAX) + { + png_warning(png_ptr, + "Ignoring attempt to set chromaticity value exceeding 21474.83"); + return; + } + info_ptr->int_x_white = white_x; + info_ptr->int_y_white = white_y; + info_ptr->int_x_red = red_x; + info_ptr->int_y_red = red_y; + info_ptr->int_x_green = green_x; + info_ptr->int_y_green = green_y; + info_ptr->int_x_blue = blue_x; + info_ptr->int_y_blue = blue_y; +#ifdef PNG_FLOATING_POINT_SUPPORTED + info_ptr->x_white = (float)(white_x/100000.); + info_ptr->y_white = (float)(white_y/100000.); + info_ptr->x_red = (float)( red_x/100000.); + info_ptr->y_red = (float)( red_y/100000.); + info_ptr->x_green = (float)(green_x/100000.); + info_ptr->y_green = (float)(green_y/100000.); + info_ptr->x_blue = (float)( blue_x/100000.); + info_ptr->y_blue = (float)( blue_y/100000.); +#endif + info_ptr->valid |= PNG_INFO_cHRM; +} +#endif +#endif + +#if defined(PNG_gAMA_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_gAMA(png_structp png_ptr, png_infop info_ptr, double file_gamma) +{ + double gamma; + png_debug1(1, "in %s storage function\n", "gAMA"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + /* Check for overflow */ + if (file_gamma > 21474.83) + { + png_warning(png_ptr, "Limiting gamma to 21474.83"); + gamma=21474.83; + } + else + gamma=file_gamma; + info_ptr->gamma = (float)gamma; +#ifdef PNG_FIXED_POINT_SUPPORTED + info_ptr->int_gamma = (int)(gamma*100000.+.5); +#endif + info_ptr->valid |= PNG_INFO_gAMA; + if(gamma == 0.0) + png_warning(png_ptr, "Setting gamma=0"); +} +#endif +void PNGAPI +png_set_gAMA_fixed(png_structp png_ptr, png_infop info_ptr, png_fixed_point + int_gamma) +{ + png_fixed_point gamma; + + png_debug1(1, "in %s storage function\n", "gAMA"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + if (int_gamma > (png_fixed_point) PNG_UINT_31_MAX) + { + png_warning(png_ptr, "Limiting gamma to 21474.83"); + gamma=PNG_UINT_31_MAX; + } + else + { + if (int_gamma < 0) + { + png_warning(png_ptr, "Setting negative gamma to zero"); + gamma=0; + } + else + gamma=int_gamma; + } +#ifdef PNG_FLOATING_POINT_SUPPORTED + info_ptr->gamma = (float)(gamma/100000.); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + info_ptr->int_gamma = gamma; +#endif + info_ptr->valid |= PNG_INFO_gAMA; + if(gamma == 0) + png_warning(png_ptr, "Setting gamma=0"); +} +#endif + +#if defined(PNG_hIST_SUPPORTED) +void PNGAPI +png_set_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_16p hist) +{ + int i; + + png_debug1(1, "in %s storage function\n", "hIST"); + if (png_ptr == NULL || info_ptr == NULL) + return; + if (info_ptr->num_palette == 0) + { + png_warning(png_ptr, + "Palette size 0, hIST allocation skipped."); + return; + } + +#ifdef PNG_FREE_ME_SUPPORTED + png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, 0); +#endif + /* Changed from info->num_palette to 256 in version 1.2.1 */ + png_ptr->hist = (png_uint_16p)png_malloc_warn(png_ptr, + (png_uint_32)(256 * png_sizeof (png_uint_16))); + if (png_ptr->hist == NULL) + { + png_warning(png_ptr, "Insufficient memory for hIST chunk data."); + return; + } + + for (i = 0; i < info_ptr->num_palette; i++) + png_ptr->hist[i] = hist[i]; + info_ptr->hist = png_ptr->hist; + info_ptr->valid |= PNG_INFO_hIST; + +#ifdef PNG_FREE_ME_SUPPORTED + info_ptr->free_me |= PNG_FREE_HIST; +#else + png_ptr->flags |= PNG_FLAG_FREE_HIST; +#endif +} +#endif + +void PNGAPI +png_set_IHDR(png_structp png_ptr, png_infop info_ptr, + png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_type, int compression_type, + int filter_type) +{ + png_debug1(1, "in %s storage function\n", "IHDR"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + /* check for width and height valid values */ + if (width == 0 || height == 0) + png_error(png_ptr, "Image width or height is zero in IHDR"); +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + if (width > png_ptr->user_width_max || height > png_ptr->user_height_max) + png_error(png_ptr, "image size exceeds user limits in IHDR"); +#else + if (width > PNG_USER_WIDTH_MAX || height > PNG_USER_HEIGHT_MAX) + png_error(png_ptr, "image size exceeds user limits in IHDR"); +#endif + if (width > PNG_UINT_31_MAX || height > PNG_UINT_31_MAX) + png_error(png_ptr, "Invalid image size in IHDR"); + if ( width > (PNG_UINT_32_MAX + >> 3) /* 8-byte RGBA pixels */ + - 64 /* bigrowbuf hack */ + - 1 /* filter byte */ + - 7*8 /* rounding of width to multiple of 8 pixels */ + - 8) /* extra max_pixel_depth pad */ + png_warning(png_ptr, "Width is too large for libpng to process pixels"); + + /* check other values */ + if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 && + bit_depth != 8 && bit_depth != 16) + png_error(png_ptr, "Invalid bit depth in IHDR"); + + if (color_type < 0 || color_type == 1 || + color_type == 5 || color_type > 6) + png_error(png_ptr, "Invalid color type in IHDR"); + + if (((color_type == PNG_COLOR_TYPE_PALETTE) && bit_depth > 8) || + ((color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8)) + png_error(png_ptr, "Invalid color type/bit depth combination in IHDR"); + + if (interlace_type >= PNG_INTERLACE_LAST) + png_error(png_ptr, "Unknown interlace method in IHDR"); + + if (compression_type != PNG_COMPRESSION_TYPE_BASE) + png_error(png_ptr, "Unknown compression method in IHDR"); + +#if defined(PNG_MNG_FEATURES_SUPPORTED) + /* Accept filter_method 64 (intrapixel differencing) only if + * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and + * 2. Libpng did not read a PNG signature (this filter_method is only + * used in PNG datastreams that are embedded in MNG datastreams) and + * 3. The application called png_permit_mng_features with a mask that + * included PNG_FLAG_MNG_FILTER_64 and + * 4. The filter_method is 64 and + * 5. The color_type is RGB or RGBA + */ + if((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE)&&png_ptr->mng_features_permitted) + png_warning(png_ptr,"MNG features are not allowed in a PNG datastream\n"); + if(filter_type != PNG_FILTER_TYPE_BASE) + { + if(!((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && + (filter_type == PNG_INTRAPIXEL_DIFFERENCING) && + ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) && + (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA))) + png_error(png_ptr, "Unknown filter method in IHDR"); + if(png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) + png_warning(png_ptr, "Invalid filter method in IHDR"); + } +#else + if(filter_type != PNG_FILTER_TYPE_BASE) + png_error(png_ptr, "Unknown filter method in IHDR"); +#endif + + info_ptr->width = width; + info_ptr->height = height; + info_ptr->bit_depth = (png_byte)bit_depth; + info_ptr->color_type =(png_byte) color_type; + info_ptr->compression_type = (png_byte)compression_type; + info_ptr->filter_type = (png_byte)filter_type; + info_ptr->interlace_type = (png_byte)interlace_type; + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + info_ptr->channels = 1; + else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) + info_ptr->channels = 3; + else + info_ptr->channels = 1; + if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) + info_ptr->channels++; + info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth); + + /* check for potential overflow */ + if ( width > (PNG_UINT_32_MAX + >> 3) /* 8-byte RGBA pixels */ + - 64 /* bigrowbuf hack */ + - 1 /* filter byte */ + - 7*8 /* rounding of width to multiple of 8 pixels */ + - 8) /* extra max_pixel_depth pad */ + info_ptr->rowbytes = (png_size_t)0; + else + info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth,width); +} + +#if defined(PNG_oFFs_SUPPORTED) +void PNGAPI +png_set_oFFs(png_structp png_ptr, png_infop info_ptr, + png_int_32 offset_x, png_int_32 offset_y, int unit_type) +{ + png_debug1(1, "in %s storage function\n", "oFFs"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->x_offset = offset_x; + info_ptr->y_offset = offset_y; + info_ptr->offset_unit_type = (png_byte)unit_type; + info_ptr->valid |= PNG_INFO_oFFs; +} +#endif + +#if defined(PNG_pCAL_SUPPORTED) +void PNGAPI +png_set_pCAL(png_structp png_ptr, png_infop info_ptr, + png_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams, + png_charp units, png_charpp params) +{ + png_uint_32 length; + int i; + + png_debug1(1, "in %s storage function\n", "pCAL"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + length = png_strlen(purpose) + 1; + png_debug1(3, "allocating purpose for info (%lu bytes)\n", length); + info_ptr->pcal_purpose = (png_charp)png_malloc_warn(png_ptr, length); + if (info_ptr->pcal_purpose == NULL) + { + png_warning(png_ptr, "Insufficient memory for pCAL purpose."); + return; + } + png_memcpy(info_ptr->pcal_purpose, purpose, (png_size_t)length); + + png_debug(3, "storing X0, X1, type, and nparams in info\n"); + info_ptr->pcal_X0 = X0; + info_ptr->pcal_X1 = X1; + info_ptr->pcal_type = (png_byte)type; + info_ptr->pcal_nparams = (png_byte)nparams; + + length = png_strlen(units) + 1; + png_debug1(3, "allocating units for info (%lu bytes)\n", length); + info_ptr->pcal_units = (png_charp)png_malloc_warn(png_ptr, length); + if (info_ptr->pcal_units == NULL) + { + png_warning(png_ptr, "Insufficient memory for pCAL units."); + return; + } + png_memcpy(info_ptr->pcal_units, units, (png_size_t)length); + + info_ptr->pcal_params = (png_charpp)png_malloc_warn(png_ptr, + (png_uint_32)((nparams + 1) * png_sizeof(png_charp))); + if (info_ptr->pcal_params == NULL) + { + png_warning(png_ptr, "Insufficient memory for pCAL params."); + return; + } + + info_ptr->pcal_params[nparams] = NULL; + + for (i = 0; i < nparams; i++) + { + length = png_strlen(params[i]) + 1; + png_debug2(3, "allocating parameter %d for info (%lu bytes)\n", i, length); + info_ptr->pcal_params[i] = (png_charp)png_malloc_warn(png_ptr, length); + if (info_ptr->pcal_params[i] == NULL) + { + png_warning(png_ptr, "Insufficient memory for pCAL parameter."); + return; + } + png_memcpy(info_ptr->pcal_params[i], params[i], (png_size_t)length); + } + + info_ptr->valid |= PNG_INFO_pCAL; +#ifdef PNG_FREE_ME_SUPPORTED + info_ptr->free_me |= PNG_FREE_PCAL; +#endif +} +#endif + +#if defined(PNG_READ_sCAL_SUPPORTED) || defined(PNG_WRITE_sCAL_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_sCAL(png_structp png_ptr, png_infop info_ptr, + int unit, double width, double height) +{ + png_debug1(1, "in %s storage function\n", "sCAL"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->scal_unit = (png_byte)unit; + info_ptr->scal_pixel_width = width; + info_ptr->scal_pixel_height = height; + + info_ptr->valid |= PNG_INFO_sCAL; +} +#else +#ifdef PNG_FIXED_POINT_SUPPORTED +void PNGAPI +png_set_sCAL_s(png_structp png_ptr, png_infop info_ptr, + int unit, png_charp swidth, png_charp sheight) +{ + png_uint_32 length; + + png_debug1(1, "in %s storage function\n", "sCAL"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->scal_unit = (png_byte)unit; + + length = png_strlen(swidth) + 1; + png_debug1(3, "allocating unit for info (%d bytes)\n", length); + info_ptr->scal_s_width = (png_charp)png_malloc_warn(png_ptr, length); + if (info_ptr->scal_s_width == NULL) + { + png_warning(png_ptr, "Memory allocation failed while processing sCAL."); + } + png_memcpy(info_ptr->scal_s_width, swidth, (png_size_t)length); + + length = png_strlen(sheight) + 1; + png_debug1(3, "allocating unit for info (%d bytes)\n", length); + info_ptr->scal_s_height = (png_charp)png_malloc_warn(png_ptr, length); + if (info_ptr->scal_s_height == NULL) + { + png_free (png_ptr, info_ptr->scal_s_width); + png_warning(png_ptr, "Memory allocation failed while processing sCAL."); + } + png_memcpy(info_ptr->scal_s_height, sheight, (png_size_t)length); + + info_ptr->valid |= PNG_INFO_sCAL; +#ifdef PNG_FREE_ME_SUPPORTED + info_ptr->free_me |= PNG_FREE_SCAL; +#endif +} +#endif +#endif +#endif + +#if defined(PNG_pHYs_SUPPORTED) +void PNGAPI +png_set_pHYs(png_structp png_ptr, png_infop info_ptr, + png_uint_32 res_x, png_uint_32 res_y, int unit_type) +{ + png_debug1(1, "in %s storage function\n", "pHYs"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->x_pixels_per_unit = res_x; + info_ptr->y_pixels_per_unit = res_y; + info_ptr->phys_unit_type = (png_byte)unit_type; + info_ptr->valid |= PNG_INFO_pHYs; +} +#endif + +void PNGAPI +png_set_PLTE(png_structp png_ptr, png_infop info_ptr, + png_colorp palette, int num_palette) +{ + + png_debug1(1, "in %s storage function\n", "PLTE"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + /* + * It may not actually be necessary to set png_ptr->palette here; + * we do it for backward compatibility with the way the png_handle_tRNS + * function used to do the allocation. + */ +#ifdef PNG_FREE_ME_SUPPORTED + png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0); +#endif + + /* Changed in libpng-1.2.1 to allocate 256 instead of num_palette entries, + in case of an invalid PNG file that has too-large sample values. */ + png_ptr->palette = (png_colorp)png_malloc(png_ptr, + 256 * png_sizeof(png_color)); + png_memset(png_ptr->palette, 0, 256 * png_sizeof(png_color)); + png_memcpy(png_ptr->palette, palette, num_palette * png_sizeof (png_color)); + info_ptr->palette = png_ptr->palette; + info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette; + +#ifdef PNG_FREE_ME_SUPPORTED + info_ptr->free_me |= PNG_FREE_PLTE; +#else + png_ptr->flags |= PNG_FLAG_FREE_PLTE; +#endif + + info_ptr->valid |= PNG_INFO_PLTE; +} + +#if defined(PNG_sBIT_SUPPORTED) +void PNGAPI +png_set_sBIT(png_structp png_ptr, png_infop info_ptr, + png_color_8p sig_bit) +{ + png_debug1(1, "in %s storage function\n", "sBIT"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + png_memcpy(&(info_ptr->sig_bit), sig_bit, png_sizeof (png_color_8)); + info_ptr->valid |= PNG_INFO_sBIT; +} +#endif + +#if defined(PNG_sRGB_SUPPORTED) +void PNGAPI +png_set_sRGB(png_structp png_ptr, png_infop info_ptr, int intent) +{ + png_debug1(1, "in %s storage function\n", "sRGB"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->srgb_intent = (png_byte)intent; + info_ptr->valid |= PNG_INFO_sRGB; +} + +void PNGAPI +png_set_sRGB_gAMA_and_cHRM(png_structp png_ptr, png_infop info_ptr, + int intent) +{ +#if defined(PNG_gAMA_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED + float file_gamma; +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + png_fixed_point int_file_gamma; +#endif +#endif +#if defined(PNG_cHRM_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED + float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y; +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + png_fixed_point int_white_x, int_white_y, int_red_x, int_red_y, int_green_x, + int_green_y, int_blue_x, int_blue_y; +#endif +#endif + png_debug1(1, "in %s storage function\n", "sRGB_gAMA_and_cHRM"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + png_set_sRGB(png_ptr, info_ptr, intent); + +#if defined(PNG_gAMA_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED + file_gamma = (float).45455; + png_set_gAMA(png_ptr, info_ptr, file_gamma); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + int_file_gamma = 45455L; + png_set_gAMA_fixed(png_ptr, info_ptr, int_file_gamma); +#endif +#endif + +#if defined(PNG_cHRM_SUPPORTED) +#ifdef PNG_FIXED_POINT_SUPPORTED + int_white_x = 31270L; + int_white_y = 32900L; + int_red_x = 64000L; + int_red_y = 33000L; + int_green_x = 30000L; + int_green_y = 60000L; + int_blue_x = 15000L; + int_blue_y = 6000L; + + png_set_cHRM_fixed(png_ptr, info_ptr, + int_white_x, int_white_y, int_red_x, int_red_y, int_green_x, int_green_y, + int_blue_x, int_blue_y); +#endif +#ifdef PNG_FLOATING_POINT_SUPPORTED + white_x = (float).3127; + white_y = (float).3290; + red_x = (float).64; + red_y = (float).33; + green_x = (float).30; + green_y = (float).60; + blue_x = (float).15; + blue_y = (float).06; + + png_set_cHRM(png_ptr, info_ptr, + white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y); +#endif +#endif +} +#endif + + +#if defined(PNG_iCCP_SUPPORTED) +void PNGAPI +png_set_iCCP(png_structp png_ptr, png_infop info_ptr, + png_charp name, int compression_type, + png_charp profile, png_uint_32 proflen) +{ + png_charp new_iccp_name; + png_charp new_iccp_profile; + + png_debug1(1, "in %s storage function\n", "iCCP"); + if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL) + return; + + new_iccp_name = (png_charp)png_malloc_warn(png_ptr, png_strlen(name)+1); + if (new_iccp_name == NULL) + { + png_warning(png_ptr, "Insufficient memory to process iCCP chunk."); + return; + } + png_strcpy(new_iccp_name, name); + new_iccp_profile = (png_charp)png_malloc_warn(png_ptr, proflen); + if (new_iccp_profile == NULL) + { + png_free (png_ptr, new_iccp_name); + png_warning(png_ptr, "Insufficient memory to process iCCP profile."); + return; + } + png_memcpy(new_iccp_profile, profile, (png_size_t)proflen); + + png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0); + + info_ptr->iccp_proflen = proflen; + info_ptr->iccp_name = new_iccp_name; + info_ptr->iccp_profile = new_iccp_profile; + /* Compression is always zero but is here so the API and info structure + * does not have to change if we introduce multiple compression types */ + info_ptr->iccp_compression = (png_byte)compression_type; +#ifdef PNG_FREE_ME_SUPPORTED + info_ptr->free_me |= PNG_FREE_ICCP; +#endif + info_ptr->valid |= PNG_INFO_iCCP; +} +#endif + +#if defined(PNG_TEXT_SUPPORTED) +void PNGAPI +png_set_text(png_structp png_ptr, png_infop info_ptr, png_textp text_ptr, + int num_text) +{ + int ret; + ret=png_set_text_2(png_ptr, info_ptr, text_ptr, num_text); + if (ret) + png_error(png_ptr, "Insufficient memory to store text"); +} + +int /* PRIVATE */ +png_set_text_2(png_structp png_ptr, png_infop info_ptr, png_textp text_ptr, + int num_text) +{ + int i; + + png_debug1(1, "in %s storage function\n", (png_ptr->chunk_name[0] == '\0' ? + "text" : (png_const_charp)png_ptr->chunk_name)); + + if (png_ptr == NULL || info_ptr == NULL || num_text == 0) + return(0); + + /* Make sure we have enough space in the "text" array in info_struct + * to hold all of the incoming text_ptr objects. + */ + if (info_ptr->num_text + num_text > info_ptr->max_text) + { + if (info_ptr->text != NULL) + { + png_textp old_text; + int old_max; + + old_max = info_ptr->max_text; + info_ptr->max_text = info_ptr->num_text + num_text + 8; + old_text = info_ptr->text; + info_ptr->text = (png_textp)png_malloc_warn(png_ptr, + (png_uint_32)(info_ptr->max_text * png_sizeof (png_text))); + if (info_ptr->text == NULL) + { + png_free(png_ptr, old_text); + return(1); + } + png_memcpy(info_ptr->text, old_text, (png_size_t)(old_max * + png_sizeof(png_text))); + png_free(png_ptr, old_text); + } + else + { + info_ptr->max_text = num_text + 8; + info_ptr->num_text = 0; + info_ptr->text = (png_textp)png_malloc_warn(png_ptr, + (png_uint_32)(info_ptr->max_text * png_sizeof (png_text))); + if (info_ptr->text == NULL) + return(1); +#ifdef PNG_FREE_ME_SUPPORTED + info_ptr->free_me |= PNG_FREE_TEXT; +#endif + } + png_debug1(3, "allocated %d entries for info_ptr->text\n", + info_ptr->max_text); + } + for (i = 0; i < num_text; i++) + { + png_size_t text_length,key_len; + png_size_t lang_len,lang_key_len; + png_textp textp = &(info_ptr->text[info_ptr->num_text]); + + if (text_ptr[i].key == NULL) + continue; + + key_len = png_strlen(text_ptr[i].key); + + if(text_ptr[i].compression <= 0) + { + lang_len = 0; + lang_key_len = 0; + } + else +#ifdef PNG_iTXt_SUPPORTED + { + /* set iTXt data */ + if (text_ptr[i].lang != NULL) + lang_len = png_strlen(text_ptr[i].lang); + else + lang_len = 0; + if (text_ptr[i].lang_key != NULL) + lang_key_len = png_strlen(text_ptr[i].lang_key); + else + lang_key_len = 0; + } +#else + { + png_warning(png_ptr, "iTXt chunk not supported."); + continue; + } +#endif + + if (text_ptr[i].text == NULL || text_ptr[i].text[0] == '\0') + { + text_length = 0; +#ifdef PNG_iTXt_SUPPORTED + if(text_ptr[i].compression > 0) + textp->compression = PNG_ITXT_COMPRESSION_NONE; + else +#endif + textp->compression = PNG_TEXT_COMPRESSION_NONE; + } + else + { + text_length = png_strlen(text_ptr[i].text); + textp->compression = text_ptr[i].compression; + } + + textp->key = (png_charp)png_malloc_warn(png_ptr, + (png_uint_32)(key_len + text_length + lang_len + lang_key_len + 4)); + if (textp->key == NULL) + return(1); + png_debug2(2, "Allocated %lu bytes at %x in png_set_text\n", + (png_uint_32)(key_len + lang_len + lang_key_len + text_length + 4), + (int)textp->key); + + png_memcpy(textp->key, text_ptr[i].key, + (png_size_t)(key_len)); + *(textp->key+key_len) = '\0'; +#ifdef PNG_iTXt_SUPPORTED + if (text_ptr[i].compression > 0) + { + textp->lang=textp->key + key_len + 1; + png_memcpy(textp->lang, text_ptr[i].lang, lang_len); + *(textp->lang+lang_len) = '\0'; + textp->lang_key=textp->lang + lang_len + 1; + png_memcpy(textp->lang_key, text_ptr[i].lang_key, lang_key_len); + *(textp->lang_key+lang_key_len) = '\0'; + textp->text=textp->lang_key + lang_key_len + 1; + } + else +#endif + { +#ifdef PNG_iTXt_SUPPORTED + textp->lang=NULL; + textp->lang_key=NULL; +#endif + textp->text=textp->key + key_len + 1; + } + if(text_length) + png_memcpy(textp->text, text_ptr[i].text, + (png_size_t)(text_length)); + *(textp->text+text_length) = '\0'; + +#ifdef PNG_iTXt_SUPPORTED + if(textp->compression > 0) + { + textp->text_length = 0; + textp->itxt_length = text_length; + } + else +#endif + { + textp->text_length = text_length; +#ifdef PNG_iTXt_SUPPORTED + textp->itxt_length = 0; +#endif + } + info_ptr->text[info_ptr->num_text]= *textp; + info_ptr->num_text++; + png_debug1(3, "transferred text chunk %d\n", info_ptr->num_text); + } + return(0); +} +#endif + +#if defined(PNG_tIME_SUPPORTED) +void PNGAPI +png_set_tIME(png_structp png_ptr, png_infop info_ptr, png_timep mod_time) +{ + png_debug1(1, "in %s storage function\n", "tIME"); + if (png_ptr == NULL || info_ptr == NULL || + (png_ptr->mode & PNG_WROTE_tIME)) + return; + + png_memcpy(&(info_ptr->mod_time), mod_time, png_sizeof (png_time)); + info_ptr->valid |= PNG_INFO_tIME; +} +#endif + +#if defined(PNG_tRNS_SUPPORTED) +void PNGAPI +png_set_tRNS(png_structp png_ptr, png_infop info_ptr, + png_bytep trans, int num_trans, png_color_16p trans_values) +{ + png_debug1(1, "in %s storage function\n", "tRNS"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + if (trans != NULL) + { + /* + * It may not actually be necessary to set png_ptr->trans here; + * we do it for backward compatibility with the way the png_handle_tRNS + * function used to do the allocation. + */ +#ifdef PNG_FREE_ME_SUPPORTED + png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0); +#endif + /* Changed from num_trans to 256 in version 1.2.1 */ + png_ptr->trans = info_ptr->trans = (png_bytep)png_malloc(png_ptr, + (png_uint_32)256); + png_memcpy(info_ptr->trans, trans, (png_size_t)num_trans); +#ifdef PNG_FREE_ME_SUPPORTED + info_ptr->free_me |= PNG_FREE_TRNS; +#else + png_ptr->flags |= PNG_FLAG_FREE_TRNS; +#endif + } + + if (trans_values != NULL) + { + png_memcpy(&(info_ptr->trans_values), trans_values, + png_sizeof(png_color_16)); + if (num_trans == 0) + num_trans = 1; + } + info_ptr->num_trans = (png_uint_16)num_trans; + info_ptr->valid |= PNG_INFO_tRNS; +} +#endif + +#if defined(PNG_sPLT_SUPPORTED) +void PNGAPI +png_set_sPLT(png_structp png_ptr, + png_infop info_ptr, png_sPLT_tp entries, int nentries) +{ + png_sPLT_tp np; + int i; + + np = (png_sPLT_tp)png_malloc_warn(png_ptr, + (info_ptr->splt_palettes_num + nentries) * png_sizeof(png_sPLT_t)); + if (np == NULL) + { + png_warning(png_ptr, "No memory for sPLT palettes."); + return; + } + + png_memcpy(np, info_ptr->splt_palettes, + info_ptr->splt_palettes_num * png_sizeof(png_sPLT_t)); + png_free(png_ptr, info_ptr->splt_palettes); + info_ptr->splt_palettes=NULL; + + for (i = 0; i < nentries; i++) + { + png_sPLT_tp to = np + info_ptr->splt_palettes_num + i; + png_sPLT_tp from = entries + i; + + to->name = (png_charp)png_malloc(png_ptr, + png_strlen(from->name) + 1); + /* TODO: use png_malloc_warn */ + png_strcpy(to->name, from->name); + to->entries = (png_sPLT_entryp)png_malloc(png_ptr, + from->nentries * png_sizeof(png_sPLT_t)); + /* TODO: use png_malloc_warn */ + png_memcpy(to->entries, from->entries, + from->nentries * png_sizeof(png_sPLT_t)); + to->nentries = from->nentries; + to->depth = from->depth; + } + + info_ptr->splt_palettes = np; + info_ptr->splt_palettes_num += nentries; + info_ptr->valid |= PNG_INFO_sPLT; +#ifdef PNG_FREE_ME_SUPPORTED + info_ptr->free_me |= PNG_FREE_SPLT; +#endif +} +#endif /* PNG_sPLT_SUPPORTED */ + +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) +void PNGAPI +png_set_unknown_chunks(png_structp png_ptr, + png_infop info_ptr, png_unknown_chunkp unknowns, int num_unknowns) +{ + png_unknown_chunkp np; + int i; + + if (png_ptr == NULL || info_ptr == NULL || num_unknowns == 0) + return; + + np = (png_unknown_chunkp)png_malloc_warn(png_ptr, + (info_ptr->unknown_chunks_num + num_unknowns) * + png_sizeof(png_unknown_chunk)); + if (np == NULL) + { + png_warning(png_ptr, "Out of memory while processing unknown chunk."); + return; + } + + png_memcpy(np, info_ptr->unknown_chunks, + info_ptr->unknown_chunks_num * png_sizeof(png_unknown_chunk)); + png_free(png_ptr, info_ptr->unknown_chunks); + info_ptr->unknown_chunks=NULL; + + for (i = 0; i < num_unknowns; i++) + { + png_unknown_chunkp to = np + info_ptr->unknown_chunks_num + i; + png_unknown_chunkp from = unknowns + i; + + png_strncpy((png_charp)to->name, (png_charp)from->name, 5); + to->data = (png_bytep)png_malloc_warn(png_ptr, from->size); + if (to->data == NULL) + { + png_warning(png_ptr, "Out of memory processing unknown chunk."); + } + else + { + png_memcpy(to->data, from->data, from->size); + to->size = from->size; + + /* note our location in the read or write sequence */ + to->location = (png_byte)(png_ptr->mode & 0xff); + } + } + + info_ptr->unknown_chunks = np; + info_ptr->unknown_chunks_num += num_unknowns; +#ifdef PNG_FREE_ME_SUPPORTED + info_ptr->free_me |= PNG_FREE_UNKN; +#endif +} +void PNGAPI +png_set_unknown_chunk_location(png_structp png_ptr, png_infop info_ptr, + int chunk, int location) +{ + if(png_ptr != NULL && info_ptr != NULL && chunk >= 0 && chunk < + (int)info_ptr->unknown_chunks_num) + info_ptr->unknown_chunks[chunk].location = (png_byte)location; +} +#endif + +#if defined(PNG_READ_EMPTY_PLTE_SUPPORTED) || \ + defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) +void PNGAPI +png_permit_empty_plte (png_structp png_ptr, int empty_plte_permitted) +{ + /* This function is deprecated in favor of png_permit_mng_features() + and will be removed from libpng-2.0.0 */ + png_debug(1, "in png_permit_empty_plte, DEPRECATED.\n"); + if (png_ptr == NULL) + return; + png_ptr->mng_features_permitted = (png_byte) + ((png_ptr->mng_features_permitted & (~(PNG_FLAG_MNG_EMPTY_PLTE))) | + ((empty_plte_permitted & PNG_FLAG_MNG_EMPTY_PLTE))); +} +#endif + +#if defined(PNG_MNG_FEATURES_SUPPORTED) +png_uint_32 PNGAPI +png_permit_mng_features (png_structp png_ptr, png_uint_32 mng_features) +{ + png_debug(1, "in png_permit_mng_features\n"); + if (png_ptr == NULL) + return (png_uint_32)0; + png_ptr->mng_features_permitted = + (png_byte)(mng_features & PNG_ALL_MNG_FEATURES); + return (png_uint_32)png_ptr->mng_features_permitted; +} +#endif + +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) +void PNGAPI +png_set_keep_unknown_chunks(png_structp png_ptr, int keep, png_bytep + chunk_list, int num_chunks) +{ + png_bytep new_list, p; + int i, old_num_chunks; + if (num_chunks == 0) + { + if(keep == PNG_HANDLE_CHUNK_ALWAYS || keep == PNG_HANDLE_CHUNK_IF_SAFE) + png_ptr->flags |= PNG_FLAG_KEEP_UNKNOWN_CHUNKS; + else + png_ptr->flags &= ~PNG_FLAG_KEEP_UNKNOWN_CHUNKS; + + if(keep == PNG_HANDLE_CHUNK_ALWAYS) + png_ptr->flags |= PNG_FLAG_KEEP_UNSAFE_CHUNKS; + else + png_ptr->flags &= ~PNG_FLAG_KEEP_UNSAFE_CHUNKS; + return; + } + if (chunk_list == NULL) + return; + old_num_chunks=png_ptr->num_chunk_list; + new_list=(png_bytep)png_malloc(png_ptr, + (png_uint_32)(5*(num_chunks+old_num_chunks))); + if(png_ptr->chunk_list != NULL) + { + png_memcpy(new_list, png_ptr->chunk_list, + (png_size_t)(5*old_num_chunks)); + png_free(png_ptr, png_ptr->chunk_list); + png_ptr->chunk_list=NULL; + } + png_memcpy(new_list+5*old_num_chunks, chunk_list, + (png_size_t)(5*num_chunks)); + for (p=new_list+5*old_num_chunks+4, i=0; i<num_chunks; i++, p+=5) + *p=(png_byte)keep; + png_ptr->num_chunk_list=old_num_chunks+num_chunks; + png_ptr->chunk_list=new_list; +#ifdef PNG_FREE_ME_SUPPORTED + png_ptr->free_me |= PNG_FREE_LIST; +#endif +} +#endif + +#if defined(PNG_READ_USER_CHUNKS_SUPPORTED) +void PNGAPI +png_set_read_user_chunk_fn(png_structp png_ptr, png_voidp user_chunk_ptr, + png_user_chunk_ptr read_user_chunk_fn) +{ + png_debug(1, "in png_set_read_user_chunk_fn\n"); + png_ptr->read_user_chunk_fn = read_user_chunk_fn; + png_ptr->user_chunk_ptr = user_chunk_ptr; +} +#endif + +#if defined(PNG_INFO_IMAGE_SUPPORTED) +void PNGAPI +png_set_rows(png_structp png_ptr, png_infop info_ptr, png_bytepp row_pointers) +{ + png_debug1(1, "in %s storage function\n", "rows"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + if(info_ptr->row_pointers && (info_ptr->row_pointers != row_pointers)) + png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); + info_ptr->row_pointers = row_pointers; + if(row_pointers) + info_ptr->valid |= PNG_INFO_IDAT; +} +#endif + +#ifdef PNG_WRITE_SUPPORTED +void PNGAPI +png_set_compression_buffer_size(png_structp png_ptr, png_uint_32 size) +{ + if(png_ptr->zbuf) + png_free(png_ptr, png_ptr->zbuf); + png_ptr->zbuf_size = (png_size_t)size; + png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, size); + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; +} +#endif + +void PNGAPI +png_set_invalid(png_structp png_ptr, png_infop info_ptr, int mask) +{ + if (png_ptr && info_ptr) + info_ptr->valid &= ~(mask); +} + + +#ifndef PNG_1_0_X +#ifdef PNG_ASSEMBLER_CODE_SUPPORTED +/* this function was added to libpng 1.2.0 and should always exist by default */ +void PNGAPI +png_set_asm_flags (png_structp png_ptr, png_uint_32 asm_flags) +{ + png_uint_32 settable_asm_flags; + png_uint_32 settable_mmx_flags; + + settable_mmx_flags = +#ifdef PNG_HAVE_ASSEMBLER_COMBINE_ROW + PNG_ASM_FLAG_MMX_READ_COMBINE_ROW | +#endif +#ifdef PNG_HAVE_ASSEMBLER_READ_INTERLACE + PNG_ASM_FLAG_MMX_READ_INTERLACE | +#endif +#ifdef PNG_HAVE_ASSEMBLER_READ_FILTER_ROW + PNG_ASM_FLAG_MMX_READ_FILTER_SUB | + PNG_ASM_FLAG_MMX_READ_FILTER_UP | + PNG_ASM_FLAG_MMX_READ_FILTER_AVG | + PNG_ASM_FLAG_MMX_READ_FILTER_PAETH | +#endif + 0; + + /* could be some non-MMX ones in the future, but not currently: */ + settable_asm_flags = settable_mmx_flags; + + if (!(png_ptr->asm_flags & PNG_ASM_FLAG_MMX_SUPPORT_COMPILED) || + !(png_ptr->asm_flags & PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU)) + { + /* clear all MMX flags if MMX isn't supported */ + settable_asm_flags &= ~settable_mmx_flags; + png_ptr->asm_flags &= ~settable_mmx_flags; + } + + /* we're replacing the settable bits with those passed in by the user, + * so first zero them out of the master copy, then logical-OR in the + * allowed subset that was requested */ + + png_ptr->asm_flags &= ~settable_asm_flags; /* zero them */ + png_ptr->asm_flags |= (asm_flags & settable_asm_flags); /* set them */ +} +#endif /* ?PNG_ASSEMBLER_CODE_SUPPORTED */ + +#ifdef PNG_ASSEMBLER_CODE_SUPPORTED +/* this function was added to libpng 1.2.0 */ +void PNGAPI +png_set_mmx_thresholds (png_structp png_ptr, + png_byte mmx_bitdepth_threshold, + png_uint_32 mmx_rowbytes_threshold) +{ + png_ptr->mmx_bitdepth_threshold = mmx_bitdepth_threshold; + png_ptr->mmx_rowbytes_threshold = mmx_rowbytes_threshold; +} +#endif /* ?PNG_ASSEMBLER_CODE_SUPPORTED */ + +#ifdef PNG_SET_USER_LIMITS_SUPPORTED +/* this function was added to libpng 1.2.6 */ +void PNGAPI +png_set_user_limits (png_structp png_ptr, png_uint_32 user_width_max, + png_uint_32 user_height_max) +{ + /* Images with dimensions larger than these limits will be + * rejected by png_set_IHDR(). To accept any PNG datastream + * regardless of dimensions, set both limits to 0x7ffffffL. + */ + png_ptr->user_width_max = user_width_max; + png_ptr->user_height_max = user_height_max; +} +#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */ + +#endif /* ?PNG_1_0_X */ diff --git a/syslinux/com32/lib/libpng/pngtest.c b/syslinux/com32/lib/libpng/pngtest.c new file mode 100644 index 0000000..f2085e1 --- /dev/null +++ b/syslinux/com32/lib/libpng/pngtest.c @@ -0,0 +1,1554 @@ + +/* pngtest.c - a simple test program to test libpng + * + * libpng 1.2.8 - December 3, 2004 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2004 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This program reads in a PNG image, writes it out again, and then + * compares the two files. If the files are identical, this shows that + * the basic chunk handling, filtering, and (de)compression code is working + * properly. It does not currently test all of the transforms, although + * it probably should. + * + * The program will report "FAIL" in certain legitimate cases: + * 1) when the compression level or filter selection method is changed. + * 2) when the maximum IDAT size (PNG_ZBUF_SIZE in pngconf.h) is not 8192. + * 3) unknown unsafe-to-copy ancillary chunks or unknown critical chunks + * exist in the input file. + * 4) others not listed here... + * In these cases, it is best to check with another tool such as "pngcheck" + * to see what the differences between the two files are. + * + * If a filename is given on the command-line, then this file is used + * for the input, rather than the default "pngtest.png". This allows + * testing a wide variety of files easily. You can also test a number + * of files at once by typing "pngtest -m file1.png file2.png ..." + */ + +#include "png.h" + +#if defined(_WIN32_WCE) +# if _WIN32_WCE < 211 + __error__ (f|w)printf functions are not supported on old WindowsCE.; +# endif +# include <windows.h> +# include <stdlib.h> +# define READFILE(file, data, length, check) \ + if (ReadFile(file, data, length, &check,NULL)) check = 0 +# define WRITEFILE(file, data, length, check)) \ + if (WriteFile(file, data, length, &check, NULL)) check = 0 +# define FCLOSE(file) CloseHandle(file) +#else +# include <stdio.h> +# include <stdlib.h> +# include <assert.h> +# define READFILE(file, data, length, check) \ + check=(png_size_t)fread(data,(png_size_t)1,length,file) +# define WRITEFILE(file, data, length, check) \ + check=(png_size_t)fwrite(data,(png_size_t)1, length, file) +# define FCLOSE(file) fclose(file) +#endif + +#if defined(PNG_NO_STDIO) +# if defined(_WIN32_WCE) + typedef HANDLE png_FILE_p; +# else + typedef FILE * png_FILE_p; +# endif +#endif + +/* Makes pngtest verbose so we can find problems (needs to be before png.h) */ +#ifndef PNG_DEBUG +# define PNG_DEBUG 0 +#endif + +#if !PNG_DEBUG +# define SINGLE_ROWBUF_ALLOC /* makes buffer overruns easier to nail */ +#endif + +/* Turn on CPU timing +#define PNGTEST_TIMING +*/ + +#ifdef PNG_NO_FLOATING_POINT_SUPPORTED +#undef PNGTEST_TIMING +#endif + +#ifdef PNGTEST_TIMING +static float t_start, t_stop, t_decode, t_encode, t_misc; +#include <time.h> +#endif + +/* Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng */ +#ifndef png_jmpbuf +# define png_jmpbuf(png_ptr) png_ptr->jmpbuf +#endif + +#ifdef PNGTEST_TIMING +static float t_start, t_stop, t_decode, t_encode, t_misc; +#if !defined(PNG_tIME_SUPPORTED) +#include <time.h> +#endif +#endif + +#if defined(PNG_TIME_RFC1123_SUPPORTED) +static int tIME_chunk_present=0; +static char tIME_string[30] = "no tIME chunk present in file"; +#endif + +static int verbose = 0; + +int test_one_file PNGARG((PNG_CONST char *inname, PNG_CONST char *outname)); + +#ifdef __TURBOC__ +#include <mem.h> +#endif + +/* defined so I can write to a file on gui/windowing platforms */ +/* #define STDERR stderr */ +#define STDERR stdout /* for DOS */ + +/* example of using row callbacks to make a simple progress meter */ +static int status_pass=1; +static int status_dots_requested=0; +static int status_dots=1; + +void +#ifdef PNG_1_0_X +PNGAPI +#endif +read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass); +void +#ifdef PNG_1_0_X +PNGAPI +#endif +read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass) +{ + if(png_ptr == NULL || row_number > PNG_UINT_31_MAX) return; + if(status_pass != pass) + { + fprintf(stdout,"\n Pass %d: ",pass); + status_pass = pass; + status_dots = 31; + } + status_dots--; + if(status_dots == 0) + { + fprintf(stdout, "\n "); + status_dots=30; + } + fprintf(stdout, "r"); +} + +void +#ifdef PNG_1_0_X +PNGAPI +#endif +write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass); +void +#ifdef PNG_1_0_X +PNGAPI +#endif +write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass) +{ + if(png_ptr == NULL || row_number > PNG_UINT_31_MAX || pass > 7) return; + fprintf(stdout, "w"); +} + + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) +/* Example of using user transform callback (we don't transform anything, + but merely examine the row filters. We set this to 256 rather than + 5 in case illegal filter values are present.) */ +static png_uint_32 filters_used[256]; +void +#ifdef PNG_1_0_X +PNGAPI +#endif +count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data); +void +#ifdef PNG_1_0_X +PNGAPI +#endif +count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data) +{ + if(png_ptr != NULL && row_info != NULL) + ++filters_used[*(data-1)]; +} +#endif + +#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) +/* example of using user transform callback (we don't transform anything, + but merely count the zero samples) */ + +static png_uint_32 zero_samples; + +void +#ifdef PNG_1_0_X +PNGAPI +#endif +count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data); +void +#ifdef PNG_1_0_X +PNGAPI +#endif +count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data) +{ + png_bytep dp = data; + if(png_ptr == NULL)return; + + /* contents of row_info: + * png_uint_32 width width of row + * png_uint_32 rowbytes number of bytes in row + * png_byte color_type color type of pixels + * png_byte bit_depth bit depth of samples + * png_byte channels number of channels (1-4) + * png_byte pixel_depth bits per pixel (depth*channels) + */ + + + /* counts the number of zero samples (or zero pixels if color_type is 3 */ + + if(row_info->color_type == 0 || row_info->color_type == 3) + { + int pos=0; + png_uint_32 n, nstop; + for (n=0, nstop=row_info->width; n<nstop; n++) + { + if(row_info->bit_depth == 1) + { + if(((*dp << pos++ ) & 0x80) == 0) zero_samples++; + if(pos == 8) + { + pos = 0; + dp++; + } + } + if(row_info->bit_depth == 2) + { + if(((*dp << (pos+=2)) & 0xc0) == 0) zero_samples++; + if(pos == 8) + { + pos = 0; + dp++; + } + } + if(row_info->bit_depth == 4) + { + if(((*dp << (pos+=4)) & 0xf0) == 0) zero_samples++; + if(pos == 8) + { + pos = 0; + dp++; + } + } + if(row_info->bit_depth == 8) + if(*dp++ == 0) zero_samples++; + if(row_info->bit_depth == 16) + { + if((*dp | *(dp+1)) == 0) zero_samples++; + dp+=2; + } + } + } + else /* other color types */ + { + png_uint_32 n, nstop; + int channel; + int color_channels = row_info->channels; + if(row_info->color_type > 3)color_channels--; + + for (n=0, nstop=row_info->width; n<nstop; n++) + { + for (channel = 0; channel < color_channels; channel++) + { + if(row_info->bit_depth == 8) + if(*dp++ == 0) zero_samples++; + if(row_info->bit_depth == 16) + { + if((*dp | *(dp+1)) == 0) zero_samples++; + dp+=2; + } + } + if(row_info->color_type > 3) + { + dp++; + if(row_info->bit_depth == 16)dp++; + } + } + } +} +#endif /* PNG_WRITE_USER_TRANSFORM_SUPPORTED */ + +static int wrote_question = 0; + +#if defined(PNG_NO_STDIO) +/* START of code to validate stdio-free compilation */ +/* These copies of the default read/write functions come from pngrio.c and */ +/* pngwio.c. They allow "don't include stdio" testing of the library. */ +/* This is the function that does the actual reading of data. If you are + not reading from a standard C stream, you should create a replacement + read_data function and use it at run time with png_set_read_fn(), rather + than changing the library. */ + +#ifndef USE_FAR_KEYWORD +static void +pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_size_t check; + + /* fread() returns 0 on error, so it is OK to store this in a png_size_t + * instead of an int, which is what fread() actually returns. + */ + READFILE((png_FILE_p)png_ptr->io_ptr, data, length, check); + + if (check != length) + { + png_error(png_ptr, "Read Error!"); + } +} +#else +/* this is the model-independent version. Since the standard I/O library + can't handle far buffers in the medium and small models, we have to copy + the data. +*/ + +#define NEAR_BUF_SIZE 1024 +#define MIN(a,b) (a <= b ? a : b) + +static void +pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + int check; + png_byte *n_data; + png_FILE_p io_ptr; + + /* Check if data really is near. If so, use usual code. */ + n_data = (png_byte *)CVT_PTR_NOCHECK(data); + io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr); + if ((png_bytep)n_data == data) + { + READFILE(io_ptr, n_data, length, check); + } + else + { + png_byte buf[NEAR_BUF_SIZE]; + png_size_t read, remaining, err; + check = 0; + remaining = length; + do + { + read = MIN(NEAR_BUF_SIZE, remaining); + READFILE(io_ptr, buf, 1, err); + png_memcpy(data, buf, read); /* copy far buffer to near buffer */ + if(err != read) + break; + else + check += err; + data += read; + remaining -= read; + } + while (remaining != 0); + } + if (check != length) + { + png_error(png_ptr, "read Error"); + } +} +#endif /* USE_FAR_KEYWORD */ + +#if defined(PNG_WRITE_FLUSH_SUPPORTED) +static void +pngtest_flush(png_structp png_ptr) +{ +#if !defined(_WIN32_WCE) + png_FILE_p io_ptr; + io_ptr = (png_FILE_p)CVT_PTR((png_ptr->io_ptr)); + if (io_ptr != NULL) + fflush(io_ptr); +#endif +} +#endif + +/* This is the function that does the actual writing of data. If you are + not writing to a standard C stream, you should create a replacement + write_data function and use it at run time with png_set_write_fn(), rather + than changing the library. */ +#ifndef USE_FAR_KEYWORD +static void +pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_uint_32 check; + + WRITEFILE((png_FILE_p)png_ptr->io_ptr, data, length, check); + if (check != length) + { + png_error(png_ptr, "Write Error"); + } +} +#else +/* this is the model-independent version. Since the standard I/O library + can't handle far buffers in the medium and small models, we have to copy + the data. +*/ + +#define NEAR_BUF_SIZE 1024 +#define MIN(a,b) (a <= b ? a : b) + +static void +pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_uint_32 check; + png_byte *near_data; /* Needs to be "png_byte *" instead of "png_bytep" */ + png_FILE_p io_ptr; + + /* Check if data really is near. If so, use usual code. */ + near_data = (png_byte *)CVT_PTR_NOCHECK(data); + io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr); + if ((png_bytep)near_data == data) + { + WRITEFILE(io_ptr, near_data, length, check); + } + else + { + png_byte buf[NEAR_BUF_SIZE]; + png_size_t written, remaining, err; + check = 0; + remaining = length; + do + { + written = MIN(NEAR_BUF_SIZE, remaining); + png_memcpy(buf, data, written); /* copy far buffer to near buffer */ + WRITEFILE(io_ptr, buf, written, err); + if (err != written) + break; + else + check += err; + data += written; + remaining -= written; + } + while (remaining != 0); + } + if (check != length) + { + png_error(png_ptr, "Write Error"); + } +} + +#endif /* USE_FAR_KEYWORD */ + +/* This function is called when there is a warning, but the library thinks + * it can continue anyway. Replacement functions don't have to do anything + * here if you don't want to. In the default configuration, png_ptr is + * not used, but it is passed in case it may be useful. + */ +static void +pngtest_warning(png_structp png_ptr, png_const_charp message) +{ + PNG_CONST char *name = "UNKNOWN (ERROR!)"; + if (png_ptr != NULL && png_ptr->error_ptr != NULL) + name = png_ptr->error_ptr; + fprintf(STDERR, "%s: libpng warning: %s\n", name, message); +} + +/* This is the default error handling function. Note that replacements for + * this function MUST NOT RETURN, or the program will likely crash. This + * function is used by default, or if the program supplies NULL for the + * error function pointer in png_set_error_fn(). + */ +static void +pngtest_error(png_structp png_ptr, png_const_charp message) +{ + pngtest_warning(png_ptr, message); + /* We can return because png_error calls the default handler, which is + * actually OK in this case. */ +} +#endif /* PNG_NO_STDIO */ +/* END of code to validate stdio-free compilation */ + +/* START of code to validate memory allocation and deallocation */ +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + +/* Allocate memory. For reasonable files, size should never exceed + 64K. However, zlib may allocate more then 64K if you don't tell + it not to. See zconf.h and png.h for more information. zlib does + need to allocate exactly 64K, so whatever you call here must + have the ability to do that. + + This piece of code can be compiled to validate max 64K allocations + by setting MAXSEG_64K in zlib zconf.h *or* PNG_MAX_MALLOC_64K. */ +typedef struct memory_information +{ + png_uint_32 size; + png_voidp pointer; + struct memory_information FAR *next; +} memory_information; +typedef memory_information FAR *memory_infop; + +static memory_infop pinformation = NULL; +static int current_allocation = 0; +static int maximum_allocation = 0; +static int total_allocation = 0; +static int num_allocations = 0; + +png_voidp png_debug_malloc PNGARG((png_structp png_ptr, png_uint_32 size)); +void png_debug_free PNGARG((png_structp png_ptr, png_voidp ptr)); + +png_voidp +png_debug_malloc(png_structp png_ptr, png_uint_32 size) +{ + + /* png_malloc has already tested for NULL; png_create_struct calls + png_debug_malloc directly, with png_ptr == NULL which is OK */ + + if (size == 0) + return (NULL); + + /* This calls the library allocator twice, once to get the requested + buffer and once to get a new free list entry. */ + { + /* Disable malloc_fn and free_fn */ + memory_infop pinfo; + png_set_mem_fn(png_ptr, NULL, NULL, NULL); + pinfo = (memory_infop)png_malloc(png_ptr, + (png_uint_32)png_sizeof (*pinfo)); + pinfo->size = size; + current_allocation += size; + total_allocation += size; + num_allocations ++; + if (current_allocation > maximum_allocation) + maximum_allocation = current_allocation; + pinfo->pointer = (png_voidp)png_malloc(png_ptr, size); + /* Restore malloc_fn and free_fn */ + png_set_mem_fn(png_ptr, png_voidp_NULL, (png_malloc_ptr)png_debug_malloc, + (png_free_ptr)png_debug_free); + if (size != 0 && pinfo->pointer == NULL) + { + current_allocation -= size; + total_allocation -= size; + png_error(png_ptr, + "out of memory in pngtest->png_debug_malloc."); + } + pinfo->next = pinformation; + pinformation = pinfo; + /* Make sure the caller isn't assuming zeroed memory. */ + png_memset(pinfo->pointer, 0xdd, pinfo->size); + if(verbose) + printf("png_malloc %lu bytes at %x\n",size,pinfo->pointer); + assert(pinfo->size != 12345678); + return (png_voidp)(pinfo->pointer); + } +} + +/* Free a pointer. It is removed from the list at the same time. */ +void +png_debug_free(png_structp png_ptr, png_voidp ptr) +{ + if (png_ptr == NULL) + fprintf(STDERR, "NULL pointer to png_debug_free.\n"); + if (ptr == 0) + { +#if 0 /* This happens all the time. */ + fprintf(STDERR, "WARNING: freeing NULL pointer\n"); +#endif + return; + } + + /* Unlink the element from the list. */ + { + memory_infop FAR *ppinfo = &pinformation; + for (;;) + { + memory_infop pinfo = *ppinfo; + if (pinfo->pointer == ptr) + { + *ppinfo = pinfo->next; + current_allocation -= pinfo->size; + if (current_allocation < 0) + fprintf(STDERR, "Duplicate free of memory\n"); + /* We must free the list element too, but first kill + the memory that is to be freed. */ + png_memset(ptr, 0x55, pinfo->size); + png_free_default(png_ptr, pinfo); + pinfo=NULL; + break; + } + if (pinfo->next == NULL) + { + fprintf(STDERR, "Pointer %x not found\n", (unsigned int)ptr); + break; + } + ppinfo = &pinfo->next; + } + } + + /* Finally free the data. */ + if(verbose) + printf("Freeing %x\n",ptr); + png_free_default(png_ptr, ptr); + ptr=NULL; +} +#endif /* PNG_USER_MEM_SUPPORTED && PNG_DEBUG */ +/* END of code to test memory allocation/deallocation */ + +/* Test one file */ +int +test_one_file(PNG_CONST char *inname, PNG_CONST char *outname) +{ + static png_FILE_p fpin; + static png_FILE_p fpout; /* "static" prevents setjmp corruption */ + png_structp read_ptr; + png_infop read_info_ptr, end_info_ptr; +#ifdef PNG_WRITE_SUPPORTED + png_structp write_ptr; + png_infop write_info_ptr; + png_infop write_end_info_ptr; +#else + png_structp write_ptr = NULL; + png_infop write_info_ptr = NULL; + png_infop write_end_info_ptr = NULL; +#endif + png_bytep row_buf; + png_uint_32 y; + png_uint_32 width, height; + int num_pass, pass; + int bit_depth, color_type; +#ifdef PNG_SETJMP_SUPPORTED +#ifdef USE_FAR_KEYWORD + jmp_buf jmpbuf; +#endif +#endif + +#if defined(_WIN32_WCE) + TCHAR path[MAX_PATH]; +#endif + char inbuf[256], outbuf[256]; + + row_buf = NULL; + +#if defined(_WIN32_WCE) + MultiByteToWideChar(CP_ACP, 0, inname, -1, path, MAX_PATH); + if ((fpin = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) +#else + if ((fpin = fopen(inname, "rb")) == NULL) +#endif + { + fprintf(STDERR, "Could not find input file %s\n", inname); + return (1); + } + +#if defined(_WIN32_WCE) + MultiByteToWideChar(CP_ACP, 0, outname, -1, path, MAX_PATH); + if ((fpout = CreateFile(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL)) == INVALID_HANDLE_VALUE) +#else + if ((fpout = fopen(outname, "wb")) == NULL) +#endif + { + fprintf(STDERR, "Could not open output file %s\n", outname); + FCLOSE(fpin); + return (1); + } + + png_debug(0, "Allocating read and write structures\n"); +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + read_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, png_voidp_NULL, + png_error_ptr_NULL, png_error_ptr_NULL, png_voidp_NULL, + (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free); +#else + read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, png_voidp_NULL, + png_error_ptr_NULL, png_error_ptr_NULL); +#endif +#if defined(PNG_NO_STDIO) + png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error, + pngtest_warning); +#endif +#ifdef PNG_WRITE_SUPPORTED +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + write_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, png_voidp_NULL, + png_error_ptr_NULL, png_error_ptr_NULL, png_voidp_NULL, + (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free); +#else + write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, png_voidp_NULL, + png_error_ptr_NULL, png_error_ptr_NULL); +#endif +#if defined(PNG_NO_STDIO) + png_set_error_fn(write_ptr, (png_voidp)inname, pngtest_error, + pngtest_warning); +#endif +#endif + png_debug(0, "Allocating read_info, write_info and end_info structures\n"); + read_info_ptr = png_create_info_struct(read_ptr); + end_info_ptr = png_create_info_struct(read_ptr); +#ifdef PNG_WRITE_SUPPORTED + write_info_ptr = png_create_info_struct(write_ptr); + write_end_info_ptr = png_create_info_struct(write_ptr); +#endif + +#ifdef PNG_SETJMP_SUPPORTED + png_debug(0, "Setting jmpbuf for read struct\n"); +#ifdef USE_FAR_KEYWORD + if (setjmp(jmpbuf)) +#else + if (setjmp(png_jmpbuf(read_ptr))) +#endif + { + fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname); + if (row_buf) + png_free(read_ptr, row_buf); + png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); +#ifdef PNG_WRITE_SUPPORTED + png_destroy_info_struct(write_ptr, &write_end_info_ptr); + png_destroy_write_struct(&write_ptr, &write_info_ptr); +#endif + FCLOSE(fpin); + FCLOSE(fpout); + return (1); + } +#ifdef USE_FAR_KEYWORD + png_memcpy(png_jmpbuf(read_ptr),jmpbuf,png_sizeof(jmp_buf)); +#endif + +#ifdef PNG_WRITE_SUPPORTED + png_debug(0, "Setting jmpbuf for write struct\n"); +#ifdef USE_FAR_KEYWORD + if (setjmp(jmpbuf)) +#else + if (setjmp(png_jmpbuf(write_ptr))) +#endif + { + fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname); + png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); + png_destroy_info_struct(write_ptr, &write_end_info_ptr); +#ifdef PNG_WRITE_SUPPORTED + png_destroy_write_struct(&write_ptr, &write_info_ptr); +#endif + FCLOSE(fpin); + FCLOSE(fpout); + return (1); + } +#ifdef USE_FAR_KEYWORD + png_memcpy(png_jmpbuf(write_ptr),jmpbuf,png_sizeof(jmp_buf)); +#endif +#endif +#endif + + png_debug(0, "Initializing input and output streams\n"); +#if !defined(PNG_NO_STDIO) + png_init_io(read_ptr, fpin); +# ifdef PNG_WRITE_SUPPORTED + png_init_io(write_ptr, fpout); +# endif +#else + png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data); +# ifdef PNG_WRITE_SUPPORTED + png_set_write_fn(write_ptr, (png_voidp)fpout, pngtest_write_data, +# if defined(PNG_WRITE_FLUSH_SUPPORTED) + pngtest_flush); +# else + NULL); +# endif +# endif +#endif + if(status_dots_requested == 1) + { +#ifdef PNG_WRITE_SUPPORTED + png_set_write_status_fn(write_ptr, write_row_callback); +#endif + png_set_read_status_fn(read_ptr, read_row_callback); + } + else + { +#ifdef PNG_WRITE_SUPPORTED + png_set_write_status_fn(write_ptr, png_write_status_ptr_NULL); +#endif + png_set_read_status_fn(read_ptr, png_read_status_ptr_NULL); + } + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) + { + int i; + for(i=0; i<256; i++) + filters_used[i]=0; + png_set_read_user_transform_fn(read_ptr, count_filters); + } +#endif +#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) + zero_samples=0; + png_set_write_user_transform_fn(write_ptr, count_zero_samples); +#endif + +#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) +# ifndef PNG_HANDLE_CHUNK_ALWAYS +# define PNG_HANDLE_CHUNK_ALWAYS 3 +# endif + png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS, + png_bytep_NULL, 0); +#endif +#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) +# ifndef PNG_HANDLE_CHUNK_IF_SAFE +# define PNG_HANDLE_CHUNK_IF_SAFE 2 +# endif + png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_IF_SAFE, + png_bytep_NULL, 0); +#endif + + png_debug(0, "Reading info struct\n"); + png_read_info(read_ptr, read_info_ptr); + + png_debug(0, "Transferring info struct\n"); + { + int interlace_type, compression_type, filter_type; + + if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth, + &color_type, &interlace_type, &compression_type, &filter_type)) + { + png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth, +#if defined(PNG_WRITE_INTERLACING_SUPPORTED) + color_type, interlace_type, compression_type, filter_type); +#else + color_type, PNG_INTERLACE_NONE, compression_type, filter_type); +#endif + } + } +#if defined(PNG_FIXED_POINT_SUPPORTED) +#if defined(PNG_cHRM_SUPPORTED) + { + png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x, + blue_y; + if (png_get_cHRM_fixed(read_ptr, read_info_ptr, &white_x, &white_y, &red_x, + &red_y, &green_x, &green_y, &blue_x, &blue_y)) + { + png_set_cHRM_fixed(write_ptr, write_info_ptr, white_x, white_y, red_x, + red_y, green_x, green_y, blue_x, blue_y); + } + } +#endif +#if defined(PNG_gAMA_SUPPORTED) + { + png_fixed_point gamma; + + if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma)) + { + png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma); + } + } +#endif +#else /* Use floating point versions */ +#if defined(PNG_FLOATING_POINT_SUPPORTED) +#if defined(PNG_cHRM_SUPPORTED) + { + double white_x, white_y, red_x, red_y, green_x, green_y, blue_x, + blue_y; + if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x, + &red_y, &green_x, &green_y, &blue_x, &blue_y)) + { + png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, red_x, + red_y, green_x, green_y, blue_x, blue_y); + } + } +#endif +#if defined(PNG_gAMA_SUPPORTED) + { + double gamma; + + if (png_get_gAMA(read_ptr, read_info_ptr, &gamma)) + { + png_set_gAMA(write_ptr, write_info_ptr, gamma); + } + } +#endif +#endif /* floating point */ +#endif /* fixed point */ +#if defined(PNG_iCCP_SUPPORTED) + { + png_charp name; + png_charp profile; + png_uint_32 proflen; + int compression_type; + + if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type, + &profile, &proflen)) + { + png_set_iCCP(write_ptr, write_info_ptr, name, compression_type, + profile, proflen); + } + } +#endif +#if defined(PNG_sRGB_SUPPORTED) + { + int intent; + + if (png_get_sRGB(read_ptr, read_info_ptr, &intent)) + { + png_set_sRGB(write_ptr, write_info_ptr, intent); + } + } +#endif + { + png_colorp palette; + int num_palette; + + if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette)) + { + png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette); + } + } +#if defined(PNG_bKGD_SUPPORTED) + { + png_color_16p background; + + if (png_get_bKGD(read_ptr, read_info_ptr, &background)) + { + png_set_bKGD(write_ptr, write_info_ptr, background); + } + } +#endif +#if defined(PNG_hIST_SUPPORTED) + { + png_uint_16p hist; + + if (png_get_hIST(read_ptr, read_info_ptr, &hist)) + { + png_set_hIST(write_ptr, write_info_ptr, hist); + } + } +#endif +#if defined(PNG_oFFs_SUPPORTED) + { + png_int_32 offset_x, offset_y; + int unit_type; + + if (png_get_oFFs(read_ptr, read_info_ptr,&offset_x,&offset_y,&unit_type)) + { + png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type); + } + } +#endif +#if defined(PNG_pCAL_SUPPORTED) + { + png_charp purpose, units; + png_charpp params; + png_int_32 X0, X1; + int type, nparams; + + if (png_get_pCAL(read_ptr, read_info_ptr, &purpose, &X0, &X1, &type, + &nparams, &units, ¶ms)) + { + png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type, + nparams, units, params); + } + } +#endif +#if defined(PNG_pHYs_SUPPORTED) + { + png_uint_32 res_x, res_y; + int unit_type; + + if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y, &unit_type)) + { + png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type); + } + } +#endif +#if defined(PNG_sBIT_SUPPORTED) + { + png_color_8p sig_bit; + + if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit)) + { + png_set_sBIT(write_ptr, write_info_ptr, sig_bit); + } + } +#endif +#if defined(PNG_sCAL_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED + { + int unit; + double scal_width, scal_height; + + if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width, + &scal_height)) + { + png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height); + } + } +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + { + int unit; + png_charp scal_width, scal_height; + + if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width, + &scal_height)) + { + png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width, scal_height); + } + } +#endif +#endif +#endif +#if defined(PNG_TEXT_SUPPORTED) + { + png_textp text_ptr; + int num_text; + + if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0) + { + png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks\n", num_text); + png_set_text(write_ptr, write_info_ptr, text_ptr, num_text); + } + } +#endif +#if defined(PNG_tIME_SUPPORTED) + { + png_timep mod_time; + + if (png_get_tIME(read_ptr, read_info_ptr, &mod_time)) + { + png_set_tIME(write_ptr, write_info_ptr, mod_time); +#if defined(PNG_TIME_RFC1123_SUPPORTED) + /* we have to use png_strcpy instead of "=" because the string + pointed to by png_convert_to_rfc1123() gets free'ed before + we use it */ + png_strcpy(tIME_string,png_convert_to_rfc1123(read_ptr, mod_time)); + tIME_chunk_present++; +#endif /* PNG_TIME_RFC1123_SUPPORTED */ + } + } +#endif +#if defined(PNG_tRNS_SUPPORTED) + { + png_bytep trans; + int num_trans; + png_color_16p trans_values; + + if (png_get_tRNS(read_ptr, read_info_ptr, &trans, &num_trans, + &trans_values)) + { + png_set_tRNS(write_ptr, write_info_ptr, trans, num_trans, + trans_values); + } + } +#endif +#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) + { + png_unknown_chunkp unknowns; + int num_unknowns = (int)png_get_unknown_chunks(read_ptr, read_info_ptr, + &unknowns); + if (num_unknowns) + { + png_size_t i; + png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns, + num_unknowns); + /* copy the locations from the read_info_ptr. The automatically + generated locations in write_info_ptr are wrong because we + haven't written anything yet */ + for (i = 0; i < (png_size_t)num_unknowns; i++) + png_set_unknown_chunk_location(write_ptr, write_info_ptr, i, + unknowns[i].location); + } + } +#endif + +#ifdef PNG_WRITE_SUPPORTED + png_debug(0, "\nWriting info struct\n"); + +/* If we wanted, we could write info in two steps: + png_write_info_before_PLTE(write_ptr, write_info_ptr); + */ + png_write_info(write_ptr, write_info_ptr); +#endif + +#ifdef SINGLE_ROWBUF_ALLOC + png_debug(0, "\nAllocating row buffer..."); + row_buf = (png_bytep)png_malloc(read_ptr, + png_get_rowbytes(read_ptr, read_info_ptr)); + png_debug1(0, "0x%08lx\n\n", (unsigned long)row_buf); +#endif /* SINGLE_ROWBUF_ALLOC */ + png_debug(0, "Writing row data\n"); + +#if defined(PNG_READ_INTERLACING_SUPPORTED) || \ + defined(PNG_WRITE_INTERLACING_SUPPORTED) + num_pass = png_set_interlace_handling(read_ptr); +# ifdef PNG_WRITE_SUPPORTED + png_set_interlace_handling(write_ptr); +# endif +#else + num_pass=1; +#endif + +#ifdef PNGTEST_TIMING + t_stop = (float)clock(); + t_misc += (t_stop - t_start); + t_start = t_stop; +#endif + for (pass = 0; pass < num_pass; pass++) + { + png_debug1(0, "Writing row data for pass %d\n",pass); + for (y = 0; y < height; y++) + { +#ifndef SINGLE_ROWBUF_ALLOC + png_debug2(0, "\nAllocating row buffer (pass %d, y = %ld)...", pass,y); + row_buf = (png_bytep)png_malloc(read_ptr, + png_get_rowbytes(read_ptr, read_info_ptr)); + png_debug2(0, "0x%08lx (%ld bytes)\n", (unsigned long)row_buf, + png_get_rowbytes(read_ptr, read_info_ptr)); +#endif /* !SINGLE_ROWBUF_ALLOC */ + png_read_rows(read_ptr, (png_bytepp)&row_buf, png_bytepp_NULL, 1); + +#ifdef PNG_WRITE_SUPPORTED +#ifdef PNGTEST_TIMING + t_stop = (float)clock(); + t_decode += (t_stop - t_start); + t_start = t_stop; +#endif + png_write_rows(write_ptr, (png_bytepp)&row_buf, 1); +#ifdef PNGTEST_TIMING + t_stop = (float)clock(); + t_encode += (t_stop - t_start); + t_start = t_stop; +#endif +#endif /* PNG_WRITE_SUPPORTED */ + +#ifndef SINGLE_ROWBUF_ALLOC + png_debug2(0, "Freeing row buffer (pass %d, y = %ld)\n\n", pass, y); + png_free(read_ptr, row_buf); +#endif /* !SINGLE_ROWBUF_ALLOC */ + } + } + +#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) + png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1); +#endif +#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) + png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1); +#endif + + png_debug(0, "Reading and writing end_info data\n"); + + png_read_end(read_ptr, end_info_ptr); +#if defined(PNG_TEXT_SUPPORTED) + { + png_textp text_ptr; + int num_text; + + if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0) + { + png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks\n", num_text); + png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text); + } + } +#endif +#if defined(PNG_tIME_SUPPORTED) + { + png_timep mod_time; + + if (png_get_tIME(read_ptr, end_info_ptr, &mod_time)) + { + png_set_tIME(write_ptr, write_end_info_ptr, mod_time); +#if defined(PNG_TIME_RFC1123_SUPPORTED) + /* we have to use png_strcpy instead of "=" because the string + pointed to by png_convert_to_rfc1123() gets free'ed before + we use it */ + png_strcpy(tIME_string,png_convert_to_rfc1123(read_ptr, mod_time)); + tIME_chunk_present++; +#endif /* PNG_TIME_RFC1123_SUPPORTED */ + } + } +#endif +#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) + { + png_unknown_chunkp unknowns; + int num_unknowns; + num_unknowns = (int)png_get_unknown_chunks(read_ptr, end_info_ptr, + &unknowns); + if (num_unknowns) + { + png_size_t i; + png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns, + num_unknowns); + /* copy the locations from the read_info_ptr. The automatically + generated locations in write_end_info_ptr are wrong because we + haven't written the end_info yet */ + for (i = 0; i < (png_size_t)num_unknowns; i++) + png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, i, + unknowns[i].location); + } + } +#endif +#ifdef PNG_WRITE_SUPPORTED + png_write_end(write_ptr, write_end_info_ptr); +#endif + +#ifdef PNG_EASY_ACCESS_SUPPORTED + if(verbose) + { + png_uint_32 iwidth, iheight; + iwidth = png_get_image_width(write_ptr, write_info_ptr); + iheight = png_get_image_height(write_ptr, write_info_ptr); + fprintf(STDERR, "Image width = %lu, height = %lu\n", + iwidth, iheight); + } +#endif + + png_debug(0, "Destroying data structs\n"); +#ifdef SINGLE_ROWBUF_ALLOC + png_debug(1, "destroying row_buf for read_ptr\n"); + png_free(read_ptr, row_buf); + row_buf=NULL; +#endif /* SINGLE_ROWBUF_ALLOC */ + png_debug(1, "destroying read_ptr, read_info_ptr, end_info_ptr\n"); + png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); +#ifdef PNG_WRITE_SUPPORTED + png_debug(1, "destroying write_end_info_ptr\n"); + png_destroy_info_struct(write_ptr, &write_end_info_ptr); + png_debug(1, "destroying write_ptr, write_info_ptr\n"); + png_destroy_write_struct(&write_ptr, &write_info_ptr); +#endif + png_debug(0, "Destruction complete.\n"); + + FCLOSE(fpin); + FCLOSE(fpout); + + png_debug(0, "Opening files for comparison\n"); +#if defined(_WIN32_WCE) + MultiByteToWideChar(CP_ACP, 0, inname, -1, path, MAX_PATH); + if ((fpin = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) +#else + if ((fpin = fopen(inname, "rb")) == NULL) +#endif + { + fprintf(STDERR, "Could not find file %s\n", inname); + return (1); + } + +#if defined(_WIN32_WCE) + MultiByteToWideChar(CP_ACP, 0, outname, -1, path, MAX_PATH); + if ((fpout = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) +#else + if ((fpout = fopen(outname, "rb")) == NULL) +#endif + { + fprintf(STDERR, "Could not find file %s\n", outname); + FCLOSE(fpin); + return (1); + } + + for(;;) + { + png_size_t num_in, num_out; + + READFILE(fpin, inbuf, 1, num_in); + READFILE(fpout, outbuf, 1, num_out); + + if (num_in != num_out) + { + fprintf(STDERR, "\nFiles %s and %s are of a different size\n", + inname, outname); + if(wrote_question == 0) + { + fprintf(STDERR, + " Was %s written with the same maximum IDAT chunk size (%d bytes),", + inname,PNG_ZBUF_SIZE); + fprintf(STDERR, + "\n filtering heuristic (libpng default), compression"); + fprintf(STDERR, + " level (zlib default),\n and zlib version (%s)?\n\n", + ZLIB_VERSION); + wrote_question=1; + } + FCLOSE(fpin); + FCLOSE(fpout); + return (0); + } + + if (!num_in) + break; + + if (png_memcmp(inbuf, outbuf, num_in)) + { + fprintf(STDERR, "\nFiles %s and %s are different\n", inname, outname); + if(wrote_question == 0) + { + fprintf(STDERR, + " Was %s written with the same maximum IDAT chunk size (%d bytes),", + inname,PNG_ZBUF_SIZE); + fprintf(STDERR, + "\n filtering heuristic (libpng default), compression"); + fprintf(STDERR, + " level (zlib default),\n and zlib version (%s)?\n\n", + ZLIB_VERSION); + wrote_question=1; + } + FCLOSE(fpin); + FCLOSE(fpout); + return (0); + } + } + + FCLOSE(fpin); + FCLOSE(fpout); + + return (0); +} + +/* input and output filenames */ +#ifdef RISCOS +static PNG_CONST char *inname = "pngtest/png"; +static PNG_CONST char *outname = "pngout/png"; +#else +static PNG_CONST char *inname = "pngtest.png"; +static PNG_CONST char *outname = "pngout.png"; +#endif + +int +main(int argc, char *argv[]) +{ + int multiple = 0; + int ierror = 0; + + fprintf(STDERR, "Testing libpng version %s\n", PNG_LIBPNG_VER_STRING); + fprintf(STDERR, " with zlib version %s\n", ZLIB_VERSION); + fprintf(STDERR,"%s",png_get_copyright(NULL)); + /* Show the version of libpng used in building the library */ + fprintf(STDERR," library (%lu):%s", png_access_version_number(), + png_get_header_version(NULL)); + /* Show the version of libpng used in building the application */ + fprintf(STDERR," pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER, + PNG_HEADER_VERSION_STRING); + fprintf(STDERR," png_sizeof(png_struct)=%ld, png_sizeof(png_info)=%ld\n", + (long)png_sizeof(png_struct), (long)png_sizeof(png_info)); + + /* Do some consistency checking on the memory allocation settings, I'm + not sure this matters, but it is nice to know, the first of these + tests should be impossible because of the way the macros are set + in pngconf.h */ +#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K) + fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n"); +#endif + /* I think the following can happen. */ +#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K) + fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n"); +#endif + + if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING)) + { + fprintf(STDERR, + "Warning: versions are different between png.h and png.c\n"); + fprintf(STDERR, " png.h version: %s\n", PNG_LIBPNG_VER_STRING); + fprintf(STDERR, " png.c version: %s\n\n", png_libpng_ver); + ++ierror; + } + + if (argc > 1) + { + if (strcmp(argv[1], "-m") == 0) + { + multiple = 1; + status_dots_requested = 0; + } + else if (strcmp(argv[1], "-mv") == 0 || + strcmp(argv[1], "-vm") == 0 ) + { + multiple = 1; + verbose = 1; + status_dots_requested = 1; + } + else if (strcmp(argv[1], "-v") == 0) + { + verbose = 1; + status_dots_requested = 1; + inname = argv[2]; + } + else + { + inname = argv[1]; + status_dots_requested = 0; + } + } + + if (!multiple && argc == 3+verbose) + outname = argv[2+verbose]; + + if ((!multiple && argc > 3+verbose) || (multiple && argc < 2)) + { + fprintf(STDERR, + "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n", + argv[0], argv[0]); + fprintf(STDERR, + " reads/writes one PNG file (without -m) or multiple files (-m)\n"); + fprintf(STDERR, + " with -m %s is used as a temporary file\n", outname); + exit(1); + } + + if (multiple) + { + int i; +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + int allocation_now = current_allocation; +#endif + for (i=2; i<argc; ++i) + { +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) + int k; +#endif + int kerror; + fprintf(STDERR, "Testing %s:",argv[i]); + kerror = test_one_file(argv[i], outname); + if (kerror == 0) + { +#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) + fprintf(STDERR, "\n PASS (%lu zero samples)\n",zero_samples); +#else + fprintf(STDERR, " PASS\n"); +#endif +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) + for (k=0; k<256; k++) + if(filters_used[k]) + fprintf(STDERR, " Filter %d was used %lu times\n", + k,filters_used[k]); +#endif +#if defined(PNG_TIME_RFC1123_SUPPORTED) + if(tIME_chunk_present != 0) + fprintf(STDERR, " tIME = %s\n",tIME_string); + tIME_chunk_present = 0; +#endif /* PNG_TIME_RFC1123_SUPPORTED */ + } + else + { + fprintf(STDERR, " FAIL\n"); + ierror += kerror; + } +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + if (allocation_now != current_allocation) + fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n", + current_allocation-allocation_now); + if (current_allocation != 0) + { + memory_infop pinfo = pinformation; + + fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n", + current_allocation); + while (pinfo != NULL) + { + fprintf(STDERR, " %lu bytes at %x\n", pinfo->size, + (unsigned int) pinfo->pointer); + pinfo = pinfo->next; + } + } +#endif + } +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + fprintf(STDERR, " Current memory allocation: %10d bytes\n", + current_allocation); + fprintf(STDERR, " Maximum memory allocation: %10d bytes\n", + maximum_allocation); + fprintf(STDERR, " Total memory allocation: %10d bytes\n", + total_allocation); + fprintf(STDERR, " Number of allocations: %10d\n", + num_allocations); +#endif + } + else + { + int i; + for (i=0; i<3; ++i) + { + int kerror; +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + int allocation_now = current_allocation; +#endif + if (i == 1) status_dots_requested = 1; + else if(verbose == 0)status_dots_requested = 0; + if (i == 0 || verbose == 1 || ierror != 0) + fprintf(STDERR, "Testing %s:",inname); + kerror = test_one_file(inname, outname); + if(kerror == 0) + { + if(verbose == 1 || i == 2) + { +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) + int k; +#endif +#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) + fprintf(STDERR, "\n PASS (%lu zero samples)\n",zero_samples); +#else + fprintf(STDERR, " PASS\n"); +#endif +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) + for (k=0; k<256; k++) + if(filters_used[k]) + fprintf(STDERR, " Filter %d was used %lu times\n", + k,filters_used[k]); +#endif +#if defined(PNG_TIME_RFC1123_SUPPORTED) + if(tIME_chunk_present != 0) + fprintf(STDERR, " tIME = %s\n",tIME_string); +#endif /* PNG_TIME_RFC1123_SUPPORTED */ + } + } + else + { + if(verbose == 0 && i != 2) + fprintf(STDERR, "Testing %s:",inname); + fprintf(STDERR, " FAIL\n"); + ierror += kerror; + } +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + if (allocation_now != current_allocation) + fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n", + current_allocation-allocation_now); + if (current_allocation != 0) + { + memory_infop pinfo = pinformation; + + fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n", + current_allocation); + while (pinfo != NULL) + { + fprintf(STDERR," %lu bytes at %x\n", + pinfo->size, (unsigned int)pinfo->pointer); + pinfo = pinfo->next; + } + } +#endif + } +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + fprintf(STDERR, " Current memory allocation: %10d bytes\n", + current_allocation); + fprintf(STDERR, " Maximum memory allocation: %10d bytes\n", + maximum_allocation); + fprintf(STDERR, " Total memory allocation: %10d bytes\n", + total_allocation); + fprintf(STDERR, " Number of allocations: %10d\n", + num_allocations); +#endif + } + +#ifdef PNGTEST_TIMING + t_stop = (float)clock(); + t_misc += (t_stop - t_start); + t_start = t_stop; + fprintf(STDERR," CPU time used = %.3f seconds", + (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC); + fprintf(STDERR," (decoding %.3f,\n", + t_decode/(float)CLOCKS_PER_SEC); + fprintf(STDERR," encoding %.3f ,", + t_encode/(float)CLOCKS_PER_SEC); + fprintf(STDERR," other %.3f seconds)\n\n", + t_misc/(float)CLOCKS_PER_SEC); +#endif + + if (ierror == 0) + fprintf(STDERR, "libpng passes test\n"); + else + fprintf(STDERR, "libpng FAILS test\n"); + return (int)(ierror != 0); +} + +/* Generate a compiler error if there is an old png.h in the search path. */ +typedef version_1_2_8 your_png_h_is_not_version_1_2_8; diff --git a/syslinux/com32/lib/libpng/pngtrans.c b/syslinux/com32/lib/libpng/pngtrans.c new file mode 100644 index 0000000..9003a21 --- /dev/null +++ b/syslinux/com32/lib/libpng/pngtrans.c @@ -0,0 +1,650 @@ + +/* pngtrans.c - transforms the data in a row (used by both readers and writers) + * + * libpng 1.2.8 - December 3, 2004 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2004 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + */ + +#define PNG_INTERNAL +#include "png.h" + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +/* turn on BGR-to-RGB mapping */ +void PNGAPI +png_set_bgr(png_structp png_ptr) +{ + png_debug(1, "in png_set_bgr\n"); + png_ptr->transformations |= PNG_BGR; +} +#endif + +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +/* turn on 16 bit byte swapping */ +void PNGAPI +png_set_swap(png_structp png_ptr) +{ + png_debug(1, "in png_set_swap\n"); + if (png_ptr->bit_depth == 16) + png_ptr->transformations |= PNG_SWAP_BYTES; +} +#endif + +#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) +/* turn on pixel packing */ +void PNGAPI +png_set_packing(png_structp png_ptr) +{ + png_debug(1, "in png_set_packing\n"); + if (png_ptr->bit_depth < 8) + { + png_ptr->transformations |= PNG_PACK; + png_ptr->usr_bit_depth = 8; + } +} +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED) +/* turn on packed pixel swapping */ +void PNGAPI +png_set_packswap(png_structp png_ptr) +{ + png_debug(1, "in png_set_packswap\n"); + if (png_ptr->bit_depth < 8) + png_ptr->transformations |= PNG_PACKSWAP; +} +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) +void PNGAPI +png_set_shift(png_structp png_ptr, png_color_8p true_bits) +{ + png_debug(1, "in png_set_shift\n"); + png_ptr->transformations |= PNG_SHIFT; + png_ptr->shift = *true_bits; +} +#endif + +#if defined(PNG_READ_INTERLACING_SUPPORTED) || \ + defined(PNG_WRITE_INTERLACING_SUPPORTED) +int PNGAPI +png_set_interlace_handling(png_structp png_ptr) +{ + png_debug(1, "in png_set_interlace handling\n"); + if (png_ptr->interlaced) + { + png_ptr->transformations |= PNG_INTERLACE; + return (7); + } + + return (1); +} +#endif + +#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) +/* Add a filler byte on read, or remove a filler or alpha byte on write. + * The filler type has changed in v0.95 to allow future 2-byte fillers + * for 48-bit input data, as well as to avoid problems with some compilers + * that don't like bytes as parameters. + */ +void PNGAPI +png_set_filler(png_structp png_ptr, png_uint_32 filler, int filler_loc) +{ + png_debug(1, "in png_set_filler\n"); + png_ptr->transformations |= PNG_FILLER; + png_ptr->filler = (png_byte)filler; + if (filler_loc == PNG_FILLER_AFTER) + png_ptr->flags |= PNG_FLAG_FILLER_AFTER; + else + png_ptr->flags &= ~PNG_FLAG_FILLER_AFTER; + + /* This should probably go in the "do_read_filler" routine. + * I attempted to do that in libpng-1.0.1a but that caused problems + * so I restored it in libpng-1.0.2a + */ + + if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) + { + png_ptr->usr_channels = 4; + } + + /* Also I added this in libpng-1.0.2a (what happens when we expand + * a less-than-8-bit grayscale to GA? */ + + if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY && png_ptr->bit_depth >= 8) + { + png_ptr->usr_channels = 2; + } +} + +#if !defined(PNG_1_0_X) +/* Added to libpng-1.2.7 */ +void PNGAPI +png_set_add_alpha(png_structp png_ptr, png_uint_32 filler, int filler_loc) +{ + png_debug(1, "in png_set_add_alpha\n"); + png_set_filler(png_ptr, filler, filler_loc); + png_ptr->transformations |= PNG_ADD_ALPHA; +} +#endif + +#endif + +#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) +void PNGAPI +png_set_swap_alpha(png_structp png_ptr) +{ + png_debug(1, "in png_set_swap_alpha\n"); + png_ptr->transformations |= PNG_SWAP_ALPHA; +} +#endif + +#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) +void PNGAPI +png_set_invert_alpha(png_structp png_ptr) +{ + png_debug(1, "in png_set_invert_alpha\n"); + png_ptr->transformations |= PNG_INVERT_ALPHA; +} +#endif + +#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) +void PNGAPI +png_set_invert_mono(png_structp png_ptr) +{ + png_debug(1, "in png_set_invert_mono\n"); + png_ptr->transformations |= PNG_INVERT_MONO; +} + +/* invert monochrome grayscale data */ +void /* PRIVATE */ +png_do_invert(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_invert\n"); + /* This test removed from libpng version 1.0.13 and 1.2.0: + * if (row_info->bit_depth == 1 && + */ +#if defined(PNG_USELESS_TESTS_SUPPORTED) + if (row == NULL || row_info == NULL) + return; +#endif + if (row_info->color_type == PNG_COLOR_TYPE_GRAY) + { + png_bytep rp = row; + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + + for (i = 0; i < istop; i++) + { + *rp = (png_byte)(~(*rp)); + rp++; + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && + row_info->bit_depth == 8) + { + png_bytep rp = row; + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + + for (i = 0; i < istop; i+=2) + { + *rp = (png_byte)(~(*rp)); + rp+=2; + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && + row_info->bit_depth == 16) + { + png_bytep rp = row; + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + + for (i = 0; i < istop; i+=4) + { + *rp = (png_byte)(~(*rp)); + *(rp+1) = (png_byte)(~(*(rp+1))); + rp+=4; + } + } +} +#endif + +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +/* swaps byte order on 16 bit depth images */ +void /* PRIVATE */ +png_do_swap(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_swap\n"); + if ( +#if defined(PNG_USELESS_TESTS_SUPPORTED) + row != NULL && row_info != NULL && +#endif + row_info->bit_depth == 16) + { + png_bytep rp = row; + png_uint_32 i; + png_uint_32 istop= row_info->width * row_info->channels; + + for (i = 0; i < istop; i++, rp += 2) + { + png_byte t = *rp; + *rp = *(rp + 1); + *(rp + 1) = t; + } + } +} +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED) +static png_byte onebppswaptable[256] = { + 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, + 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, + 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, + 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, + 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, + 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, + 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, + 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, + 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, + 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, + 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, + 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, + 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, + 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, + 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, + 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, + 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, + 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1, + 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, + 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, + 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, + 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, + 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, + 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD, + 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, + 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, + 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, + 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, + 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, + 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, + 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, + 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF +}; + +static png_byte twobppswaptable[256] = { + 0x00, 0x40, 0x80, 0xC0, 0x10, 0x50, 0x90, 0xD0, + 0x20, 0x60, 0xA0, 0xE0, 0x30, 0x70, 0xB0, 0xF0, + 0x04, 0x44, 0x84, 0xC4, 0x14, 0x54, 0x94, 0xD4, + 0x24, 0x64, 0xA4, 0xE4, 0x34, 0x74, 0xB4, 0xF4, + 0x08, 0x48, 0x88, 0xC8, 0x18, 0x58, 0x98, 0xD8, + 0x28, 0x68, 0xA8, 0xE8, 0x38, 0x78, 0xB8, 0xF8, + 0x0C, 0x4C, 0x8C, 0xCC, 0x1C, 0x5C, 0x9C, 0xDC, + 0x2C, 0x6C, 0xAC, 0xEC, 0x3C, 0x7C, 0xBC, 0xFC, + 0x01, 0x41, 0x81, 0xC1, 0x11, 0x51, 0x91, 0xD1, + 0x21, 0x61, 0xA1, 0xE1, 0x31, 0x71, 0xB1, 0xF1, + 0x05, 0x45, 0x85, 0xC5, 0x15, 0x55, 0x95, 0xD5, + 0x25, 0x65, 0xA5, 0xE5, 0x35, 0x75, 0xB5, 0xF5, + 0x09, 0x49, 0x89, 0xC9, 0x19, 0x59, 0x99, 0xD9, + 0x29, 0x69, 0xA9, 0xE9, 0x39, 0x79, 0xB9, 0xF9, + 0x0D, 0x4D, 0x8D, 0xCD, 0x1D, 0x5D, 0x9D, 0xDD, + 0x2D, 0x6D, 0xAD, 0xED, 0x3D, 0x7D, 0xBD, 0xFD, + 0x02, 0x42, 0x82, 0xC2, 0x12, 0x52, 0x92, 0xD2, + 0x22, 0x62, 0xA2, 0xE2, 0x32, 0x72, 0xB2, 0xF2, + 0x06, 0x46, 0x86, 0xC6, 0x16, 0x56, 0x96, 0xD6, + 0x26, 0x66, 0xA6, 0xE6, 0x36, 0x76, 0xB6, 0xF6, + 0x0A, 0x4A, 0x8A, 0xCA, 0x1A, 0x5A, 0x9A, 0xDA, + 0x2A, 0x6A, 0xAA, 0xEA, 0x3A, 0x7A, 0xBA, 0xFA, + 0x0E, 0x4E, 0x8E, 0xCE, 0x1E, 0x5E, 0x9E, 0xDE, + 0x2E, 0x6E, 0xAE, 0xEE, 0x3E, 0x7E, 0xBE, 0xFE, + 0x03, 0x43, 0x83, 0xC3, 0x13, 0x53, 0x93, 0xD3, + 0x23, 0x63, 0xA3, 0xE3, 0x33, 0x73, 0xB3, 0xF3, + 0x07, 0x47, 0x87, 0xC7, 0x17, 0x57, 0x97, 0xD7, + 0x27, 0x67, 0xA7, 0xE7, 0x37, 0x77, 0xB7, 0xF7, + 0x0B, 0x4B, 0x8B, 0xCB, 0x1B, 0x5B, 0x9B, 0xDB, + 0x2B, 0x6B, 0xAB, 0xEB, 0x3B, 0x7B, 0xBB, 0xFB, + 0x0F, 0x4F, 0x8F, 0xCF, 0x1F, 0x5F, 0x9F, 0xDF, + 0x2F, 0x6F, 0xAF, 0xEF, 0x3F, 0x7F, 0xBF, 0xFF +}; + +static png_byte fourbppswaptable[256] = { + 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, + 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0, + 0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71, + 0x81, 0x91, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1, + 0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72, + 0x82, 0x92, 0xA2, 0xB2, 0xC2, 0xD2, 0xE2, 0xF2, + 0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73, + 0x83, 0x93, 0xA3, 0xB3, 0xC3, 0xD3, 0xE3, 0xF3, + 0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74, + 0x84, 0x94, 0xA4, 0xB4, 0xC4, 0xD4, 0xE4, 0xF4, + 0x05, 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75, + 0x85, 0x95, 0xA5, 0xB5, 0xC5, 0xD5, 0xE5, 0xF5, + 0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76, + 0x86, 0x96, 0xA6, 0xB6, 0xC6, 0xD6, 0xE6, 0xF6, + 0x07, 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77, + 0x87, 0x97, 0xA7, 0xB7, 0xC7, 0xD7, 0xE7, 0xF7, + 0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78, + 0x88, 0x98, 0xA8, 0xB8, 0xC8, 0xD8, 0xE8, 0xF8, + 0x09, 0x19, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79, + 0x89, 0x99, 0xA9, 0xB9, 0xC9, 0xD9, 0xE9, 0xF9, + 0x0A, 0x1A, 0x2A, 0x3A, 0x4A, 0x5A, 0x6A, 0x7A, + 0x8A, 0x9A, 0xAA, 0xBA, 0xCA, 0xDA, 0xEA, 0xFA, + 0x0B, 0x1B, 0x2B, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B, + 0x8B, 0x9B, 0xAB, 0xBB, 0xCB, 0xDB, 0xEB, 0xFB, + 0x0C, 0x1C, 0x2C, 0x3C, 0x4C, 0x5C, 0x6C, 0x7C, + 0x8C, 0x9C, 0xAC, 0xBC, 0xCC, 0xDC, 0xEC, 0xFC, + 0x0D, 0x1D, 0x2D, 0x3D, 0x4D, 0x5D, 0x6D, 0x7D, + 0x8D, 0x9D, 0xAD, 0xBD, 0xCD, 0xDD, 0xED, 0xFD, + 0x0E, 0x1E, 0x2E, 0x3E, 0x4E, 0x5E, 0x6E, 0x7E, + 0x8E, 0x9E, 0xAE, 0xBE, 0xCE, 0xDE, 0xEE, 0xFE, + 0x0F, 0x1F, 0x2F, 0x3F, 0x4F, 0x5F, 0x6F, 0x7F, + 0x8F, 0x9F, 0xAF, 0xBF, 0xCF, 0xDF, 0xEF, 0xFF +}; + +/* swaps pixel packing order within bytes */ +void /* PRIVATE */ +png_do_packswap(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_packswap\n"); + if ( +#if defined(PNG_USELESS_TESTS_SUPPORTED) + row != NULL && row_info != NULL && +#endif + row_info->bit_depth < 8) + { + png_bytep rp, end, table; + + end = row + row_info->rowbytes; + + if (row_info->bit_depth == 1) + table = onebppswaptable; + else if (row_info->bit_depth == 2) + table = twobppswaptable; + else if (row_info->bit_depth == 4) + table = fourbppswaptable; + else + return; + + for (rp = row; rp < end; rp++) + *rp = table[*rp]; + } +} +#endif /* PNG_READ_PACKSWAP_SUPPORTED or PNG_WRITE_PACKSWAP_SUPPORTED */ + +#if defined(PNG_WRITE_FILLER_SUPPORTED) || \ + defined(PNG_READ_STRIP_ALPHA_SUPPORTED) +/* remove filler or alpha byte(s) */ +void /* PRIVATE */ +png_do_strip_filler(png_row_infop row_info, png_bytep row, png_uint_32 flags) +{ + png_debug(1, "in png_do_strip_filler\n"); +#if defined(PNG_USELESS_TESTS_SUPPORTED) + if (row != NULL && row_info != NULL) +#endif + { + png_bytep sp=row; + png_bytep dp=row; + png_uint_32 row_width=row_info->width; + png_uint_32 i; + + if ((row_info->color_type == PNG_COLOR_TYPE_RGB || + (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA && + (flags & PNG_FLAG_STRIP_ALPHA))) && + row_info->channels == 4) + { + if (row_info->bit_depth == 8) + { + /* This converts from RGBX or RGBA to RGB */ + if (flags & PNG_FLAG_FILLER_AFTER) + { + dp+=3; sp+=4; + for (i = 1; i < row_width; i++) + { + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + sp++; + } + } + /* This converts from XRGB or ARGB to RGB */ + else + { + for (i = 0; i < row_width; i++) + { + sp++; + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + } + } + row_info->pixel_depth = 24; + row_info->rowbytes = row_width * 3; + } + else /* if (row_info->bit_depth == 16) */ + { + if (flags & PNG_FLAG_FILLER_AFTER) + { + /* This converts from RRGGBBXX or RRGGBBAA to RRGGBB */ + sp += 8; dp += 6; + for (i = 1; i < row_width; i++) + { + /* This could be (although png_memcpy is probably slower): + png_memcpy(dp, sp, 6); + sp += 8; + dp += 6; + */ + + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + sp += 2; + } + } + else + { + /* This converts from XXRRGGBB or AARRGGBB to RRGGBB */ + for (i = 0; i < row_width; i++) + { + /* This could be (although png_memcpy is probably slower): + png_memcpy(dp, sp, 6); + sp += 8; + dp += 6; + */ + + sp+=2; + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + } + } + row_info->pixel_depth = 48; + row_info->rowbytes = row_width * 6; + } + row_info->channels = 3; + } + else if ((row_info->color_type == PNG_COLOR_TYPE_GRAY || + (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && + (flags & PNG_FLAG_STRIP_ALPHA))) && + row_info->channels == 2) + { + if (row_info->bit_depth == 8) + { + /* This converts from GX or GA to G */ + if (flags & PNG_FLAG_FILLER_AFTER) + { + for (i = 0; i < row_width; i++) + { + *dp++ = *sp++; + sp++; + } + } + /* This converts from XG or AG to G */ + else + { + for (i = 0; i < row_width; i++) + { + sp++; + *dp++ = *sp++; + } + } + row_info->pixel_depth = 8; + row_info->rowbytes = row_width; + } + else /* if (row_info->bit_depth == 16) */ + { + if (flags & PNG_FLAG_FILLER_AFTER) + { + /* This converts from GGXX or GGAA to GG */ + sp += 4; dp += 2; + for (i = 1; i < row_width; i++) + { + *dp++ = *sp++; + *dp++ = *sp++; + sp += 2; + } + } + else + { + /* This converts from XXGG or AAGG to GG */ + for (i = 0; i < row_width; i++) + { + sp += 2; + *dp++ = *sp++; + *dp++ = *sp++; + } + } + row_info->pixel_depth = 16; + row_info->rowbytes = row_width * 2; + } + row_info->channels = 1; + } + if (flags & PNG_FLAG_STRIP_ALPHA) + row_info->color_type &= ~PNG_COLOR_MASK_ALPHA; + } +} +#endif + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +/* swaps red and blue bytes within a pixel */ +void /* PRIVATE */ +png_do_bgr(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_bgr\n"); + if ( +#if defined(PNG_USELESS_TESTS_SUPPORTED) + row != NULL && row_info != NULL && +#endif + (row_info->color_type & PNG_COLOR_MASK_COLOR)) + { + png_uint_32 row_width = row_info->width; + if (row_info->bit_depth == 8) + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + { + png_bytep rp; + png_uint_32 i; + + for (i = 0, rp = row; i < row_width; i++, rp += 3) + { + png_byte save = *rp; + *rp = *(rp + 2); + *(rp + 2) = save; + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + png_bytep rp; + png_uint_32 i; + + for (i = 0, rp = row; i < row_width; i++, rp += 4) + { + png_byte save = *rp; + *rp = *(rp + 2); + *(rp + 2) = save; + } + } + } + else if (row_info->bit_depth == 16) + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + { + png_bytep rp; + png_uint_32 i; + + for (i = 0, rp = row; i < row_width; i++, rp += 6) + { + png_byte save = *rp; + *rp = *(rp + 4); + *(rp + 4) = save; + save = *(rp + 1); + *(rp + 1) = *(rp + 5); + *(rp + 5) = save; + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + png_bytep rp; + png_uint_32 i; + + for (i = 0, rp = row; i < row_width; i++, rp += 8) + { + png_byte save = *rp; + *rp = *(rp + 4); + *(rp + 4) = save; + save = *(rp + 1); + *(rp + 1) = *(rp + 5); + *(rp + 5) = save; + } + } + } + } +} +#endif /* PNG_READ_BGR_SUPPORTED or PNG_WRITE_BGR_SUPPORTED */ + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_LEGACY_SUPPORTED) +void PNGAPI +png_set_user_transform_info(png_structp png_ptr, png_voidp + user_transform_ptr, int user_transform_depth, int user_transform_channels) +{ + png_debug(1, "in png_set_user_transform_info\n"); +#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) + png_ptr->user_transform_ptr = user_transform_ptr; + png_ptr->user_transform_depth = (png_byte)user_transform_depth; + png_ptr->user_transform_channels = (png_byte)user_transform_channels; +#else + if(user_transform_ptr || user_transform_depth || user_transform_channels) + png_warning(png_ptr, + "This version of libpng does not support user transform info"); +#endif +} +#endif + +/* This function returns a pointer to the user_transform_ptr associated with + * the user transform functions. The application should free any memory + * associated with this pointer before png_write_destroy and png_read_destroy + * are called. + */ +png_voidp PNGAPI +png_get_user_transform_ptr(png_structp png_ptr) +{ +#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) + return ((png_voidp)png_ptr->user_transform_ptr); +#else + if(png_ptr) + return (NULL); + return (NULL); +#endif +} diff --git a/syslinux/com32/lib/libpng/pngvcrd.c b/syslinux/com32/lib/libpng/pngvcrd.c new file mode 100644 index 0000000..940a7fc --- /dev/null +++ b/syslinux/com32/lib/libpng/pngvcrd.c @@ -0,0 +1,3903 @@ +/* pngvcrd.c - mixed C/assembler version of utilities to read a PNG file + * + * For Intel x86 CPU and Microsoft Visual C++ compiler + * + * libpng version 1.2.8 - December 3, 2004 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2004 Glenn Randers-Pehrson + * Copyright (c) 1998, Intel Corporation + * + * Contributed by Nirav Chhatrapati, Intel Corporation, 1998 + * Interface to libpng contributed by Gilles Vollant, 1999 + * + * + * In png_do_read_interlace() in libpng versions 1.0.3a through 1.0.4d, + * a sign error in the post-MMX cleanup code for each pixel_depth resulted + * in bad pixels at the beginning of some rows of some images, and also + * (due to out-of-range memory reads and writes) caused heap corruption + * when compiled with MSVC 6.0. The error was fixed in version 1.0.4e. + * + * [png_read_filter_row_mmx_avg() bpp == 2 bugfix, GRR 20000916] + * + * [runtime MMX configuration, GRR 20010102] + * + */ + +#define PNG_INTERNAL +#include "png.h" + +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_USE_PNGVCRD) + +static int mmx_supported=2; + + +int PNGAPI +png_mmx_support(void) +{ + int mmx_supported_local = 0; + _asm { + push ebx //CPUID will trash these + push ecx + push edx + + pushfd //Save Eflag to stack + pop eax //Get Eflag from stack into eax + mov ecx, eax //Make another copy of Eflag in ecx + xor eax, 0x200000 //Toggle ID bit in Eflag [i.e. bit(21)] + push eax //Save modified Eflag back to stack + + popfd //Restored modified value back to Eflag reg + pushfd //Save Eflag to stack + pop eax //Get Eflag from stack + push ecx // save original Eflag to stack + popfd // restore original Eflag + xor eax, ecx //Compare the new Eflag with the original Eflag + jz NOT_SUPPORTED //If the same, CPUID instruction is not supported, + //skip following instructions and jump to + //NOT_SUPPORTED label + + xor eax, eax //Set eax to zero + + _asm _emit 0x0f //CPUID instruction (two bytes opcode) + _asm _emit 0xa2 + + cmp eax, 1 //make sure eax return non-zero value + jl NOT_SUPPORTED //If eax is zero, mmx not supported + + xor eax, eax //set eax to zero + inc eax //Now increment eax to 1. This instruction is + //faster than the instruction "mov eax, 1" + + _asm _emit 0x0f //CPUID instruction + _asm _emit 0xa2 + + and edx, 0x00800000 //mask out all bits but mmx bit(24) + cmp edx, 0 // 0 = mmx not supported + jz NOT_SUPPORTED // non-zero = Yes, mmx IS supported + + mov mmx_supported_local, 1 //set return value to 1 + +NOT_SUPPORTED: + mov eax, mmx_supported_local //move return value to eax + pop edx //CPUID trashed these + pop ecx + pop ebx + } + + //mmx_supported_local=0; // test code for force don't support MMX + //printf("MMX : %u (1=MMX supported)\n",mmx_supported_local); + + mmx_supported = mmx_supported_local; + return mmx_supported_local; +} + +/* Combines the row recently read in with the previous row. + This routine takes care of alpha and transparency if requested. + This routine also handles the two methods of progressive display + of interlaced images, depending on the mask value. + The mask value describes which pixels are to be combined with + the row. The pattern always repeats every 8 pixels, so just 8 + bits are needed. A one indicates the pixel is to be combined; a + zero indicates the pixel is to be skipped. This is in addition + to any alpha or transparency value associated with the pixel. If + you want all pixels to be combined, pass 0xff (255) in mask. */ + +/* Use this routine for x86 platform - uses faster MMX routine if machine + supports MMX */ + +void /* PRIVATE */ +png_combine_row(png_structp png_ptr, png_bytep row, int mask) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + const int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; +#endif + + png_debug(1,"in png_combine_row_asm\n"); + + if (mmx_supported == 2) { +#if !defined(PNG_1_0_X) + /* this should have happened in png_init_mmx_flags() already */ + png_warning(png_ptr, "asm_flags may not have been initialized"); +#endif + png_mmx_support(); + } + + if (mask == 0xff) + { + png_memcpy(row, png_ptr->row_buf + 1, + (png_size_t)PNG_ROWBYTES(png_ptr->row_info.pixel_depth, + png_ptr->width)); + } + /* GRR: add "else if (mask == 0)" case? + * or does png_combine_row() not even get called in that case? */ + else + { + switch (png_ptr->row_info.pixel_depth) + { + case 1: + { + png_bytep sp; + png_bytep dp; + int s_inc, s_start, s_end; + int m; + int shift; + png_uint_32 i; + + sp = png_ptr->row_buf + 1; + dp = row; + m = 0x80; +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + { + s_start = 0; + s_end = 7; + s_inc = 1; + } + else +#endif + { + s_start = 7; + s_end = 0; + s_inc = -1; + } + + shift = s_start; + + for (i = 0; i < png_ptr->width; i++) + { + if (m & mask) + { + int value; + + value = (*sp >> shift) & 0x1; + *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff); + *dp |= (png_byte)(value << shift); + } + + if (shift == s_end) + { + shift = s_start; + sp++; + dp++; + } + else + shift += s_inc; + + if (m == 1) + m = 0x80; + else + m >>= 1; + } + break; + } + + case 2: + { + png_bytep sp; + png_bytep dp; + int s_start, s_end, s_inc; + int m; + int shift; + png_uint_32 i; + int value; + + sp = png_ptr->row_buf + 1; + dp = row; + m = 0x80; +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + { + s_start = 0; + s_end = 6; + s_inc = 2; + } + else +#endif + { + s_start = 6; + s_end = 0; + s_inc = -2; + } + + shift = s_start; + + for (i = 0; i < png_ptr->width; i++) + { + if (m & mask) + { + value = (*sp >> shift) & 0x3; + *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); + *dp |= (png_byte)(value << shift); + } + + if (shift == s_end) + { + shift = s_start; + sp++; + dp++; + } + else + shift += s_inc; + if (m == 1) + m = 0x80; + else + m >>= 1; + } + break; + } + + case 4: + { + png_bytep sp; + png_bytep dp; + int s_start, s_end, s_inc; + int m; + int shift; + png_uint_32 i; + int value; + + sp = png_ptr->row_buf + 1; + dp = row; + m = 0x80; +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + { + s_start = 0; + s_end = 4; + s_inc = 4; + } + else +#endif + { + s_start = 4; + s_end = 0; + s_inc = -4; + } + shift = s_start; + + for (i = 0; i < png_ptr->width; i++) + { + if (m & mask) + { + value = (*sp >> shift) & 0xf; + *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); + *dp |= (png_byte)(value << shift); + } + + if (shift == s_end) + { + shift = s_start; + sp++; + dp++; + } + else + shift += s_inc; + if (m == 1) + m = 0x80; + else + m >>= 1; + } + break; + } + + case 8: + { + png_bytep srcptr; + png_bytep dstptr; + png_uint_32 len; + int m; + int diff, unmask; + + __int64 mask0=0x0102040810204080; + +#if !defined(PNG_1_0_X) + if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW) + /* && mmx_supported */ ) +#else + if (mmx_supported) +#endif + { + srcptr = png_ptr->row_buf + 1; + dstptr = row; + m = 0x80; + unmask = ~mask; + len = png_ptr->width &~7; //reduce to multiple of 8 + diff = png_ptr->width & 7; //amount lost + + _asm + { + movd mm7, unmask //load bit pattern + psubb mm6,mm6 //zero mm6 + punpcklbw mm7,mm7 + punpcklwd mm7,mm7 + punpckldq mm7,mm7 //fill register with 8 masks + + movq mm0,mask0 + + pand mm0,mm7 //nonzero if keep byte + pcmpeqb mm0,mm6 //zeros->1s, v versa + + mov ecx,len //load length of line (pixels) + mov esi,srcptr //load source + mov ebx,dstptr //load dest + cmp ecx,0 //lcr + je mainloop8end + +mainloop8: + movq mm4,[esi] + pand mm4,mm0 + movq mm6,mm0 + pandn mm6,[ebx] + por mm4,mm6 + movq [ebx],mm4 + + add esi,8 //inc by 8 bytes processed + add ebx,8 + sub ecx,8 //dec by 8 pixels processed + + ja mainloop8 +mainloop8end: + + mov ecx,diff + cmp ecx,0 + jz end8 + + mov edx,mask + sal edx,24 //make low byte the high byte + +secondloop8: + sal edx,1 //move high bit to CF + jnc skip8 //if CF = 0 + mov al,[esi] + mov [ebx],al +skip8: + inc esi + inc ebx + + dec ecx + jnz secondloop8 +end8: + emms + } + } + else /* mmx not supported - use modified C routine */ + { + register unsigned int incr1, initial_val, final_val; + png_size_t pixel_bytes; + png_uint_32 i; + register int disp = png_pass_inc[png_ptr->pass]; + int offset_table[7] = {0, 4, 0, 2, 0, 1, 0}; + + pixel_bytes = (png_ptr->row_info.pixel_depth >> 3); + srcptr = png_ptr->row_buf + 1 + offset_table[png_ptr->pass]* + pixel_bytes; + dstptr = row + offset_table[png_ptr->pass]*pixel_bytes; + initial_val = offset_table[png_ptr->pass]*pixel_bytes; + final_val = png_ptr->width*pixel_bytes; + incr1 = (disp)*pixel_bytes; + for (i = initial_val; i < final_val; i += incr1) + { + png_memcpy(dstptr, srcptr, pixel_bytes); + srcptr += incr1; + dstptr += incr1; + } + } /* end of else */ + + break; + } // end 8 bpp + + case 16: + { + png_bytep srcptr; + png_bytep dstptr; + png_uint_32 len; + int unmask, diff; + __int64 mask1=0x0101020204040808, + mask0=0x1010202040408080; + +#if !defined(PNG_1_0_X) + if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW) + /* && mmx_supported */ ) +#else + if (mmx_supported) +#endif + { + srcptr = png_ptr->row_buf + 1; + dstptr = row; + + unmask = ~mask; + len = (png_ptr->width)&~7; + diff = (png_ptr->width)&7; + _asm + { + movd mm7, unmask //load bit pattern + psubb mm6,mm6 //zero mm6 + punpcklbw mm7,mm7 + punpcklwd mm7,mm7 + punpckldq mm7,mm7 //fill register with 8 masks + + movq mm0,mask0 + movq mm1,mask1 + + pand mm0,mm7 + pand mm1,mm7 + + pcmpeqb mm0,mm6 + pcmpeqb mm1,mm6 + + mov ecx,len //load length of line + mov esi,srcptr //load source + mov ebx,dstptr //load dest + cmp ecx,0 //lcr + jz mainloop16end + +mainloop16: + movq mm4,[esi] + pand mm4,mm0 + movq mm6,mm0 + movq mm7,[ebx] + pandn mm6,mm7 + por mm4,mm6 + movq [ebx],mm4 + + movq mm5,[esi+8] + pand mm5,mm1 + movq mm7,mm1 + movq mm6,[ebx+8] + pandn mm7,mm6 + por mm5,mm7 + movq [ebx+8],mm5 + + add esi,16 //inc by 16 bytes processed + add ebx,16 + sub ecx,8 //dec by 8 pixels processed + + ja mainloop16 + +mainloop16end: + mov ecx,diff + cmp ecx,0 + jz end16 + + mov edx,mask + sal edx,24 //make low byte the high byte +secondloop16: + sal edx,1 //move high bit to CF + jnc skip16 //if CF = 0 + mov ax,[esi] + mov [ebx],ax +skip16: + add esi,2 + add ebx,2 + + dec ecx + jnz secondloop16 +end16: + emms + } + } + else /* mmx not supported - use modified C routine */ + { + register unsigned int incr1, initial_val, final_val; + png_size_t pixel_bytes; + png_uint_32 i; + register int disp = png_pass_inc[png_ptr->pass]; + int offset_table[7] = {0, 4, 0, 2, 0, 1, 0}; + + pixel_bytes = (png_ptr->row_info.pixel_depth >> 3); + srcptr = png_ptr->row_buf + 1 + offset_table[png_ptr->pass]* + pixel_bytes; + dstptr = row + offset_table[png_ptr->pass]*pixel_bytes; + initial_val = offset_table[png_ptr->pass]*pixel_bytes; + final_val = png_ptr->width*pixel_bytes; + incr1 = (disp)*pixel_bytes; + for (i = initial_val; i < final_val; i += incr1) + { + png_memcpy(dstptr, srcptr, pixel_bytes); + srcptr += incr1; + dstptr += incr1; + } + } /* end of else */ + + break; + } // end 16 bpp + + case 24: + { + png_bytep srcptr; + png_bytep dstptr; + png_uint_32 len; + int unmask, diff; + + __int64 mask2=0x0101010202020404, //24bpp + mask1=0x0408080810101020, + mask0=0x2020404040808080; + + srcptr = png_ptr->row_buf + 1; + dstptr = row; + + unmask = ~mask; + len = (png_ptr->width)&~7; + diff = (png_ptr->width)&7; + +#if !defined(PNG_1_0_X) + if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW) + /* && mmx_supported */ ) +#else + if (mmx_supported) +#endif + { + _asm + { + movd mm7, unmask //load bit pattern + psubb mm6,mm6 //zero mm6 + punpcklbw mm7,mm7 + punpcklwd mm7,mm7 + punpckldq mm7,mm7 //fill register with 8 masks + + movq mm0,mask0 + movq mm1,mask1 + movq mm2,mask2 + + pand mm0,mm7 + pand mm1,mm7 + pand mm2,mm7 + + pcmpeqb mm0,mm6 + pcmpeqb mm1,mm6 + pcmpeqb mm2,mm6 + + mov ecx,len //load length of line + mov esi,srcptr //load source + mov ebx,dstptr //load dest + cmp ecx,0 + jz mainloop24end + +mainloop24: + movq mm4,[esi] + pand mm4,mm0 + movq mm6,mm0 + movq mm7,[ebx] + pandn mm6,mm7 + por mm4,mm6 + movq [ebx],mm4 + + + movq mm5,[esi+8] + pand mm5,mm1 + movq mm7,mm1 + movq mm6,[ebx+8] + pandn mm7,mm6 + por mm5,mm7 + movq [ebx+8],mm5 + + movq mm6,[esi+16] + pand mm6,mm2 + movq mm4,mm2 + movq mm7,[ebx+16] + pandn mm4,mm7 + por mm6,mm4 + movq [ebx+16],mm6 + + add esi,24 //inc by 24 bytes processed + add ebx,24 + sub ecx,8 //dec by 8 pixels processed + + ja mainloop24 + +mainloop24end: + mov ecx,diff + cmp ecx,0 + jz end24 + + mov edx,mask + sal edx,24 //make low byte the high byte +secondloop24: + sal edx,1 //move high bit to CF + jnc skip24 //if CF = 0 + mov ax,[esi] + mov [ebx],ax + xor eax,eax + mov al,[esi+2] + mov [ebx+2],al +skip24: + add esi,3 + add ebx,3 + + dec ecx + jnz secondloop24 + +end24: + emms + } + } + else /* mmx not supported - use modified C routine */ + { + register unsigned int incr1, initial_val, final_val; + png_size_t pixel_bytes; + png_uint_32 i; + register int disp = png_pass_inc[png_ptr->pass]; + int offset_table[7] = {0, 4, 0, 2, 0, 1, 0}; + + pixel_bytes = (png_ptr->row_info.pixel_depth >> 3); + srcptr = png_ptr->row_buf + 1 + offset_table[png_ptr->pass]* + pixel_bytes; + dstptr = row + offset_table[png_ptr->pass]*pixel_bytes; + initial_val = offset_table[png_ptr->pass]*pixel_bytes; + final_val = png_ptr->width*pixel_bytes; + incr1 = (disp)*pixel_bytes; + for (i = initial_val; i < final_val; i += incr1) + { + png_memcpy(dstptr, srcptr, pixel_bytes); + srcptr += incr1; + dstptr += incr1; + } + } /* end of else */ + + break; + } // end 24 bpp + + case 32: + { + png_bytep srcptr; + png_bytep dstptr; + png_uint_32 len; + int unmask, diff; + + __int64 mask3=0x0101010102020202, //32bpp + mask2=0x0404040408080808, + mask1=0x1010101020202020, + mask0=0x4040404080808080; + + srcptr = png_ptr->row_buf + 1; + dstptr = row; + + unmask = ~mask; + len = (png_ptr->width)&~7; + diff = (png_ptr->width)&7; + +#if !defined(PNG_1_0_X) + if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW) + /* && mmx_supported */ ) +#else + if (mmx_supported) +#endif + { + _asm + { + movd mm7, unmask //load bit pattern + psubb mm6,mm6 //zero mm6 + punpcklbw mm7,mm7 + punpcklwd mm7,mm7 + punpckldq mm7,mm7 //fill register with 8 masks + + movq mm0,mask0 + movq mm1,mask1 + movq mm2,mask2 + movq mm3,mask3 + + pand mm0,mm7 + pand mm1,mm7 + pand mm2,mm7 + pand mm3,mm7 + + pcmpeqb mm0,mm6 + pcmpeqb mm1,mm6 + pcmpeqb mm2,mm6 + pcmpeqb mm3,mm6 + + mov ecx,len //load length of line + mov esi,srcptr //load source + mov ebx,dstptr //load dest + + cmp ecx,0 //lcr + jz mainloop32end + +mainloop32: + movq mm4,[esi] + pand mm4,mm0 + movq mm6,mm0 + movq mm7,[ebx] + pandn mm6,mm7 + por mm4,mm6 + movq [ebx],mm4 + + movq mm5,[esi+8] + pand mm5,mm1 + movq mm7,mm1 + movq mm6,[ebx+8] + pandn mm7,mm6 + por mm5,mm7 + movq [ebx+8],mm5 + + movq mm6,[esi+16] + pand mm6,mm2 + movq mm4,mm2 + movq mm7,[ebx+16] + pandn mm4,mm7 + por mm6,mm4 + movq [ebx+16],mm6 + + movq mm7,[esi+24] + pand mm7,mm3 + movq mm5,mm3 + movq mm4,[ebx+24] + pandn mm5,mm4 + por mm7,mm5 + movq [ebx+24],mm7 + + add esi,32 //inc by 32 bytes processed + add ebx,32 + sub ecx,8 //dec by 8 pixels processed + + ja mainloop32 + +mainloop32end: + mov ecx,diff + cmp ecx,0 + jz end32 + + mov edx,mask + sal edx,24 //make low byte the high byte +secondloop32: + sal edx,1 //move high bit to CF + jnc skip32 //if CF = 0 + mov eax,[esi] + mov [ebx],eax +skip32: + add esi,4 + add ebx,4 + + dec ecx + jnz secondloop32 + +end32: + emms + } + } + else /* mmx _not supported - Use modified C routine */ + { + register unsigned int incr1, initial_val, final_val; + png_size_t pixel_bytes; + png_uint_32 i; + register int disp = png_pass_inc[png_ptr->pass]; + int offset_table[7] = {0, 4, 0, 2, 0, 1, 0}; + + pixel_bytes = (png_ptr->row_info.pixel_depth >> 3); + srcptr = png_ptr->row_buf + 1 + offset_table[png_ptr->pass]* + pixel_bytes; + dstptr = row + offset_table[png_ptr->pass]*pixel_bytes; + initial_val = offset_table[png_ptr->pass]*pixel_bytes; + final_val = png_ptr->width*pixel_bytes; + incr1 = (disp)*pixel_bytes; + for (i = initial_val; i < final_val; i += incr1) + { + png_memcpy(dstptr, srcptr, pixel_bytes); + srcptr += incr1; + dstptr += incr1; + } + } /* end of else */ + + break; + } // end 32 bpp + + case 48: + { + png_bytep srcptr; + png_bytep dstptr; + png_uint_32 len; + int unmask, diff; + + __int64 mask5=0x0101010101010202, + mask4=0x0202020204040404, + mask3=0x0404080808080808, + mask2=0x1010101010102020, + mask1=0x2020202040404040, + mask0=0x4040808080808080; + +#if !defined(PNG_1_0_X) + if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW) + /* && mmx_supported */ ) +#else + if (mmx_supported) +#endif + { + srcptr = png_ptr->row_buf + 1; + dstptr = row; + + unmask = ~mask; + len = (png_ptr->width)&~7; + diff = (png_ptr->width)&7; + _asm + { + movd mm7, unmask //load bit pattern + psubb mm6,mm6 //zero mm6 + punpcklbw mm7,mm7 + punpcklwd mm7,mm7 + punpckldq mm7,mm7 //fill register with 8 masks + + movq mm0,mask0 + movq mm1,mask1 + movq mm2,mask2 + movq mm3,mask3 + movq mm4,mask4 + movq mm5,mask5 + + pand mm0,mm7 + pand mm1,mm7 + pand mm2,mm7 + pand mm3,mm7 + pand mm4,mm7 + pand mm5,mm7 + + pcmpeqb mm0,mm6 + pcmpeqb mm1,mm6 + pcmpeqb mm2,mm6 + pcmpeqb mm3,mm6 + pcmpeqb mm4,mm6 + pcmpeqb mm5,mm6 + + mov ecx,len //load length of line + mov esi,srcptr //load source + mov ebx,dstptr //load dest + + cmp ecx,0 + jz mainloop48end + +mainloop48: + movq mm7,[esi] + pand mm7,mm0 + movq mm6,mm0 + pandn mm6,[ebx] + por mm7,mm6 + movq [ebx],mm7 + + movq mm6,[esi+8] + pand mm6,mm1 + movq mm7,mm1 + pandn mm7,[ebx+8] + por mm6,mm7 + movq [ebx+8],mm6 + + movq mm6,[esi+16] + pand mm6,mm2 + movq mm7,mm2 + pandn mm7,[ebx+16] + por mm6,mm7 + movq [ebx+16],mm6 + + movq mm7,[esi+24] + pand mm7,mm3 + movq mm6,mm3 + pandn mm6,[ebx+24] + por mm7,mm6 + movq [ebx+24],mm7 + + movq mm6,[esi+32] + pand mm6,mm4 + movq mm7,mm4 + pandn mm7,[ebx+32] + por mm6,mm7 + movq [ebx+32],mm6 + + movq mm7,[esi+40] + pand mm7,mm5 + movq mm6,mm5 + pandn mm6,[ebx+40] + por mm7,mm6 + movq [ebx+40],mm7 + + add esi,48 //inc by 32 bytes processed + add ebx,48 + sub ecx,8 //dec by 8 pixels processed + + ja mainloop48 +mainloop48end: + + mov ecx,diff + cmp ecx,0 + jz end48 + + mov edx,mask + sal edx,24 //make low byte the high byte + +secondloop48: + sal edx,1 //move high bit to CF + jnc skip48 //if CF = 0 + mov eax,[esi] + mov [ebx],eax +skip48: + add esi,4 + add ebx,4 + + dec ecx + jnz secondloop48 + +end48: + emms + } + } + else /* mmx _not supported - Use modified C routine */ + { + register unsigned int incr1, initial_val, final_val; + png_size_t pixel_bytes; + png_uint_32 i; + register int disp = png_pass_inc[png_ptr->pass]; + int offset_table[7] = {0, 4, 0, 2, 0, 1, 0}; + + pixel_bytes = (png_ptr->row_info.pixel_depth >> 3); + srcptr = png_ptr->row_buf + 1 + offset_table[png_ptr->pass]* + pixel_bytes; + dstptr = row + offset_table[png_ptr->pass]*pixel_bytes; + initial_val = offset_table[png_ptr->pass]*pixel_bytes; + final_val = png_ptr->width*pixel_bytes; + incr1 = (disp)*pixel_bytes; + for (i = initial_val; i < final_val; i += incr1) + { + png_memcpy(dstptr, srcptr, pixel_bytes); + srcptr += incr1; + dstptr += incr1; + } + } /* end of else */ + + break; + } // end 48 bpp + + default: + { + png_bytep sptr; + png_bytep dp; + png_size_t pixel_bytes; + int offset_table[7] = {0, 4, 0, 2, 0, 1, 0}; + unsigned int i; + register int disp = png_pass_inc[png_ptr->pass]; // get the offset + register unsigned int incr1, initial_val, final_val; + + pixel_bytes = (png_ptr->row_info.pixel_depth >> 3); + sptr = png_ptr->row_buf + 1 + offset_table[png_ptr->pass]* + pixel_bytes; + dp = row + offset_table[png_ptr->pass]*pixel_bytes; + initial_val = offset_table[png_ptr->pass]*pixel_bytes; + final_val = png_ptr->width*pixel_bytes; + incr1 = (disp)*pixel_bytes; + for (i = initial_val; i < final_val; i += incr1) + { + png_memcpy(dp, sptr, pixel_bytes); + sptr += incr1; + dp += incr1; + } + break; + } + } /* end switch (png_ptr->row_info.pixel_depth) */ + } /* end if (non-trivial mask) */ + +} /* end png_combine_row() */ + + +#if defined(PNG_READ_INTERLACING_SUPPORTED) + +void /* PRIVATE */ +png_do_read_interlace(png_structp png_ptr) +{ + png_row_infop row_info = &(png_ptr->row_info); + png_bytep row = png_ptr->row_buf + 1; + int pass = png_ptr->pass; + png_uint_32 transformations = png_ptr->transformations; +#ifdef PNG_USE_LOCAL_ARRAYS + const int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; +#endif + + png_debug(1,"in png_do_read_interlace\n"); + + if (mmx_supported == 2) { +#if !defined(PNG_1_0_X) + /* this should have happened in png_init_mmx_flags() already */ + png_warning(png_ptr, "asm_flags may not have been initialized"); +#endif + png_mmx_support(); + } + + if (row != NULL && row_info != NULL) + { + png_uint_32 final_width; + + final_width = row_info->width * png_pass_inc[pass]; + + switch (row_info->pixel_depth) + { + case 1: + { + png_bytep sp, dp; + int sshift, dshift; + int s_start, s_end, s_inc; + png_byte v; + png_uint_32 i; + int j; + + sp = row + (png_size_t)((row_info->width - 1) >> 3); + dp = row + (png_size_t)((final_width - 1) >> 3); +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (transformations & PNG_PACKSWAP) + { + sshift = (int)((row_info->width + 7) & 7); + dshift = (int)((final_width + 7) & 7); + s_start = 7; + s_end = 0; + s_inc = -1; + } + else +#endif + { + sshift = 7 - (int)((row_info->width + 7) & 7); + dshift = 7 - (int)((final_width + 7) & 7); + s_start = 0; + s_end = 7; + s_inc = 1; + } + + for (i = row_info->width; i; i--) + { + v = (png_byte)((*sp >> sshift) & 0x1); + for (j = 0; j < png_pass_inc[pass]; j++) + { + *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff); + *dp |= (png_byte)(v << dshift); + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + else + dshift += s_inc; + } + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + else + sshift += s_inc; + } + break; + } + + case 2: + { + png_bytep sp, dp; + int sshift, dshift; + int s_start, s_end, s_inc; + png_uint_32 i; + + sp = row + (png_size_t)((row_info->width - 1) >> 2); + dp = row + (png_size_t)((final_width - 1) >> 2); +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (transformations & PNG_PACKSWAP) + { + sshift = (png_size_t)(((row_info->width + 3) & 3) << 1); + dshift = (png_size_t)(((final_width + 3) & 3) << 1); + s_start = 6; + s_end = 0; + s_inc = -2; + } + else +#endif + { + sshift = (png_size_t)((3 - ((row_info->width + 3) & 3)) << 1); + dshift = (png_size_t)((3 - ((final_width + 3) & 3)) << 1); + s_start = 0; + s_end = 6; + s_inc = 2; + } + + for (i = row_info->width; i; i--) + { + png_byte v; + int j; + + v = (png_byte)((*sp >> sshift) & 0x3); + for (j = 0; j < png_pass_inc[pass]; j++) + { + *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff); + *dp |= (png_byte)(v << dshift); + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + else + dshift += s_inc; + } + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + else + sshift += s_inc; + } + break; + } + + case 4: + { + png_bytep sp, dp; + int sshift, dshift; + int s_start, s_end, s_inc; + png_uint_32 i; + + sp = row + (png_size_t)((row_info->width - 1) >> 1); + dp = row + (png_size_t)((final_width - 1) >> 1); +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (transformations & PNG_PACKSWAP) + { + sshift = (png_size_t)(((row_info->width + 1) & 1) << 2); + dshift = (png_size_t)(((final_width + 1) & 1) << 2); + s_start = 4; + s_end = 0; + s_inc = -4; + } + else +#endif + { + sshift = (png_size_t)((1 - ((row_info->width + 1) & 1)) << 2); + dshift = (png_size_t)((1 - ((final_width + 1) & 1)) << 2); + s_start = 0; + s_end = 4; + s_inc = 4; + } + + for (i = row_info->width; i; i--) + { + png_byte v; + int j; + + v = (png_byte)((*sp >> sshift) & 0xf); + for (j = 0; j < png_pass_inc[pass]; j++) + { + *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff); + *dp |= (png_byte)(v << dshift); + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + else + dshift += s_inc; + } + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + else + sshift += s_inc; + } + break; + } + + default: // This is the place where the routine is modified + { + __int64 const4 = 0x0000000000FFFFFF; + // __int64 const5 = 0x000000FFFFFF0000; // unused... + __int64 const6 = 0x00000000000000FF; + png_bytep sptr, dp; + png_uint_32 i; + png_size_t pixel_bytes; + int width = row_info->width; + + pixel_bytes = (row_info->pixel_depth >> 3); + + sptr = row + (width - 1) * pixel_bytes; + dp = row + (final_width - 1) * pixel_bytes; + // New code by Nirav Chhatrapati - Intel Corporation + // sign fix by GRR + // NOTE: there is NO MMX code for 48-bit and 64-bit images + + // use MMX routine if machine supports it +#if !defined(PNG_1_0_X) + if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_INTERLACE) + /* && mmx_supported */ ) +#else + if (mmx_supported) +#endif + { + if (pixel_bytes == 3) + { + if (((pass == 0) || (pass == 1)) && width) + { + _asm + { + mov esi, sptr + mov edi, dp + mov ecx, width + sub edi, 21 // (png_pass_inc[pass] - 1)*pixel_bytes +loop_pass0: + movd mm0, [esi] ; X X X X X v2 v1 v0 + pand mm0, const4 ; 0 0 0 0 0 v2 v1 v0 + movq mm1, mm0 ; 0 0 0 0 0 v2 v1 v0 + psllq mm0, 16 ; 0 0 0 v2 v1 v0 0 0 + movq mm2, mm0 ; 0 0 0 v2 v1 v0 0 0 + psllq mm0, 24 ; v2 v1 v0 0 0 0 0 0 + psrlq mm1, 8 ; 0 0 0 0 0 0 v2 v1 + por mm0, mm2 ; v2 v1 v0 v2 v1 v0 0 0 + por mm0, mm1 ; v2 v1 v0 v2 v1 v0 v2 v1 + movq mm3, mm0 ; v2 v1 v0 v2 v1 v0 v2 v1 + psllq mm0, 16 ; v0 v2 v1 v0 v2 v1 0 0 + movq mm4, mm3 ; v2 v1 v0 v2 v1 v0 v2 v1 + punpckhdq mm3, mm0 ; v0 v2 v1 v0 v2 v1 v0 v2 + movq [edi+16] , mm4 + psrlq mm0, 32 ; 0 0 0 0 v0 v2 v1 v0 + movq [edi+8] , mm3 + punpckldq mm0, mm4 ; v1 v0 v2 v1 v0 v2 v1 v0 + sub esi, 3 + movq [edi], mm0 + sub edi, 24 + //sub esi, 3 + dec ecx + jnz loop_pass0 + EMMS + } + } + else if (((pass == 2) || (pass == 3)) && width) + { + _asm + { + mov esi, sptr + mov edi, dp + mov ecx, width + sub edi, 9 // (png_pass_inc[pass] - 1)*pixel_bytes +loop_pass2: + movd mm0, [esi] ; X X X X X v2 v1 v0 + pand mm0, const4 ; 0 0 0 0 0 v2 v1 v0 + movq mm1, mm0 ; 0 0 0 0 0 v2 v1 v0 + psllq mm0, 16 ; 0 0 0 v2 v1 v0 0 0 + movq mm2, mm0 ; 0 0 0 v2 v1 v0 0 0 + psllq mm0, 24 ; v2 v1 v0 0 0 0 0 0 + psrlq mm1, 8 ; 0 0 0 0 0 0 v2 v1 + por mm0, mm2 ; v2 v1 v0 v2 v1 v0 0 0 + por mm0, mm1 ; v2 v1 v0 v2 v1 v0 v2 v1 + movq [edi+4], mm0 ; move to memory + psrlq mm0, 16 ; 0 0 v2 v1 v0 v2 v1 v0 + movd [edi], mm0 ; move to memory + sub esi, 3 + sub edi, 12 + dec ecx + jnz loop_pass2 + EMMS + } + } + else if (width) /* && ((pass == 4) || (pass == 5)) */ + { + int width_mmx = ((width >> 1) << 1) - 8; + if (width_mmx < 0) + width_mmx = 0; + width -= width_mmx; // 8 or 9 pix, 24 or 27 bytes + if (width_mmx) + { + _asm + { + mov esi, sptr + mov edi, dp + mov ecx, width_mmx + sub esi, 3 + sub edi, 9 +loop_pass4: + movq mm0, [esi] ; X X v2 v1 v0 v5 v4 v3 + movq mm7, mm0 ; X X v2 v1 v0 v5 v4 v3 + movq mm6, mm0 ; X X v2 v1 v0 v5 v4 v3 + psllq mm0, 24 ; v1 v0 v5 v4 v3 0 0 0 + pand mm7, const4 ; 0 0 0 0 0 v5 v4 v3 + psrlq mm6, 24 ; 0 0 0 X X v2 v1 v0 + por mm0, mm7 ; v1 v0 v5 v4 v3 v5 v4 v3 + movq mm5, mm6 ; 0 0 0 X X v2 v1 v0 + psllq mm6, 8 ; 0 0 X X v2 v1 v0 0 + movq [edi], mm0 ; move quad to memory + psrlq mm5, 16 ; 0 0 0 0 0 X X v2 + pand mm5, const6 ; 0 0 0 0 0 0 0 v2 + por mm6, mm5 ; 0 0 X X v2 v1 v0 v2 + movd [edi+8], mm6 ; move double to memory + sub esi, 6 + sub edi, 12 + sub ecx, 2 + jnz loop_pass4 + EMMS + } + } + + sptr -= width_mmx*3; + dp -= width_mmx*6; + for (i = width; i; i--) + { + png_byte v[8]; + int j; + + png_memcpy(v, sptr, 3); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, 3); + dp -= 3; + } + sptr -= 3; + } + } + } /* end of pixel_bytes == 3 */ + + else if (pixel_bytes == 1) + { + if (((pass == 0) || (pass == 1)) && width) + { + int width_mmx = ((width >> 2) << 2); + width -= width_mmx; + if (width_mmx) + { + _asm + { + mov esi, sptr + mov edi, dp + mov ecx, width_mmx + sub edi, 31 + sub esi, 3 +loop1_pass0: + movd mm0, [esi] ; X X X X v0 v1 v2 v3 + movq mm1, mm0 ; X X X X v0 v1 v2 v3 + punpcklbw mm0, mm0 ; v0 v0 v1 v1 v2 v2 v3 v3 + movq mm2, mm0 ; v0 v0 v1 v1 v2 v2 v3 v3 + punpcklwd mm0, mm0 ; v2 v2 v2 v2 v3 v3 v3 v3 + movq mm3, mm0 ; v2 v2 v2 v2 v3 v3 v3 v3 + punpckldq mm0, mm0 ; v3 v3 v3 v3 v3 v3 v3 v3 + punpckhdq mm3, mm3 ; v2 v2 v2 v2 v2 v2 v2 v2 + movq [edi], mm0 ; move to memory v3 + punpckhwd mm2, mm2 ; v0 v0 v0 v0 v1 v1 v1 v1 + movq [edi+8], mm3 ; move to memory v2 + movq mm4, mm2 ; v0 v0 v0 v0 v1 v1 v1 v1 + punpckldq mm2, mm2 ; v1 v1 v1 v1 v1 v1 v1 v1 + punpckhdq mm4, mm4 ; v0 v0 v0 v0 v0 v0 v0 v0 + movq [edi+16], mm2 ; move to memory v1 + movq [edi+24], mm4 ; move to memory v0 + sub esi, 4 + sub edi, 32 + sub ecx, 4 + jnz loop1_pass0 + EMMS + } + } + + sptr -= width_mmx; + dp -= width_mmx*8; + for (i = width; i; i--) + { + int j; + + /* I simplified this part in version 1.0.4e + * here and in several other instances where + * pixel_bytes == 1 -- GR-P + * + * Original code: + * + * png_byte v[8]; + * png_memcpy(v, sptr, pixel_bytes); + * for (j = 0; j < png_pass_inc[pass]; j++) + * { + * png_memcpy(dp, v, pixel_bytes); + * dp -= pixel_bytes; + * } + * sptr -= pixel_bytes; + * + * Replacement code is in the next three lines: + */ + + for (j = 0; j < png_pass_inc[pass]; j++) + *dp-- = *sptr; + sptr--; + } + } + else if (((pass == 2) || (pass == 3)) && width) + { + int width_mmx = ((width >> 2) << 2); + width -= width_mmx; + if (width_mmx) + { + _asm + { + mov esi, sptr + mov edi, dp + mov ecx, width_mmx + sub edi, 15 + sub esi, 3 +loop1_pass2: + movd mm0, [esi] ; X X X X v0 v1 v2 v3 + punpcklbw mm0, mm0 ; v0 v0 v1 v1 v2 v2 v3 v3 + movq mm1, mm0 ; v0 v0 v1 v1 v2 v2 v3 v3 + punpcklwd mm0, mm0 ; v2 v2 v2 v2 v3 v3 v3 v3 + punpckhwd mm1, mm1 ; v0 v0 v0 v0 v1 v1 v1 v1 + movq [edi], mm0 ; move to memory v2 and v3 + sub esi, 4 + movq [edi+8], mm1 ; move to memory v1 and v0 + sub edi, 16 + sub ecx, 4 + jnz loop1_pass2 + EMMS + } + } + + sptr -= width_mmx; + dp -= width_mmx*4; + for (i = width; i; i--) + { + int j; + + for (j = 0; j < png_pass_inc[pass]; j++) + { + *dp-- = *sptr; + } + sptr --; + } + } + else if (width) /* && ((pass == 4) || (pass == 5))) */ + { + int width_mmx = ((width >> 3) << 3); + width -= width_mmx; + if (width_mmx) + { + _asm + { + mov esi, sptr + mov edi, dp + mov ecx, width_mmx + sub edi, 15 + sub esi, 7 +loop1_pass4: + movq mm0, [esi] ; v0 v1 v2 v3 v4 v5 v6 v7 + movq mm1, mm0 ; v0 v1 v2 v3 v4 v5 v6 v7 + punpcklbw mm0, mm0 ; v4 v4 v5 v5 v6 v6 v7 v7 + //movq mm1, mm0 ; v0 v0 v1 v1 v2 v2 v3 v3 + punpckhbw mm1, mm1 ;v0 v0 v1 v1 v2 v2 v3 v3 + movq [edi+8], mm1 ; move to memory v0 v1 v2 and v3 + sub esi, 8 + movq [edi], mm0 ; move to memory v4 v5 v6 and v7 + //sub esi, 4 + sub edi, 16 + sub ecx, 8 + jnz loop1_pass4 + EMMS + } + } + + sptr -= width_mmx; + dp -= width_mmx*2; + for (i = width; i; i--) + { + int j; + + for (j = 0; j < png_pass_inc[pass]; j++) + { + *dp-- = *sptr; + } + sptr --; + } + } + } /* end of pixel_bytes == 1 */ + + else if (pixel_bytes == 2) + { + if (((pass == 0) || (pass == 1)) && width) + { + int width_mmx = ((width >> 1) << 1); + width -= width_mmx; + if (width_mmx) + { + _asm + { + mov esi, sptr + mov edi, dp + mov ecx, width_mmx + sub esi, 2 + sub edi, 30 +loop2_pass0: + movd mm0, [esi] ; X X X X v1 v0 v3 v2 + punpcklwd mm0, mm0 ; v1 v0 v1 v0 v3 v2 v3 v2 + movq mm1, mm0 ; v1 v0 v1 v0 v3 v2 v3 v2 + punpckldq mm0, mm0 ; v3 v2 v3 v2 v3 v2 v3 v2 + punpckhdq mm1, mm1 ; v1 v0 v1 v0 v1 v0 v1 v0 + movq [edi], mm0 + movq [edi + 8], mm0 + movq [edi + 16], mm1 + movq [edi + 24], mm1 + sub esi, 4 + sub edi, 32 + sub ecx, 2 + jnz loop2_pass0 + EMMS + } + } + + sptr -= (width_mmx*2 - 2); // sign fixed + dp -= (width_mmx*16 - 2); // sign fixed + for (i = width; i; i--) + { + png_byte v[8]; + int j; + sptr -= 2; + png_memcpy(v, sptr, 2); + for (j = 0; j < png_pass_inc[pass]; j++) + { + dp -= 2; + png_memcpy(dp, v, 2); + } + } + } + else if (((pass == 2) || (pass == 3)) && width) + { + int width_mmx = ((width >> 1) << 1) ; + width -= width_mmx; + if (width_mmx) + { + _asm + { + mov esi, sptr + mov edi, dp + mov ecx, width_mmx + sub esi, 2 + sub edi, 14 +loop2_pass2: + movd mm0, [esi] ; X X X X v1 v0 v3 v2 + punpcklwd mm0, mm0 ; v1 v0 v1 v0 v3 v2 v3 v2 + movq mm1, mm0 ; v1 v0 v1 v0 v3 v2 v3 v2 + punpckldq mm0, mm0 ; v3 v2 v3 v2 v3 v2 v3 v2 + punpckhdq mm1, mm1 ; v1 v0 v1 v0 v1 v0 v1 v0 + movq [edi], mm0 + sub esi, 4 + movq [edi + 8], mm1 + //sub esi, 4 + sub edi, 16 + sub ecx, 2 + jnz loop2_pass2 + EMMS + } + } + + sptr -= (width_mmx*2 - 2); // sign fixed + dp -= (width_mmx*8 - 2); // sign fixed + for (i = width; i; i--) + { + png_byte v[8]; + int j; + sptr -= 2; + png_memcpy(v, sptr, 2); + for (j = 0; j < png_pass_inc[pass]; j++) + { + dp -= 2; + png_memcpy(dp, v, 2); + } + } + } + else if (width) // pass == 4 or 5 + { + int width_mmx = ((width >> 1) << 1) ; + width -= width_mmx; + if (width_mmx) + { + _asm + { + mov esi, sptr + mov edi, dp + mov ecx, width_mmx + sub esi, 2 + sub edi, 6 +loop2_pass4: + movd mm0, [esi] ; X X X X v1 v0 v3 v2 + punpcklwd mm0, mm0 ; v1 v0 v1 v0 v3 v2 v3 v2 + sub esi, 4 + movq [edi], mm0 + sub edi, 8 + sub ecx, 2 + jnz loop2_pass4 + EMMS + } + } + + sptr -= (width_mmx*2 - 2); // sign fixed + dp -= (width_mmx*4 - 2); // sign fixed + for (i = width; i; i--) + { + png_byte v[8]; + int j; + sptr -= 2; + png_memcpy(v, sptr, 2); + for (j = 0; j < png_pass_inc[pass]; j++) + { + dp -= 2; + png_memcpy(dp, v, 2); + } + } + } + } /* end of pixel_bytes == 2 */ + + else if (pixel_bytes == 4) + { + if (((pass == 0) || (pass == 1)) && width) + { + int width_mmx = ((width >> 1) << 1) ; + width -= width_mmx; + if (width_mmx) + { + _asm + { + mov esi, sptr + mov edi, dp + mov ecx, width_mmx + sub esi, 4 + sub edi, 60 +loop4_pass0: + movq mm0, [esi] ; v3 v2 v1 v0 v7 v6 v5 v4 + movq mm1, mm0 ; v3 v2 v1 v0 v7 v6 v5 v4 + punpckldq mm0, mm0 ; v7 v6 v5 v4 v7 v6 v5 v4 + punpckhdq mm1, mm1 ; v3 v2 v1 v0 v3 v2 v1 v0 + movq [edi], mm0 + movq [edi + 8], mm0 + movq [edi + 16], mm0 + movq [edi + 24], mm0 + movq [edi+32], mm1 + movq [edi + 40], mm1 + movq [edi+ 48], mm1 + sub esi, 8 + movq [edi + 56], mm1 + sub edi, 64 + sub ecx, 2 + jnz loop4_pass0 + EMMS + } + } + + sptr -= (width_mmx*4 - 4); // sign fixed + dp -= (width_mmx*32 - 4); // sign fixed + for (i = width; i; i--) + { + png_byte v[8]; + int j; + sptr -= 4; + png_memcpy(v, sptr, 4); + for (j = 0; j < png_pass_inc[pass]; j++) + { + dp -= 4; + png_memcpy(dp, v, 4); + } + } + } + else if (((pass == 2) || (pass == 3)) && width) + { + int width_mmx = ((width >> 1) << 1) ; + width -= width_mmx; + if (width_mmx) + { + _asm + { + mov esi, sptr + mov edi, dp + mov ecx, width_mmx + sub esi, 4 + sub edi, 28 +loop4_pass2: + movq mm0, [esi] ; v3 v2 v1 v0 v7 v6 v5 v4 + movq mm1, mm0 ; v3 v2 v1 v0 v7 v6 v5 v4 + punpckldq mm0, mm0 ; v7 v6 v5 v4 v7 v6 v5 v4 + punpckhdq mm1, mm1 ; v3 v2 v1 v0 v3 v2 v1 v0 + movq [edi], mm0 + movq [edi + 8], mm0 + movq [edi+16], mm1 + movq [edi + 24], mm1 + sub esi, 8 + sub edi, 32 + sub ecx, 2 + jnz loop4_pass2 + EMMS + } + } + + sptr -= (width_mmx*4 - 4); // sign fixed + dp -= (width_mmx*16 - 4); // sign fixed + for (i = width; i; i--) + { + png_byte v[8]; + int j; + sptr -= 4; + png_memcpy(v, sptr, 4); + for (j = 0; j < png_pass_inc[pass]; j++) + { + dp -= 4; + png_memcpy(dp, v, 4); + } + } + } + else if (width) // pass == 4 or 5 + { + int width_mmx = ((width >> 1) << 1) ; + width -= width_mmx; + if (width_mmx) + { + _asm + { + mov esi, sptr + mov edi, dp + mov ecx, width_mmx + sub esi, 4 + sub edi, 12 +loop4_pass4: + movq mm0, [esi] ; v3 v2 v1 v0 v7 v6 v5 v4 + movq mm1, mm0 ; v3 v2 v1 v0 v7 v6 v5 v4 + punpckldq mm0, mm0 ; v7 v6 v5 v4 v7 v6 v5 v4 + punpckhdq mm1, mm1 ; v3 v2 v1 v0 v3 v2 v1 v0 + movq [edi], mm0 + sub esi, 8 + movq [edi + 8], mm1 + sub edi, 16 + sub ecx, 2 + jnz loop4_pass4 + EMMS + } + } + + sptr -= (width_mmx*4 - 4); // sign fixed + dp -= (width_mmx*8 - 4); // sign fixed + for (i = width; i; i--) + { + png_byte v[8]; + int j; + sptr -= 4; + png_memcpy(v, sptr, 4); + for (j = 0; j < png_pass_inc[pass]; j++) + { + dp -= 4; + png_memcpy(dp, v, 4); + } + } + } + + } /* end of pixel_bytes == 4 */ + + else if (pixel_bytes == 6) + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, 6); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, 6); + dp -= 6; + } + sptr -= 6; + } + } /* end of pixel_bytes == 6 */ + + else + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, pixel_bytes); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, pixel_bytes); + dp -= pixel_bytes; + } + sptr-= pixel_bytes; + } + } + } /* end of mmx_supported */ + + else /* MMX not supported: use modified C code - takes advantage + * of inlining of memcpy for a constant */ + { + if (pixel_bytes == 1) + { + for (i = width; i; i--) + { + int j; + for (j = 0; j < png_pass_inc[pass]; j++) + *dp-- = *sptr; + sptr--; + } + } + else if (pixel_bytes == 3) + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, pixel_bytes); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, pixel_bytes); + dp -= pixel_bytes; + } + sptr -= pixel_bytes; + } + } + else if (pixel_bytes == 2) + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, pixel_bytes); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, pixel_bytes); + dp -= pixel_bytes; + } + sptr -= pixel_bytes; + } + } + else if (pixel_bytes == 4) + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, pixel_bytes); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, pixel_bytes); + dp -= pixel_bytes; + } + sptr -= pixel_bytes; + } + } + else if (pixel_bytes == 6) + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, pixel_bytes); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, pixel_bytes); + dp -= pixel_bytes; + } + sptr -= pixel_bytes; + } + } + else + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, pixel_bytes); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, pixel_bytes); + dp -= pixel_bytes; + } + sptr -= pixel_bytes; + } + } + + } /* end of MMX not supported */ + break; + } + } /* end switch (row_info->pixel_depth) */ + + row_info->width = final_width; + + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,final_width); + } + +} + +#endif /* PNG_READ_INTERLACING_SUPPORTED */ + + +// These variables are utilized in the functions below. They are declared +// globally here to ensure alignment on 8-byte boundaries. + +union uAll { + __int64 use; + double align; +} LBCarryMask = {0x0101010101010101}, + HBClearMask = {0x7f7f7f7f7f7f7f7f}, + ActiveMask, ActiveMask2, ActiveMaskEnd, ShiftBpp, ShiftRem; + + +// Optimized code for PNG Average filter decoder +void /* PRIVATE */ +png_read_filter_row_mmx_avg(png_row_infop row_info, png_bytep row + , png_bytep prev_row) +{ + int bpp; + png_uint_32 FullLength; + png_uint_32 MMXLength; + //png_uint_32 len; + int diff; + + bpp = (row_info->pixel_depth + 7) >> 3; // Get # bytes per pixel + FullLength = row_info->rowbytes; // # of bytes to filter + _asm { + // Init address pointers and offset + mov edi, row // edi ==> Avg(x) + xor ebx, ebx // ebx ==> x + mov edx, edi + mov esi, prev_row // esi ==> Prior(x) + sub edx, bpp // edx ==> Raw(x-bpp) + + xor eax, eax + // Compute the Raw value for the first bpp bytes + // Raw(x) = Avg(x) + (Prior(x)/2) +davgrlp: + mov al, [esi + ebx] // Load al with Prior(x) + inc ebx + shr al, 1 // divide by 2 + add al, [edi+ebx-1] // Add Avg(x); -1 to offset inc ebx + cmp ebx, bpp + mov [edi+ebx-1], al // Write back Raw(x); + // mov does not affect flags; -1 to offset inc ebx + jb davgrlp + // get # of bytes to alignment + mov diff, edi // take start of row + add diff, ebx // add bpp + add diff, 0xf // add 7 + 8 to incr past alignment boundary + and diff, 0xfffffff8 // mask to alignment boundary + sub diff, edi // subtract from start ==> value ebx at alignment + jz davggo + // fix alignment + // Compute the Raw value for the bytes upto the alignment boundary + // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2) + xor ecx, ecx +davglp1: + xor eax, eax + mov cl, [esi + ebx] // load cl with Prior(x) + mov al, [edx + ebx] // load al with Raw(x-bpp) + add ax, cx + inc ebx + shr ax, 1 // divide by 2 + add al, [edi+ebx-1] // Add Avg(x); -1 to offset inc ebx + cmp ebx, diff // Check if at alignment boundary + mov [edi+ebx-1], al // Write back Raw(x); + // mov does not affect flags; -1 to offset inc ebx + jb davglp1 // Repeat until at alignment boundary +davggo: + mov eax, FullLength + mov ecx, eax + sub eax, ebx // subtract alignment fix + and eax, 0x00000007 // calc bytes over mult of 8 + sub ecx, eax // drop over bytes from original length + mov MMXLength, ecx + } // end _asm block + // Now do the math for the rest of the row + switch ( bpp ) + { + case 3: + { + ActiveMask.use = 0x0000000000ffffff; + ShiftBpp.use = 24; // == 3 * 8 + ShiftRem.use = 40; // == 64 - 24 + _asm { + // Re-init address pointers and offset + movq mm7, ActiveMask + mov ebx, diff // ebx ==> x = offset to alignment boundary + movq mm5, LBCarryMask + mov edi, row // edi ==> Avg(x) + movq mm4, HBClearMask + mov esi, prev_row // esi ==> Prior(x) + // PRIME the pump (load the first Raw(x-bpp) data set + movq mm2, [edi + ebx - 8] // Load previous aligned 8 bytes + // (we correct position in loop below) +davg3lp: + movq mm0, [edi + ebx] // Load mm0 with Avg(x) + // Add (Prev_row/2) to Average + movq mm3, mm5 + psrlq mm2, ShiftRem // Correct position Raw(x-bpp) data + movq mm1, [esi + ebx] // Load mm1 with Prior(x) + movq mm6, mm7 + pand mm3, mm1 // get lsb for each prev_row byte + psrlq mm1, 1 // divide prev_row bytes by 2 + pand mm1, mm4 // clear invalid bit 7 of each byte + paddb mm0, mm1 // add (Prev_row/2) to Avg for each byte + // Add 1st active group (Raw(x-bpp)/2) to Average with LBCarry + movq mm1, mm3 // now use mm1 for getting LBCarrys + pand mm1, mm2 // get LBCarrys for each byte where both + // lsb's were == 1 (Only valid for active group) + psrlq mm2, 1 // divide raw bytes by 2 + pand mm2, mm4 // clear invalid bit 7 of each byte + paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte + pand mm2, mm6 // Leave only Active Group 1 bytes to add to Avg + paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active + // byte + // Add 2nd active group (Raw(x-bpp)/2) to Average with LBCarry + psllq mm6, ShiftBpp // shift the mm6 mask to cover bytes 3-5 + movq mm2, mm0 // mov updated Raws to mm2 + psllq mm2, ShiftBpp // shift data to position correctly + movq mm1, mm3 // now use mm1 for getting LBCarrys + pand mm1, mm2 // get LBCarrys for each byte where both + // lsb's were == 1 (Only valid for active group) + psrlq mm2, 1 // divide raw bytes by 2 + pand mm2, mm4 // clear invalid bit 7 of each byte + paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte + pand mm2, mm6 // Leave only Active Group 2 bytes to add to Avg + paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active + // byte + + // Add 3rd active group (Raw(x-bpp)/2) to Average with LBCarry + psllq mm6, ShiftBpp // shift the mm6 mask to cover the last two + // bytes + movq mm2, mm0 // mov updated Raws to mm2 + psllq mm2, ShiftBpp // shift data to position correctly + // Data only needs to be shifted once here to + // get the correct x-bpp offset. + movq mm1, mm3 // now use mm1 for getting LBCarrys + pand mm1, mm2 // get LBCarrys for each byte where both + // lsb's were == 1 (Only valid for active group) + psrlq mm2, 1 // divide raw bytes by 2 + pand mm2, mm4 // clear invalid bit 7 of each byte + paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte + pand mm2, mm6 // Leave only Active Group 2 bytes to add to Avg + add ebx, 8 + paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active + // byte + + // Now ready to write back to memory + movq [edi + ebx - 8], mm0 + // Move updated Raw(x) to use as Raw(x-bpp) for next loop + cmp ebx, MMXLength + movq mm2, mm0 // mov updated Raw(x) to mm2 + jb davg3lp + } // end _asm block + } + break; + + case 6: + case 4: + case 7: + case 5: + { + ActiveMask.use = 0xffffffffffffffff; // use shift below to clear + // appropriate inactive bytes + ShiftBpp.use = bpp << 3; + ShiftRem.use = 64 - ShiftBpp.use; + _asm { + movq mm4, HBClearMask + // Re-init address pointers and offset + mov ebx, diff // ebx ==> x = offset to alignment boundary + // Load ActiveMask and clear all bytes except for 1st active group + movq mm7, ActiveMask + mov edi, row // edi ==> Avg(x) + psrlq mm7, ShiftRem + mov esi, prev_row // esi ==> Prior(x) + movq mm6, mm7 + movq mm5, LBCarryMask + psllq mm6, ShiftBpp // Create mask for 2nd active group + // PRIME the pump (load the first Raw(x-bpp) data set + movq mm2, [edi + ebx - 8] // Load previous aligned 8 bytes + // (we correct position in loop below) +davg4lp: + movq mm0, [edi + ebx] + psrlq mm2, ShiftRem // shift data to position correctly + movq mm1, [esi + ebx] + // Add (Prev_row/2) to Average + movq mm3, mm5 + pand mm3, mm1 // get lsb for each prev_row byte + psrlq mm1, 1 // divide prev_row bytes by 2 + pand mm1, mm4 // clear invalid bit 7 of each byte + paddb mm0, mm1 // add (Prev_row/2) to Avg for each byte + // Add 1st active group (Raw(x-bpp)/2) to Average with LBCarry + movq mm1, mm3 // now use mm1 for getting LBCarrys + pand mm1, mm2 // get LBCarrys for each byte where both + // lsb's were == 1 (Only valid for active group) + psrlq mm2, 1 // divide raw bytes by 2 + pand mm2, mm4 // clear invalid bit 7 of each byte + paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte + pand mm2, mm7 // Leave only Active Group 1 bytes to add to Avg + paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active + // byte + // Add 2nd active group (Raw(x-bpp)/2) to Average with LBCarry + movq mm2, mm0 // mov updated Raws to mm2 + psllq mm2, ShiftBpp // shift data to position correctly + add ebx, 8 + movq mm1, mm3 // now use mm1 for getting LBCarrys + pand mm1, mm2 // get LBCarrys for each byte where both + // lsb's were == 1 (Only valid for active group) + psrlq mm2, 1 // divide raw bytes by 2 + pand mm2, mm4 // clear invalid bit 7 of each byte + paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte + pand mm2, mm6 // Leave only Active Group 2 bytes to add to Avg + paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active + // byte + cmp ebx, MMXLength + // Now ready to write back to memory + movq [edi + ebx - 8], mm0 + // Prep Raw(x-bpp) for next loop + movq mm2, mm0 // mov updated Raws to mm2 + jb davg4lp + } // end _asm block + } + break; + case 2: + { + ActiveMask.use = 0x000000000000ffff; + ShiftBpp.use = 16; // == 2 * 8 [BUGFIX] + ShiftRem.use = 48; // == 64 - 16 [BUGFIX] + _asm { + // Load ActiveMask + movq mm7, ActiveMask + // Re-init address pointers and offset + mov ebx, diff // ebx ==> x = offset to alignment boundary + movq mm5, LBCarryMask + mov edi, row // edi ==> Avg(x) + movq mm4, HBClearMask + mov esi, prev_row // esi ==> Prior(x) + // PRIME the pump (load the first Raw(x-bpp) data set + movq mm2, [edi + ebx - 8] // Load previous aligned 8 bytes + // (we correct position in loop below) +davg2lp: + movq mm0, [edi + ebx] + psrlq mm2, ShiftRem // shift data to position correctly [BUGFIX] + movq mm1, [esi + ebx] + // Add (Prev_row/2) to Average + movq mm3, mm5 + pand mm3, mm1 // get lsb for each prev_row byte + psrlq mm1, 1 // divide prev_row bytes by 2 + pand mm1, mm4 // clear invalid bit 7 of each byte + movq mm6, mm7 + paddb mm0, mm1 // add (Prev_row/2) to Avg for each byte + // Add 1st active group (Raw(x-bpp)/2) to Average with LBCarry + movq mm1, mm3 // now use mm1 for getting LBCarrys + pand mm1, mm2 // get LBCarrys for each byte where both + // lsb's were == 1 (Only valid for active group) + psrlq mm2, 1 // divide raw bytes by 2 + pand mm2, mm4 // clear invalid bit 7 of each byte + paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte + pand mm2, mm6 // Leave only Active Group 1 bytes to add to Avg + paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active byte + // Add 2nd active group (Raw(x-bpp)/2) to Average with LBCarry + psllq mm6, ShiftBpp // shift the mm6 mask to cover bytes 2 & 3 + movq mm2, mm0 // mov updated Raws to mm2 + psllq mm2, ShiftBpp // shift data to position correctly + movq mm1, mm3 // now use mm1 for getting LBCarrys + pand mm1, mm2 // get LBCarrys for each byte where both + // lsb's were == 1 (Only valid for active group) + psrlq mm2, 1 // divide raw bytes by 2 + pand mm2, mm4 // clear invalid bit 7 of each byte + paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte + pand mm2, mm6 // Leave only Active Group 2 bytes to add to Avg + paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active byte + + // Add rdd active group (Raw(x-bpp)/2) to Average with LBCarry + psllq mm6, ShiftBpp // shift the mm6 mask to cover bytes 4 & 5 + movq mm2, mm0 // mov updated Raws to mm2 + psllq mm2, ShiftBpp // shift data to position correctly + // Data only needs to be shifted once here to + // get the correct x-bpp offset. + movq mm1, mm3 // now use mm1 for getting LBCarrys + pand mm1, mm2 // get LBCarrys for each byte where both + // lsb's were == 1 (Only valid for active group) + psrlq mm2, 1 // divide raw bytes by 2 + pand mm2, mm4 // clear invalid bit 7 of each byte + paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte + pand mm2, mm6 // Leave only Active Group 2 bytes to add to Avg + paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active byte + + // Add 4th active group (Raw(x-bpp)/2) to Average with LBCarry + psllq mm6, ShiftBpp // shift the mm6 mask to cover bytes 6 & 7 + movq mm2, mm0 // mov updated Raws to mm2 + psllq mm2, ShiftBpp // shift data to position correctly + // Data only needs to be shifted once here to + // get the correct x-bpp offset. + add ebx, 8 + movq mm1, mm3 // now use mm1 for getting LBCarrys + pand mm1, mm2 // get LBCarrys for each byte where both + // lsb's were == 1 (Only valid for active group) + psrlq mm2, 1 // divide raw bytes by 2 + pand mm2, mm4 // clear invalid bit 7 of each byte + paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte + pand mm2, mm6 // Leave only Active Group 2 bytes to add to Avg + paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active byte + + cmp ebx, MMXLength + // Now ready to write back to memory + movq [edi + ebx - 8], mm0 + // Prep Raw(x-bpp) for next loop + movq mm2, mm0 // mov updated Raws to mm2 + jb davg2lp + } // end _asm block + } + break; + + case 1: // bpp == 1 + { + _asm { + // Re-init address pointers and offset + mov ebx, diff // ebx ==> x = offset to alignment boundary + mov edi, row // edi ==> Avg(x) + cmp ebx, FullLength // Test if offset at end of array + jnb davg1end + // Do Paeth decode for remaining bytes + mov esi, prev_row // esi ==> Prior(x) + mov edx, edi + xor ecx, ecx // zero ecx before using cl & cx in loop below + sub edx, bpp // edx ==> Raw(x-bpp) +davg1lp: + // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2) + xor eax, eax + mov cl, [esi + ebx] // load cl with Prior(x) + mov al, [edx + ebx] // load al with Raw(x-bpp) + add ax, cx + inc ebx + shr ax, 1 // divide by 2 + add al, [edi+ebx-1] // Add Avg(x); -1 to offset inc ebx + cmp ebx, FullLength // Check if at end of array + mov [edi+ebx-1], al // Write back Raw(x); + // mov does not affect flags; -1 to offset inc ebx + jb davg1lp +davg1end: + } // end _asm block + } + return; + + case 8: // bpp == 8 + { + _asm { + // Re-init address pointers and offset + mov ebx, diff // ebx ==> x = offset to alignment boundary + movq mm5, LBCarryMask + mov edi, row // edi ==> Avg(x) + movq mm4, HBClearMask + mov esi, prev_row // esi ==> Prior(x) + // PRIME the pump (load the first Raw(x-bpp) data set + movq mm2, [edi + ebx - 8] // Load previous aligned 8 bytes + // (NO NEED to correct position in loop below) +davg8lp: + movq mm0, [edi + ebx] + movq mm3, mm5 + movq mm1, [esi + ebx] + add ebx, 8 + pand mm3, mm1 // get lsb for each prev_row byte + psrlq mm1, 1 // divide prev_row bytes by 2 + pand mm3, mm2 // get LBCarrys for each byte where both + // lsb's were == 1 + psrlq mm2, 1 // divide raw bytes by 2 + pand mm1, mm4 // clear invalid bit 7 of each byte + paddb mm0, mm3 // add LBCarrys to Avg for each byte + pand mm2, mm4 // clear invalid bit 7 of each byte + paddb mm0, mm1 // add (Prev_row/2) to Avg for each byte + paddb mm0, mm2 // add (Raw/2) to Avg for each byte + cmp ebx, MMXLength + movq [edi + ebx - 8], mm0 + movq mm2, mm0 // reuse as Raw(x-bpp) + jb davg8lp + } // end _asm block + } + break; + default: // bpp greater than 8 + { + _asm { + movq mm5, LBCarryMask + // Re-init address pointers and offset + mov ebx, diff // ebx ==> x = offset to alignment boundary + mov edi, row // edi ==> Avg(x) + movq mm4, HBClearMask + mov edx, edi + mov esi, prev_row // esi ==> Prior(x) + sub edx, bpp // edx ==> Raw(x-bpp) +davgAlp: + movq mm0, [edi + ebx] + movq mm3, mm5 + movq mm1, [esi + ebx] + pand mm3, mm1 // get lsb for each prev_row byte + movq mm2, [edx + ebx] + psrlq mm1, 1 // divide prev_row bytes by 2 + pand mm3, mm2 // get LBCarrys for each byte where both + // lsb's were == 1 + psrlq mm2, 1 // divide raw bytes by 2 + pand mm1, mm4 // clear invalid bit 7 of each byte + paddb mm0, mm3 // add LBCarrys to Avg for each byte + pand mm2, mm4 // clear invalid bit 7 of each byte + paddb mm0, mm1 // add (Prev_row/2) to Avg for each byte + add ebx, 8 + paddb mm0, mm2 // add (Raw/2) to Avg for each byte + cmp ebx, MMXLength + movq [edi + ebx - 8], mm0 + jb davgAlp + } // end _asm block + } + break; + } // end switch ( bpp ) + + _asm { + // MMX acceleration complete now do clean-up + // Check if any remaining bytes left to decode + mov ebx, MMXLength // ebx ==> x = offset bytes remaining after MMX + mov edi, row // edi ==> Avg(x) + cmp ebx, FullLength // Test if offset at end of array + jnb davgend + // Do Paeth decode for remaining bytes + mov esi, prev_row // esi ==> Prior(x) + mov edx, edi + xor ecx, ecx // zero ecx before using cl & cx in loop below + sub edx, bpp // edx ==> Raw(x-bpp) +davglp2: + // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2) + xor eax, eax + mov cl, [esi + ebx] // load cl with Prior(x) + mov al, [edx + ebx] // load al with Raw(x-bpp) + add ax, cx + inc ebx + shr ax, 1 // divide by 2 + add al, [edi+ebx-1] // Add Avg(x); -1 to offset inc ebx + cmp ebx, FullLength // Check if at end of array + mov [edi+ebx-1], al // Write back Raw(x); + // mov does not affect flags; -1 to offset inc ebx + jb davglp2 +davgend: + emms // End MMX instructions; prep for possible FP instrs. + } // end _asm block +} + +// Optimized code for PNG Paeth filter decoder +void /* PRIVATE */ +png_read_filter_row_mmx_paeth(png_row_infop row_info, png_bytep row, + png_bytep prev_row) +{ + png_uint_32 FullLength; + png_uint_32 MMXLength; + //png_uint_32 len; + int bpp; + int diff; + //int ptemp; + int patemp, pbtemp, pctemp; + + bpp = (row_info->pixel_depth + 7) >> 3; // Get # bytes per pixel + FullLength = row_info->rowbytes; // # of bytes to filter + _asm + { + xor ebx, ebx // ebx ==> x offset + mov edi, row + xor edx, edx // edx ==> x-bpp offset + mov esi, prev_row + xor eax, eax + + // Compute the Raw value for the first bpp bytes + // Note: the formula works out to be always + // Paeth(x) = Raw(x) + Prior(x) where x < bpp +dpthrlp: + mov al, [edi + ebx] + add al, [esi + ebx] + inc ebx + cmp ebx, bpp + mov [edi + ebx - 1], al + jb dpthrlp + // get # of bytes to alignment + mov diff, edi // take start of row + add diff, ebx // add bpp + xor ecx, ecx + add diff, 0xf // add 7 + 8 to incr past alignment boundary + and diff, 0xfffffff8 // mask to alignment boundary + sub diff, edi // subtract from start ==> value ebx at alignment + jz dpthgo + // fix alignment +dpthlp1: + xor eax, eax + // pav = p - a = (a + b - c) - a = b - c + mov al, [esi + ebx] // load Prior(x) into al + mov cl, [esi + edx] // load Prior(x-bpp) into cl + sub eax, ecx // subtract Prior(x-bpp) + mov patemp, eax // Save pav for later use + xor eax, eax + // pbv = p - b = (a + b - c) - b = a - c + mov al, [edi + edx] // load Raw(x-bpp) into al + sub eax, ecx // subtract Prior(x-bpp) + mov ecx, eax + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + add eax, patemp // pcv = pav + pbv + // pc = abs(pcv) + test eax, 0x80000000 + jz dpthpca + neg eax // reverse sign of neg values +dpthpca: + mov pctemp, eax // save pc for later use + // pb = abs(pbv) + test ecx, 0x80000000 + jz dpthpba + neg ecx // reverse sign of neg values +dpthpba: + mov pbtemp, ecx // save pb for later use + // pa = abs(pav) + mov eax, patemp + test eax, 0x80000000 + jz dpthpaa + neg eax // reverse sign of neg values +dpthpaa: + mov patemp, eax // save pa for later use + // test if pa <= pb + cmp eax, ecx + jna dpthabb + // pa > pb; now test if pb <= pc + cmp ecx, pctemp + jna dpthbbc + // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp) + mov cl, [esi + edx] // load Prior(x-bpp) into cl + jmp dpthpaeth +dpthbbc: + // pb <= pc; Raw(x) = Paeth(x) + Prior(x) + mov cl, [esi + ebx] // load Prior(x) into cl + jmp dpthpaeth +dpthabb: + // pa <= pb; now test if pa <= pc + cmp eax, pctemp + jna dpthabc + // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp) + mov cl, [esi + edx] // load Prior(x-bpp) into cl + jmp dpthpaeth +dpthabc: + // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp) + mov cl, [edi + edx] // load Raw(x-bpp) into cl +dpthpaeth: + inc ebx + inc edx + // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256 + add [edi + ebx - 1], cl + cmp ebx, diff + jb dpthlp1 +dpthgo: + mov ecx, FullLength + mov eax, ecx + sub eax, ebx // subtract alignment fix + and eax, 0x00000007 // calc bytes over mult of 8 + sub ecx, eax // drop over bytes from original length + mov MMXLength, ecx + } // end _asm block + // Now do the math for the rest of the row + switch ( bpp ) + { + case 3: + { + ActiveMask.use = 0x0000000000ffffff; + ActiveMaskEnd.use = 0xffff000000000000; + ShiftBpp.use = 24; // == bpp(3) * 8 + ShiftRem.use = 40; // == 64 - 24 + _asm + { + mov ebx, diff + mov edi, row + mov esi, prev_row + pxor mm0, mm0 + // PRIME the pump (load the first Raw(x-bpp) data set + movq mm1, [edi+ebx-8] +dpth3lp: + psrlq mm1, ShiftRem // shift last 3 bytes to 1st 3 bytes + movq mm2, [esi + ebx] // load b=Prior(x) + punpcklbw mm1, mm0 // Unpack High bytes of a + movq mm3, [esi+ebx-8] // Prep c=Prior(x-bpp) bytes + punpcklbw mm2, mm0 // Unpack High bytes of b + psrlq mm3, ShiftRem // shift last 3 bytes to 1st 3 bytes + // pav = p - a = (a + b - c) - a = b - c + movq mm4, mm2 + punpcklbw mm3, mm0 // Unpack High bytes of c + // pbv = p - b = (a + b - c) - b = a - c + movq mm5, mm1 + psubw mm4, mm3 + pxor mm7, mm7 + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + movq mm6, mm4 + psubw mm5, mm3 + + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + pcmpgtw mm0, mm4 // Create mask pav bytes < 0 + paddw mm6, mm5 + pand mm0, mm4 // Only pav bytes < 0 in mm7 + pcmpgtw mm7, mm5 // Create mask pbv bytes < 0 + psubw mm4, mm0 + pand mm7, mm5 // Only pbv bytes < 0 in mm0 + psubw mm4, mm0 + psubw mm5, mm7 + pxor mm0, mm0 + pcmpgtw mm0, mm6 // Create mask pcv bytes < 0 + pand mm0, mm6 // Only pav bytes < 0 in mm7 + psubw mm5, mm7 + psubw mm6, mm0 + // test pa <= pb + movq mm7, mm4 + psubw mm6, mm0 + pcmpgtw mm7, mm5 // pa > pb? + movq mm0, mm7 + // use mm7 mask to merge pa & pb + pand mm5, mm7 + // use mm0 mask copy to merge a & b + pand mm2, mm0 + pandn mm7, mm4 + pandn mm0, mm1 + paddw mm7, mm5 + paddw mm0, mm2 + // test ((pa <= pb)? pa:pb) <= pc + pcmpgtw mm7, mm6 // pab > pc? + pxor mm1, mm1 + pand mm3, mm7 + pandn mm7, mm0 + paddw mm7, mm3 + pxor mm0, mm0 + packuswb mm7, mm1 + movq mm3, [esi + ebx] // load c=Prior(x-bpp) + pand mm7, ActiveMask + movq mm2, mm3 // load b=Prior(x) step 1 + paddb mm7, [edi + ebx] // add Paeth predictor with Raw(x) + punpcklbw mm3, mm0 // Unpack High bytes of c + movq [edi + ebx], mm7 // write back updated value + movq mm1, mm7 // Now mm1 will be used as Raw(x-bpp) + // Now do Paeth for 2nd set of bytes (3-5) + psrlq mm2, ShiftBpp // load b=Prior(x) step 2 + punpcklbw mm1, mm0 // Unpack High bytes of a + pxor mm7, mm7 + punpcklbw mm2, mm0 // Unpack High bytes of b + // pbv = p - b = (a + b - c) - b = a - c + movq mm5, mm1 + // pav = p - a = (a + b - c) - a = b - c + movq mm4, mm2 + psubw mm5, mm3 + psubw mm4, mm3 + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = + // pav + pbv = pbv + pav + movq mm6, mm5 + paddw mm6, mm4 + + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + pcmpgtw mm0, mm5 // Create mask pbv bytes < 0 + pcmpgtw mm7, mm4 // Create mask pav bytes < 0 + pand mm0, mm5 // Only pbv bytes < 0 in mm0 + pand mm7, mm4 // Only pav bytes < 0 in mm7 + psubw mm5, mm0 + psubw mm4, mm7 + psubw mm5, mm0 + psubw mm4, mm7 + pxor mm0, mm0 + pcmpgtw mm0, mm6 // Create mask pcv bytes < 0 + pand mm0, mm6 // Only pav bytes < 0 in mm7 + psubw mm6, mm0 + // test pa <= pb + movq mm7, mm4 + psubw mm6, mm0 + pcmpgtw mm7, mm5 // pa > pb? + movq mm0, mm7 + // use mm7 mask to merge pa & pb + pand mm5, mm7 + // use mm0 mask copy to merge a & b + pand mm2, mm0 + pandn mm7, mm4 + pandn mm0, mm1 + paddw mm7, mm5 + paddw mm0, mm2 + // test ((pa <= pb)? pa:pb) <= pc + pcmpgtw mm7, mm6 // pab > pc? + movq mm2, [esi + ebx] // load b=Prior(x) + pand mm3, mm7 + pandn mm7, mm0 + pxor mm1, mm1 + paddw mm7, mm3 + pxor mm0, mm0 + packuswb mm7, mm1 + movq mm3, mm2 // load c=Prior(x-bpp) step 1 + pand mm7, ActiveMask + punpckhbw mm2, mm0 // Unpack High bytes of b + psllq mm7, ShiftBpp // Shift bytes to 2nd group of 3 bytes + // pav = p - a = (a + b - c) - a = b - c + movq mm4, mm2 + paddb mm7, [edi + ebx] // add Paeth predictor with Raw(x) + psllq mm3, ShiftBpp // load c=Prior(x-bpp) step 2 + movq [edi + ebx], mm7 // write back updated value + movq mm1, mm7 + punpckhbw mm3, mm0 // Unpack High bytes of c + psllq mm1, ShiftBpp // Shift bytes + // Now mm1 will be used as Raw(x-bpp) + // Now do Paeth for 3rd, and final, set of bytes (6-7) + pxor mm7, mm7 + punpckhbw mm1, mm0 // Unpack High bytes of a + psubw mm4, mm3 + // pbv = p - b = (a + b - c) - b = a - c + movq mm5, mm1 + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + movq mm6, mm4 + psubw mm5, mm3 + pxor mm0, mm0 + paddw mm6, mm5 + + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + pcmpgtw mm0, mm4 // Create mask pav bytes < 0 + pcmpgtw mm7, mm5 // Create mask pbv bytes < 0 + pand mm0, mm4 // Only pav bytes < 0 in mm7 + pand mm7, mm5 // Only pbv bytes < 0 in mm0 + psubw mm4, mm0 + psubw mm5, mm7 + psubw mm4, mm0 + psubw mm5, mm7 + pxor mm0, mm0 + pcmpgtw mm0, mm6 // Create mask pcv bytes < 0 + pand mm0, mm6 // Only pav bytes < 0 in mm7 + psubw mm6, mm0 + // test pa <= pb + movq mm7, mm4 + psubw mm6, mm0 + pcmpgtw mm7, mm5 // pa > pb? + movq mm0, mm7 + // use mm0 mask copy to merge a & b + pand mm2, mm0 + // use mm7 mask to merge pa & pb + pand mm5, mm7 + pandn mm0, mm1 + pandn mm7, mm4 + paddw mm0, mm2 + paddw mm7, mm5 + // test ((pa <= pb)? pa:pb) <= pc + pcmpgtw mm7, mm6 // pab > pc? + pand mm3, mm7 + pandn mm7, mm0 + paddw mm7, mm3 + pxor mm1, mm1 + packuswb mm1, mm7 + // Step ebx to next set of 8 bytes and repeat loop til done + add ebx, 8 + pand mm1, ActiveMaskEnd + paddb mm1, [edi + ebx - 8] // add Paeth predictor with Raw(x) + + cmp ebx, MMXLength + pxor mm0, mm0 // pxor does not affect flags + movq [edi + ebx - 8], mm1 // write back updated value + // mm1 will be used as Raw(x-bpp) next loop + // mm3 ready to be used as Prior(x-bpp) next loop + jb dpth3lp + } // end _asm block + } + break; + + case 6: + case 7: + case 5: + { + ActiveMask.use = 0x00000000ffffffff; + ActiveMask2.use = 0xffffffff00000000; + ShiftBpp.use = bpp << 3; // == bpp * 8 + ShiftRem.use = 64 - ShiftBpp.use; + _asm + { + mov ebx, diff + mov edi, row + mov esi, prev_row + // PRIME the pump (load the first Raw(x-bpp) data set + movq mm1, [edi+ebx-8] + pxor mm0, mm0 +dpth6lp: + // Must shift to position Raw(x-bpp) data + psrlq mm1, ShiftRem + // Do first set of 4 bytes + movq mm3, [esi+ebx-8] // read c=Prior(x-bpp) bytes + punpcklbw mm1, mm0 // Unpack Low bytes of a + movq mm2, [esi + ebx] // load b=Prior(x) + punpcklbw mm2, mm0 // Unpack Low bytes of b + // Must shift to position Prior(x-bpp) data + psrlq mm3, ShiftRem + // pav = p - a = (a + b - c) - a = b - c + movq mm4, mm2 + punpcklbw mm3, mm0 // Unpack Low bytes of c + // pbv = p - b = (a + b - c) - b = a - c + movq mm5, mm1 + psubw mm4, mm3 + pxor mm7, mm7 + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + movq mm6, mm4 + psubw mm5, mm3 + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + pcmpgtw mm0, mm4 // Create mask pav bytes < 0 + paddw mm6, mm5 + pand mm0, mm4 // Only pav bytes < 0 in mm7 + pcmpgtw mm7, mm5 // Create mask pbv bytes < 0 + psubw mm4, mm0 + pand mm7, mm5 // Only pbv bytes < 0 in mm0 + psubw mm4, mm0 + psubw mm5, mm7 + pxor mm0, mm0 + pcmpgtw mm0, mm6 // Create mask pcv bytes < 0 + pand mm0, mm6 // Only pav bytes < 0 in mm7 + psubw mm5, mm7 + psubw mm6, mm0 + // test pa <= pb + movq mm7, mm4 + psubw mm6, mm0 + pcmpgtw mm7, mm5 // pa > pb? + movq mm0, mm7 + // use mm7 mask to merge pa & pb + pand mm5, mm7 + // use mm0 mask copy to merge a & b + pand mm2, mm0 + pandn mm7, mm4 + pandn mm0, mm1 + paddw mm7, mm5 + paddw mm0, mm2 + // test ((pa <= pb)? pa:pb) <= pc + pcmpgtw mm7, mm6 // pab > pc? + pxor mm1, mm1 + pand mm3, mm7 + pandn mm7, mm0 + paddw mm7, mm3 + pxor mm0, mm0 + packuswb mm7, mm1 + movq mm3, [esi + ebx - 8] // load c=Prior(x-bpp) + pand mm7, ActiveMask + psrlq mm3, ShiftRem + movq mm2, [esi + ebx] // load b=Prior(x) step 1 + paddb mm7, [edi + ebx] // add Paeth predictor with Raw(x) + movq mm6, mm2 + movq [edi + ebx], mm7 // write back updated value + movq mm1, [edi+ebx-8] + psllq mm6, ShiftBpp + movq mm5, mm7 + psrlq mm1, ShiftRem + por mm3, mm6 + psllq mm5, ShiftBpp + punpckhbw mm3, mm0 // Unpack High bytes of c + por mm1, mm5 + // Do second set of 4 bytes + punpckhbw mm2, mm0 // Unpack High bytes of b + punpckhbw mm1, mm0 // Unpack High bytes of a + // pav = p - a = (a + b - c) - a = b - c + movq mm4, mm2 + // pbv = p - b = (a + b - c) - b = a - c + movq mm5, mm1 + psubw mm4, mm3 + pxor mm7, mm7 + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + movq mm6, mm4 + psubw mm5, mm3 + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + pcmpgtw mm0, mm4 // Create mask pav bytes < 0 + paddw mm6, mm5 + pand mm0, mm4 // Only pav bytes < 0 in mm7 + pcmpgtw mm7, mm5 // Create mask pbv bytes < 0 + psubw mm4, mm0 + pand mm7, mm5 // Only pbv bytes < 0 in mm0 + psubw mm4, mm0 + psubw mm5, mm7 + pxor mm0, mm0 + pcmpgtw mm0, mm6 // Create mask pcv bytes < 0 + pand mm0, mm6 // Only pav bytes < 0 in mm7 + psubw mm5, mm7 + psubw mm6, mm0 + // test pa <= pb + movq mm7, mm4 + psubw mm6, mm0 + pcmpgtw mm7, mm5 // pa > pb? + movq mm0, mm7 + // use mm7 mask to merge pa & pb + pand mm5, mm7 + // use mm0 mask copy to merge a & b + pand mm2, mm0 + pandn mm7, mm4 + pandn mm0, mm1 + paddw mm7, mm5 + paddw mm0, mm2 + // test ((pa <= pb)? pa:pb) <= pc + pcmpgtw mm7, mm6 // pab > pc? + pxor mm1, mm1 + pand mm3, mm7 + pandn mm7, mm0 + pxor mm1, mm1 + paddw mm7, mm3 + pxor mm0, mm0 + // Step ex to next set of 8 bytes and repeat loop til done + add ebx, 8 + packuswb mm1, mm7 + paddb mm1, [edi + ebx - 8] // add Paeth predictor with Raw(x) + cmp ebx, MMXLength + movq [edi + ebx - 8], mm1 // write back updated value + // mm1 will be used as Raw(x-bpp) next loop + jb dpth6lp + } // end _asm block + } + break; + + case 4: + { + ActiveMask.use = 0x00000000ffffffff; + _asm { + mov ebx, diff + mov edi, row + mov esi, prev_row + pxor mm0, mm0 + // PRIME the pump (load the first Raw(x-bpp) data set + movq mm1, [edi+ebx-8] // Only time should need to read + // a=Raw(x-bpp) bytes +dpth4lp: + // Do first set of 4 bytes + movq mm3, [esi+ebx-8] // read c=Prior(x-bpp) bytes + punpckhbw mm1, mm0 // Unpack Low bytes of a + movq mm2, [esi + ebx] // load b=Prior(x) + punpcklbw mm2, mm0 // Unpack High bytes of b + // pav = p - a = (a + b - c) - a = b - c + movq mm4, mm2 + punpckhbw mm3, mm0 // Unpack High bytes of c + // pbv = p - b = (a + b - c) - b = a - c + movq mm5, mm1 + psubw mm4, mm3 + pxor mm7, mm7 + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + movq mm6, mm4 + psubw mm5, mm3 + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + pcmpgtw mm0, mm4 // Create mask pav bytes < 0 + paddw mm6, mm5 + pand mm0, mm4 // Only pav bytes < 0 in mm7 + pcmpgtw mm7, mm5 // Create mask pbv bytes < 0 + psubw mm4, mm0 + pand mm7, mm5 // Only pbv bytes < 0 in mm0 + psubw mm4, mm0 + psubw mm5, mm7 + pxor mm0, mm0 + pcmpgtw mm0, mm6 // Create mask pcv bytes < 0 + pand mm0, mm6 // Only pav bytes < 0 in mm7 + psubw mm5, mm7 + psubw mm6, mm0 + // test pa <= pb + movq mm7, mm4 + psubw mm6, mm0 + pcmpgtw mm7, mm5 // pa > pb? + movq mm0, mm7 + // use mm7 mask to merge pa & pb + pand mm5, mm7 + // use mm0 mask copy to merge a & b + pand mm2, mm0 + pandn mm7, mm4 + pandn mm0, mm1 + paddw mm7, mm5 + paddw mm0, mm2 + // test ((pa <= pb)? pa:pb) <= pc + pcmpgtw mm7, mm6 // pab > pc? + pxor mm1, mm1 + pand mm3, mm7 + pandn mm7, mm0 + paddw mm7, mm3 + pxor mm0, mm0 + packuswb mm7, mm1 + movq mm3, [esi + ebx] // load c=Prior(x-bpp) + pand mm7, ActiveMask + movq mm2, mm3 // load b=Prior(x) step 1 + paddb mm7, [edi + ebx] // add Paeth predictor with Raw(x) + punpcklbw mm3, mm0 // Unpack High bytes of c + movq [edi + ebx], mm7 // write back updated value + movq mm1, mm7 // Now mm1 will be used as Raw(x-bpp) + // Do second set of 4 bytes + punpckhbw mm2, mm0 // Unpack Low bytes of b + punpcklbw mm1, mm0 // Unpack Low bytes of a + // pav = p - a = (a + b - c) - a = b - c + movq mm4, mm2 + // pbv = p - b = (a + b - c) - b = a - c + movq mm5, mm1 + psubw mm4, mm3 + pxor mm7, mm7 + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + movq mm6, mm4 + psubw mm5, mm3 + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + pcmpgtw mm0, mm4 // Create mask pav bytes < 0 + paddw mm6, mm5 + pand mm0, mm4 // Only pav bytes < 0 in mm7 + pcmpgtw mm7, mm5 // Create mask pbv bytes < 0 + psubw mm4, mm0 + pand mm7, mm5 // Only pbv bytes < 0 in mm0 + psubw mm4, mm0 + psubw mm5, mm7 + pxor mm0, mm0 + pcmpgtw mm0, mm6 // Create mask pcv bytes < 0 + pand mm0, mm6 // Only pav bytes < 0 in mm7 + psubw mm5, mm7 + psubw mm6, mm0 + // test pa <= pb + movq mm7, mm4 + psubw mm6, mm0 + pcmpgtw mm7, mm5 // pa > pb? + movq mm0, mm7 + // use mm7 mask to merge pa & pb + pand mm5, mm7 + // use mm0 mask copy to merge a & b + pand mm2, mm0 + pandn mm7, mm4 + pandn mm0, mm1 + paddw mm7, mm5 + paddw mm0, mm2 + // test ((pa <= pb)? pa:pb) <= pc + pcmpgtw mm7, mm6 // pab > pc? + pxor mm1, mm1 + pand mm3, mm7 + pandn mm7, mm0 + pxor mm1, mm1 + paddw mm7, mm3 + pxor mm0, mm0 + // Step ex to next set of 8 bytes and repeat loop til done + add ebx, 8 + packuswb mm1, mm7 + paddb mm1, [edi + ebx - 8] // add Paeth predictor with Raw(x) + cmp ebx, MMXLength + movq [edi + ebx - 8], mm1 // write back updated value + // mm1 will be used as Raw(x-bpp) next loop + jb dpth4lp + } // end _asm block + } + break; + case 8: // bpp == 8 + { + ActiveMask.use = 0x00000000ffffffff; + _asm { + mov ebx, diff + mov edi, row + mov esi, prev_row + pxor mm0, mm0 + // PRIME the pump (load the first Raw(x-bpp) data set + movq mm1, [edi+ebx-8] // Only time should need to read + // a=Raw(x-bpp) bytes +dpth8lp: + // Do first set of 4 bytes + movq mm3, [esi+ebx-8] // read c=Prior(x-bpp) bytes + punpcklbw mm1, mm0 // Unpack Low bytes of a + movq mm2, [esi + ebx] // load b=Prior(x) + punpcklbw mm2, mm0 // Unpack Low bytes of b + // pav = p - a = (a + b - c) - a = b - c + movq mm4, mm2 + punpcklbw mm3, mm0 // Unpack Low bytes of c + // pbv = p - b = (a + b - c) - b = a - c + movq mm5, mm1 + psubw mm4, mm3 + pxor mm7, mm7 + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + movq mm6, mm4 + psubw mm5, mm3 + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + pcmpgtw mm0, mm4 // Create mask pav bytes < 0 + paddw mm6, mm5 + pand mm0, mm4 // Only pav bytes < 0 in mm7 + pcmpgtw mm7, mm5 // Create mask pbv bytes < 0 + psubw mm4, mm0 + pand mm7, mm5 // Only pbv bytes < 0 in mm0 + psubw mm4, mm0 + psubw mm5, mm7 + pxor mm0, mm0 + pcmpgtw mm0, mm6 // Create mask pcv bytes < 0 + pand mm0, mm6 // Only pav bytes < 0 in mm7 + psubw mm5, mm7 + psubw mm6, mm0 + // test pa <= pb + movq mm7, mm4 + psubw mm6, mm0 + pcmpgtw mm7, mm5 // pa > pb? + movq mm0, mm7 + // use mm7 mask to merge pa & pb + pand mm5, mm7 + // use mm0 mask copy to merge a & b + pand mm2, mm0 + pandn mm7, mm4 + pandn mm0, mm1 + paddw mm7, mm5 + paddw mm0, mm2 + // test ((pa <= pb)? pa:pb) <= pc + pcmpgtw mm7, mm6 // pab > pc? + pxor mm1, mm1 + pand mm3, mm7 + pandn mm7, mm0 + paddw mm7, mm3 + pxor mm0, mm0 + packuswb mm7, mm1 + movq mm3, [esi+ebx-8] // read c=Prior(x-bpp) bytes + pand mm7, ActiveMask + movq mm2, [esi + ebx] // load b=Prior(x) + paddb mm7, [edi + ebx] // add Paeth predictor with Raw(x) + punpckhbw mm3, mm0 // Unpack High bytes of c + movq [edi + ebx], mm7 // write back updated value + movq mm1, [edi+ebx-8] // read a=Raw(x-bpp) bytes + + // Do second set of 4 bytes + punpckhbw mm2, mm0 // Unpack High bytes of b + punpckhbw mm1, mm0 // Unpack High bytes of a + // pav = p - a = (a + b - c) - a = b - c + movq mm4, mm2 + // pbv = p - b = (a + b - c) - b = a - c + movq mm5, mm1 + psubw mm4, mm3 + pxor mm7, mm7 + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + movq mm6, mm4 + psubw mm5, mm3 + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + pcmpgtw mm0, mm4 // Create mask pav bytes < 0 + paddw mm6, mm5 + pand mm0, mm4 // Only pav bytes < 0 in mm7 + pcmpgtw mm7, mm5 // Create mask pbv bytes < 0 + psubw mm4, mm0 + pand mm7, mm5 // Only pbv bytes < 0 in mm0 + psubw mm4, mm0 + psubw mm5, mm7 + pxor mm0, mm0 + pcmpgtw mm0, mm6 // Create mask pcv bytes < 0 + pand mm0, mm6 // Only pav bytes < 0 in mm7 + psubw mm5, mm7 + psubw mm6, mm0 + // test pa <= pb + movq mm7, mm4 + psubw mm6, mm0 + pcmpgtw mm7, mm5 // pa > pb? + movq mm0, mm7 + // use mm7 mask to merge pa & pb + pand mm5, mm7 + // use mm0 mask copy to merge a & b + pand mm2, mm0 + pandn mm7, mm4 + pandn mm0, mm1 + paddw mm7, mm5 + paddw mm0, mm2 + // test ((pa <= pb)? pa:pb) <= pc + pcmpgtw mm7, mm6 // pab > pc? + pxor mm1, mm1 + pand mm3, mm7 + pandn mm7, mm0 + pxor mm1, mm1 + paddw mm7, mm3 + pxor mm0, mm0 + // Step ex to next set of 8 bytes and repeat loop til done + add ebx, 8 + packuswb mm1, mm7 + paddb mm1, [edi + ebx - 8] // add Paeth predictor with Raw(x) + cmp ebx, MMXLength + movq [edi + ebx - 8], mm1 // write back updated value + // mm1 will be used as Raw(x-bpp) next loop + jb dpth8lp + } // end _asm block + } + break; + + case 1: // bpp = 1 + case 2: // bpp = 2 + default: // bpp > 8 + { + _asm { + mov ebx, diff + cmp ebx, FullLength + jnb dpthdend + mov edi, row + mov esi, prev_row + // Do Paeth decode for remaining bytes + mov edx, ebx + xor ecx, ecx // zero ecx before using cl & cx in loop below + sub edx, bpp // Set edx = ebx - bpp +dpthdlp: + xor eax, eax + // pav = p - a = (a + b - c) - a = b - c + mov al, [esi + ebx] // load Prior(x) into al + mov cl, [esi + edx] // load Prior(x-bpp) into cl + sub eax, ecx // subtract Prior(x-bpp) + mov patemp, eax // Save pav for later use + xor eax, eax + // pbv = p - b = (a + b - c) - b = a - c + mov al, [edi + edx] // load Raw(x-bpp) into al + sub eax, ecx // subtract Prior(x-bpp) + mov ecx, eax + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + add eax, patemp // pcv = pav + pbv + // pc = abs(pcv) + test eax, 0x80000000 + jz dpthdpca + neg eax // reverse sign of neg values +dpthdpca: + mov pctemp, eax // save pc for later use + // pb = abs(pbv) + test ecx, 0x80000000 + jz dpthdpba + neg ecx // reverse sign of neg values +dpthdpba: + mov pbtemp, ecx // save pb for later use + // pa = abs(pav) + mov eax, patemp + test eax, 0x80000000 + jz dpthdpaa + neg eax // reverse sign of neg values +dpthdpaa: + mov patemp, eax // save pa for later use + // test if pa <= pb + cmp eax, ecx + jna dpthdabb + // pa > pb; now test if pb <= pc + cmp ecx, pctemp + jna dpthdbbc + // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp) + mov cl, [esi + edx] // load Prior(x-bpp) into cl + jmp dpthdpaeth +dpthdbbc: + // pb <= pc; Raw(x) = Paeth(x) + Prior(x) + mov cl, [esi + ebx] // load Prior(x) into cl + jmp dpthdpaeth +dpthdabb: + // pa <= pb; now test if pa <= pc + cmp eax, pctemp + jna dpthdabc + // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp) + mov cl, [esi + edx] // load Prior(x-bpp) into cl + jmp dpthdpaeth +dpthdabc: + // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp) + mov cl, [edi + edx] // load Raw(x-bpp) into cl +dpthdpaeth: + inc ebx + inc edx + // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256 + add [edi + ebx - 1], cl + cmp ebx, FullLength + jb dpthdlp +dpthdend: + } // end _asm block + } + return; // No need to go further with this one + } // end switch ( bpp ) + _asm + { + // MMX acceleration complete now do clean-up + // Check if any remaining bytes left to decode + mov ebx, MMXLength + cmp ebx, FullLength + jnb dpthend + mov edi, row + mov esi, prev_row + // Do Paeth decode for remaining bytes + mov edx, ebx + xor ecx, ecx // zero ecx before using cl & cx in loop below + sub edx, bpp // Set edx = ebx - bpp +dpthlp2: + xor eax, eax + // pav = p - a = (a + b - c) - a = b - c + mov al, [esi + ebx] // load Prior(x) into al + mov cl, [esi + edx] // load Prior(x-bpp) into cl + sub eax, ecx // subtract Prior(x-bpp) + mov patemp, eax // Save pav for later use + xor eax, eax + // pbv = p - b = (a + b - c) - b = a - c + mov al, [edi + edx] // load Raw(x-bpp) into al + sub eax, ecx // subtract Prior(x-bpp) + mov ecx, eax + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + add eax, patemp // pcv = pav + pbv + // pc = abs(pcv) + test eax, 0x80000000 + jz dpthpca2 + neg eax // reverse sign of neg values +dpthpca2: + mov pctemp, eax // save pc for later use + // pb = abs(pbv) + test ecx, 0x80000000 + jz dpthpba2 + neg ecx // reverse sign of neg values +dpthpba2: + mov pbtemp, ecx // save pb for later use + // pa = abs(pav) + mov eax, patemp + test eax, 0x80000000 + jz dpthpaa2 + neg eax // reverse sign of neg values +dpthpaa2: + mov patemp, eax // save pa for later use + // test if pa <= pb + cmp eax, ecx + jna dpthabb2 + // pa > pb; now test if pb <= pc + cmp ecx, pctemp + jna dpthbbc2 + // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp) + mov cl, [esi + edx] // load Prior(x-bpp) into cl + jmp dpthpaeth2 +dpthbbc2: + // pb <= pc; Raw(x) = Paeth(x) + Prior(x) + mov cl, [esi + ebx] // load Prior(x) into cl + jmp dpthpaeth2 +dpthabb2: + // pa <= pb; now test if pa <= pc + cmp eax, pctemp + jna dpthabc2 + // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp) + mov cl, [esi + edx] // load Prior(x-bpp) into cl + jmp dpthpaeth2 +dpthabc2: + // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp) + mov cl, [edi + edx] // load Raw(x-bpp) into cl +dpthpaeth2: + inc ebx + inc edx + // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256 + add [edi + ebx - 1], cl + cmp ebx, FullLength + jb dpthlp2 +dpthend: + emms // End MMX instructions; prep for possible FP instrs. + } // end _asm block +} + +// Optimized code for PNG Sub filter decoder +void /* PRIVATE */ +png_read_filter_row_mmx_sub(png_row_infop row_info, png_bytep row) +{ + //int test; + int bpp; + png_uint_32 FullLength; + png_uint_32 MMXLength; + int diff; + + bpp = (row_info->pixel_depth + 7) >> 3; // Get # bytes per pixel + FullLength = row_info->rowbytes - bpp; // # of bytes to filter + _asm { + mov edi, row + mov esi, edi // lp = row + add edi, bpp // rp = row + bpp + xor eax, eax + // get # of bytes to alignment + mov diff, edi // take start of row + add diff, 0xf // add 7 + 8 to incr past + // alignment boundary + xor ebx, ebx + and diff, 0xfffffff8 // mask to alignment boundary + sub diff, edi // subtract from start ==> value + // ebx at alignment + jz dsubgo + // fix alignment +dsublp1: + mov al, [esi+ebx] + add [edi+ebx], al + inc ebx + cmp ebx, diff + jb dsublp1 +dsubgo: + mov ecx, FullLength + mov edx, ecx + sub edx, ebx // subtract alignment fix + and edx, 0x00000007 // calc bytes over mult of 8 + sub ecx, edx // drop over bytes from length + mov MMXLength, ecx + } // end _asm block + + // Now do the math for the rest of the row + switch ( bpp ) + { + case 3: + { + ActiveMask.use = 0x0000ffffff000000; + ShiftBpp.use = 24; // == 3 * 8 + ShiftRem.use = 40; // == 64 - 24 + _asm { + mov edi, row + movq mm7, ActiveMask // Load ActiveMask for 2nd active byte group + mov esi, edi // lp = row + add edi, bpp // rp = row + bpp + movq mm6, mm7 + mov ebx, diff + psllq mm6, ShiftBpp // Move mask in mm6 to cover 3rd active + // byte group + // PRIME the pump (load the first Raw(x-bpp) data set + movq mm1, [edi+ebx-8] +dsub3lp: + psrlq mm1, ShiftRem // Shift data for adding 1st bpp bytes + // no need for mask; shift clears inactive bytes + // Add 1st active group + movq mm0, [edi+ebx] + paddb mm0, mm1 + // Add 2nd active group + movq mm1, mm0 // mov updated Raws to mm1 + psllq mm1, ShiftBpp // shift data to position correctly + pand mm1, mm7 // mask to use only 2nd active group + paddb mm0, mm1 + // Add 3rd active group + movq mm1, mm0 // mov updated Raws to mm1 + psllq mm1, ShiftBpp // shift data to position correctly + pand mm1, mm6 // mask to use only 3rd active group + add ebx, 8 + paddb mm0, mm1 + cmp ebx, MMXLength + movq [edi+ebx-8], mm0 // Write updated Raws back to array + // Prep for doing 1st add at top of loop + movq mm1, mm0 + jb dsub3lp + } // end _asm block + } + break; + + case 1: + { + // Placed here just in case this is a duplicate of the + // non-MMX code for the SUB filter in png_read_filter_row below + // + // png_bytep rp; + // png_bytep lp; + // png_uint_32 i; + // bpp = (row_info->pixel_depth + 7) >> 3; + // for (i = (png_uint_32)bpp, rp = row + bpp, lp = row; + // i < row_info->rowbytes; i++, rp++, lp++) + // { + // *rp = (png_byte)(((int)(*rp) + (int)(*lp)) & 0xff); + // } + _asm { + mov ebx, diff + mov edi, row + cmp ebx, FullLength + jnb dsub1end + mov esi, edi // lp = row + xor eax, eax + add edi, bpp // rp = row + bpp +dsub1lp: + mov al, [esi+ebx] + add [edi+ebx], al + inc ebx + cmp ebx, FullLength + jb dsub1lp +dsub1end: + } // end _asm block + } + return; + + case 6: + case 7: + case 4: + case 5: + { + ShiftBpp.use = bpp << 3; + ShiftRem.use = 64 - ShiftBpp.use; + _asm { + mov edi, row + mov ebx, diff + mov esi, edi // lp = row + add edi, bpp // rp = row + bpp + // PRIME the pump (load the first Raw(x-bpp) data set + movq mm1, [edi+ebx-8] +dsub4lp: + psrlq mm1, ShiftRem // Shift data for adding 1st bpp bytes + // no need for mask; shift clears inactive bytes + movq mm0, [edi+ebx] + paddb mm0, mm1 + // Add 2nd active group + movq mm1, mm0 // mov updated Raws to mm1 + psllq mm1, ShiftBpp // shift data to position correctly + // there is no need for any mask + // since shift clears inactive bits/bytes + add ebx, 8 + paddb mm0, mm1 + cmp ebx, MMXLength + movq [edi+ebx-8], mm0 + movq mm1, mm0 // Prep for doing 1st add at top of loop + jb dsub4lp + } // end _asm block + } + break; + + case 2: + { + ActiveMask.use = 0x00000000ffff0000; + ShiftBpp.use = 16; // == 2 * 8 + ShiftRem.use = 48; // == 64 - 16 + _asm { + movq mm7, ActiveMask // Load ActiveMask for 2nd active byte group + mov ebx, diff + movq mm6, mm7 + mov edi, row + psllq mm6, ShiftBpp // Move mask in mm6 to cover 3rd active + // byte group + mov esi, edi // lp = row + movq mm5, mm6 + add edi, bpp // rp = row + bpp + psllq mm5, ShiftBpp // Move mask in mm5 to cover 4th active + // byte group + // PRIME the pump (load the first Raw(x-bpp) data set + movq mm1, [edi+ebx-8] +dsub2lp: + // Add 1st active group + psrlq mm1, ShiftRem // Shift data for adding 1st bpp bytes + // no need for mask; shift clears inactive + // bytes + movq mm0, [edi+ebx] + paddb mm0, mm1 + // Add 2nd active group + movq mm1, mm0 // mov updated Raws to mm1 + psllq mm1, ShiftBpp // shift data to position correctly + pand mm1, mm7 // mask to use only 2nd active group + paddb mm0, mm1 + // Add 3rd active group + movq mm1, mm0 // mov updated Raws to mm1 + psllq mm1, ShiftBpp // shift data to position correctly + pand mm1, mm6 // mask to use only 3rd active group + paddb mm0, mm1 + // Add 4th active group + movq mm1, mm0 // mov updated Raws to mm1 + psllq mm1, ShiftBpp // shift data to position correctly + pand mm1, mm5 // mask to use only 4th active group + add ebx, 8 + paddb mm0, mm1 + cmp ebx, MMXLength + movq [edi+ebx-8], mm0 // Write updated Raws back to array + movq mm1, mm0 // Prep for doing 1st add at top of loop + jb dsub2lp + } // end _asm block + } + break; + case 8: + { + _asm { + mov edi, row + mov ebx, diff + mov esi, edi // lp = row + add edi, bpp // rp = row + bpp + mov ecx, MMXLength + movq mm7, [edi+ebx-8] // PRIME the pump (load the first + // Raw(x-bpp) data set + and ecx, 0x0000003f // calc bytes over mult of 64 +dsub8lp: + movq mm0, [edi+ebx] // Load Sub(x) for 1st 8 bytes + paddb mm0, mm7 + movq mm1, [edi+ebx+8] // Load Sub(x) for 2nd 8 bytes + movq [edi+ebx], mm0 // Write Raw(x) for 1st 8 bytes + // Now mm0 will be used as Raw(x-bpp) for + // the 2nd group of 8 bytes. This will be + // repeated for each group of 8 bytes with + // the 8th group being used as the Raw(x-bpp) + // for the 1st group of the next loop. + paddb mm1, mm0 + movq mm2, [edi+ebx+16] // Load Sub(x) for 3rd 8 bytes + movq [edi+ebx+8], mm1 // Write Raw(x) for 2nd 8 bytes + paddb mm2, mm1 + movq mm3, [edi+ebx+24] // Load Sub(x) for 4th 8 bytes + movq [edi+ebx+16], mm2 // Write Raw(x) for 3rd 8 bytes + paddb mm3, mm2 + movq mm4, [edi+ebx+32] // Load Sub(x) for 5th 8 bytes + movq [edi+ebx+24], mm3 // Write Raw(x) for 4th 8 bytes + paddb mm4, mm3 + movq mm5, [edi+ebx+40] // Load Sub(x) for 6th 8 bytes + movq [edi+ebx+32], mm4 // Write Raw(x) for 5th 8 bytes + paddb mm5, mm4 + movq mm6, [edi+ebx+48] // Load Sub(x) for 7th 8 bytes + movq [edi+ebx+40], mm5 // Write Raw(x) for 6th 8 bytes + paddb mm6, mm5 + movq mm7, [edi+ebx+56] // Load Sub(x) for 8th 8 bytes + movq [edi+ebx+48], mm6 // Write Raw(x) for 7th 8 bytes + add ebx, 64 + paddb mm7, mm6 + cmp ebx, ecx + movq [edi+ebx-8], mm7 // Write Raw(x) for 8th 8 bytes + jb dsub8lp + cmp ebx, MMXLength + jnb dsub8lt8 +dsub8lpA: + movq mm0, [edi+ebx] + add ebx, 8 + paddb mm0, mm7 + cmp ebx, MMXLength + movq [edi+ebx-8], mm0 // use -8 to offset early add to ebx + movq mm7, mm0 // Move calculated Raw(x) data to mm1 to + // be the new Raw(x-bpp) for the next loop + jb dsub8lpA +dsub8lt8: + } // end _asm block + } + break; + + default: // bpp greater than 8 bytes + { + _asm { + mov ebx, diff + mov edi, row + mov esi, edi // lp = row + add edi, bpp // rp = row + bpp +dsubAlp: + movq mm0, [edi+ebx] + movq mm1, [esi+ebx] + add ebx, 8 + paddb mm0, mm1 + cmp ebx, MMXLength + movq [edi+ebx-8], mm0 // mov does not affect flags; -8 to offset + // add ebx + jb dsubAlp + } // end _asm block + } + break; + + } // end switch ( bpp ) + + _asm { + mov ebx, MMXLength + mov edi, row + cmp ebx, FullLength + jnb dsubend + mov esi, edi // lp = row + xor eax, eax + add edi, bpp // rp = row + bpp +dsublp2: + mov al, [esi+ebx] + add [edi+ebx], al + inc ebx + cmp ebx, FullLength + jb dsublp2 +dsubend: + emms // End MMX instructions; prep for possible FP instrs. + } // end _asm block +} + +// Optimized code for PNG Up filter decoder +void /* PRIVATE */ +png_read_filter_row_mmx_up(png_row_infop row_info, png_bytep row, + png_bytep prev_row) +{ + png_uint_32 len; + len = row_info->rowbytes; // # of bytes to filter + _asm { + mov edi, row + // get # of bytes to alignment + mov ecx, edi + xor ebx, ebx + add ecx, 0x7 + xor eax, eax + and ecx, 0xfffffff8 + mov esi, prev_row + sub ecx, edi + jz dupgo + // fix alignment +duplp1: + mov al, [edi+ebx] + add al, [esi+ebx] + inc ebx + cmp ebx, ecx + mov [edi + ebx-1], al // mov does not affect flags; -1 to offset inc ebx + jb duplp1 +dupgo: + mov ecx, len + mov edx, ecx + sub edx, ebx // subtract alignment fix + and edx, 0x0000003f // calc bytes over mult of 64 + sub ecx, edx // drop over bytes from length + // Unrolled loop - use all MMX registers and interleave to reduce + // number of branch instructions (loops) and reduce partial stalls +duploop: + movq mm1, [esi+ebx] + movq mm0, [edi+ebx] + movq mm3, [esi+ebx+8] + paddb mm0, mm1 + movq mm2, [edi+ebx+8] + movq [edi+ebx], mm0 + paddb mm2, mm3 + movq mm5, [esi+ebx+16] + movq [edi+ebx+8], mm2 + movq mm4, [edi+ebx+16] + movq mm7, [esi+ebx+24] + paddb mm4, mm5 + movq mm6, [edi+ebx+24] + movq [edi+ebx+16], mm4 + paddb mm6, mm7 + movq mm1, [esi+ebx+32] + movq [edi+ebx+24], mm6 + movq mm0, [edi+ebx+32] + movq mm3, [esi+ebx+40] + paddb mm0, mm1 + movq mm2, [edi+ebx+40] + movq [edi+ebx+32], mm0 + paddb mm2, mm3 + movq mm5, [esi+ebx+48] + movq [edi+ebx+40], mm2 + movq mm4, [edi+ebx+48] + movq mm7, [esi+ebx+56] + paddb mm4, mm5 + movq mm6, [edi+ebx+56] + movq [edi+ebx+48], mm4 + add ebx, 64 + paddb mm6, mm7 + cmp ebx, ecx + movq [edi+ebx-8], mm6 // (+56)movq does not affect flags; + // -8 to offset add ebx + jb duploop + + cmp edx, 0 // Test for bytes over mult of 64 + jz dupend + + + // 2 lines added by lcreeve at netins.net + // (mail 11 Jul 98 in png-implement list) + cmp edx, 8 //test for less than 8 bytes + jb duplt8 + + + add ecx, edx + and edx, 0x00000007 // calc bytes over mult of 8 + sub ecx, edx // drop over bytes from length + jz duplt8 + // Loop using MMX registers mm0 & mm1 to update 8 bytes simultaneously +duplpA: + movq mm1, [esi+ebx] + movq mm0, [edi+ebx] + add ebx, 8 + paddb mm0, mm1 + cmp ebx, ecx + movq [edi+ebx-8], mm0 // movq does not affect flags; -8 to offset add ebx + jb duplpA + cmp edx, 0 // Test for bytes over mult of 8 + jz dupend +duplt8: + xor eax, eax + add ecx, edx // move over byte count into counter + // Loop using x86 registers to update remaining bytes +duplp2: + mov al, [edi + ebx] + add al, [esi + ebx] + inc ebx + cmp ebx, ecx + mov [edi + ebx-1], al // mov does not affect flags; -1 to offset inc ebx + jb duplp2 +dupend: + // Conversion of filtered row completed + emms // End MMX instructions; prep for possible FP instrs. + } // end _asm block +} + + +// Optimized png_read_filter_row routines +void /* PRIVATE */ +png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep + row, png_bytep prev_row, int filter) +{ +#ifdef PNG_DEBUG + char filnm[10]; +#endif + + if (mmx_supported == 2) { +#if !defined(PNG_1_0_X) + /* this should have happened in png_init_mmx_flags() already */ + png_warning(png_ptr, "asm_flags may not have been initialized"); +#endif + png_mmx_support(); + } + +#ifdef PNG_DEBUG + png_debug(1, "in png_read_filter_row\n"); + switch (filter) + { + case 0: sprintf(filnm, "none"); + break; +#if !defined(PNG_1_0_X) + case 1: sprintf(filnm, "sub-%s", + (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_SUB)? "MMX" : "x86"); + break; + case 2: sprintf(filnm, "up-%s", + (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_UP)? "MMX" : "x86"); + break; + case 3: sprintf(filnm, "avg-%s", + (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_AVG)? "MMX" : "x86"); + break; + case 4: sprintf(filnm, "Paeth-%s", + (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_PAETH)? "MMX":"x86"); + break; +#else + case 1: sprintf(filnm, "sub"); + break; + case 2: sprintf(filnm, "up"); + break; + case 3: sprintf(filnm, "avg"); + break; + case 4: sprintf(filnm, "Paeth"); + break; +#endif + default: sprintf(filnm, "unknw"); + break; + } + png_debug2(0,"row=%5d, %s, ", png_ptr->row_number, filnm); + png_debug2(0, "pd=%2d, b=%d, ", (int)row_info->pixel_depth, + (int)((row_info->pixel_depth + 7) >> 3)); + png_debug1(0,"len=%8d, ", row_info->rowbytes); +#endif /* PNG_DEBUG */ + + switch (filter) + { + case PNG_FILTER_VALUE_NONE: + break; + + case PNG_FILTER_VALUE_SUB: + { +#if !defined(PNG_1_0_X) + if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_SUB) && + (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) && + (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold)) +#else + if (mmx_supported) +#endif + { + png_read_filter_row_mmx_sub(row_info, row); + } + else + { + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; + png_bytep rp = row + bpp; + png_bytep lp = row; + + for (i = bpp; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff); + rp++; + } + } + break; + } + + case PNG_FILTER_VALUE_UP: + { +#if !defined(PNG_1_0_X) + if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_UP) && + (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) && + (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold)) +#else + if (mmx_supported) +#endif + { + png_read_filter_row_mmx_up(row_info, row, prev_row); + } + else + { + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + png_bytep rp = row; + png_bytep pp = prev_row; + + for (i = 0; i < istop; ++i) + { + *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff); + rp++; + } + } + break; + } + + case PNG_FILTER_VALUE_AVG: + { +#if !defined(PNG_1_0_X) + if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_AVG) && + (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) && + (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold)) +#else + if (mmx_supported) +#endif + { + png_read_filter_row_mmx_avg(row_info, row, prev_row); + } + else + { + png_uint_32 i; + png_bytep rp = row; + png_bytep pp = prev_row; + png_bytep lp = row; + png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; + png_uint_32 istop = row_info->rowbytes - bpp; + + for (i = 0; i < bpp; i++) + { + *rp = (png_byte)(((int)(*rp) + + ((int)(*pp++) >> 1)) & 0xff); + rp++; + } + + for (i = 0; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + + ((int)(*pp++ + *lp++) >> 1)) & 0xff); + rp++; + } + } + break; + } + + case PNG_FILTER_VALUE_PAETH: + { +#if !defined(PNG_1_0_X) + if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_PAETH) && + (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) && + (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold)) +#else + if (mmx_supported) +#endif + { + png_read_filter_row_mmx_paeth(row_info, row, prev_row); + } + else + { + png_uint_32 i; + png_bytep rp = row; + png_bytep pp = prev_row; + png_bytep lp = row; + png_bytep cp = prev_row; + png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; + png_uint_32 istop=row_info->rowbytes - bpp; + + for (i = 0; i < bpp; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff); + rp++; + } + + for (i = 0; i < istop; i++) // use leftover rp,pp + { + int a, b, c, pa, pb, pc, p; + + a = *lp++; + b = *pp++; + c = *cp++; + + p = b - c; + pc = a - c; + +#ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +#else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +#endif + + /* + if (pa <= pb && pa <= pc) + p = a; + else if (pb <= pc) + p = b; + else + p = c; + */ + + p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; + + *rp = (png_byte)(((int)(*rp) + p) & 0xff); + rp++; + } + } + break; + } + + default: + png_warning(png_ptr, "Ignoring bad row filter type"); + *row=0; + break; + } +} + +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED && PNG_USE_PNGVCRD */ diff --git a/syslinux/com32/lib/libpng/pngwio.c b/syslinux/com32/lib/libpng/pngwio.c new file mode 100644 index 0000000..d5d61f4 --- /dev/null +++ b/syslinux/com32/lib/libpng/pngwio.c @@ -0,0 +1,228 @@ + +/* pngwio.c - functions for data output + * + * libpng 1.2.8 - December 3, 2004 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2004 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This file provides a location for all output. Users who need + * special handling are expected to write functions that have the same + * arguments as these and perform similar functions, but that possibly + * use different output methods. Note that you shouldn't change these + * functions, but rather write replacement functions and then change + * them at run time with png_set_write_fn(...). + */ + +#define PNG_INTERNAL +#include "png.h" +#ifdef PNG_WRITE_SUPPORTED + +/* Write the data to whatever output you are using. The default routine + writes to a file pointer. Note that this routine sometimes gets called + with very small lengths, so you should implement some kind of simple + buffering if you are using unbuffered writes. This should never be asked + to write more than 64K on a 16 bit machine. */ + +void /* PRIVATE */ +png_write_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + if (png_ptr->write_data_fn != NULL ) + (*(png_ptr->write_data_fn))(png_ptr, data, length); + else + png_error(png_ptr, "Call to NULL write function"); +} + +#if !defined(PNG_NO_STDIO) +/* This is the function that does the actual writing of data. If you are + not writing to a standard C stream, you should create a replacement + write_data function and use it at run time with png_set_write_fn(), rather + than changing the library. */ +#ifndef USE_FAR_KEYWORD +void PNGAPI +png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_uint_32 check; + +#if defined(_WIN32_WCE) + if ( !WriteFile((HANDLE)(png_ptr->io_ptr), data, length, &check, NULL) ) + check = 0; +#else + check = fwrite(data, 1, length, (png_FILE_p)(png_ptr->io_ptr)); +#endif + if (check != length) + png_error(png_ptr, "Write Error"); +} +#else +/* this is the model-independent version. Since the standard I/O library + can't handle far buffers in the medium and small models, we have to copy + the data. +*/ + +#define NEAR_BUF_SIZE 1024 +#define MIN(a,b) (a <= b ? a : b) + +void PNGAPI +png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_uint_32 check; + png_byte *near_data; /* Needs to be "png_byte *" instead of "png_bytep" */ + png_FILE_p io_ptr; + + /* Check if data really is near. If so, use usual code. */ + near_data = (png_byte *)CVT_PTR_NOCHECK(data); + io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr); + if ((png_bytep)near_data == data) + { +#if defined(_WIN32_WCE) + if ( !WriteFile(io_ptr, near_data, length, &check, NULL) ) + check = 0; +#else + check = fwrite(near_data, 1, length, io_ptr); +#endif + } + else + { + png_byte buf[NEAR_BUF_SIZE]; + png_size_t written, remaining, err; + check = 0; + remaining = length; + do + { + written = MIN(NEAR_BUF_SIZE, remaining); + png_memcpy(buf, data, written); /* copy far buffer to near buffer */ +#if defined(_WIN32_WCE) + if ( !WriteFile(io_ptr, buf, written, &err, NULL) ) + err = 0; +#else + err = fwrite(buf, 1, written, io_ptr); +#endif + if (err != written) + break; + else + check += err; + data += written; + remaining -= written; + } + while (remaining != 0); + } + if (check != length) + png_error(png_ptr, "Write Error"); +} + +#endif +#endif + +/* This function is called to output any data pending writing (normally + to disk). After png_flush is called, there should be no data pending + writing in any buffers. */ +#if defined(PNG_WRITE_FLUSH_SUPPORTED) +void /* PRIVATE */ +png_flush(png_structp png_ptr) +{ + if (png_ptr->output_flush_fn != NULL) + (*(png_ptr->output_flush_fn))(png_ptr); +} + +#if !defined(PNG_NO_STDIO) +void PNGAPI +png_default_flush(png_structp png_ptr) +{ +#if !defined(_WIN32_WCE) + png_FILE_p io_ptr; + io_ptr = (png_FILE_p)CVT_PTR((png_ptr->io_ptr)); + if (io_ptr != NULL) + fflush(io_ptr); +#endif +} +#endif +#endif + +/* This function allows the application to supply new output functions for + libpng if standard C streams aren't being used. + + This function takes as its arguments: + png_ptr - pointer to a png output data structure + io_ptr - pointer to user supplied structure containing info about + the output functions. May be NULL. + write_data_fn - pointer to a new output function that takes as its + arguments a pointer to a png_struct, a pointer to + data to be written, and a 32-bit unsigned int that is + the number of bytes to be written. The new write + function should call png_error(png_ptr, "Error msg") + to exit and output any fatal error messages. + flush_data_fn - pointer to a new flush function that takes as its + arguments a pointer to a png_struct. After a call to + the flush function, there should be no data in any buffers + or pending transmission. If the output method doesn't do + any buffering of ouput, a function prototype must still be + supplied although it doesn't have to do anything. If + PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile + time, output_flush_fn will be ignored, although it must be + supplied for compatibility. */ +void PNGAPI +png_set_write_fn(png_structp png_ptr, png_voidp io_ptr, + png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn) +{ + png_ptr->io_ptr = io_ptr; + +#if !defined(PNG_NO_STDIO) + if (write_data_fn != NULL) + png_ptr->write_data_fn = write_data_fn; + else + png_ptr->write_data_fn = png_default_write_data; +#else + png_ptr->write_data_fn = write_data_fn; +#endif + +#if defined(PNG_WRITE_FLUSH_SUPPORTED) +#if !defined(PNG_NO_STDIO) + if (output_flush_fn != NULL) + png_ptr->output_flush_fn = output_flush_fn; + else + png_ptr->output_flush_fn = png_default_flush; +#else + png_ptr->output_flush_fn = output_flush_fn; +#endif +#endif /* PNG_WRITE_FLUSH_SUPPORTED */ + + /* It is an error to read while writing a png file */ + if (png_ptr->read_data_fn != NULL) + { + png_ptr->read_data_fn = NULL; + png_warning(png_ptr, + "Attempted to set both read_data_fn and write_data_fn in"); + png_warning(png_ptr, + "the same structure. Resetting read_data_fn to NULL."); + } +} + +#if defined(USE_FAR_KEYWORD) +#if defined(_MSC_VER) +void *png_far_to_near(png_structp png_ptr,png_voidp ptr, int check) +{ + void *near_ptr; + void FAR *far_ptr; + FP_OFF(near_ptr) = FP_OFF(ptr); + far_ptr = (void FAR *)near_ptr; + if(check != 0) + if(FP_SEG(ptr) != FP_SEG(far_ptr)) + png_error(png_ptr,"segment lost in conversion"); + return(near_ptr); +} +# else +void *png_far_to_near(png_structp png_ptr,png_voidp ptr, int check) +{ + void *near_ptr; + void FAR *far_ptr; + near_ptr = (void FAR *)ptr; + far_ptr = (void FAR *)near_ptr; + if(check != 0) + if(far_ptr != ptr) + png_error(png_ptr,"segment lost in conversion"); + return(near_ptr); +} +# endif +# endif +#endif /* PNG_WRITE_SUPPORTED */ diff --git a/syslinux/com32/lib/libpng/pngwrite.c b/syslinux/com32/lib/libpng/pngwrite.c new file mode 100644 index 0000000..97cb566 --- /dev/null +++ b/syslinux/com32/lib/libpng/pngwrite.c @@ -0,0 +1,1464 @@ + +/* pngwrite.c - general routines to write a PNG file + * + * libpng 1.2.8 - December 3, 2004 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2004 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + */ + +/* get internal access to png.h */ +#define PNG_INTERNAL +#include "png.h" +#ifdef PNG_WRITE_SUPPORTED + +/* Writes all the PNG information. This is the suggested way to use the + * library. If you have a new chunk to add, make a function to write it, + * and put it in the correct location here. If you want the chunk written + * after the image data, put it in png_write_end(). I strongly encourage + * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing + * the chunk, as that will keep the code from breaking if you want to just + * write a plain PNG file. If you have long comments, I suggest writing + * them in png_write_end(), and compressing them. + */ +void PNGAPI +png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr) +{ + png_debug(1, "in png_write_info_before_PLTE\n"); + if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE)) + { + png_write_sig(png_ptr); /* write PNG signature */ +#if defined(PNG_MNG_FEATURES_SUPPORTED) + if((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE)&&(png_ptr->mng_features_permitted)) + { + png_warning(png_ptr,"MNG features are not allowed in a PNG datastream\n"); + png_ptr->mng_features_permitted=0; + } +#endif + /* write IHDR information. */ + png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height, + info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type, + info_ptr->filter_type, +#if defined(PNG_WRITE_INTERLACING_SUPPORTED) + info_ptr->interlace_type); +#else + 0); +#endif + /* the rest of these check to see if the valid field has the appropriate + flag set, and if it does, writes the chunk. */ +#if defined(PNG_WRITE_gAMA_SUPPORTED) + if (info_ptr->valid & PNG_INFO_gAMA) + { +# ifdef PNG_FLOATING_POINT_SUPPORTED + png_write_gAMA(png_ptr, info_ptr->gamma); +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + png_write_gAMA_fixed(png_ptr, info_ptr->int_gamma); +# endif +#endif + } +#endif +#if defined(PNG_WRITE_sRGB_SUPPORTED) + if (info_ptr->valid & PNG_INFO_sRGB) + png_write_sRGB(png_ptr, (int)info_ptr->srgb_intent); +#endif +#if defined(PNG_WRITE_iCCP_SUPPORTED) + if (info_ptr->valid & PNG_INFO_iCCP) + png_write_iCCP(png_ptr, info_ptr->iccp_name, PNG_COMPRESSION_TYPE_BASE, + info_ptr->iccp_profile, (int)info_ptr->iccp_proflen); +#endif +#if defined(PNG_WRITE_sBIT_SUPPORTED) + if (info_ptr->valid & PNG_INFO_sBIT) + png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type); +#endif +#if defined(PNG_WRITE_cHRM_SUPPORTED) + if (info_ptr->valid & PNG_INFO_cHRM) + { +#ifdef PNG_FLOATING_POINT_SUPPORTED + png_write_cHRM(png_ptr, + info_ptr->x_white, info_ptr->y_white, + info_ptr->x_red, info_ptr->y_red, + info_ptr->x_green, info_ptr->y_green, + info_ptr->x_blue, info_ptr->y_blue); +#else +# ifdef PNG_FIXED_POINT_SUPPORTED + png_write_cHRM_fixed(png_ptr, + info_ptr->int_x_white, info_ptr->int_y_white, + info_ptr->int_x_red, info_ptr->int_y_red, + info_ptr->int_x_green, info_ptr->int_y_green, + info_ptr->int_x_blue, info_ptr->int_y_blue); +# endif +#endif + } +#endif +#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) + if (info_ptr->unknown_chunks_num) + { + png_unknown_chunk *up; + + png_debug(5, "writing extra chunks\n"); + + for (up = info_ptr->unknown_chunks; + up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; + up++) + { + int keep=png_handle_as_unknown(png_ptr, up->name); + if (keep != PNG_HANDLE_CHUNK_NEVER && + up->location && !(up->location & PNG_HAVE_PLTE) && + !(up->location & PNG_HAVE_IDAT) && + ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || + (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) + { + png_write_chunk(png_ptr, up->name, up->data, up->size); + } + } + } +#endif + png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE; + } +} + +void PNGAPI +png_write_info(png_structp png_ptr, png_infop info_ptr) +{ +#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) + int i; +#endif + + png_debug(1, "in png_write_info\n"); + + png_write_info_before_PLTE(png_ptr, info_ptr); + + if (info_ptr->valid & PNG_INFO_PLTE) + png_write_PLTE(png_ptr, info_ptr->palette, + (png_uint_32)info_ptr->num_palette); + else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + png_error(png_ptr, "Valid palette required for paletted images\n"); + +#if defined(PNG_WRITE_tRNS_SUPPORTED) + if (info_ptr->valid & PNG_INFO_tRNS) + { +#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) + /* invert the alpha channel (in tRNS) */ + if ((png_ptr->transformations & PNG_INVERT_ALPHA) && + info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + int j; + for (j=0; j<(int)info_ptr->num_trans; j++) + info_ptr->trans[j] = (png_byte)(255 - info_ptr->trans[j]); + } +#endif + png_write_tRNS(png_ptr, info_ptr->trans, &(info_ptr->trans_values), + info_ptr->num_trans, info_ptr->color_type); + } +#endif +#if defined(PNG_WRITE_bKGD_SUPPORTED) + if (info_ptr->valid & PNG_INFO_bKGD) + png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type); +#endif +#if defined(PNG_WRITE_hIST_SUPPORTED) + if (info_ptr->valid & PNG_INFO_hIST) + png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette); +#endif +#if defined(PNG_WRITE_oFFs_SUPPORTED) + if (info_ptr->valid & PNG_INFO_oFFs) + png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset, + info_ptr->offset_unit_type); +#endif +#if defined(PNG_WRITE_pCAL_SUPPORTED) + if (info_ptr->valid & PNG_INFO_pCAL) + png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0, + info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams, + info_ptr->pcal_units, info_ptr->pcal_params); +#endif +#if defined(PNG_WRITE_sCAL_SUPPORTED) + if (info_ptr->valid & PNG_INFO_sCAL) +#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO) + png_write_sCAL(png_ptr, (int)info_ptr->scal_unit, + info_ptr->scal_pixel_width, info_ptr->scal_pixel_height); +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit, + info_ptr->scal_s_width, info_ptr->scal_s_height); +#else + png_warning(png_ptr, + "png_write_sCAL not supported; sCAL chunk not written.\n"); +#endif +#endif +#endif +#if defined(PNG_WRITE_pHYs_SUPPORTED) + if (info_ptr->valid & PNG_INFO_pHYs) + png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit, + info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type); +#endif +#if defined(PNG_WRITE_tIME_SUPPORTED) + if (info_ptr->valid & PNG_INFO_tIME) + { + png_write_tIME(png_ptr, &(info_ptr->mod_time)); + png_ptr->mode |= PNG_WROTE_tIME; + } +#endif +#if defined(PNG_WRITE_sPLT_SUPPORTED) + if (info_ptr->valid & PNG_INFO_sPLT) + for (i = 0; i < (int)info_ptr->splt_palettes_num; i++) + png_write_sPLT(png_ptr, info_ptr->splt_palettes + i); +#endif +#if defined(PNG_WRITE_TEXT_SUPPORTED) + /* Check to see if we need to write text chunks */ + for (i = 0; i < info_ptr->num_text; i++) + { + png_debug2(2, "Writing header text chunk %d, type %d\n", i, + info_ptr->text[i].compression); + /* an internationalized chunk? */ + if (info_ptr->text[i].compression > 0) + { +#if defined(PNG_WRITE_iTXt_SUPPORTED) + /* write international chunk */ + png_write_iTXt(png_ptr, + info_ptr->text[i].compression, + info_ptr->text[i].key, + info_ptr->text[i].lang, + info_ptr->text[i].lang_key, + info_ptr->text[i].text); +#else + png_warning(png_ptr, "Unable to write international text\n"); +#endif + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; + } + /* If we want a compressed text chunk */ + else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt) + { +#if defined(PNG_WRITE_zTXt_SUPPORTED) + /* write compressed chunk */ + png_write_zTXt(png_ptr, info_ptr->text[i].key, + info_ptr->text[i].text, 0, + info_ptr->text[i].compression); +#else + png_warning(png_ptr, "Unable to write compressed text\n"); +#endif + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; + } + else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) + { +#if defined(PNG_WRITE_tEXt_SUPPORTED) + /* write uncompressed chunk */ + png_write_tEXt(png_ptr, info_ptr->text[i].key, + info_ptr->text[i].text, + 0); +#else + png_warning(png_ptr, "Unable to write uncompressed text\n"); +#endif + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; + } + } +#endif +#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) + if (info_ptr->unknown_chunks_num) + { + png_unknown_chunk *up; + + png_debug(5, "writing extra chunks\n"); + + for (up = info_ptr->unknown_chunks; + up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; + up++) + { + int keep=png_handle_as_unknown(png_ptr, up->name); + if (keep != PNG_HANDLE_CHUNK_NEVER && + up->location && (up->location & PNG_HAVE_PLTE) && + !(up->location & PNG_HAVE_IDAT) && + ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || + (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) + { + png_write_chunk(png_ptr, up->name, up->data, up->size); + } + } + } +#endif +} + +/* Writes the end of the PNG file. If you don't want to write comments or + * time information, you can pass NULL for info. If you already wrote these + * in png_write_info(), do not write them again here. If you have long + * comments, I suggest writing them here, and compressing them. + */ +void PNGAPI +png_write_end(png_structp png_ptr, png_infop info_ptr) +{ + png_debug(1, "in png_write_end\n"); + if (!(png_ptr->mode & PNG_HAVE_IDAT)) + png_error(png_ptr, "No IDATs written into file"); + + /* see if user wants us to write information chunks */ + if (info_ptr != NULL) + { +#if defined(PNG_WRITE_TEXT_SUPPORTED) + int i; /* local index variable */ +#endif +#if defined(PNG_WRITE_tIME_SUPPORTED) + /* check to see if user has supplied a time chunk */ + if ((info_ptr->valid & PNG_INFO_tIME) && + !(png_ptr->mode & PNG_WROTE_tIME)) + png_write_tIME(png_ptr, &(info_ptr->mod_time)); +#endif +#if defined(PNG_WRITE_TEXT_SUPPORTED) + /* loop through comment chunks */ + for (i = 0; i < info_ptr->num_text; i++) + { + png_debug2(2, "Writing trailer text chunk %d, type %d\n", i, + info_ptr->text[i].compression); + /* an internationalized chunk? */ + if (info_ptr->text[i].compression > 0) + { +#if defined(PNG_WRITE_iTXt_SUPPORTED) + /* write international chunk */ + png_write_iTXt(png_ptr, + info_ptr->text[i].compression, + info_ptr->text[i].key, + info_ptr->text[i].lang, + info_ptr->text[i].lang_key, + info_ptr->text[i].text); +#else + png_warning(png_ptr, "Unable to write international text\n"); +#endif + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; + } + else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt) + { +#if defined(PNG_WRITE_zTXt_SUPPORTED) + /* write compressed chunk */ + png_write_zTXt(png_ptr, info_ptr->text[i].key, + info_ptr->text[i].text, 0, + info_ptr->text[i].compression); +#else + png_warning(png_ptr, "Unable to write compressed text\n"); +#endif + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; + } + else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) + { +#if defined(PNG_WRITE_tEXt_SUPPORTED) + /* write uncompressed chunk */ + png_write_tEXt(png_ptr, info_ptr->text[i].key, + info_ptr->text[i].text, 0); +#else + png_warning(png_ptr, "Unable to write uncompressed text\n"); +#endif + + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; + } + } +#endif +#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) + if (info_ptr->unknown_chunks_num) + { + png_unknown_chunk *up; + + png_debug(5, "writing extra chunks\n"); + + for (up = info_ptr->unknown_chunks; + up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; + up++) + { + int keep=png_handle_as_unknown(png_ptr, up->name); + if (keep != PNG_HANDLE_CHUNK_NEVER && + up->location && (up->location & PNG_AFTER_IDAT) && + ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || + (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) + { + png_write_chunk(png_ptr, up->name, up->data, up->size); + } + } + } +#endif + } + + png_ptr->mode |= PNG_AFTER_IDAT; + + /* write end of PNG file */ + png_write_IEND(png_ptr); +#if 0 +/* This flush, added in libpng-1.0.8, causes some applications to crash + because they do not set png_ptr->output_flush_fn */ + png_flush(png_ptr); +#endif +} + +#if defined(PNG_WRITE_tIME_SUPPORTED) +#if !defined(_WIN32_WCE) +/* "time.h" functions are not supported on WindowsCE */ +void PNGAPI +png_convert_from_struct_tm(png_timep ptime, struct tm FAR * ttime) +{ + png_debug(1, "in png_convert_from_struct_tm\n"); + ptime->year = (png_uint_16)(1900 + ttime->tm_year); + ptime->month = (png_byte)(ttime->tm_mon + 1); + ptime->day = (png_byte)ttime->tm_mday; + ptime->hour = (png_byte)ttime->tm_hour; + ptime->minute = (png_byte)ttime->tm_min; + ptime->second = (png_byte)ttime->tm_sec; +} + +void PNGAPI +png_convert_from_time_t(png_timep ptime, time_t ttime) +{ + struct tm *tbuf; + + png_debug(1, "in png_convert_from_time_t\n"); + tbuf = gmtime(&ttime); + png_convert_from_struct_tm(ptime, tbuf); +} +#endif +#endif + +/* Initialize png_ptr structure, and allocate any memory needed */ +png_structp PNGAPI +png_create_write_struct(png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn) +{ +#ifdef PNG_USER_MEM_SUPPORTED + return (png_create_write_struct_2(user_png_ver, error_ptr, error_fn, + warn_fn, png_voidp_NULL, png_malloc_ptr_NULL, png_free_ptr_NULL)); +} + +/* Alternate initialize png_ptr structure, and allocate any memory needed */ +png_structp PNGAPI +png_create_write_struct_2(png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn) +{ +#endif /* PNG_USER_MEM_SUPPORTED */ + volatile png_structp png_ptr; +#ifdef PNG_SETJMP_SUPPORTED +#ifdef USE_FAR_KEYWORD + jmp_buf jmpbuf; +#endif +#endif + int i; + png_debug(1, "in png_create_write_struct\n"); +#ifdef PNG_USER_MEM_SUPPORTED + png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG, + (png_malloc_ptr)malloc_fn, (png_voidp)mem_ptr); +#else + png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG); +#endif /* PNG_USER_MEM_SUPPORTED */ + if (png_ptr == NULL) + return (NULL); + +#if !defined(PNG_1_0_X) +#ifdef PNG_ASSEMBLER_CODE_SUPPORTED + png_init_mmx_flags(png_ptr); /* 1.2.0 addition */ +#endif +#endif /* PNG_1_0_X */ + + /* added at libpng-1.2.6 */ +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + png_ptr->user_width_max=PNG_USER_WIDTH_MAX; + png_ptr->user_height_max=PNG_USER_HEIGHT_MAX; +#endif + +#ifdef PNG_SETJMP_SUPPORTED +#ifdef USE_FAR_KEYWORD + if (setjmp(jmpbuf)) +#else + if (setjmp(png_ptr->jmpbuf)) +#endif + { + png_free(png_ptr, png_ptr->zbuf); + png_ptr->zbuf=NULL; + png_destroy_struct(png_ptr); + return (NULL); + } +#ifdef USE_FAR_KEYWORD + png_memcpy(png_ptr->jmpbuf,jmpbuf,png_sizeof(jmp_buf)); +#endif +#endif + +#ifdef PNG_USER_MEM_SUPPORTED + png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn); +#endif /* PNG_USER_MEM_SUPPORTED */ + png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn); + + i=0; + do + { + if(user_png_ver[i] != png_libpng_ver[i]) + png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; + } while (png_libpng_ver[i++]); + + if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) + { + /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so + * we must recompile any applications that use any older library version. + * For versions after libpng 1.0, we will be compatible, so we need + * only check the first digit. + */ + if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] || + (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) || + (user_png_ver[0] == '0' && user_png_ver[2] < '9')) + { +#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) + char msg[80]; + if (user_png_ver) + { + sprintf(msg, "Application was compiled with png.h from libpng-%.20s", + user_png_ver); + png_warning(png_ptr, msg); + } + sprintf(msg, "Application is running with png.c from libpng-%.20s", + png_libpng_ver); + png_warning(png_ptr, msg); +#endif +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + png_ptr->flags=0; +#endif + png_error(png_ptr, + "Incompatible libpng version in application and library"); + } + } + + /* initialize zbuf - compression buffer */ + png_ptr->zbuf_size = PNG_ZBUF_SIZE; + png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, + (png_uint_32)png_ptr->zbuf_size); + + png_set_write_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL, + png_flush_ptr_NULL); + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) + png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT, + 1, png_doublep_NULL, png_doublep_NULL); +#endif + +#ifdef PNG_SETJMP_SUPPORTED +/* Applications that neglect to set up their own setjmp() and then encounter + a png_error() will longjmp here. Since the jmpbuf is then meaningless we + abort instead of returning. */ +#ifdef USE_FAR_KEYWORD + if (setjmp(jmpbuf)) + PNG_ABORT(); + png_memcpy(png_ptr->jmpbuf,jmpbuf,png_sizeof(jmp_buf)); +#else + if (setjmp(png_ptr->jmpbuf)) + PNG_ABORT(); +#endif +#endif + return (png_ptr); +} + +/* Initialize png_ptr structure, and allocate any memory needed */ +#undef png_write_init +void PNGAPI +png_write_init(png_structp png_ptr) +{ + /* We only come here via pre-1.0.7-compiled applications */ + png_write_init_2(png_ptr, "1.0.6 or earlier", 0, 0); +} + +void PNGAPI +png_write_init_2(png_structp png_ptr, png_const_charp user_png_ver, + png_size_t png_struct_size, png_size_t png_info_size) +{ + /* We only come here via pre-1.0.12-compiled applications */ +#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) + if(png_sizeof(png_struct) > png_struct_size || + png_sizeof(png_info) > png_info_size) + { + char msg[80]; + png_ptr->warning_fn=NULL; + if (user_png_ver) + { + sprintf(msg, "Application was compiled with png.h from libpng-%.20s", + user_png_ver); + png_warning(png_ptr, msg); + } + sprintf(msg, "Application is running with png.c from libpng-%.20s", + png_libpng_ver); + png_warning(png_ptr, msg); + } +#endif + if(png_sizeof(png_struct) > png_struct_size) + { + png_ptr->error_fn=NULL; +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + png_ptr->flags=0; +#endif + png_error(png_ptr, + "The png struct allocated by the application for writing is too small."); + } + if(png_sizeof(png_info) > png_info_size) + { + png_ptr->error_fn=NULL; +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + png_ptr->flags=0; +#endif + png_error(png_ptr, + "The info struct allocated by the application for writing is too small."); + } + png_write_init_3(&png_ptr, user_png_ver, png_struct_size); +} + + +void PNGAPI +png_write_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver, + png_size_t png_struct_size) +{ + png_structp png_ptr=*ptr_ptr; +#ifdef PNG_SETJMP_SUPPORTED + jmp_buf tmp_jmp; /* to save current jump buffer */ +#endif + int i = 0; + do + { + if (user_png_ver[i] != png_libpng_ver[i]) + { +#ifdef PNG_LEGACY_SUPPORTED + png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; +#else + png_ptr->warning_fn=NULL; + png_warning(png_ptr, + "Application uses deprecated png_write_init() and should be recompiled."); + break; +#endif + } + } while (png_libpng_ver[i++]); + + png_debug(1, "in png_write_init_3\n"); + +#ifdef PNG_SETJMP_SUPPORTED + /* save jump buffer and error functions */ + png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof (jmp_buf)); +#endif + + if (png_sizeof(png_struct) > png_struct_size) + { + png_destroy_struct(png_ptr); + png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG); + *ptr_ptr = png_ptr; + } + + /* reset all variables to 0 */ + png_memset(png_ptr, 0, png_sizeof (png_struct)); + + /* added at libpng-1.2.6 */ +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + png_ptr->user_width_max=PNG_USER_WIDTH_MAX; + png_ptr->user_height_max=PNG_USER_HEIGHT_MAX; +#endif + +#if !defined(PNG_1_0_X) +#ifdef PNG_ASSEMBLER_CODE_SUPPORTED + png_init_mmx_flags(png_ptr); /* 1.2.0 addition */ +#endif +#endif /* PNG_1_0_X */ + +#ifdef PNG_SETJMP_SUPPORTED + /* restore jump buffer */ + png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof (jmp_buf)); +#endif + + png_set_write_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL, + png_flush_ptr_NULL); + + /* initialize zbuf - compression buffer */ + png_ptr->zbuf_size = PNG_ZBUF_SIZE; + png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, + (png_uint_32)png_ptr->zbuf_size); + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) + png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT, + 1, png_doublep_NULL, png_doublep_NULL); +#endif +} + +/* Write a few rows of image data. If the image is interlaced, + * either you will have to write the 7 sub images, or, if you + * have called png_set_interlace_handling(), you will have to + * "write" the image seven times. + */ +void PNGAPI +png_write_rows(png_structp png_ptr, png_bytepp row, + png_uint_32 num_rows) +{ + png_uint_32 i; /* row counter */ + png_bytepp rp; /* row pointer */ + + png_debug(1, "in png_write_rows\n"); + /* loop through the rows */ + for (i = 0, rp = row; i < num_rows; i++, rp++) + { + png_write_row(png_ptr, *rp); + } +} + +/* Write the image. You only need to call this function once, even + * if you are writing an interlaced image. + */ +void PNGAPI +png_write_image(png_structp png_ptr, png_bytepp image) +{ + png_uint_32 i; /* row index */ + int pass, num_pass; /* pass variables */ + png_bytepp rp; /* points to current row */ + + png_debug(1, "in png_write_image\n"); +#if defined(PNG_WRITE_INTERLACING_SUPPORTED) + /* intialize interlace handling. If image is not interlaced, + this will set pass to 1 */ + num_pass = png_set_interlace_handling(png_ptr); +#else + num_pass = 1; +#endif + /* loop through passes */ + for (pass = 0; pass < num_pass; pass++) + { + /* loop through image */ + for (i = 0, rp = image; i < png_ptr->height; i++, rp++) + { + png_write_row(png_ptr, *rp); + } + } +} + +/* called by user to write a row of image data */ +void PNGAPI +png_write_row(png_structp png_ptr, png_bytep row) +{ + png_debug2(1, "in png_write_row (row %ld, pass %d)\n", + png_ptr->row_number, png_ptr->pass); + /* initialize transformations and other stuff if first time */ + if (png_ptr->row_number == 0 && png_ptr->pass == 0) + { + /* make sure we wrote the header info */ + if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE)) + png_error(png_ptr, + "png_write_info was never called before png_write_row."); + + /* check for transforms that have been set but were defined out */ +#if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED) + if (png_ptr->transformations & PNG_INVERT_MONO) + png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined."); +#endif +#if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED) + if (png_ptr->transformations & PNG_FILLER) + png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined."); +#endif +#if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + png_warning(png_ptr, "PNG_WRITE_PACKSWAP_SUPPORTED is not defined."); +#endif +#if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED) + if (png_ptr->transformations & PNG_PACK) + png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined."); +#endif +#if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED) + if (png_ptr->transformations & PNG_SHIFT) + png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined."); +#endif +#if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED) + if (png_ptr->transformations & PNG_BGR) + png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined."); +#endif +#if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED) + if (png_ptr->transformations & PNG_SWAP_BYTES) + png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined."); +#endif + + png_write_start_row(png_ptr); + } + +#if defined(PNG_WRITE_INTERLACING_SUPPORTED) + /* if interlaced and not interested in row, return */ + if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) + { + switch (png_ptr->pass) + { + case 0: + if (png_ptr->row_number & 0x07) + { + png_write_finish_row(png_ptr); + return; + } + break; + case 1: + if ((png_ptr->row_number & 0x07) || png_ptr->width < 5) + { + png_write_finish_row(png_ptr); + return; + } + break; + case 2: + if ((png_ptr->row_number & 0x07) != 4) + { + png_write_finish_row(png_ptr); + return; + } + break; + case 3: + if ((png_ptr->row_number & 0x03) || png_ptr->width < 3) + { + png_write_finish_row(png_ptr); + return; + } + break; + case 4: + if ((png_ptr->row_number & 0x03) != 2) + { + png_write_finish_row(png_ptr); + return; + } + break; + case 5: + if ((png_ptr->row_number & 0x01) || png_ptr->width < 2) + { + png_write_finish_row(png_ptr); + return; + } + break; + case 6: + if (!(png_ptr->row_number & 0x01)) + { + png_write_finish_row(png_ptr); + return; + } + break; + } + } +#endif + + /* set up row info for transformations */ + png_ptr->row_info.color_type = png_ptr->color_type; + png_ptr->row_info.width = png_ptr->usr_width; + png_ptr->row_info.channels = png_ptr->usr_channels; + png_ptr->row_info.bit_depth = png_ptr->usr_bit_depth; + png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth * + png_ptr->row_info.channels); + + png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth, + png_ptr->row_info.width); + + png_debug1(3, "row_info->color_type = %d\n", png_ptr->row_info.color_type); + png_debug1(3, "row_info->width = %lu\n", png_ptr->row_info.width); + png_debug1(3, "row_info->channels = %d\n", png_ptr->row_info.channels); + png_debug1(3, "row_info->bit_depth = %d\n", png_ptr->row_info.bit_depth); + png_debug1(3, "row_info->pixel_depth = %d\n", png_ptr->row_info.pixel_depth); + png_debug1(3, "row_info->rowbytes = %lu\n", png_ptr->row_info.rowbytes); + + /* Copy user's row into buffer, leaving room for filter byte. */ + png_memcpy_check(png_ptr, png_ptr->row_buf + 1, row, + png_ptr->row_info.rowbytes); + +#if defined(PNG_WRITE_INTERLACING_SUPPORTED) + /* handle interlacing */ + if (png_ptr->interlaced && png_ptr->pass < 6 && + (png_ptr->transformations & PNG_INTERLACE)) + { + png_do_write_interlace(&(png_ptr->row_info), + png_ptr->row_buf + 1, png_ptr->pass); + /* this should always get caught above, but still ... */ + if (!(png_ptr->row_info.width)) + { + png_write_finish_row(png_ptr); + return; + } + } +#endif + + /* handle other transformations */ + if (png_ptr->transformations) + png_do_write_transformations(png_ptr); + +#if defined(PNG_MNG_FEATURES_SUPPORTED) + /* Write filter_method 64 (intrapixel differencing) only if + * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and + * 2. Libpng did not write a PNG signature (this filter_method is only + * used in PNG datastreams that are embedded in MNG datastreams) and + * 3. The application called png_permit_mng_features with a mask that + * included PNG_FLAG_MNG_FILTER_64 and + * 4. The filter_method is 64 and + * 5. The color_type is RGB or RGBA + */ + if((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && + (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) + { + /* Intrapixel differencing */ + png_do_write_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1); + } +#endif + + /* Find a filter if necessary, filter the row and write it out. */ + png_write_find_filter(png_ptr, &(png_ptr->row_info)); + + if (png_ptr->write_row_fn != NULL) + (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); +} + +#if defined(PNG_WRITE_FLUSH_SUPPORTED) +/* Set the automatic flush interval or 0 to turn flushing off */ +void PNGAPI +png_set_flush(png_structp png_ptr, int nrows) +{ + png_debug(1, "in png_set_flush\n"); + png_ptr->flush_dist = (nrows < 0 ? 0 : nrows); +} + +/* flush the current output buffers now */ +void PNGAPI +png_write_flush(png_structp png_ptr) +{ + int wrote_IDAT; + + png_debug(1, "in png_write_flush\n"); + /* We have already written out all of the data */ + if (png_ptr->row_number >= png_ptr->num_rows) + return; + + do + { + int ret; + + /* compress the data */ + ret = deflate(&png_ptr->zstream, Z_SYNC_FLUSH); + wrote_IDAT = 0; + + /* check for compression errors */ + if (ret != Z_OK) + { + if (png_ptr->zstream.msg != NULL) + png_error(png_ptr, png_ptr->zstream.msg); + else + png_error(png_ptr, "zlib error"); + } + + if (!(png_ptr->zstream.avail_out)) + { + /* write the IDAT and reset the zlib output buffer */ + png_write_IDAT(png_ptr, png_ptr->zbuf, + png_ptr->zbuf_size); + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + wrote_IDAT = 1; + } + } while(wrote_IDAT == 1); + + /* If there is any data left to be output, write it into a new IDAT */ + if (png_ptr->zbuf_size != png_ptr->zstream.avail_out) + { + /* write the IDAT and reset the zlib output buffer */ + png_write_IDAT(png_ptr, png_ptr->zbuf, + png_ptr->zbuf_size - png_ptr->zstream.avail_out); + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + } + png_ptr->flush_rows = 0; + png_flush(png_ptr); +} +#endif /* PNG_WRITE_FLUSH_SUPPORTED */ + +/* free all memory used by the write */ +void PNGAPI +png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr) +{ + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; +#ifdef PNG_USER_MEM_SUPPORTED + png_free_ptr free_fn = NULL; + png_voidp mem_ptr = NULL; +#endif + + png_debug(1, "in png_destroy_write_struct\n"); + if (png_ptr_ptr != NULL) + { + png_ptr = *png_ptr_ptr; +#ifdef PNG_USER_MEM_SUPPORTED + free_fn = png_ptr->free_fn; + mem_ptr = png_ptr->mem_ptr; +#endif + } + + if (info_ptr_ptr != NULL) + info_ptr = *info_ptr_ptr; + + if (info_ptr != NULL) + { + png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); + +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) + if (png_ptr->num_chunk_list) + { + png_free(png_ptr, png_ptr->chunk_list); + png_ptr->chunk_list=NULL; + png_ptr->num_chunk_list=0; + } +#endif + +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn, + (png_voidp)mem_ptr); +#else + png_destroy_struct((png_voidp)info_ptr); +#endif + *info_ptr_ptr = NULL; + } + + if (png_ptr != NULL) + { + png_write_destroy(png_ptr); +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn, + (png_voidp)mem_ptr); +#else + png_destroy_struct((png_voidp)png_ptr); +#endif + *png_ptr_ptr = NULL; + } +} + + +/* Free any memory used in png_ptr struct (old method) */ +void /* PRIVATE */ +png_write_destroy(png_structp png_ptr) +{ +#ifdef PNG_SETJMP_SUPPORTED + jmp_buf tmp_jmp; /* save jump buffer */ +#endif + png_error_ptr error_fn; + png_error_ptr warning_fn; + png_voidp error_ptr; +#ifdef PNG_USER_MEM_SUPPORTED + png_free_ptr free_fn; +#endif + + png_debug(1, "in png_write_destroy\n"); + /* free any memory zlib uses */ + deflateEnd(&png_ptr->zstream); + + /* free our memory. png_free checks NULL for us. */ + png_free(png_ptr, png_ptr->zbuf); + png_free(png_ptr, png_ptr->row_buf); + png_free(png_ptr, png_ptr->prev_row); + png_free(png_ptr, png_ptr->sub_row); + png_free(png_ptr, png_ptr->up_row); + png_free(png_ptr, png_ptr->avg_row); + png_free(png_ptr, png_ptr->paeth_row); + +#if defined(PNG_TIME_RFC1123_SUPPORTED) + png_free(png_ptr, png_ptr->time_buffer); +#endif + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) + png_free(png_ptr, png_ptr->prev_filters); + png_free(png_ptr, png_ptr->filter_weights); + png_free(png_ptr, png_ptr->inv_filter_weights); + png_free(png_ptr, png_ptr->filter_costs); + png_free(png_ptr, png_ptr->inv_filter_costs); +#endif + +#ifdef PNG_SETJMP_SUPPORTED + /* reset structure */ + png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof (jmp_buf)); +#endif + + error_fn = png_ptr->error_fn; + warning_fn = png_ptr->warning_fn; + error_ptr = png_ptr->error_ptr; +#ifdef PNG_USER_MEM_SUPPORTED + free_fn = png_ptr->free_fn; +#endif + + png_memset(png_ptr, 0, png_sizeof (png_struct)); + + png_ptr->error_fn = error_fn; + png_ptr->warning_fn = warning_fn; + png_ptr->error_ptr = error_ptr; +#ifdef PNG_USER_MEM_SUPPORTED + png_ptr->free_fn = free_fn; +#endif + +#ifdef PNG_SETJMP_SUPPORTED + png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof (jmp_buf)); +#endif +} + +/* Allow the application to select one or more row filters to use. */ +void PNGAPI +png_set_filter(png_structp png_ptr, int method, int filters) +{ + png_debug(1, "in png_set_filter\n"); +#if defined(PNG_MNG_FEATURES_SUPPORTED) + if((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && + (method == PNG_INTRAPIXEL_DIFFERENCING)) + method = PNG_FILTER_TYPE_BASE; +#endif + if (method == PNG_FILTER_TYPE_BASE) + { + switch (filters & (PNG_ALL_FILTERS | 0x07)) + { + case 5: + case 6: + case 7: png_warning(png_ptr, "Unknown row filter for method 0"); + case PNG_FILTER_VALUE_NONE: png_ptr->do_filter=PNG_FILTER_NONE; break; + case PNG_FILTER_VALUE_SUB: png_ptr->do_filter=PNG_FILTER_SUB; break; + case PNG_FILTER_VALUE_UP: png_ptr->do_filter=PNG_FILTER_UP; break; + case PNG_FILTER_VALUE_AVG: png_ptr->do_filter=PNG_FILTER_AVG; break; + case PNG_FILTER_VALUE_PAETH: png_ptr->do_filter=PNG_FILTER_PAETH;break; + default: png_ptr->do_filter = (png_byte)filters; break; + } + + /* If we have allocated the row_buf, this means we have already started + * with the image and we should have allocated all of the filter buffers + * that have been selected. If prev_row isn't already allocated, then + * it is too late to start using the filters that need it, since we + * will be missing the data in the previous row. If an application + * wants to start and stop using particular filters during compression, + * it should start out with all of the filters, and then add and + * remove them after the start of compression. + */ + if (png_ptr->row_buf != NULL) + { + if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL) + { + png_ptr->sub_row = (png_bytep)png_malloc(png_ptr, + (png_ptr->rowbytes + 1)); + png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB; + } + + if ((png_ptr->do_filter & PNG_FILTER_UP) && png_ptr->up_row == NULL) + { + if (png_ptr->prev_row == NULL) + { + png_warning(png_ptr, "Can't add Up filter after starting"); + png_ptr->do_filter &= ~PNG_FILTER_UP; + } + else + { + png_ptr->up_row = (png_bytep)png_malloc(png_ptr, + (png_ptr->rowbytes + 1)); + png_ptr->up_row[0] = PNG_FILTER_VALUE_UP; + } + } + + if ((png_ptr->do_filter & PNG_FILTER_AVG) && png_ptr->avg_row == NULL) + { + if (png_ptr->prev_row == NULL) + { + png_warning(png_ptr, "Can't add Average filter after starting"); + png_ptr->do_filter &= ~PNG_FILTER_AVG; + } + else + { + png_ptr->avg_row = (png_bytep)png_malloc(png_ptr, + (png_ptr->rowbytes + 1)); + png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG; + } + } + + if ((png_ptr->do_filter & PNG_FILTER_PAETH) && + png_ptr->paeth_row == NULL) + { + if (png_ptr->prev_row == NULL) + { + png_warning(png_ptr, "Can't add Paeth filter after starting"); + png_ptr->do_filter &= (png_byte)(~PNG_FILTER_PAETH); + } + else + { + png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr, + (png_ptr->rowbytes + 1)); + png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH; + } + } + + if (png_ptr->do_filter == PNG_NO_FILTERS) + png_ptr->do_filter = PNG_FILTER_NONE; + } + } + else + png_error(png_ptr, "Unknown custom filter method"); +} + +/* This allows us to influence the way in which libpng chooses the "best" + * filter for the current scanline. While the "minimum-sum-of-absolute- + * differences metric is relatively fast and effective, there is some + * question as to whether it can be improved upon by trying to keep the + * filtered data going to zlib more consistent, hopefully resulting in + * better compression. + */ +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) /* GRR 970116 */ +void PNGAPI +png_set_filter_heuristics(png_structp png_ptr, int heuristic_method, + int num_weights, png_doublep filter_weights, + png_doublep filter_costs) +{ + int i; + + png_debug(1, "in png_set_filter_heuristics\n"); + if (heuristic_method >= PNG_FILTER_HEURISTIC_LAST) + { + png_warning(png_ptr, "Unknown filter heuristic method"); + return; + } + + if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT) + { + heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED; + } + + if (num_weights < 0 || filter_weights == NULL || + heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED) + { + num_weights = 0; + } + + png_ptr->num_prev_filters = (png_byte)num_weights; + png_ptr->heuristic_method = (png_byte)heuristic_method; + + if (num_weights > 0) + { + if (png_ptr->prev_filters == NULL) + { + png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr, + (png_uint_32)(png_sizeof(png_byte) * num_weights)); + + /* To make sure that the weighting starts out fairly */ + for (i = 0; i < num_weights; i++) + { + png_ptr->prev_filters[i] = 255; + } + } + + if (png_ptr->filter_weights == NULL) + { + png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(png_sizeof(png_uint_16) * num_weights)); + + png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(png_sizeof(png_uint_16) * num_weights)); + for (i = 0; i < num_weights; i++) + { + png_ptr->inv_filter_weights[i] = + png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR; + } + } + + for (i = 0; i < num_weights; i++) + { + if (filter_weights[i] < 0.0) + { + png_ptr->inv_filter_weights[i] = + png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR; + } + else + { + png_ptr->inv_filter_weights[i] = + (png_uint_16)((double)PNG_WEIGHT_FACTOR*filter_weights[i]+0.5); + png_ptr->filter_weights[i] = + (png_uint_16)((double)PNG_WEIGHT_FACTOR/filter_weights[i]+0.5); + } + } + } + + /* If, in the future, there are other filter methods, this would + * need to be based on png_ptr->filter. + */ + if (png_ptr->filter_costs == NULL) + { + png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST)); + + png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST)); + + for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) + { + png_ptr->inv_filter_costs[i] = + png_ptr->filter_costs[i] = PNG_COST_FACTOR; + } + } + + /* Here is where we set the relative costs of the different filters. We + * should take the desired compression level into account when setting + * the costs, so that Paeth, for instance, has a high relative cost at low + * compression levels, while it has a lower relative cost at higher + * compression settings. The filter types are in order of increasing + * relative cost, so it would be possible to do this with an algorithm. + */ + for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) + { + if (filter_costs == NULL || filter_costs[i] < 0.0) + { + png_ptr->inv_filter_costs[i] = + png_ptr->filter_costs[i] = PNG_COST_FACTOR; + } + else if (filter_costs[i] >= 1.0) + { + png_ptr->inv_filter_costs[i] = + (png_uint_16)((double)PNG_COST_FACTOR / filter_costs[i] + 0.5); + png_ptr->filter_costs[i] = + (png_uint_16)((double)PNG_COST_FACTOR * filter_costs[i] + 0.5); + } + } +} +#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ + +void PNGAPI +png_set_compression_level(png_structp png_ptr, int level) +{ + png_debug(1, "in png_set_compression_level\n"); + png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL; + png_ptr->zlib_level = level; +} + +void PNGAPI +png_set_compression_mem_level(png_structp png_ptr, int mem_level) +{ + png_debug(1, "in png_set_compression_mem_level\n"); + png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL; + png_ptr->zlib_mem_level = mem_level; +} + +void PNGAPI +png_set_compression_strategy(png_structp png_ptr, int strategy) +{ + png_debug(1, "in png_set_compression_strategy\n"); + png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY; + png_ptr->zlib_strategy = strategy; +} + +void PNGAPI +png_set_compression_window_bits(png_structp png_ptr, int window_bits) +{ + if (window_bits > 15) + png_warning(png_ptr, "Only compression windows <= 32k supported by PNG"); + else if (window_bits < 8) + png_warning(png_ptr, "Only compression windows >= 256 supported by PNG"); +#ifndef WBITS_8_OK + /* avoid libpng bug with 256-byte windows */ + if (window_bits == 8) + { + png_warning(png_ptr, "Compression window is being reset to 512"); + window_bits=9; + } +#endif + png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS; + png_ptr->zlib_window_bits = window_bits; +} + +void PNGAPI +png_set_compression_method(png_structp png_ptr, int method) +{ + png_debug(1, "in png_set_compression_method\n"); + if (method != 8) + png_warning(png_ptr, "Only compression method 8 is supported by PNG"); + png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD; + png_ptr->zlib_method = method; +} + +void PNGAPI +png_set_write_status_fn(png_structp png_ptr, png_write_status_ptr write_row_fn) +{ + png_ptr->write_row_fn = write_row_fn; +} + +#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) +void PNGAPI +png_set_write_user_transform_fn(png_structp png_ptr, png_user_transform_ptr + write_user_transform_fn) +{ + png_debug(1, "in png_set_write_user_transform_fn\n"); + png_ptr->transformations |= PNG_USER_TRANSFORM; + png_ptr->write_user_transform_fn = write_user_transform_fn; +} +#endif + + +#if defined(PNG_INFO_IMAGE_SUPPORTED) +void PNGAPI +png_write_png(png_structp png_ptr, png_infop info_ptr, + int transforms, voidp params) +{ +#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) + /* invert the alpha channel from opacity to transparency */ + if (transforms & PNG_TRANSFORM_INVERT_ALPHA) + png_set_invert_alpha(png_ptr); +#endif + + /* Write the file header information. */ + png_write_info(png_ptr, info_ptr); + + /* ------ these transformations don't touch the info structure ------- */ + +#if defined(PNG_WRITE_INVERT_SUPPORTED) + /* invert monochrome pixels */ + if (transforms & PNG_TRANSFORM_INVERT_MONO) + png_set_invert_mono(png_ptr); +#endif + +#if defined(PNG_WRITE_SHIFT_SUPPORTED) + /* Shift the pixels up to a legal bit depth and fill in + * as appropriate to correctly scale the image. + */ + if ((transforms & PNG_TRANSFORM_SHIFT) + && (info_ptr->valid & PNG_INFO_sBIT)) + png_set_shift(png_ptr, &info_ptr->sig_bit); +#endif + +#if defined(PNG_WRITE_PACK_SUPPORTED) + /* pack pixels into bytes */ + if (transforms & PNG_TRANSFORM_PACKING) + png_set_packing(png_ptr); +#endif + +#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) + /* swap location of alpha bytes from ARGB to RGBA */ + if (transforms & PNG_TRANSFORM_SWAP_ALPHA) + png_set_swap_alpha(png_ptr); +#endif + +#if defined(PNG_WRITE_FILLER_SUPPORTED) + /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into + * RGB (4 channels -> 3 channels). The second parameter is not used. + */ + if (transforms & PNG_TRANSFORM_STRIP_FILLER) + png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); +#endif + +#if defined(PNG_WRITE_BGR_SUPPORTED) + /* flip BGR pixels to RGB */ + if (transforms & PNG_TRANSFORM_BGR) + png_set_bgr(png_ptr); +#endif + +#if defined(PNG_WRITE_SWAP_SUPPORTED) + /* swap bytes of 16-bit files to most significant byte first */ + if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) + png_set_swap(png_ptr); +#endif + +#if defined(PNG_WRITE_PACKSWAP_SUPPORTED) + /* swap bits of 1, 2, 4 bit packed pixel formats */ + if (transforms & PNG_TRANSFORM_PACKSWAP) + png_set_packswap(png_ptr); +#endif + + /* ----------------------- end of transformations ------------------- */ + + /* write the bits */ + if (info_ptr->valid & PNG_INFO_IDAT) + png_write_image(png_ptr, info_ptr->row_pointers); + + /* It is REQUIRED to call this to finish writing the rest of the file */ + png_write_end(png_ptr, info_ptr); + + if(transforms == 0 || params == NULL) + /* quiet compiler warnings */ return; +} +#endif +#endif /* PNG_WRITE_SUPPORTED */ diff --git a/syslinux/com32/lib/libpng/pngwtran.c b/syslinux/com32/lib/libpng/pngwtran.c new file mode 100644 index 0000000..f1c8b3e --- /dev/null +++ b/syslinux/com32/lib/libpng/pngwtran.c @@ -0,0 +1,563 @@ + +/* pngwtran.c - transforms the data in a row for PNG writers + * + * libpng version 1.2.8 - December 3, 2004 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2004 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + */ + +#define PNG_INTERNAL +#include "png.h" +#ifdef PNG_WRITE_SUPPORTED + +/* Transform the data according to the user's wishes. The order of + * transformations is significant. + */ +void /* PRIVATE */ +png_do_write_transformations(png_structp png_ptr) +{ + png_debug(1, "in png_do_write_transformations\n"); + + if (png_ptr == NULL) + return; + +#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) + if (png_ptr->transformations & PNG_USER_TRANSFORM) + if(png_ptr->write_user_transform_fn != NULL) + (*(png_ptr->write_user_transform_fn)) /* user write transform function */ + (png_ptr, /* png_ptr */ + &(png_ptr->row_info), /* row_info: */ + /* png_uint_32 width; width of row */ + /* png_uint_32 rowbytes; number of bytes in row */ + /* png_byte color_type; color type of pixels */ + /* png_byte bit_depth; bit depth of samples */ + /* png_byte channels; number of channels (1-4) */ + /* png_byte pixel_depth; bits per pixel (depth*channels) */ + png_ptr->row_buf + 1); /* start of pixel data for row */ +#endif +#if defined(PNG_WRITE_FILLER_SUPPORTED) + if (png_ptr->transformations & PNG_FILLER) + png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1, + png_ptr->flags); +#endif +#if defined(PNG_WRITE_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif +#if defined(PNG_WRITE_PACK_SUPPORTED) + if (png_ptr->transformations & PNG_PACK) + png_do_pack(&(png_ptr->row_info), png_ptr->row_buf + 1, + (png_uint_32)png_ptr->bit_depth); +#endif +#if defined(PNG_WRITE_SWAP_SUPPORTED) + if (png_ptr->transformations & PNG_SWAP_BYTES) + png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif +#if defined(PNG_WRITE_SHIFT_SUPPORTED) + if (png_ptr->transformations & PNG_SHIFT) + png_do_shift(&(png_ptr->row_info), png_ptr->row_buf + 1, + &(png_ptr->shift)); +#endif +#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) + if (png_ptr->transformations & PNG_INVERT_ALPHA) + png_do_write_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif +#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) + if (png_ptr->transformations & PNG_SWAP_ALPHA) + png_do_write_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif +#if defined(PNG_WRITE_BGR_SUPPORTED) + if (png_ptr->transformations & PNG_BGR) + png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif +#if defined(PNG_WRITE_INVERT_SUPPORTED) + if (png_ptr->transformations & PNG_INVERT_MONO) + png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif +} + +#if defined(PNG_WRITE_PACK_SUPPORTED) +/* Pack pixels into bytes. Pass the true bit depth in bit_depth. The + * row_info bit depth should be 8 (one pixel per byte). The channels + * should be 1 (this only happens on grayscale and paletted images). + */ +void /* PRIVATE */ +png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth) +{ + png_debug(1, "in png_do_pack\n"); + if (row_info->bit_depth == 8 && +#if defined(PNG_USELESS_TESTS_SUPPORTED) + row != NULL && row_info != NULL && +#endif + row_info->channels == 1) + { + switch ((int)bit_depth) + { + case 1: + { + png_bytep sp, dp; + int mask, v; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + sp = row; + dp = row; + mask = 0x80; + v = 0; + + for (i = 0; i < row_width; i++) + { + if (*sp != 0) + v |= mask; + sp++; + if (mask > 1) + mask >>= 1; + else + { + mask = 0x80; + *dp = (png_byte)v; + dp++; + v = 0; + } + } + if (mask != 0x80) + *dp = (png_byte)v; + break; + } + case 2: + { + png_bytep sp, dp; + int shift, v; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + sp = row; + dp = row; + shift = 6; + v = 0; + for (i = 0; i < row_width; i++) + { + png_byte value; + + value = (png_byte)(*sp & 0x03); + v |= (value << shift); + if (shift == 0) + { + shift = 6; + *dp = (png_byte)v; + dp++; + v = 0; + } + else + shift -= 2; + sp++; + } + if (shift != 6) + *dp = (png_byte)v; + break; + } + case 4: + { + png_bytep sp, dp; + int shift, v; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + sp = row; + dp = row; + shift = 4; + v = 0; + for (i = 0; i < row_width; i++) + { + png_byte value; + + value = (png_byte)(*sp & 0x0f); + v |= (value << shift); + + if (shift == 0) + { + shift = 4; + *dp = (png_byte)v; + dp++; + v = 0; + } + else + shift -= 4; + + sp++; + } + if (shift != 4) + *dp = (png_byte)v; + break; + } + } + row_info->bit_depth = (png_byte)bit_depth; + row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, + row_info->width); + } +} +#endif + +#if defined(PNG_WRITE_SHIFT_SUPPORTED) +/* Shift pixel values to take advantage of whole range. Pass the + * true number of bits in bit_depth. The row should be packed + * according to row_info->bit_depth. Thus, if you had a row of + * bit depth 4, but the pixels only had values from 0 to 7, you + * would pass 3 as bit_depth, and this routine would translate the + * data to 0 to 15. + */ +void /* PRIVATE */ +png_do_shift(png_row_infop row_info, png_bytep row, png_color_8p bit_depth) +{ + png_debug(1, "in png_do_shift\n"); +#if defined(PNG_USELESS_TESTS_SUPPORTED) + if (row != NULL && row_info != NULL && +#else + if ( +#endif + row_info->color_type != PNG_COLOR_TYPE_PALETTE) + { + int shift_start[4], shift_dec[4]; + int channels = 0; + + if (row_info->color_type & PNG_COLOR_MASK_COLOR) + { + shift_start[channels] = row_info->bit_depth - bit_depth->red; + shift_dec[channels] = bit_depth->red; + channels++; + shift_start[channels] = row_info->bit_depth - bit_depth->green; + shift_dec[channels] = bit_depth->green; + channels++; + shift_start[channels] = row_info->bit_depth - bit_depth->blue; + shift_dec[channels] = bit_depth->blue; + channels++; + } + else + { + shift_start[channels] = row_info->bit_depth - bit_depth->gray; + shift_dec[channels] = bit_depth->gray; + channels++; + } + if (row_info->color_type & PNG_COLOR_MASK_ALPHA) + { + shift_start[channels] = row_info->bit_depth - bit_depth->alpha; + shift_dec[channels] = bit_depth->alpha; + channels++; + } + + /* with low row depths, could only be grayscale, so one channel */ + if (row_info->bit_depth < 8) + { + png_bytep bp = row; + png_uint_32 i; + png_byte mask; + png_uint_32 row_bytes = row_info->rowbytes; + + if (bit_depth->gray == 1 && row_info->bit_depth == 2) + mask = 0x55; + else if (row_info->bit_depth == 4 && bit_depth->gray == 3) + mask = 0x11; + else + mask = 0xff; + + for (i = 0; i < row_bytes; i++, bp++) + { + png_uint_16 v; + int j; + + v = *bp; + *bp = 0; + for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0]) + { + if (j > 0) + *bp |= (png_byte)((v << j) & 0xff); + else + *bp |= (png_byte)((v >> (-j)) & mask); + } + } + } + else if (row_info->bit_depth == 8) + { + png_bytep bp = row; + png_uint_32 i; + png_uint_32 istop = channels * row_info->width; + + for (i = 0; i < istop; i++, bp++) + { + + png_uint_16 v; + int j; + int c = (int)(i%channels); + + v = *bp; + *bp = 0; + for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c]) + { + if (j > 0) + *bp |= (png_byte)((v << j) & 0xff); + else + *bp |= (png_byte)((v >> (-j)) & 0xff); + } + } + } + else + { + png_bytep bp; + png_uint_32 i; + png_uint_32 istop = channels * row_info->width; + + for (bp = row, i = 0; i < istop; i++) + { + int c = (int)(i%channels); + png_uint_16 value, v; + int j; + + v = (png_uint_16)(((png_uint_16)(*bp) << 8) + *(bp + 1)); + value = 0; + for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c]) + { + if (j > 0) + value |= (png_uint_16)((v << j) & (png_uint_16)0xffff); + else + value |= (png_uint_16)((v >> (-j)) & (png_uint_16)0xffff); + } + *bp++ = (png_byte)(value >> 8); + *bp++ = (png_byte)(value & 0xff); + } + } + } +} +#endif + +#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) +void /* PRIVATE */ +png_do_write_swap_alpha(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_write_swap_alpha\n"); +#if defined(PNG_USELESS_TESTS_SUPPORTED) + if (row != NULL && row_info != NULL) +#endif + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + /* This converts from ARGB to RGBA */ + if (row_info->bit_depth == 8) + { + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + for (i = 0, sp = dp = row; i < row_width; i++) + { + png_byte save = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = save; + } + } + /* This converts from AARRGGBB to RRGGBBAA */ + else + { + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + png_byte save[2]; + save[0] = *(sp++); + save[1] = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = save[0]; + *(dp++) = save[1]; + } + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + /* This converts from AG to GA */ + if (row_info->bit_depth == 8) + { + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + png_byte save = *(sp++); + *(dp++) = *(sp++); + *(dp++) = save; + } + } + /* This converts from AAGG to GGAA */ + else + { + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + png_byte save[2]; + save[0] = *(sp++); + save[1] = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = save[0]; + *(dp++) = save[1]; + } + } + } + } +} +#endif + +#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) +void /* PRIVATE */ +png_do_write_invert_alpha(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_write_invert_alpha\n"); +#if defined(PNG_USELESS_TESTS_SUPPORTED) + if (row != NULL && row_info != NULL) +#endif + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + /* This inverts the alpha channel in RGBA */ + if (row_info->bit_depth == 8) + { + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + for (i = 0, sp = dp = row; i < row_width; i++) + { + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = (png_byte)(255 - *(sp++)); + } + } + /* This inverts the alpha channel in RRGGBBAA */ + else + { + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = (png_byte)(255 - *(sp++)); + *(dp++) = (png_byte)(255 - *(sp++)); + } + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + /* This inverts the alpha channel in GA */ + if (row_info->bit_depth == 8) + { + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + *(dp++) = *(sp++); + *(dp++) = (png_byte)(255 - *(sp++)); + } + } + /* This inverts the alpha channel in GGAA */ + else + { + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = (png_byte)(255 - *(sp++)); + *(dp++) = (png_byte)(255 - *(sp++)); + } + } + } + } +} +#endif + +#if defined(PNG_MNG_FEATURES_SUPPORTED) +/* undoes intrapixel differencing */ +void /* PRIVATE */ +png_do_write_intrapixel(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_write_intrapixel\n"); + if ( +#if defined(PNG_USELESS_TESTS_SUPPORTED) + row != NULL && row_info != NULL && +#endif + (row_info->color_type & PNG_COLOR_MASK_COLOR)) + { + int bytes_per_pixel; + png_uint_32 row_width = row_info->width; + if (row_info->bit_depth == 8) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 3; + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 4; + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + *(rp) = (png_byte)((*rp - *(rp+1))&0xff); + *(rp+2) = (png_byte)((*(rp+2) - *(rp+1))&0xff); + } + } + else if (row_info->bit_depth == 16) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 6; + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 8; + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + png_uint_32 s0 = (*(rp ) << 8) | *(rp+1); + png_uint_32 s1 = (*(rp+2) << 8) | *(rp+3); + png_uint_32 s2 = (*(rp+4) << 8) | *(rp+5); + png_uint_32 red = (png_uint_32)((s0-s1) & 0xffffL); + png_uint_32 blue = (png_uint_32)((s2-s1) & 0xffffL); + *(rp ) = (png_byte)((red >> 8) & 0xff); + *(rp+1) = (png_byte)(red & 0xff); + *(rp+4) = (png_byte)((blue >> 8) & 0xff); + *(rp+5) = (png_byte)(blue & 0xff); + } + } + } +} +#endif /* PNG_MNG_FEATURES_SUPPORTED */ +#endif /* PNG_WRITE_SUPPORTED */ diff --git a/syslinux/com32/lib/libpng/pngwutil.c b/syslinux/com32/lib/libpng/pngwutil.c new file mode 100644 index 0000000..dd7b150 --- /dev/null +++ b/syslinux/com32/lib/libpng/pngwutil.c @@ -0,0 +1,2730 @@ + +/* pngwutil.c - utilities to write a PNG file + * + * libpng version 1.2.8 - December 3, 2004 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2004 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + */ + +#define PNG_INTERNAL +#include "png.h" +#ifdef PNG_WRITE_SUPPORTED + +/* Place a 32-bit number into a buffer in PNG byte order. We work + * with unsigned numbers for convenience, although one supported + * ancillary chunk uses signed (two's complement) numbers. + */ +void /* PRIVATE */ +png_save_uint_32(png_bytep buf, png_uint_32 i) +{ + buf[0] = (png_byte)((i >> 24) & 0xff); + buf[1] = (png_byte)((i >> 16) & 0xff); + buf[2] = (png_byte)((i >> 8) & 0xff); + buf[3] = (png_byte)(i & 0xff); +} + +#if defined(PNG_WRITE_pCAL_SUPPORTED) || defined(PNG_WRITE_oFFs_SUPPORTED) +/* The png_save_int_32 function assumes integers are stored in two's + * complement format. If this isn't the case, then this routine needs to + * be modified to write data in two's complement format. + */ +void /* PRIVATE */ +png_save_int_32(png_bytep buf, png_int_32 i) +{ + buf[0] = (png_byte)((i >> 24) & 0xff); + buf[1] = (png_byte)((i >> 16) & 0xff); + buf[2] = (png_byte)((i >> 8) & 0xff); + buf[3] = (png_byte)(i & 0xff); +} +#endif + +/* Place a 16-bit number into a buffer in PNG byte order. + * The parameter is declared unsigned int, not png_uint_16, + * just to avoid potential problems on pre-ANSI C compilers. + */ +void /* PRIVATE */ +png_save_uint_16(png_bytep buf, unsigned int i) +{ + buf[0] = (png_byte)((i >> 8) & 0xff); + buf[1] = (png_byte)(i & 0xff); +} + +/* Write a PNG chunk all at once. The type is an array of ASCII characters + * representing the chunk name. The array must be at least 4 bytes in + * length, and does not need to be null terminated. To be safe, pass the + * pre-defined chunk names here, and if you need a new one, define it + * where the others are defined. The length is the length of the data. + * All the data must be present. If that is not possible, use the + * png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end() + * functions instead. + */ +void PNGAPI +png_write_chunk(png_structp png_ptr, png_bytep chunk_name, + png_bytep data, png_size_t length) +{ + png_write_chunk_start(png_ptr, chunk_name, (png_uint_32)length); + png_write_chunk_data(png_ptr, data, length); + png_write_chunk_end(png_ptr); +} + +/* Write the start of a PNG chunk. The type is the chunk type. + * The total_length is the sum of the lengths of all the data you will be + * passing in png_write_chunk_data(). + */ +void PNGAPI +png_write_chunk_start(png_structp png_ptr, png_bytep chunk_name, + png_uint_32 length) +{ + png_byte buf[4]; + png_debug2(0, "Writing %s chunk (%lu bytes)\n", chunk_name, length); + + /* write the length */ + png_save_uint_32(buf, length); + png_write_data(png_ptr, buf, (png_size_t)4); + + /* write the chunk name */ + png_write_data(png_ptr, chunk_name, (png_size_t)4); + /* reset the crc and run it over the chunk name */ + png_reset_crc(png_ptr); + png_calculate_crc(png_ptr, chunk_name, (png_size_t)4); +} + +/* Write the data of a PNG chunk started with png_write_chunk_start(). + * Note that multiple calls to this function are allowed, and that the + * sum of the lengths from these calls *must* add up to the total_length + * given to png_write_chunk_start(). + */ +void PNGAPI +png_write_chunk_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + /* write the data, and run the CRC over it */ + if (data != NULL && length > 0) + { + png_calculate_crc(png_ptr, data, length); + png_write_data(png_ptr, data, length); + } +} + +/* Finish a chunk started with png_write_chunk_start(). */ +void PNGAPI +png_write_chunk_end(png_structp png_ptr) +{ + png_byte buf[4]; + + /* write the crc */ + png_save_uint_32(buf, png_ptr->crc); + + png_write_data(png_ptr, buf, (png_size_t)4); +} + +/* Simple function to write the signature. If we have already written + * the magic bytes of the signature, or more likely, the PNG stream is + * being embedded into another stream and doesn't need its own signature, + * we should call png_set_sig_bytes() to tell libpng how many of the + * bytes have already been written. + */ +void /* PRIVATE */ +png_write_sig(png_structp png_ptr) +{ + png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; + /* write the rest of the 8 byte signature */ + png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes], + (png_size_t)8 - png_ptr->sig_bytes); + if(png_ptr->sig_bytes < 3) + png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE; +} + +#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_iCCP_SUPPORTED) +/* + * This pair of functions encapsulates the operation of (a) compressing a + * text string, and (b) issuing it later as a series of chunk data writes. + * The compression_state structure is shared context for these functions + * set up by the caller in order to make the whole mess thread-safe. + */ + +typedef struct +{ + char *input; /* the uncompressed input data */ + int input_len; /* its length */ + int num_output_ptr; /* number of output pointers used */ + int max_output_ptr; /* size of output_ptr */ + png_charpp output_ptr; /* array of pointers to output */ +} compression_state; + +/* compress given text into storage in the png_ptr structure */ +static int /* PRIVATE */ +png_text_compress(png_structp png_ptr, + png_charp text, png_size_t text_len, int compression, + compression_state *comp) +{ + int ret; + + comp->num_output_ptr = comp->max_output_ptr = 0; + comp->output_ptr = NULL; + comp->input = NULL; + + /* we may just want to pass the text right through */ + if (compression == PNG_TEXT_COMPRESSION_NONE) + { + comp->input = text; + comp->input_len = text_len; + return((int)text_len); + } + + if (compression >= PNG_TEXT_COMPRESSION_LAST) + { +#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) + char msg[50]; + sprintf(msg, "Unknown compression type %d", compression); + png_warning(png_ptr, msg); +#else + png_warning(png_ptr, "Unknown compression type"); +#endif + } + + /* We can't write the chunk until we find out how much data we have, + * which means we need to run the compressor first and save the + * output. This shouldn't be a problem, as the vast majority of + * comments should be reasonable, but we will set up an array of + * malloc'd pointers to be sure. + * + * If we knew the application was well behaved, we could simplify this + * greatly by assuming we can always malloc an output buffer large + * enough to hold the compressed text ((1001 * text_len / 1000) + 12) + * and malloc this directly. The only time this would be a bad idea is + * if we can't malloc more than 64K and we have 64K of random input + * data, or if the input string is incredibly large (although this + * wouldn't cause a failure, just a slowdown due to swapping). + */ + + /* set up the compression buffers */ + png_ptr->zstream.avail_in = (uInt)text_len; + png_ptr->zstream.next_in = (Bytef *)text; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + png_ptr->zstream.next_out = (Bytef *)png_ptr->zbuf; + + /* this is the same compression loop as in png_write_row() */ + do + { + /* compress the data */ + ret = deflate(&png_ptr->zstream, Z_NO_FLUSH); + if (ret != Z_OK) + { + /* error */ + if (png_ptr->zstream.msg != NULL) + png_error(png_ptr, png_ptr->zstream.msg); + else + png_error(png_ptr, "zlib error"); + } + /* check to see if we need more room */ + if (!(png_ptr->zstream.avail_out)) + { + /* make sure the output array has room */ + if (comp->num_output_ptr >= comp->max_output_ptr) + { + int old_max; + + old_max = comp->max_output_ptr; + comp->max_output_ptr = comp->num_output_ptr + 4; + if (comp->output_ptr != NULL) + { + png_charpp old_ptr; + + old_ptr = comp->output_ptr; + comp->output_ptr = (png_charpp)png_malloc(png_ptr, + (png_uint_32)(comp->max_output_ptr * + png_sizeof (png_charpp))); + png_memcpy(comp->output_ptr, old_ptr, old_max + * png_sizeof (png_charp)); + png_free(png_ptr, old_ptr); + } + else + comp->output_ptr = (png_charpp)png_malloc(png_ptr, + (png_uint_32)(comp->max_output_ptr * + png_sizeof (png_charp))); + } + + /* save the data */ + comp->output_ptr[comp->num_output_ptr] = (png_charp)png_malloc(png_ptr, + (png_uint_32)png_ptr->zbuf_size); + png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf, + png_ptr->zbuf_size); + comp->num_output_ptr++; + + /* and reset the buffer */ + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + png_ptr->zstream.next_out = png_ptr->zbuf; + } + /* continue until we don't have any more to compress */ + } while (png_ptr->zstream.avail_in); + + /* finish the compression */ + do + { + /* tell zlib we are finished */ + ret = deflate(&png_ptr->zstream, Z_FINISH); + + if (ret == Z_OK) + { + /* check to see if we need more room */ + if (!(png_ptr->zstream.avail_out)) + { + /* check to make sure our output array has room */ + if (comp->num_output_ptr >= comp->max_output_ptr) + { + int old_max; + + old_max = comp->max_output_ptr; + comp->max_output_ptr = comp->num_output_ptr + 4; + if (comp->output_ptr != NULL) + { + png_charpp old_ptr; + + old_ptr = comp->output_ptr; + /* This could be optimized to realloc() */ + comp->output_ptr = (png_charpp)png_malloc(png_ptr, + (png_uint_32)(comp->max_output_ptr * + png_sizeof (png_charpp))); + png_memcpy(comp->output_ptr, old_ptr, + old_max * png_sizeof (png_charp)); + png_free(png_ptr, old_ptr); + } + else + comp->output_ptr = (png_charpp)png_malloc(png_ptr, + (png_uint_32)(comp->max_output_ptr * + png_sizeof (png_charp))); + } + + /* save off the data */ + comp->output_ptr[comp->num_output_ptr] = + (png_charp)png_malloc(png_ptr, (png_uint_32)png_ptr->zbuf_size); + png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf, + png_ptr->zbuf_size); + comp->num_output_ptr++; + + /* and reset the buffer pointers */ + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + png_ptr->zstream.next_out = png_ptr->zbuf; + } + } + else if (ret != Z_STREAM_END) + { + /* we got an error */ + if (png_ptr->zstream.msg != NULL) + png_error(png_ptr, png_ptr->zstream.msg); + else + png_error(png_ptr, "zlib error"); + } + } while (ret != Z_STREAM_END); + + /* text length is number of buffers plus last buffer */ + text_len = png_ptr->zbuf_size * comp->num_output_ptr; + if (png_ptr->zstream.avail_out < png_ptr->zbuf_size) + text_len += png_ptr->zbuf_size - (png_size_t)png_ptr->zstream.avail_out; + + return((int)text_len); +} + +/* ship the compressed text out via chunk writes */ +static void /* PRIVATE */ +png_write_compressed_data_out(png_structp png_ptr, compression_state *comp) +{ + int i; + + /* handle the no-compression case */ + if (comp->input) + { + png_write_chunk_data(png_ptr, (png_bytep)comp->input, + (png_size_t)comp->input_len); + return; + } + + /* write saved output buffers, if any */ + for (i = 0; i < comp->num_output_ptr; i++) + { + png_write_chunk_data(png_ptr,(png_bytep)comp->output_ptr[i], + png_ptr->zbuf_size); + png_free(png_ptr, comp->output_ptr[i]); + comp->output_ptr[i]=NULL; + } + if (comp->max_output_ptr != 0) + png_free(png_ptr, comp->output_ptr); + comp->output_ptr=NULL; + /* write anything left in zbuf */ + if (png_ptr->zstream.avail_out < (png_uint_32)png_ptr->zbuf_size) + png_write_chunk_data(png_ptr, png_ptr->zbuf, + png_ptr->zbuf_size - png_ptr->zstream.avail_out); + + /* reset zlib for another zTXt/iTXt or image data */ + deflateReset(&png_ptr->zstream); + png_ptr->zstream.data_type = Z_BINARY; +} +#endif + +/* Write the IHDR chunk, and update the png_struct with the necessary + * information. Note that the rest of this code depends upon this + * information being correct. + */ +void /* PRIVATE */ +png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height, + int bit_depth, int color_type, int compression_type, int filter_type, + int interlace_type) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_IHDR; +#endif + png_byte buf[13]; /* buffer to store the IHDR info */ + + png_debug(1, "in png_write_IHDR\n"); + /* Check that we have valid input data from the application info */ + switch (color_type) + { + case PNG_COLOR_TYPE_GRAY: + switch (bit_depth) + { + case 1: + case 2: + case 4: + case 8: + case 16: png_ptr->channels = 1; break; + default: png_error(png_ptr,"Invalid bit depth for grayscale image"); + } + break; + case PNG_COLOR_TYPE_RGB: + if (bit_depth != 8 && bit_depth != 16) + png_error(png_ptr, "Invalid bit depth for RGB image"); + png_ptr->channels = 3; + break; + case PNG_COLOR_TYPE_PALETTE: + switch (bit_depth) + { + case 1: + case 2: + case 4: + case 8: png_ptr->channels = 1; break; + default: png_error(png_ptr, "Invalid bit depth for paletted image"); + } + break; + case PNG_COLOR_TYPE_GRAY_ALPHA: + if (bit_depth != 8 && bit_depth != 16) + png_error(png_ptr, "Invalid bit depth for grayscale+alpha image"); + png_ptr->channels = 2; + break; + case PNG_COLOR_TYPE_RGB_ALPHA: + if (bit_depth != 8 && bit_depth != 16) + png_error(png_ptr, "Invalid bit depth for RGBA image"); + png_ptr->channels = 4; + break; + default: + png_error(png_ptr, "Invalid image color type specified"); + } + + if (compression_type != PNG_COMPRESSION_TYPE_BASE) + { + png_warning(png_ptr, "Invalid compression type specified"); + compression_type = PNG_COMPRESSION_TYPE_BASE; + } + + /* Write filter_method 64 (intrapixel differencing) only if + * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and + * 2. Libpng did not write a PNG signature (this filter_method is only + * used in PNG datastreams that are embedded in MNG datastreams) and + * 3. The application called png_permit_mng_features with a mask that + * included PNG_FLAG_MNG_FILTER_64 and + * 4. The filter_method is 64 and + * 5. The color_type is RGB or RGBA + */ + if ( +#if defined(PNG_MNG_FEATURES_SUPPORTED) + !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && + ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) && + (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) && + (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) && +#endif + filter_type != PNG_FILTER_TYPE_BASE) + { + png_warning(png_ptr, "Invalid filter type specified"); + filter_type = PNG_FILTER_TYPE_BASE; + } + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + if (interlace_type != PNG_INTERLACE_NONE && + interlace_type != PNG_INTERLACE_ADAM7) + { + png_warning(png_ptr, "Invalid interlace type specified"); + interlace_type = PNG_INTERLACE_ADAM7; + } +#else + interlace_type=PNG_INTERLACE_NONE; +#endif + + /* save off the relevent information */ + png_ptr->bit_depth = (png_byte)bit_depth; + png_ptr->color_type = (png_byte)color_type; + png_ptr->interlaced = (png_byte)interlace_type; +#if defined(PNG_MNG_FEATURES_SUPPORTED) + png_ptr->filter_type = (png_byte)filter_type; +#endif + png_ptr->compression_type = (png_byte)compression_type; + png_ptr->width = width; + png_ptr->height = height; + + png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels); + png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width); + /* set the usr info, so any transformations can modify it */ + png_ptr->usr_width = png_ptr->width; + png_ptr->usr_bit_depth = png_ptr->bit_depth; + png_ptr->usr_channels = png_ptr->channels; + + /* pack the header information into the buffer */ + png_save_uint_32(buf, width); + png_save_uint_32(buf + 4, height); + buf[8] = (png_byte)bit_depth; + buf[9] = (png_byte)color_type; + buf[10] = (png_byte)compression_type; + buf[11] = (png_byte)filter_type; + buf[12] = (png_byte)interlace_type; + + /* write the chunk */ + png_write_chunk(png_ptr, (png_bytep)png_IHDR, buf, (png_size_t)13); + + /* initialize zlib with PNG info */ + png_ptr->zstream.zalloc = png_zalloc; + png_ptr->zstream.zfree = png_zfree; + png_ptr->zstream.opaque = (voidpf)png_ptr; + if (!(png_ptr->do_filter)) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE || + png_ptr->bit_depth < 8) + png_ptr->do_filter = PNG_FILTER_NONE; + else + png_ptr->do_filter = PNG_ALL_FILTERS; + } + if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY)) + { + if (png_ptr->do_filter != PNG_FILTER_NONE) + png_ptr->zlib_strategy = Z_FILTERED; + else + png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY; + } + if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL)) + png_ptr->zlib_level = Z_DEFAULT_COMPRESSION; + if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL)) + png_ptr->zlib_mem_level = 8; + if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS)) + png_ptr->zlib_window_bits = 15; + if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD)) + png_ptr->zlib_method = 8; + deflateInit2(&png_ptr->zstream, png_ptr->zlib_level, + png_ptr->zlib_method, png_ptr->zlib_window_bits, + png_ptr->zlib_mem_level, png_ptr->zlib_strategy); + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + /* libpng is not interested in zstream.data_type */ + /* set it to a predefined value, to avoid its evaluation inside zlib */ + png_ptr->zstream.data_type = Z_BINARY; + + png_ptr->mode = PNG_HAVE_IHDR; +} + +/* write the palette. We are careful not to trust png_color to be in the + * correct order for PNG, so people can redefine it to any convenient + * structure. + */ +void /* PRIVATE */ +png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_PLTE; +#endif + png_uint_32 i; + png_colorp pal_ptr; + png_byte buf[3]; + + png_debug(1, "in png_write_PLTE\n"); + if (( +#if defined(PNG_MNG_FEATURES_SUPPORTED) + !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) && +#endif + num_pal == 0) || num_pal > 256) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + png_error(png_ptr, "Invalid number of colors in palette"); + } + else + { + png_warning(png_ptr, "Invalid number of colors in palette"); + return; + } + } + + if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR)) + { + png_warning(png_ptr, + "Ignoring request to write a PLTE chunk in grayscale PNG"); + return; + } + + png_ptr->num_palette = (png_uint_16)num_pal; + png_debug1(3, "num_palette = %d\n", png_ptr->num_palette); + + png_write_chunk_start(png_ptr, (png_bytep)png_PLTE, num_pal * 3); +#ifndef PNG_NO_POINTER_INDEXING + for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++) + { + buf[0] = pal_ptr->red; + buf[1] = pal_ptr->green; + buf[2] = pal_ptr->blue; + png_write_chunk_data(png_ptr, buf, (png_size_t)3); + } +#else + /* This is a little slower but some buggy compilers need to do this instead */ + pal_ptr=palette; + for (i = 0; i < num_pal; i++) + { + buf[0] = pal_ptr[i].red; + buf[1] = pal_ptr[i].green; + buf[2] = pal_ptr[i].blue; + png_write_chunk_data(png_ptr, buf, (png_size_t)3); + } +#endif + png_write_chunk_end(png_ptr); + png_ptr->mode |= PNG_HAVE_PLTE; +} + +/* write an IDAT chunk */ +void /* PRIVATE */ +png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_IDAT; +#endif + png_debug(1, "in png_write_IDAT\n"); + + /* Optimize the CMF field in the zlib stream. */ + /* This hack of the zlib stream is compliant to the stream specification. */ + if (!(png_ptr->mode & PNG_HAVE_IDAT) && + png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) + { + unsigned int z_cmf = data[0]; /* zlib compression method and flags */ + if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70) + { + /* Avoid memory underflows and multiplication overflows. */ + /* The conditions below are practically always satisfied; + however, they still must be checked. */ + if (length >= 2 && + png_ptr->height < 16384 && png_ptr->width < 16384) + { + png_uint_32 uncompressed_idat_size = png_ptr->height * + ((png_ptr->width * + png_ptr->channels * png_ptr->bit_depth + 15) >> 3); + unsigned int z_cinfo = z_cmf >> 4; + unsigned int half_z_window_size = 1 << (z_cinfo + 7); + while (uncompressed_idat_size <= half_z_window_size && + half_z_window_size >= 256) + { + z_cinfo--; + half_z_window_size >>= 1; + } + z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4); + if (data[0] != (png_byte)z_cmf) + { + data[0] = (png_byte)z_cmf; + data[1] &= 0xe0; + data[1] += (png_byte)(0x1f - ((z_cmf << 8) + data[1]) % 0x1f); + } + } + } + else + png_error(png_ptr, + "Invalid zlib compression method or flags in IDAT"); + } + + png_write_chunk(png_ptr, (png_bytep)png_IDAT, data, length); + png_ptr->mode |= PNG_HAVE_IDAT; +} + +/* write an IEND chunk */ +void /* PRIVATE */ +png_write_IEND(png_structp png_ptr) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_IEND; +#endif + png_debug(1, "in png_write_IEND\n"); + png_write_chunk(png_ptr, (png_bytep)png_IEND, png_bytep_NULL, + (png_size_t)0); + png_ptr->mode |= PNG_HAVE_IEND; +} + +#if defined(PNG_WRITE_gAMA_SUPPORTED) +/* write a gAMA chunk */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +void /* PRIVATE */ +png_write_gAMA(png_structp png_ptr, double file_gamma) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_gAMA; +#endif + png_uint_32 igamma; + png_byte buf[4]; + + png_debug(1, "in png_write_gAMA\n"); + /* file_gamma is saved in 1/100,000ths */ + igamma = (png_uint_32)(file_gamma * 100000.0 + 0.5); + png_save_uint_32(buf, igamma); + png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4); +} +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +void /* PRIVATE */ +png_write_gAMA_fixed(png_structp png_ptr, png_fixed_point file_gamma) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_gAMA; +#endif + png_byte buf[4]; + + png_debug(1, "in png_write_gAMA\n"); + /* file_gamma is saved in 1/100,000ths */ + png_save_uint_32(buf, (png_uint_32)file_gamma); + png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4); +} +#endif +#endif + +#if defined(PNG_WRITE_sRGB_SUPPORTED) +/* write a sRGB chunk */ +void /* PRIVATE */ +png_write_sRGB(png_structp png_ptr, int srgb_intent) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_sRGB; +#endif + png_byte buf[1]; + + png_debug(1, "in png_write_sRGB\n"); + if(srgb_intent >= PNG_sRGB_INTENT_LAST) + png_warning(png_ptr, + "Invalid sRGB rendering intent specified"); + buf[0]=(png_byte)srgb_intent; + png_write_chunk(png_ptr, (png_bytep)png_sRGB, buf, (png_size_t)1); +} +#endif + +#if defined(PNG_WRITE_iCCP_SUPPORTED) +/* write an iCCP chunk */ +void /* PRIVATE */ +png_write_iCCP(png_structp png_ptr, png_charp name, int compression_type, + png_charp profile, int profile_len) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_iCCP; +#endif + png_size_t name_len; + png_charp new_name; + compression_state comp; + + png_debug(1, "in png_write_iCCP\n"); + if (name == NULL || (name_len = png_check_keyword(png_ptr, name, + &new_name)) == 0) + { + png_warning(png_ptr, "Empty keyword in iCCP chunk"); + return; + } + + if (compression_type != PNG_COMPRESSION_TYPE_BASE) + png_warning(png_ptr, "Unknown compression type in iCCP chunk"); + + if (profile == NULL) + profile_len = 0; + + if (profile_len) + profile_len = png_text_compress(png_ptr, profile, (png_size_t)profile_len, + PNG_COMPRESSION_TYPE_BASE, &comp); + + /* make sure we include the NULL after the name and the compression type */ + png_write_chunk_start(png_ptr, (png_bytep)png_iCCP, + (png_uint_32)name_len+profile_len+2); + new_name[name_len+1]=0x00; + png_write_chunk_data(png_ptr, (png_bytep)new_name, name_len + 2); + + if (profile_len) + png_write_compressed_data_out(png_ptr, &comp); + + png_write_chunk_end(png_ptr); + png_free(png_ptr, new_name); +} +#endif + +#if defined(PNG_WRITE_sPLT_SUPPORTED) +/* write a sPLT chunk */ +void /* PRIVATE */ +png_write_sPLT(png_structp png_ptr, png_sPLT_tp spalette) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_sPLT; +#endif + png_size_t name_len; + png_charp new_name; + png_byte entrybuf[10]; + int entry_size = (spalette->depth == 8 ? 6 : 10); + int palette_size = entry_size * spalette->nentries; + png_sPLT_entryp ep; +#ifdef PNG_NO_POINTER_INDEXING + int i; +#endif + + png_debug(1, "in png_write_sPLT\n"); + if (spalette->name == NULL || (name_len = png_check_keyword(png_ptr, + spalette->name, &new_name))==0) + { + png_warning(png_ptr, "Empty keyword in sPLT chunk"); + return; + } + + /* make sure we include the NULL after the name */ + png_write_chunk_start(png_ptr, (png_bytep)png_sPLT, + (png_uint_32)(name_len + 2 + palette_size)); + png_write_chunk_data(png_ptr, (png_bytep)new_name, name_len + 1); + png_write_chunk_data(png_ptr, (png_bytep)&spalette->depth, 1); + + /* loop through each palette entry, writing appropriately */ +#ifndef PNG_NO_POINTER_INDEXING + for (ep = spalette->entries; ep<spalette->entries+spalette->nentries; ep++) + { + if (spalette->depth == 8) + { + entrybuf[0] = (png_byte)ep->red; + entrybuf[1] = (png_byte)ep->green; + entrybuf[2] = (png_byte)ep->blue; + entrybuf[3] = (png_byte)ep->alpha; + png_save_uint_16(entrybuf + 4, ep->frequency); + } + else + { + png_save_uint_16(entrybuf + 0, ep->red); + png_save_uint_16(entrybuf + 2, ep->green); + png_save_uint_16(entrybuf + 4, ep->blue); + png_save_uint_16(entrybuf + 6, ep->alpha); + png_save_uint_16(entrybuf + 8, ep->frequency); + } + png_write_chunk_data(png_ptr, entrybuf, (png_size_t)entry_size); + } +#else + ep=spalette->entries; + for (i=0; i>spalette->nentries; i++) + { + if (spalette->depth == 8) + { + entrybuf[0] = (png_byte)ep[i].red; + entrybuf[1] = (png_byte)ep[i].green; + entrybuf[2] = (png_byte)ep[i].blue; + entrybuf[3] = (png_byte)ep[i].alpha; + png_save_uint_16(entrybuf + 4, ep[i].frequency); + } + else + { + png_save_uint_16(entrybuf + 0, ep[i].red); + png_save_uint_16(entrybuf + 2, ep[i].green); + png_save_uint_16(entrybuf + 4, ep[i].blue); + png_save_uint_16(entrybuf + 6, ep[i].alpha); + png_save_uint_16(entrybuf + 8, ep[i].frequency); + } + png_write_chunk_data(png_ptr, entrybuf, entry_size); + } +#endif + + png_write_chunk_end(png_ptr); + png_free(png_ptr, new_name); +} +#endif + +#if defined(PNG_WRITE_sBIT_SUPPORTED) +/* write the sBIT chunk */ +void /* PRIVATE */ +png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_sBIT; +#endif + png_byte buf[4]; + png_size_t size; + + png_debug(1, "in png_write_sBIT\n"); + /* make sure we don't depend upon the order of PNG_COLOR_8 */ + if (color_type & PNG_COLOR_MASK_COLOR) + { + png_byte maxbits; + + maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 : + png_ptr->usr_bit_depth); + if (sbit->red == 0 || sbit->red > maxbits || + sbit->green == 0 || sbit->green > maxbits || + sbit->blue == 0 || sbit->blue > maxbits) + { + png_warning(png_ptr, "Invalid sBIT depth specified"); + return; + } + buf[0] = sbit->red; + buf[1] = sbit->green; + buf[2] = sbit->blue; + size = 3; + } + else + { + if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth) + { + png_warning(png_ptr, "Invalid sBIT depth specified"); + return; + } + buf[0] = sbit->gray; + size = 1; + } + + if (color_type & PNG_COLOR_MASK_ALPHA) + { + if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth) + { + png_warning(png_ptr, "Invalid sBIT depth specified"); + return; + } + buf[size++] = sbit->alpha; + } + + png_write_chunk(png_ptr, (png_bytep)png_sBIT, buf, size); +} +#endif + +#if defined(PNG_WRITE_cHRM_SUPPORTED) +/* write the cHRM chunk */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +void /* PRIVATE */ +png_write_cHRM(png_structp png_ptr, double white_x, double white_y, + double red_x, double red_y, double green_x, double green_y, + double blue_x, double blue_y) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_cHRM; +#endif + png_byte buf[32]; + png_uint_32 itemp; + + png_debug(1, "in png_write_cHRM\n"); + /* each value is saved in 1/100,000ths */ + if (white_x < 0 || white_x > 0.8 || white_y < 0 || white_y > 0.8 || + white_x + white_y > 1.0) + { + png_warning(png_ptr, "Invalid cHRM white point specified"); +#if !defined(PNG_NO_CONSOLE_IO) + fprintf(stderr,"white_x=%f, white_y=%f\n",white_x, white_y); +#endif + return; + } + itemp = (png_uint_32)(white_x * 100000.0 + 0.5); + png_save_uint_32(buf, itemp); + itemp = (png_uint_32)(white_y * 100000.0 + 0.5); + png_save_uint_32(buf + 4, itemp); + + if (red_x < 0 || red_x > 0.8 || red_y < 0 || red_y > 0.8 || + red_x + red_y > 1.0) + { + png_warning(png_ptr, "Invalid cHRM red point specified"); + return; + } + itemp = (png_uint_32)(red_x * 100000.0 + 0.5); + png_save_uint_32(buf + 8, itemp); + itemp = (png_uint_32)(red_y * 100000.0 + 0.5); + png_save_uint_32(buf + 12, itemp); + + if (green_x < 0 || green_x > 0.8 || green_y < 0 || green_y > 0.8 || + green_x + green_y > 1.0) + { + png_warning(png_ptr, "Invalid cHRM green point specified"); + return; + } + itemp = (png_uint_32)(green_x * 100000.0 + 0.5); + png_save_uint_32(buf + 16, itemp); + itemp = (png_uint_32)(green_y * 100000.0 + 0.5); + png_save_uint_32(buf + 20, itemp); + + if (blue_x < 0 || blue_x > 0.8 || blue_y < 0 || blue_y > 0.8 || + blue_x + blue_y > 1.0) + { + png_warning(png_ptr, "Invalid cHRM blue point specified"); + return; + } + itemp = (png_uint_32)(blue_x * 100000.0 + 0.5); + png_save_uint_32(buf + 24, itemp); + itemp = (png_uint_32)(blue_y * 100000.0 + 0.5); + png_save_uint_32(buf + 28, itemp); + + png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32); +} +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +void /* PRIVATE */ +png_write_cHRM_fixed(png_structp png_ptr, png_fixed_point white_x, + png_fixed_point white_y, png_fixed_point red_x, png_fixed_point red_y, + png_fixed_point green_x, png_fixed_point green_y, png_fixed_point blue_x, + png_fixed_point blue_y) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_cHRM; +#endif + png_byte buf[32]; + + png_debug(1, "in png_write_cHRM\n"); + /* each value is saved in 1/100,000ths */ + if (white_x > 80000L || white_y > 80000L || white_x + white_y > 100000L) + { + png_warning(png_ptr, "Invalid fixed cHRM white point specified"); +#if !defined(PNG_NO_CONSOLE_IO) + fprintf(stderr,"white_x=%ld, white_y=%ld\n",white_x, white_y); +#endif + return; + } + png_save_uint_32(buf, (png_uint_32)white_x); + png_save_uint_32(buf + 4, (png_uint_32)white_y); + + if (red_x > 80000L || red_y > 80000L || red_x + red_y > 100000L) + { + png_warning(png_ptr, "Invalid cHRM fixed red point specified"); + return; + } + png_save_uint_32(buf + 8, (png_uint_32)red_x); + png_save_uint_32(buf + 12, (png_uint_32)red_y); + + if (green_x > 80000L || green_y > 80000L || green_x + green_y > 100000L) + { + png_warning(png_ptr, "Invalid fixed cHRM green point specified"); + return; + } + png_save_uint_32(buf + 16, (png_uint_32)green_x); + png_save_uint_32(buf + 20, (png_uint_32)green_y); + + if (blue_x > 80000L || blue_y > 80000L || blue_x + blue_y > 100000L) + { + png_warning(png_ptr, "Invalid fixed cHRM blue point specified"); + return; + } + png_save_uint_32(buf + 24, (png_uint_32)blue_x); + png_save_uint_32(buf + 28, (png_uint_32)blue_y); + + png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32); +} +#endif +#endif + +#if defined(PNG_WRITE_tRNS_SUPPORTED) +/* write the tRNS chunk */ +void /* PRIVATE */ +png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran, + int num_trans, int color_type) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_tRNS; +#endif + png_byte buf[6]; + + png_debug(1, "in png_write_tRNS\n"); + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette) + { + png_warning(png_ptr,"Invalid number of transparent colors specified"); + return; + } + /* write the chunk out as it is */ + png_write_chunk(png_ptr, (png_bytep)png_tRNS, trans, (png_size_t)num_trans); + } + else if (color_type == PNG_COLOR_TYPE_GRAY) + { + /* one 16 bit value */ + if(tran->gray >= (1 << png_ptr->bit_depth)) + { + png_warning(png_ptr, + "Ignoring attempt to write tRNS chunk out-of-range for bit_depth"); + return; + } + png_save_uint_16(buf, tran->gray); + png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)2); + } + else if (color_type == PNG_COLOR_TYPE_RGB) + { + /* three 16 bit values */ + png_save_uint_16(buf, tran->red); + png_save_uint_16(buf + 2, tran->green); + png_save_uint_16(buf + 4, tran->blue); + if(png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4])) + { + png_warning(png_ptr, + "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8"); + return; + } + png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)6); + } + else + { + png_warning(png_ptr, "Can't write tRNS with an alpha channel"); + } +} +#endif + +#if defined(PNG_WRITE_bKGD_SUPPORTED) +/* write the background chunk */ +void /* PRIVATE */ +png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_bKGD; +#endif + png_byte buf[6]; + + png_debug(1, "in png_write_bKGD\n"); + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + if ( +#if defined(PNG_MNG_FEATURES_SUPPORTED) + (png_ptr->num_palette || + (!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE))) && +#endif + back->index > png_ptr->num_palette) + { + png_warning(png_ptr, "Invalid background palette index"); + return; + } + buf[0] = back->index; + png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)1); + } + else if (color_type & PNG_COLOR_MASK_COLOR) + { + png_save_uint_16(buf, back->red); + png_save_uint_16(buf + 2, back->green); + png_save_uint_16(buf + 4, back->blue); + if(png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4])) + { + png_warning(png_ptr, + "Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8"); + return; + } + png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)6); + } + else + { + if(back->gray >= (1 << png_ptr->bit_depth)) + { + png_warning(png_ptr, + "Ignoring attempt to write bKGD chunk out-of-range for bit_depth"); + return; + } + png_save_uint_16(buf, back->gray); + png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)2); + } +} +#endif + +#if defined(PNG_WRITE_hIST_SUPPORTED) +/* write the histogram */ +void /* PRIVATE */ +png_write_hIST(png_structp png_ptr, png_uint_16p hist, int num_hist) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_hIST; +#endif + int i; + png_byte buf[3]; + + png_debug(1, "in png_write_hIST\n"); + if (num_hist > (int)png_ptr->num_palette) + { + png_debug2(3, "num_hist = %d, num_palette = %d\n", num_hist, + png_ptr->num_palette); + png_warning(png_ptr, "Invalid number of histogram entries specified"); + return; + } + + png_write_chunk_start(png_ptr, (png_bytep)png_hIST, (png_uint_32)(num_hist * 2)); + for (i = 0; i < num_hist; i++) + { + png_save_uint_16(buf, hist[i]); + png_write_chunk_data(png_ptr, buf, (png_size_t)2); + } + png_write_chunk_end(png_ptr); +} +#endif + +#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \ + defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) +/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification, + * and if invalid, correct the keyword rather than discarding the entire + * chunk. The PNG 1.0 specification requires keywords 1-79 characters in + * length, forbids leading or trailing whitespace, multiple internal spaces, + * and the non-break space (0x80) from ISO 8859-1. Returns keyword length. + * + * The new_key is allocated to hold the corrected keyword and must be freed + * by the calling routine. This avoids problems with trying to write to + * static keywords without having to have duplicate copies of the strings. + */ +png_size_t /* PRIVATE */ +png_check_keyword(png_structp png_ptr, png_charp key, png_charpp new_key) +{ + png_size_t key_len; + png_charp kp, dp; + int kflag; + int kwarn=0; + + png_debug(1, "in png_check_keyword\n"); + *new_key = NULL; + + if (key == NULL || (key_len = png_strlen(key)) == 0) + { + png_warning(png_ptr, "zero length keyword"); + return ((png_size_t)0); + } + + png_debug1(2, "Keyword to be checked is '%s'\n", key); + + *new_key = (png_charp)png_malloc_warn(png_ptr, (png_uint_32)(key_len + 2)); + if (*new_key == NULL) + { + png_warning(png_ptr, "Out of memory while procesing keyword"); + return ((png_size_t)0); + } + + /* Replace non-printing characters with a blank and print a warning */ + for (kp = key, dp = *new_key; *kp != '\0'; kp++, dp++) + { + if (*kp < 0x20 || (*kp > 0x7E && (png_byte)*kp < 0xA1)) + { +#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) + char msg[40]; + + sprintf(msg, "invalid keyword character 0x%02X", *kp); + png_warning(png_ptr, msg); +#else + png_warning(png_ptr, "invalid character in keyword"); +#endif + *dp = ' '; + } + else + { + *dp = *kp; + } + } + *dp = '\0'; + + /* Remove any trailing white space. */ + kp = *new_key + key_len - 1; + if (*kp == ' ') + { + png_warning(png_ptr, "trailing spaces removed from keyword"); + + while (*kp == ' ') + { + *(kp--) = '\0'; + key_len--; + } + } + + /* Remove any leading white space. */ + kp = *new_key; + if (*kp == ' ') + { + png_warning(png_ptr, "leading spaces removed from keyword"); + + while (*kp == ' ') + { + kp++; + key_len--; + } + } + + png_debug1(2, "Checking for multiple internal spaces in '%s'\n", kp); + + /* Remove multiple internal spaces. */ + for (kflag = 0, dp = *new_key; *kp != '\0'; kp++) + { + if (*kp == ' ' && kflag == 0) + { + *(dp++) = *kp; + kflag = 1; + } + else if (*kp == ' ') + { + key_len--; + kwarn=1; + } + else + { + *(dp++) = *kp; + kflag = 0; + } + } + *dp = '\0'; + if(kwarn) + png_warning(png_ptr, "extra interior spaces removed from keyword"); + + if (key_len == 0) + { + png_free(png_ptr, *new_key); + *new_key=NULL; + png_warning(png_ptr, "Zero length keyword"); + } + + if (key_len > 79) + { + png_warning(png_ptr, "keyword length must be 1 - 79 characters"); + new_key[79] = '\0'; + key_len = 79; + } + + return (key_len); +} +#endif + +#if defined(PNG_WRITE_tEXt_SUPPORTED) +/* write a tEXt chunk */ +void /* PRIVATE */ +png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text, + png_size_t text_len) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_tEXt; +#endif + png_size_t key_len; + png_charp new_key; + + png_debug(1, "in png_write_tEXt\n"); + if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0) + { + png_warning(png_ptr, "Empty keyword in tEXt chunk"); + return; + } + + if (text == NULL || *text == '\0') + text_len = 0; + else + text_len = png_strlen(text); + + /* make sure we include the 0 after the key */ + png_write_chunk_start(png_ptr, (png_bytep)png_tEXt, (png_uint_32)key_len+text_len+1); + /* + * We leave it to the application to meet PNG-1.0 requirements on the + * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of + * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them. + * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. + */ + png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1); + if (text_len) + png_write_chunk_data(png_ptr, (png_bytep)text, text_len); + + png_write_chunk_end(png_ptr); + png_free(png_ptr, new_key); +} +#endif + +#if defined(PNG_WRITE_zTXt_SUPPORTED) +/* write a compressed text chunk */ +void /* PRIVATE */ +png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text, + png_size_t text_len, int compression) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_zTXt; +#endif + png_size_t key_len; + char buf[1]; + png_charp new_key; + compression_state comp; + + png_debug(1, "in png_write_zTXt\n"); + + if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0) + { + png_warning(png_ptr, "Empty keyword in zTXt chunk"); + return; + } + + if (text == NULL || *text == '\0' || compression==PNG_TEXT_COMPRESSION_NONE) + { + png_write_tEXt(png_ptr, new_key, text, (png_size_t)0); + png_free(png_ptr, new_key); + return; + } + + text_len = png_strlen(text); + + png_free(png_ptr, new_key); + + /* compute the compressed data; do it now for the length */ + text_len = png_text_compress(png_ptr, text, text_len, compression, + &comp); + + /* write start of chunk */ + png_write_chunk_start(png_ptr, (png_bytep)png_zTXt, (png_uint_32) + (key_len+text_len+2)); + /* write key */ + png_write_chunk_data(png_ptr, (png_bytep)key, key_len + 1); + buf[0] = (png_byte)compression; + /* write compression */ + png_write_chunk_data(png_ptr, (png_bytep)buf, (png_size_t)1); + /* write the compressed data */ + png_write_compressed_data_out(png_ptr, &comp); + + /* close the chunk */ + png_write_chunk_end(png_ptr); +} +#endif + +#if defined(PNG_WRITE_iTXt_SUPPORTED) +/* write an iTXt chunk */ +void /* PRIVATE */ +png_write_iTXt(png_structp png_ptr, int compression, png_charp key, + png_charp lang, png_charp lang_key, png_charp text) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_iTXt; +#endif + png_size_t lang_len, key_len, lang_key_len, text_len; + png_charp new_lang, new_key; + png_byte cbuf[2]; + compression_state comp; + + png_debug(1, "in png_write_iTXt\n"); + + if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0) + { + png_warning(png_ptr, "Empty keyword in iTXt chunk"); + return; + } + if (lang == NULL || (lang_len = png_check_keyword(png_ptr, lang, &new_lang))==0) + { + png_warning(png_ptr, "Empty language field in iTXt chunk"); + new_lang = NULL; + lang_len = 0; + } + + if (lang_key == NULL) + lang_key_len = 0; + else + lang_key_len = png_strlen(lang_key); + + if (text == NULL) + text_len = 0; + else + text_len = png_strlen(text); + + /* compute the compressed data; do it now for the length */ + text_len = png_text_compress(png_ptr, text, text_len, compression-2, + &comp); + + + /* make sure we include the compression flag, the compression byte, + * and the NULs after the key, lang, and lang_key parts */ + + png_write_chunk_start(png_ptr, (png_bytep)png_iTXt, + (png_uint_32)( + 5 /* comp byte, comp flag, terminators for key, lang and lang_key */ + + key_len + + lang_len + + lang_key_len + + text_len)); + + /* + * We leave it to the application to meet PNG-1.0 requirements on the + * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of + * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them. + * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. + */ + png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1); + + /* set the compression flag */ + if (compression == PNG_ITXT_COMPRESSION_NONE || \ + compression == PNG_TEXT_COMPRESSION_NONE) + cbuf[0] = 0; + else /* compression == PNG_ITXT_COMPRESSION_zTXt */ + cbuf[0] = 1; + /* set the compression method */ + cbuf[1] = 0; + png_write_chunk_data(png_ptr, cbuf, 2); + + cbuf[0] = 0; + png_write_chunk_data(png_ptr, (new_lang ? (png_bytep)new_lang : cbuf), lang_len + 1); + png_write_chunk_data(png_ptr, (lang_key ? (png_bytep)lang_key : cbuf), lang_key_len + 1); + png_write_compressed_data_out(png_ptr, &comp); + + png_write_chunk_end(png_ptr); + png_free(png_ptr, new_key); + if (new_lang) + png_free(png_ptr, new_lang); +} +#endif + +#if defined(PNG_WRITE_oFFs_SUPPORTED) +/* write the oFFs chunk */ +void /* PRIVATE */ +png_write_oFFs(png_structp png_ptr, png_int_32 x_offset, png_int_32 y_offset, + int unit_type) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_oFFs; +#endif + png_byte buf[9]; + + png_debug(1, "in png_write_oFFs\n"); + if (unit_type >= PNG_OFFSET_LAST) + png_warning(png_ptr, "Unrecognized unit type for oFFs chunk"); + + png_save_int_32(buf, x_offset); + png_save_int_32(buf + 4, y_offset); + buf[8] = (png_byte)unit_type; + + png_write_chunk(png_ptr, (png_bytep)png_oFFs, buf, (png_size_t)9); +} +#endif + +#if defined(PNG_WRITE_pCAL_SUPPORTED) +/* write the pCAL chunk (described in the PNG extensions document) */ +void /* PRIVATE */ +png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0, + png_int_32 X1, int type, int nparams, png_charp units, png_charpp params) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_pCAL; +#endif + png_size_t purpose_len, units_len, total_len; + png_uint_32p params_len; + png_byte buf[10]; + png_charp new_purpose; + int i; + + png_debug1(1, "in png_write_pCAL (%d parameters)\n", nparams); + if (type >= PNG_EQUATION_LAST) + png_warning(png_ptr, "Unrecognized equation type for pCAL chunk"); + + purpose_len = png_check_keyword(png_ptr, purpose, &new_purpose) + 1; + png_debug1(3, "pCAL purpose length = %d\n", (int)purpose_len); + units_len = png_strlen(units) + (nparams == 0 ? 0 : 1); + png_debug1(3, "pCAL units length = %d\n", (int)units_len); + total_len = purpose_len + units_len + 10; + + params_len = (png_uint_32p)png_malloc(png_ptr, (png_uint_32)(nparams + *png_sizeof(png_uint_32))); + + /* Find the length of each parameter, making sure we don't count the + null terminator for the last parameter. */ + for (i = 0; i < nparams; i++) + { + params_len[i] = png_strlen(params[i]) + (i == nparams - 1 ? 0 : 1); + png_debug2(3, "pCAL parameter %d length = %lu\n", i, params_len[i]); + total_len += (png_size_t)params_len[i]; + } + + png_debug1(3, "pCAL total length = %d\n", (int)total_len); + png_write_chunk_start(png_ptr, (png_bytep)png_pCAL, (png_uint_32)total_len); + png_write_chunk_data(png_ptr, (png_bytep)new_purpose, purpose_len); + png_save_int_32(buf, X0); + png_save_int_32(buf + 4, X1); + buf[8] = (png_byte)type; + buf[9] = (png_byte)nparams; + png_write_chunk_data(png_ptr, buf, (png_size_t)10); + png_write_chunk_data(png_ptr, (png_bytep)units, (png_size_t)units_len); + + png_free(png_ptr, new_purpose); + + for (i = 0; i < nparams; i++) + { + png_write_chunk_data(png_ptr, (png_bytep)params[i], + (png_size_t)params_len[i]); + } + + png_free(png_ptr, params_len); + png_write_chunk_end(png_ptr); +} +#endif + +#if defined(PNG_WRITE_sCAL_SUPPORTED) +/* write the sCAL chunk */ +#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO) +void /* PRIVATE */ +png_write_sCAL(png_structp png_ptr, int unit, double width,double height) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_sCAL; +#endif + png_size_t total_len; + char wbuf[32], hbuf[32]; + png_byte bunit = unit; + + png_debug(1, "in png_write_sCAL\n"); + +#if defined(_WIN32_WCE) +/* sprintf() function is not supported on WindowsCE */ + { + wchar_t wc_buf[32]; + swprintf(wc_buf, TEXT("%12.12e"), width); + WideCharToMultiByte(CP_ACP, 0, wc_buf, -1, wbuf, 32, NULL, NULL); + swprintf(wc_buf, TEXT("%12.12e"), height); + WideCharToMultiByte(CP_ACP, 0, wc_buf, -1, hbuf, 32, NULL, NULL); + } +#else + sprintf(wbuf, "%12.12e", width); + sprintf(hbuf, "%12.12e", height); +#endif + total_len = 1 + png_strlen(wbuf)+1 + png_strlen(hbuf); + + png_debug1(3, "sCAL total length = %d\n", (int)total_len); + png_write_chunk_start(png_ptr, (png_bytep)png_sCAL, (png_uint_32)total_len); + png_write_chunk_data(png_ptr, (png_bytep)&bunit, 1); + png_write_chunk_data(png_ptr, (png_bytep)wbuf, png_strlen(wbuf)+1); + png_write_chunk_data(png_ptr, (png_bytep)hbuf, png_strlen(hbuf)); + + png_write_chunk_end(png_ptr); +} +#else +#ifdef PNG_FIXED_POINT_SUPPORTED +void /* PRIVATE */ +png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width, + png_charp height) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_sCAL; +#endif + png_size_t total_len; + char wbuf[32], hbuf[32]; + png_byte bunit = unit; + + png_debug(1, "in png_write_sCAL_s\n"); + + png_strcpy(wbuf,(const char *)width); + png_strcpy(hbuf,(const char *)height); + total_len = 1 + png_strlen(wbuf)+1 + png_strlen(hbuf); + + png_debug1(3, "sCAL total length = %d\n", total_len); + png_write_chunk_start(png_ptr, (png_bytep)png_sCAL, (png_uint_32)total_len); + png_write_chunk_data(png_ptr, (png_bytep)&bunit, 1); + png_write_chunk_data(png_ptr, (png_bytep)wbuf, png_strlen(wbuf)+1); + png_write_chunk_data(png_ptr, (png_bytep)hbuf, png_strlen(hbuf)); + + png_write_chunk_end(png_ptr); +} +#endif +#endif +#endif + +#if defined(PNG_WRITE_pHYs_SUPPORTED) +/* write the pHYs chunk */ +void /* PRIVATE */ +png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit, + png_uint_32 y_pixels_per_unit, + int unit_type) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_pHYs; +#endif + png_byte buf[9]; + + png_debug(1, "in png_write_pHYs\n"); + if (unit_type >= PNG_RESOLUTION_LAST) + png_warning(png_ptr, "Unrecognized unit type for pHYs chunk"); + + png_save_uint_32(buf, x_pixels_per_unit); + png_save_uint_32(buf + 4, y_pixels_per_unit); + buf[8] = (png_byte)unit_type; + + png_write_chunk(png_ptr, (png_bytep)png_pHYs, buf, (png_size_t)9); +} +#endif + +#if defined(PNG_WRITE_tIME_SUPPORTED) +/* Write the tIME chunk. Use either png_convert_from_struct_tm() + * or png_convert_from_time_t(), or fill in the structure yourself. + */ +void /* PRIVATE */ +png_write_tIME(png_structp png_ptr, png_timep mod_time) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_tIME; +#endif + png_byte buf[7]; + + png_debug(1, "in png_write_tIME\n"); + if (mod_time->month > 12 || mod_time->month < 1 || + mod_time->day > 31 || mod_time->day < 1 || + mod_time->hour > 23 || mod_time->second > 60) + { + png_warning(png_ptr, "Invalid time specified for tIME chunk"); + return; + } + + png_save_uint_16(buf, mod_time->year); + buf[2] = mod_time->month; + buf[3] = mod_time->day; + buf[4] = mod_time->hour; + buf[5] = mod_time->minute; + buf[6] = mod_time->second; + + png_write_chunk(png_ptr, (png_bytep)png_tIME, buf, (png_size_t)7); +} +#endif + +/* initializes the row writing capability of libpng */ +void /* PRIVATE */ +png_write_start_row(png_structp png_ptr) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* start of interlace block */ + int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* offset to next interlace block */ + int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + /* start of interlace block in the y direction */ + int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + + /* offset to next interlace block in the y direction */ + int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; +#endif + + png_size_t buf_size; + + png_debug(1, "in png_write_start_row\n"); + buf_size = (png_size_t)(PNG_ROWBYTES( + png_ptr->usr_channels*png_ptr->usr_bit_depth,png_ptr->width)+1); + + /* set up row buffer */ + png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size); + png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE; + + /* set up filtering buffer, if using this filter */ + if (png_ptr->do_filter & PNG_FILTER_SUB) + { + png_ptr->sub_row = (png_bytep)png_malloc(png_ptr, + (png_ptr->rowbytes + 1)); + png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB; + } + + /* We only need to keep the previous row if we are using one of these. */ + if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH)) + { + /* set up previous row buffer */ + png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size); + png_memset(png_ptr->prev_row, 0, buf_size); + + if (png_ptr->do_filter & PNG_FILTER_UP) + { + png_ptr->up_row = (png_bytep )png_malloc(png_ptr, + (png_ptr->rowbytes + 1)); + png_ptr->up_row[0] = PNG_FILTER_VALUE_UP; + } + + if (png_ptr->do_filter & PNG_FILTER_AVG) + { + png_ptr->avg_row = (png_bytep)png_malloc(png_ptr, + (png_ptr->rowbytes + 1)); + png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG; + } + + if (png_ptr->do_filter & PNG_FILTER_PAETH) + { + png_ptr->paeth_row = (png_bytep )png_malloc(png_ptr, + (png_ptr->rowbytes + 1)); + png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH; + } + } + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* if interlaced, we need to set up width and height of pass */ + if (png_ptr->interlaced) + { + if (!(png_ptr->transformations & PNG_INTERLACE)) + { + png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - + png_pass_ystart[0]) / png_pass_yinc[0]; + png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 - + png_pass_start[0]) / png_pass_inc[0]; + } + else + { + png_ptr->num_rows = png_ptr->height; + png_ptr->usr_width = png_ptr->width; + } + } + else +#endif + { + png_ptr->num_rows = png_ptr->height; + png_ptr->usr_width = png_ptr->width; + } + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + png_ptr->zstream.next_out = png_ptr->zbuf; +} + +/* Internal use only. Called when finished processing a row of data. */ +void /* PRIVATE */ +png_write_finish_row(png_structp png_ptr) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* start of interlace block */ + int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* offset to next interlace block */ + int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + /* start of interlace block in the y direction */ + int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + + /* offset to next interlace block in the y direction */ + int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; +#endif + + int ret; + + png_debug(1, "in png_write_finish_row\n"); + /* next row */ + png_ptr->row_number++; + + /* see if we are done */ + if (png_ptr->row_number < png_ptr->num_rows) + return; + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* if interlaced, go to next pass */ + if (png_ptr->interlaced) + { + png_ptr->row_number = 0; + if (png_ptr->transformations & PNG_INTERLACE) + { + png_ptr->pass++; + } + else + { + /* loop until we find a non-zero width or height pass */ + do + { + png_ptr->pass++; + if (png_ptr->pass >= 7) + break; + png_ptr->usr_width = (png_ptr->width + + png_pass_inc[png_ptr->pass] - 1 - + png_pass_start[png_ptr->pass]) / + png_pass_inc[png_ptr->pass]; + png_ptr->num_rows = (png_ptr->height + + png_pass_yinc[png_ptr->pass] - 1 - + png_pass_ystart[png_ptr->pass]) / + png_pass_yinc[png_ptr->pass]; + if (png_ptr->transformations & PNG_INTERLACE) + break; + } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0); + + } + + /* reset the row above the image for the next pass */ + if (png_ptr->pass < 7) + { + if (png_ptr->prev_row != NULL) + png_memset(png_ptr->prev_row, 0, + (png_size_t)(PNG_ROWBYTES(png_ptr->usr_channels* + png_ptr->usr_bit_depth,png_ptr->width))+1); + return; + } + } +#endif + + /* if we get here, we've just written the last row, so we need + to flush the compressor */ + do + { + /* tell the compressor we are done */ + ret = deflate(&png_ptr->zstream, Z_FINISH); + /* check for an error */ + if (ret == Z_OK) + { + /* check to see if we need more room */ + if (!(png_ptr->zstream.avail_out)) + { + png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + } + } + else if (ret != Z_STREAM_END) + { + if (png_ptr->zstream.msg != NULL) + png_error(png_ptr, png_ptr->zstream.msg); + else + png_error(png_ptr, "zlib error"); + } + } while (ret != Z_STREAM_END); + + /* write any extra space */ + if (png_ptr->zstream.avail_out < png_ptr->zbuf_size) + { + png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size - + png_ptr->zstream.avail_out); + } + + deflateReset(&png_ptr->zstream); + png_ptr->zstream.data_type = Z_BINARY; +} + +#if defined(PNG_WRITE_INTERLACING_SUPPORTED) +/* Pick out the correct pixels for the interlace pass. + * The basic idea here is to go through the row with a source + * pointer and a destination pointer (sp and dp), and copy the + * correct pixels for the pass. As the row gets compacted, + * sp will always be >= dp, so we should never overwrite anything. + * See the default: case for the easiest code to understand. + */ +void /* PRIVATE */ +png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* start of interlace block */ + int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* offset to next interlace block */ + int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; +#endif + + png_debug(1, "in png_do_write_interlace\n"); + /* we don't have to do anything on the last pass (6) */ +#if defined(PNG_USELESS_TESTS_SUPPORTED) + if (row != NULL && row_info != NULL && pass < 6) +#else + if (pass < 6) +#endif + { + /* each pixel depth is handled separately */ + switch (row_info->pixel_depth) + { + case 1: + { + png_bytep sp; + png_bytep dp; + int shift; + int d; + int value; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + dp = row; + d = 0; + shift = 7; + for (i = png_pass_start[pass]; i < row_width; + i += png_pass_inc[pass]) + { + sp = row + (png_size_t)(i >> 3); + value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01; + d |= (value << shift); + + if (shift == 0) + { + shift = 7; + *dp++ = (png_byte)d; + d = 0; + } + else + shift--; + + } + if (shift != 7) + *dp = (png_byte)d; + break; + } + case 2: + { + png_bytep sp; + png_bytep dp; + int shift; + int d; + int value; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + dp = row; + shift = 6; + d = 0; + for (i = png_pass_start[pass]; i < row_width; + i += png_pass_inc[pass]) + { + sp = row + (png_size_t)(i >> 2); + value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03; + d |= (value << shift); + + if (shift == 0) + { + shift = 6; + *dp++ = (png_byte)d; + d = 0; + } + else + shift -= 2; + } + if (shift != 6) + *dp = (png_byte)d; + break; + } + case 4: + { + png_bytep sp; + png_bytep dp; + int shift; + int d; + int value; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + dp = row; + shift = 4; + d = 0; + for (i = png_pass_start[pass]; i < row_width; + i += png_pass_inc[pass]) + { + sp = row + (png_size_t)(i >> 1); + value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f; + d |= (value << shift); + + if (shift == 0) + { + shift = 4; + *dp++ = (png_byte)d; + d = 0; + } + else + shift -= 4; + } + if (shift != 4) + *dp = (png_byte)d; + break; + } + default: + { + png_bytep sp; + png_bytep dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + png_size_t pixel_bytes; + + /* start at the beginning */ + dp = row; + /* find out how many bytes each pixel takes up */ + pixel_bytes = (row_info->pixel_depth >> 3); + /* loop through the row, only looking at the pixels that + matter */ + for (i = png_pass_start[pass]; i < row_width; + i += png_pass_inc[pass]) + { + /* find out where the original pixel is */ + sp = row + (png_size_t)i * pixel_bytes; + /* move the pixel */ + if (dp != sp) + png_memcpy(dp, sp, pixel_bytes); + /* next pixel */ + dp += pixel_bytes; + } + break; + } + } + /* set new row width */ + row_info->width = (row_info->width + + png_pass_inc[pass] - 1 - + png_pass_start[pass]) / + png_pass_inc[pass]; + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, + row_info->width); + } +} +#endif + +/* This filters the row, chooses which filter to use, if it has not already + * been specified by the application, and then writes the row out with the + * chosen filter. + */ +#define PNG_MAXSUM (((png_uint_32)(-1)) >> 1) +#define PNG_HISHIFT 10 +#define PNG_LOMASK ((png_uint_32)0xffffL) +#define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT)) +void /* PRIVATE */ +png_write_find_filter(png_structp png_ptr, png_row_infop row_info) +{ + png_bytep prev_row, best_row, row_buf; + png_uint_32 mins, bpp; + png_byte filter_to_do = png_ptr->do_filter; + png_uint_32 row_bytes = row_info->rowbytes; +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) + int num_p_filters = (int)png_ptr->num_prev_filters; +#endif + + png_debug(1, "in png_write_find_filter\n"); + /* find out how many bytes offset each pixel is */ + bpp = (row_info->pixel_depth + 7) >> 3; + + prev_row = png_ptr->prev_row; + best_row = row_buf = png_ptr->row_buf; + mins = PNG_MAXSUM; + + /* The prediction method we use is to find which method provides the + * smallest value when summing the absolute values of the distances + * from zero, using anything >= 128 as negative numbers. This is known + * as the "minimum sum of absolute differences" heuristic. Other + * heuristics are the "weighted minimum sum of absolute differences" + * (experimental and can in theory improve compression), and the "zlib + * predictive" method (not implemented yet), which does test compressions + * of lines using different filter methods, and then chooses the + * (series of) filter(s) that give minimum compressed data size (VERY + * computationally expensive). + * + * GRR 980525: consider also + * (1) minimum sum of absolute differences from running average (i.e., + * keep running sum of non-absolute differences & count of bytes) + * [track dispersion, too? restart average if dispersion too large?] + * (1b) minimum sum of absolute differences from sliding average, probably + * with window size <= deflate window (usually 32K) + * (2) minimum sum of squared differences from zero or running average + * (i.e., ~ root-mean-square approach) + */ + + + /* We don't need to test the 'no filter' case if this is the only filter + * that has been chosen, as it doesn't actually do anything to the data. + */ + if ((filter_to_do & PNG_FILTER_NONE) && + filter_to_do != PNG_FILTER_NONE) + { + png_bytep rp; + png_uint_32 sum = 0; + png_uint_32 i; + int v; + + for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++) + { + v = *rp; + sum += (v < 128) ? v : 256 - v; + } + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + png_uint_32 sumhi, sumlo; + int j; + sumlo = sum & PNG_LOMASK; + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; /* Gives us some footroom */ + + /* Reduce the sum if we match any of the previous rows */ + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE) + { + sumlo = (sumlo * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + sumhi = (sumhi * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + /* Factor in the cost of this filter (this is here for completeness, + * but it makes no sense to have a "cost" for the NONE filter, as + * it has the minimum possible computational cost - none). + */ + sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >> + PNG_COST_SHIFT; + sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >> + PNG_COST_SHIFT; + + if (sumhi > PNG_HIMASK) + sum = PNG_MAXSUM; + else + sum = (sumhi << PNG_HISHIFT) + sumlo; + } +#endif + mins = sum; + } + + /* sub filter */ + if (filter_to_do == PNG_FILTER_SUB) + /* it's the only filter so no testing is needed */ + { + png_bytep rp, lp, dp; + png_uint_32 i; + for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp; + i++, rp++, dp++) + { + *dp = *rp; + } + for (lp = row_buf + 1; i < row_bytes; + i++, rp++, lp++, dp++) + { + *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); + } + best_row = png_ptr->sub_row; + } + + else if (filter_to_do & PNG_FILTER_SUB) + { + png_bytep rp, dp, lp; + png_uint_32 sum = 0, lmins = mins; + png_uint_32 i; + int v; + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) + /* We temporarily increase the "minimum sum" by the factor we + * would reduce the sum of this filter, so that we can do the + * early exit comparison without scaling the sum each time. + */ + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 lmhi, lmlo; + lmlo = lmins & PNG_LOMASK; + lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB) + { + lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> + PNG_COST_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> + PNG_COST_SHIFT; + + if (lmhi > PNG_HIMASK) + lmins = PNG_MAXSUM; + else + lmins = (lmhi << PNG_HISHIFT) + lmlo; + } +#endif + + for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp; + i++, rp++, dp++) + { + v = *dp = *rp; + + sum += (v < 128) ? v : 256 - v; + } + for (lp = row_buf + 1; i < row_bytes; + i++, rp++, lp++, dp++) + { + v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); + + sum += (v < 128) ? v : 256 - v; + + if (sum > lmins) /* We are already worse, don't continue. */ + break; + } + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 sumhi, sumlo; + sumlo = sum & PNG_LOMASK; + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB) + { + sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> + PNG_COST_SHIFT; + sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> + PNG_COST_SHIFT; + + if (sumhi > PNG_HIMASK) + sum = PNG_MAXSUM; + else + sum = (sumhi << PNG_HISHIFT) + sumlo; + } +#endif + + if (sum < mins) + { + mins = sum; + best_row = png_ptr->sub_row; + } + } + + /* up filter */ + if (filter_to_do == PNG_FILTER_UP) + { + png_bytep rp, dp, pp; + png_uint_32 i; + + for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1, + pp = prev_row + 1; i < row_bytes; + i++, rp++, pp++, dp++) + { + *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff); + } + best_row = png_ptr->up_row; + } + + else if (filter_to_do & PNG_FILTER_UP) + { + png_bytep rp, dp, pp; + png_uint_32 sum = 0, lmins = mins; + png_uint_32 i; + int v; + + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 lmhi, lmlo; + lmlo = lmins & PNG_LOMASK; + lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP) + { + lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >> + PNG_COST_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >> + PNG_COST_SHIFT; + + if (lmhi > PNG_HIMASK) + lmins = PNG_MAXSUM; + else + lmins = (lmhi << PNG_HISHIFT) + lmlo; + } +#endif + + for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1, + pp = prev_row + 1; i < row_bytes; i++) + { + v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); + + sum += (v < 128) ? v : 256 - v; + + if (sum > lmins) /* We are already worse, don't continue. */ + break; + } + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 sumhi, sumlo; + sumlo = sum & PNG_LOMASK; + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP) + { + sumlo = (sumlo * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + sumhi = (sumhi * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >> + PNG_COST_SHIFT; + sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >> + PNG_COST_SHIFT; + + if (sumhi > PNG_HIMASK) + sum = PNG_MAXSUM; + else + sum = (sumhi << PNG_HISHIFT) + sumlo; + } +#endif + + if (sum < mins) + { + mins = sum; + best_row = png_ptr->up_row; + } + } + + /* avg filter */ + if (filter_to_do == PNG_FILTER_AVG) + { + png_bytep rp, dp, pp, lp; + png_uint_32 i; + for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1, + pp = prev_row + 1; i < bpp; i++) + { + *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); + } + for (lp = row_buf + 1; i < row_bytes; i++) + { + *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) + & 0xff); + } + best_row = png_ptr->avg_row; + } + + else if (filter_to_do & PNG_FILTER_AVG) + { + png_bytep rp, dp, pp, lp; + png_uint_32 sum = 0, lmins = mins; + png_uint_32 i; + int v; + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 lmhi, lmlo; + lmlo = lmins & PNG_LOMASK; + lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG) + { + lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >> + PNG_COST_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >> + PNG_COST_SHIFT; + + if (lmhi > PNG_HIMASK) + lmins = PNG_MAXSUM; + else + lmins = (lmhi << PNG_HISHIFT) + lmlo; + } +#endif + + for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1, + pp = prev_row + 1; i < bpp; i++) + { + v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); + + sum += (v < 128) ? v : 256 - v; + } + for (lp = row_buf + 1; i < row_bytes; i++) + { + v = *dp++ = + (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff); + + sum += (v < 128) ? v : 256 - v; + + if (sum > lmins) /* We are already worse, don't continue. */ + break; + } + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 sumhi, sumlo; + sumlo = sum & PNG_LOMASK; + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE) + { + sumlo = (sumlo * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + sumhi = (sumhi * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >> + PNG_COST_SHIFT; + sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >> + PNG_COST_SHIFT; + + if (sumhi > PNG_HIMASK) + sum = PNG_MAXSUM; + else + sum = (sumhi << PNG_HISHIFT) + sumlo; + } +#endif + + if (sum < mins) + { + mins = sum; + best_row = png_ptr->avg_row; + } + } + + /* Paeth filter */ + if (filter_to_do == PNG_FILTER_PAETH) + { + png_bytep rp, dp, pp, cp, lp; + png_uint_32 i; + for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1, + pp = prev_row + 1; i < bpp; i++) + { + *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); + } + + for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++) + { + int a, b, c, pa, pb, pc, p; + + b = *pp++; + c = *cp++; + a = *lp++; + + p = b - c; + pc = a - c; + +#ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +#else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +#endif + + p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; + + *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); + } + best_row = png_ptr->paeth_row; + } + + else if (filter_to_do & PNG_FILTER_PAETH) + { + png_bytep rp, dp, pp, cp, lp; + png_uint_32 sum = 0, lmins = mins; + png_uint_32 i; + int v; + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 lmhi, lmlo; + lmlo = lmins & PNG_LOMASK; + lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH) + { + lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >> + PNG_COST_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >> + PNG_COST_SHIFT; + + if (lmhi > PNG_HIMASK) + lmins = PNG_MAXSUM; + else + lmins = (lmhi << PNG_HISHIFT) + lmlo; + } +#endif + + for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1, + pp = prev_row + 1; i < bpp; i++) + { + v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); + + sum += (v < 128) ? v : 256 - v; + } + + for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++) + { + int a, b, c, pa, pb, pc, p; + + b = *pp++; + c = *cp++; + a = *lp++; + +#ifndef PNG_SLOW_PAETH + p = b - c; + pc = a - c; +#ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +#else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +#endif + p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; +#else /* PNG_SLOW_PAETH */ + p = a + b - c; + pa = abs(p - a); + pb = abs(p - b); + pc = abs(p - c); + if (pa <= pb && pa <= pc) + p = a; + else if (pb <= pc) + p = b; + else + p = c; +#endif /* PNG_SLOW_PAETH */ + + v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); + + sum += (v < 128) ? v : 256 - v; + + if (sum > lmins) /* We are already worse, don't continue. */ + break; + } + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 sumhi, sumlo; + sumlo = sum & PNG_LOMASK; + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH) + { + sumlo = (sumlo * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + sumhi = (sumhi * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >> + PNG_COST_SHIFT; + sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >> + PNG_COST_SHIFT; + + if (sumhi > PNG_HIMASK) + sum = PNG_MAXSUM; + else + sum = (sumhi << PNG_HISHIFT) + sumlo; + } +#endif + + if (sum < mins) + { + best_row = png_ptr->paeth_row; + } + } + + /* Do the actual writing of the filtered row data from the chosen filter. */ + + png_write_filtered_row(png_ptr, best_row); + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) + /* Save the type of filter we picked this time for future calculations */ + if (png_ptr->num_prev_filters > 0) + { + int j; + for (j = 1; j < num_p_filters; j++) + { + png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1]; + } + png_ptr->prev_filters[j] = best_row[0]; + } +#endif +} + + +/* Do the actual writing of a previously filtered row. */ +void /* PRIVATE */ +png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row) +{ + png_debug(1, "in png_write_filtered_row\n"); + png_debug1(2, "filter = %d\n", filtered_row[0]); + /* set up the zlib input buffer */ + + png_ptr->zstream.next_in = filtered_row; + png_ptr->zstream.avail_in = (uInt)png_ptr->row_info.rowbytes + 1; + /* repeat until we have compressed all the data */ + do + { + int ret; /* return of zlib */ + + /* compress the data */ + ret = deflate(&png_ptr->zstream, Z_NO_FLUSH); + /* check for compression errors */ + if (ret != Z_OK) + { + if (png_ptr->zstream.msg != NULL) + png_error(png_ptr, png_ptr->zstream.msg); + else + png_error(png_ptr, "zlib error"); + } + + /* see if it is time to write another IDAT */ + if (!(png_ptr->zstream.avail_out)) + { + /* write the IDAT and reset the zlib output buffer */ + png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + } + /* repeat until all data has been compressed */ + } while (png_ptr->zstream.avail_in); + + /* swap the current and previous rows */ + if (png_ptr->prev_row != NULL) + { + png_bytep tptr; + + tptr = png_ptr->prev_row; + png_ptr->prev_row = png_ptr->row_buf; + png_ptr->row_buf = tptr; + } + + /* finish row - updates counters and flushes zlib if last row */ + png_write_finish_row(png_ptr); + +#if defined(PNG_WRITE_FLUSH_SUPPORTED) + png_ptr->flush_rows++; + + if (png_ptr->flush_dist > 0 && + png_ptr->flush_rows >= png_ptr->flush_dist) + { + png_write_flush(png_ptr); + } +#endif +} +#endif /* PNG_WRITE_SUPPORTED */ diff --git a/syslinux/com32/lib/lrand48.c b/syslinux/com32/lib/lrand48.c new file mode 100644 index 0000000..4d05de2 --- /dev/null +++ b/syslinux/com32/lib/lrand48.c @@ -0,0 +1,42 @@ +/* + * lrand48.c + */ + +#include <stdlib.h> +#include <stdint.h> + +unsigned short __rand48_seed[3]; + +long jrand48(unsigned short xsubi[3]) +{ + uint64_t x; + + /* The xsubi[] array is littleendian by spec */ + x = (uint64_t)xsubi[0] + + ((uint64_t)xsubi[1] << 16) + + ((uint64_t)xsubi[2] << 32); + + x = (0x5deece66dULL * x) + 0xb; + + xsubi[0] = (unsigned short)x; + xsubi[1] = (unsigned short)(x >> 16); + xsubi[2] = (unsigned short)(x >> 32); + + return (long)(int32_t)(x >> 16); +} + +long mrand48(void) +{ + return jrand48(__rand48_seed); +} + +long nrand48(unsigned short xsubi[3]) +{ + return (long)((uint32_t)jrand48(xsubi) >> 1); +} + +long lrand48(void) +{ + return (long)((uint32_t)(mrand48() >> 1)); +} + diff --git a/syslinux/com32/lib/malloc.c b/syslinux/com32/lib/malloc.c new file mode 100644 index 0000000..8f6d97d --- /dev/null +++ b/syslinux/com32/lib/malloc.c @@ -0,0 +1,120 @@ +/* + * malloc.c + * + * Very simple linked-list based malloc()/free(). + */ + +#include <stdlib.h> +#include "init.h" +#include "malloc.h" + +struct free_arena_header __malloc_head = +{ + { + ARENA_TYPE_HEAD, + 0, + &__malloc_head, + &__malloc_head, + }, + &__malloc_head, + &__malloc_head +}; + +/* This is extern so it can be overridden by the user application */ +extern size_t __stack_size; +extern void *__mem_end; /* Produced after argv parsing */ + +static inline size_t sp(void) +{ + size_t sp; + asm volatile("movl %%esp,%0" : "=rm" (sp)); + return sp; +} + +static void __constructor init_memory_arena(void) +{ + struct free_arena_header *fp; + size_t start, total_space; + + start = (size_t)ARENA_ALIGN_UP(__mem_end); + total_space = sp() - start; + + if ( __stack_size == 0 || __stack_size > total_space >> 1 ) + __stack_size = total_space >> 1; /* Half for the stack, half for the heap... */ + + if ( total_space < __stack_size + 4*sizeof(struct arena_header) ) + __stack_size = total_space - 4*sizeof(struct arena_header); + + fp = (struct free_arena_header *)start; + fp->a.type = ARENA_TYPE_FREE; + fp->a.size = total_space - __stack_size; + + /* Insert into chains */ + fp->a.next = fp->a.prev = &__malloc_head; + fp->next_free = fp->prev_free = &__malloc_head; + __malloc_head.a.next = __malloc_head.a.prev = fp; + __malloc_head.next_free = __malloc_head.prev_free = fp; +} + +static void *__malloc_from_block(struct free_arena_header *fp, size_t size) +{ + size_t fsize; + struct free_arena_header *nfp, *na; + + fsize = fp->a.size; + + /* We need the 2* to account for the larger requirements of a free block */ + if ( fsize >= size+2*sizeof(struct arena_header) ) { + /* Bigger block than required -- split block */ + nfp = (struct free_arena_header *)((char *)fp + size); + na = fp->a.next; + + nfp->a.type = ARENA_TYPE_FREE; + nfp->a.size = fsize-size; + fp->a.type = ARENA_TYPE_USED; + fp->a.size = size; + + /* Insert into all-block chain */ + nfp->a.prev = fp; + nfp->a.next = na; + na->a.prev = nfp; + fp->a.next = nfp; + + /* Replace current block on free chain */ + nfp->next_free = fp->next_free; + nfp->prev_free = fp->prev_free; + fp->next_free->prev_free = nfp; + fp->prev_free->next_free = nfp; + } else { + /* Allocate the whole block */ + fp->a.type = ARENA_TYPE_USED; + + /* Remove from free chain */ + fp->next_free->prev_free = fp->prev_free; + fp->prev_free->next_free = fp->next_free; + } + + return (void *)(&fp->a + 1); +} + +void *malloc(size_t size) +{ + struct free_arena_header *fp; + + if ( size == 0 ) + return NULL; + + /* Add the obligatory arena header, and round up */ + size = (size+2*sizeof(struct arena_header)-1) & ~ARENA_SIZE_MASK; + + for ( fp = __malloc_head.next_free ; fp->a.type != ARENA_TYPE_HEAD ; + fp = fp->next_free ) { + if ( fp->a.size >= size ) { + /* Found fit -- allocate out of this block */ + return __malloc_from_block(fp, size); + } + } + + /* Nothing found... need to request a block from the kernel */ + return NULL; /* No kernel to get stuff from */ +} diff --git a/syslinux/com32/lib/malloc.h b/syslinux/com32/lib/malloc.h new file mode 100644 index 0000000..70d0e63 --- /dev/null +++ b/syslinux/com32/lib/malloc.h @@ -0,0 +1,54 @@ +/* + * malloc.h + * + * Internals for the memory allocator + */ + +#include <stdint.h> +#include <stddef.h> + +/* + * This is the minimum chunk size we will ask the kernel for; this should + * be a multiple of the page size on all architectures. + */ +#define MALLOC_CHUNK_SIZE 65536 +#define MALLOC_CHUNK_MASK (MALLOC_CHUNK_SIZE-1) + +/* + * This structure should be a power of two. This becomes the + * alignment unit. + */ +struct free_arena_header; + +struct arena_header { + size_t type; + size_t size; /* Also gives the location of the next entry */ + struct free_arena_header *next, *prev; +}; + +#ifdef DEBUG_MALLOC +#define ARENA_TYPE_USED 0x64e69c70 +#define ARENA_TYPE_FREE 0x012d610a +#define ARENA_TYPE_HEAD 0x971676b5 +#define ARENA_TYPE_DEAD 0xeeeeeeee +#else +#define ARENA_TYPE_USED 0 +#define ARENA_TYPE_FREE 1 +#define ARENA_TYPE_HEAD 2 +#endif + +#define ARENA_SIZE_MASK (sizeof(struct arena_header)-1) + +#define ARENA_ALIGN_UP(p) ((char *)(((uintptr_t)(p) + ARENA_SIZE_MASK) & ~ARENA_SIZE_MASK)) +#define ARENA_ALIGN_DOWN(p) ((char *)((uintptr_t)(p) & ~ARENA_SIZE_MASK)) + +/* + * This structure should be no more than twice the size of the + * previous structure. + */ +struct free_arena_header { + struct arena_header a; + struct free_arena_header *next_free, *prev_free; +}; + +extern struct free_arena_header __malloc_head; diff --git a/syslinux/com32/lib/memccpy.c b/syslinux/com32/lib/memccpy.c new file mode 100644 index 0000000..22f68de --- /dev/null +++ b/syslinux/com32/lib/memccpy.c @@ -0,0 +1,23 @@ +/* + * memccpy.c + * + * memccpy() + */ + +#include <stddef.h> +#include <string.h> + +void *memccpy(void *dst, const void *src, int c, size_t n) +{ + char *q = dst; + const char *p = src; + char ch; + + while ( n-- ) { + *q++ = ch = *p++; + if ( ch == (char)c ) + return q; + } + + return NULL; /* No instance of "c" found */ +} diff --git a/syslinux/com32/lib/memchr.c b/syslinux/com32/lib/memchr.c new file mode 100644 index 0000000..c5c5fa2 --- /dev/null +++ b/syslinux/com32/lib/memchr.c @@ -0,0 +1,18 @@ +/* + * memchr.c + */ + +#include <stddef.h> +#include <string.h> + +void *memchr(const void *s, int c, size_t n) +{ + const unsigned char *sp = s; + + while ( n-- ) { + if ( *sp == (unsigned char)c ) + return (void *)sp; + } + + return NULL; +} diff --git a/syslinux/com32/lib/memcmp.c b/syslinux/com32/lib/memcmp.c new file mode 100644 index 0000000..f6bc172 --- /dev/null +++ b/syslinux/com32/lib/memcmp.c @@ -0,0 +1,19 @@ +/* + * memcmp.c + */ + +#include <string.h> + +int memcmp(const void *s1, const void *s2, size_t n) +{ + const unsigned char *c1 = s1, *c2 = s2; + int d = 0; + + while ( n-- ) { + d = (int)*c1++ - (int)*c2++; + if ( d ) + break; + } + + return d; +} diff --git a/syslinux/com32/lib/memcpy.c b/syslinux/com32/lib/memcpy.c new file mode 100644 index 0000000..b9171c3 --- /dev/null +++ b/syslinux/com32/lib/memcpy.c @@ -0,0 +1,29 @@ +/* + * memcpy.c + */ + +#include <string.h> +#include <stdint.h> + +void *memcpy(void *dst, const void *src, size_t n) +{ + const char *p = src; + char *q = dst; +#if defined(__i386__) + size_t nl = n >> 2; + asm volatile("cld ; rep ; movsl ; movl %3,%0 ; rep ; movsb" + : "+c" (nl), "+S" (p), "+D" (q) + : "r" (n & 3)); +#elif defined(__x86_64__) + size_t nq = n >> 3; + asm volatile("cld ; rep ; movsq ; movl %3,%%ecx ; rep ; movsb" + : "+c" (nq), "+S" (p), "+D" (q) + : "r" ((uint32_t)(n & 7))); +#else + while ( n-- ) { + *q++ = *p++; + } +#endif + + return dst; +} diff --git a/syslinux/com32/lib/memmem.c b/syslinux/com32/lib/memmem.c new file mode 100644 index 0000000..0f59938 --- /dev/null +++ b/syslinux/com32/lib/memmem.c @@ -0,0 +1,44 @@ +/* + * memmem.c + * + * Find a byte string inside a longer byte string + * + * This uses the "Not So Naive" algorithm, a very simple but + * usually effective algorithm, see: + * + * http://www-igm.univ-mlv.fr/~lecroq/string/ + */ + +#include <string.h> + +void *memmem(const void *haystack, size_t n, const void *needle, size_t m) +{ + const unsigned char *y = (const unsigned char *)haystack; + const unsigned char *x = (const unsigned char *)needle; + + size_t j, k, l; + + if ( m > n ) + return NULL; + + if ( x[0] == x[1] ) { + k = 2; + l = 1; + } else { + k = 1; + l = 2; + } + + j = 0; + while ( j <= n-m ) { + if (x[1] != y[j+1]) { + j += k; + } else { + if ( !memcmp(x+2, y+j+2, m-2) && x[0] == y[j] ) + return (void *)&y[j]; + j += l; + } + } + + return NULL; +} diff --git a/syslinux/com32/lib/memmove.c b/syslinux/com32/lib/memmove.c new file mode 100644 index 0000000..c1f042a --- /dev/null +++ b/syslinux/com32/lib/memmove.c @@ -0,0 +1,34 @@ +/* + * memmove.c + */ + +#include <string.h> + +void *memmove(void *dst, const void *src, size_t n) +{ + const char *p = src; + char *q = dst; +#if defined(__i386__) || defined(__x86_64__) + if ( q < p ) { + asm volatile("cld ; rep ; movsb" : "+c" (n), "+S" (p), "+D" (q)); + } else { + p += (n-1); + q += (n-1); + asm volatile("std ; rep ; movsb" : "+c" (n), "+S" (p), "+D" (q)); + } +#else + if ( q < p ) { + while ( n-- ) { + *q++ = *p++; + } + } else { + p += n; + q += n; + while ( n-- ) { + *--q = *--p; + } + } +#endif + + return dst; +} diff --git a/syslinux/com32/lib/memset.c b/syslinux/com32/lib/memset.c new file mode 100644 index 0000000..522cc59 --- /dev/null +++ b/syslinux/com32/lib/memset.c @@ -0,0 +1,30 @@ +/* + * memset.c + */ + +#include <string.h> +#include <stdint.h> + +void *memset(void *dst, int c, size_t n) +{ + char *q = dst; + +#if defined(__i386__) + size_t nl = n >> 2; + asm volatile("cld ; rep ; stosl ; movl %3,%0 ; rep ; stosb" + : "+c" (nl), "+D" (q) + : "a" ((unsigned char)c * 0x01010101U), "r" (n & 3)); +#elif defined(__x86_64__) + size_t nq = n >> 3; + asm volatile("cld ; rep ; stosq ; movl %3,%%ecx ; rep ; stosb" + : "+c" (nq), "+D" (q) + : "a" ((unsigned char)c * 0x0101010101010101U), + "r" ((uint32_t)n & 7)); +#else + while ( n-- ) { + *q++ = c; + } +#endif + + return dst; +} diff --git a/syslinux/com32/lib/memswap.c b/syslinux/com32/lib/memswap.c new file mode 100644 index 0000000..10440e3 --- /dev/null +++ b/syslinux/com32/lib/memswap.c @@ -0,0 +1,23 @@ +/* + * memswap() + * + * Swaps the contents of two nonoverlapping memory areas. + * This really could be done faster... + */ + +#include <string.h> + +void memswap(void *m1, void *m2, size_t n) +{ + char *p = m1; + char *q = m2; + char tmp; + + while ( n-- ) { + tmp = *p; + *p = *q; + *q = tmp; + + p++; q++; + } +} diff --git a/syslinux/com32/lib/onexit.c b/syslinux/com32/lib/onexit.c new file mode 100644 index 0000000..70a9c01 --- /dev/null +++ b/syslinux/com32/lib/onexit.c @@ -0,0 +1,39 @@ +/* + * onexit.c + */ + +#include <stdlib.h> +#include <unistd.h> +#include "atexit.h" + +extern __noreturn (*__exit_handler)(int); +static struct atexit *__atexit_list; + +static __noreturn on_exit_exit(int rv) +{ + struct atexit *ap; + + for ( ap = __atexit_list ; ap ; ap = ap->next ) { + ap->fctn(rv, ap->arg); /* This assumes extra args are harmless */ + } + + _exit(rv); +} + +int on_exit(void (*fctn)(int, void *), void *arg) +{ + struct atexit *as = malloc(sizeof(struct atexit)); + + if ( !as ) + return -1; + + as->fctn = fctn; + as->arg = arg; + + as->next = __atexit_list; + __atexit_list = as; + + __exit_handler = on_exit_exit; + + return 0; +} diff --git a/syslinux/com32/lib/pci/cfgtype.c b/syslinux/com32/lib/pci/cfgtype.c new file mode 100644 index 0000000..5fa72be --- /dev/null +++ b/syslinux/com32/lib/pci/cfgtype.c @@ -0,0 +1,23 @@ +#include "pci/pci.h" + +enum pci_config_type __pci_cfg_type; + +void pci_set_config_type(enum pci_config_type type) +{ + uint32_t oldcf8; + + if ( type == PCI_CFG_AUTO ) { + /* Try to detect CM #1 */ + cli(); + oldcf8 = inl(0xcf8); + outl(~0, 0xcf8); + if ( inl(0xcf8) == pci_mkaddr(255,31,7,252) ) + type = PCI_CFG_TYPE1; + else + type = PCI_CFG_TYPE2; /* ... it better be ... */ + outl(oldcf8, 0xcf8); + sti(); + } + + __pci_cfg_type = type; +} diff --git a/syslinux/com32/lib/pci/pci.h b/syslinux/com32/lib/pci/pci.h new file mode 100644 index 0000000..6946edf --- /dev/null +++ b/syslinux/com32/lib/pci/pci.h @@ -0,0 +1,14 @@ +/* + * pci/pci.h + * + * Common internal header file + */ + +#ifndef PCI_PCI_H + +#include <sys/pci.h> +#include <sys/cpu.h> + +extern enum pci_config_type __pci_cfg_type; + +#endif /* PCI_PCI_H */ diff --git a/syslinux/com32/lib/pci/readb.c b/syslinux/com32/lib/pci/readb.c new file mode 100644 index 0000000..bfc544f --- /dev/null +++ b/syslinux/com32/lib/pci/readb.c @@ -0,0 +1,3 @@ +#define TYPE uint8_t +#define BWL(x) x ## b +#include "pci/readx.c" diff --git a/syslinux/com32/lib/pci/readl.c b/syslinux/com32/lib/pci/readl.c new file mode 100644 index 0000000..ef3fdd6 --- /dev/null +++ b/syslinux/com32/lib/pci/readl.c @@ -0,0 +1,3 @@ +#define TYPE uint32_t +#define BWL(x) x ## l +#include "pci/readx.c" diff --git a/syslinux/com32/lib/pci/readw.c b/syslinux/com32/lib/pci/readw.c new file mode 100644 index 0000000..6889229 --- /dev/null +++ b/syslinux/com32/lib/pci/readw.c @@ -0,0 +1,3 @@ +#define TYPE uint16_t +#define BWL(x) x ## w +#include "pci/readx.c" diff --git a/syslinux/com32/lib/pci/readx.c b/syslinux/com32/lib/pci/readx.c new file mode 100644 index 0000000..f1e542d --- /dev/null +++ b/syslinux/com32/lib/pci/readx.c @@ -0,0 +1,48 @@ +#include "pci/pci.h" + +TYPE BWL(pci_read) (pciaddr_t a) +{ + TYPE r; + + for (;;) { + switch ( __pci_cfg_type ) { + case PCI_CFG_AUTO: + pci_set_config_type(PCI_CFG_AUTO); + break; /* Try again */ + + case PCI_CFG_TYPE1: + { + uint32_t oldcf8; + cli(); + oldcf8 = inl(0xcf8); + outl(a, 0xcf8); + r = BWL(in) (0xcfc + (a & 3)); + outl(oldcf8, 0xcf8); + sti(); + } + return r; + + case PCI_CFG_TYPE2: + { + uint8_t oldcf8, oldcfa; + + if ( a & (0x10 << 11) ) + return (TYPE)~0; + + cli(); + oldcf8 = inb(0xcf8); + oldcfa = inb(0xcfa); + outb(0xf0 + ((a >> (8-1)) & 0x0e), 0xcf8); + outb(a >> 16, 0xcfa); + r = BWL(in) (0xc000 + ((a >> (11-8)) & 0xf00) + (a & 0xff)); + outb(oldcf8, 0xcf8); + outb(oldcfa, 0xcfa); + sti(); + } + return r; + + default: + return (TYPE)~0; + } + } +} diff --git a/syslinux/com32/lib/pci/writeb.c b/syslinux/com32/lib/pci/writeb.c new file mode 100644 index 0000000..a63fcf1 --- /dev/null +++ b/syslinux/com32/lib/pci/writeb.c @@ -0,0 +1,3 @@ +#define TYPE uint8_t +#define BWL(x) x ## b +#include "pci/writex.c" diff --git a/syslinux/com32/lib/pci/writel.c b/syslinux/com32/lib/pci/writel.c new file mode 100644 index 0000000..f608baa --- /dev/null +++ b/syslinux/com32/lib/pci/writel.c @@ -0,0 +1,3 @@ +#define TYPE uint32_t +#define BWL(x) x ## l +#include "pci/writex.c" diff --git a/syslinux/com32/lib/pci/writew.c b/syslinux/com32/lib/pci/writew.c new file mode 100644 index 0000000..4399d71 --- /dev/null +++ b/syslinux/com32/lib/pci/writew.c @@ -0,0 +1,3 @@ +#define TYPE uint16_t +#define BWL(x) x ## w +#include "pci/writex.c" diff --git a/syslinux/com32/lib/pci/writex.c b/syslinux/com32/lib/pci/writex.c new file mode 100644 index 0000000..c7e715e --- /dev/null +++ b/syslinux/com32/lib/pci/writex.c @@ -0,0 +1,45 @@ +#include "pci/pci.h" + +void BWL(pci_write) (TYPE v, pciaddr_t a) +{ + for (;;) { + switch ( __pci_cfg_type ) { + case PCI_CFG_AUTO: + pci_set_config_type(PCI_CFG_AUTO); + break; /* Try again */ + + case PCI_CFG_TYPE1: + { + uint32_t oldcf8; + cli(); + oldcf8 = inl(0xcf8); + outl(a, 0xcf8); + BWL(out) (v, 0xcfc + (a & 3)); + outl(oldcf8, 0xcf8); + sti(); + } + return; + + case PCI_CFG_TYPE2: + { + uint8_t oldcf8, oldcfa; + + if ( a & (0x10 << 11) ) + return; + + cli(); + oldcf8 = inb(0xcf8); + oldcfa = inb(0xcfa); + outb(0xf0 + ((a >> (8-1)) & 0x0e), 0xcf8); + outb(a >> 16, 0xcfa); + BWL(out) (v, 0xc000 + ((a >> (11-8)) & 0xf00) + (a & 0xff)); + outb(oldcf8, 0xcf8); + outb(oldcfa, 0xcfa); + sti(); + } + + default: + return; /* Do nothing */ + } + } +} diff --git a/syslinux/com32/lib/perror.c b/syslinux/com32/lib/perror.c new file mode 100644 index 0000000..45585cd --- /dev/null +++ b/syslinux/com32/lib/perror.c @@ -0,0 +1,12 @@ +/* + * perror.c + */ + +#include <errno.h> +#include <stdio.h> +#include <string.h> + +void perror(const char *s) +{ + fprintf(stderr, "%s: error %d\n", s, errno); +} diff --git a/syslinux/com32/lib/printf.c b/syslinux/com32/lib/printf.c new file mode 100644 index 0000000..3423759 --- /dev/null +++ b/syslinux/com32/lib/printf.c @@ -0,0 +1,19 @@ +/* + * printf.c + */ + +#include <stdio.h> +#include <stdarg.h> + +#define BUFFER_SIZE 16384 + +int printf(const char *format, ...) +{ + va_list ap; + int rv; + + va_start(ap, format); + rv = vfprintf(stdout, format, ap); + va_end(ap); + return rv; +} diff --git a/syslinux/com32/lib/putchar.c b/syslinux/com32/lib/putchar.c new file mode 100644 index 0000000..4b340d1 --- /dev/null +++ b/syslinux/com32/lib/putchar.c @@ -0,0 +1,16 @@ +/* + * putchar.c + * + * gcc "printf decompilation" expects this to exist... + */ + +#include <stdio.h> + +#undef putchar + +int putchar(int c) +{ + unsigned char ch = c; + + return _fwrite(&ch, 1, stdout) == 1 ? ch : EOF; +} diff --git a/syslinux/com32/lib/puts.c b/syslinux/com32/lib/puts.c new file mode 100644 index 0000000..ecebf27 --- /dev/null +++ b/syslinux/com32/lib/puts.c @@ -0,0 +1,13 @@ +/* + * puts.c + */ + +#include <stdio.h> + +int puts(const char *s) +{ + if ( fputs(s, stdout) < 0 ) + return -1; + + return _fwrite("\n", 1, stdout); +} diff --git a/syslinux/com32/lib/qsort.c b/syslinux/com32/lib/qsort.c new file mode 100644 index 0000000..185f4da --- /dev/null +++ b/syslinux/com32/lib/qsort.c @@ -0,0 +1,42 @@ +/* + * qsort.c + * + * This is actually combsort. It's an O(n log n) algorithm with + * simplicity/small code size being its main virtue. + */ + +#include <stddef.h> +#include <string.h> + +static inline size_t newgap(size_t gap) +{ + gap = (gap*10)/13; + if ( gap == 9 || gap == 10 ) + gap = 11; + + if ( gap < 1 ) + gap = 1; + return gap; +} + +void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) +{ + size_t gap = nmemb; + size_t i, j; + char *p1, *p2; + int swapped; + + do { + gap = newgap(gap); + swapped = 0; + + for ( i = 0, p1 = base ; i < nmemb-gap ; i++, p1 += size ) { + j = i+gap; + if ( compar(p1, p2 = (char *)base+j*size) > 0 ) { + memswap(p1, p2, size); + swapped = 1; + } + } + } while ( gap > 1 || swapped ); +} + diff --git a/syslinux/com32/lib/realloc.c b/syslinux/com32/lib/realloc.c new file mode 100644 index 0000000..577c200 --- /dev/null +++ b/syslinux/com32/lib/realloc.c @@ -0,0 +1,49 @@ +/* + * realloc.c + */ + +#include <stdlib.h> +#include <string.h> + +#include "malloc.h" + +/* FIXME: This is cheesy, it should be fixed later */ + +void *realloc(void *ptr, size_t size) +{ + struct free_arena_header *ah; + void *newptr; + size_t oldsize; + + if ( !ptr ) + return malloc(size); + + if ( size == 0 ) { + free(ptr); + return NULL; + } + + /* Add the obligatory arena header, and round up */ + size = (size+2*sizeof(struct arena_header)-1) & ARENA_SIZE_MASK; + + ah = (struct free_arena_header *) + ((struct arena_header *)ptr - 1); + + if ( ah->a.size >= size && size >= (ah->a.size >> 2) ) { + /* This field is a good size already. */ + return ptr; + } else { + /* Make me a new block. This is kind of bogus; we should + be checking the adjacent blocks to see if we can do an + in-place adjustment... fix that later. */ + + oldsize = ah->a.size - sizeof(struct arena_header); + + newptr = malloc(size); + memcpy(newptr, ptr, (size < oldsize) ? size : oldsize); + free(ptr); + + return newptr; + } +} + diff --git a/syslinux/com32/lib/seed48.c b/syslinux/com32/lib/seed48.c new file mode 100644 index 0000000..f8353c8 --- /dev/null +++ b/syslinux/com32/lib/seed48.c @@ -0,0 +1,19 @@ +/* + * seed48.c + */ + +#include <stdlib.h> +#include <stdint.h> +#include <string.h> + +extern unsigned short __rand48_seed[3]; + +unsigned short *seed48(const unsigned short xsubi[3]) +{ + static unsigned short oldseed[3]; + memcpy(oldseed, __rand48_seed, sizeof __rand48_seed); + memcpy(__rand48_seed, xsubi, sizeof __rand48_seed); + + return oldseed; +} + diff --git a/syslinux/com32/lib/setjmp.S b/syslinux/com32/lib/setjmp.S new file mode 100644 index 0000000..bea900c --- /dev/null +++ b/syslinux/com32/lib/setjmp.S @@ -0,0 +1,58 @@ +# +# arch/i386/setjmp.S +# +# setjmp/longjmp for the i386 architecture +# + +# +# The jmp_buf is assumed to contain the following, in order: +# %ebx +# %esp +# %ebp +# %esi +# %edi +# <return address> +# + + .text + .align 4 + .globl setjmp + .type setjmp, @function +setjmp: +#ifdef REGPARM + movl %eax,%edx +#else + movl 4(%esp),%edx +#endif + popl %ecx # Return address, and adjust the stack + xorl %eax,%eax # Return value + movl %ebx,(%edx) + movl %esp,4(%edx) # Post-return %esp! + pushl %ecx # Make the call/return stack happy + movl %ebp,8(%edx) + movl %esi,12(%edx) + movl %edi,16(%edx) + movl %ecx,20(%edx) # Return address + ret + + .size setjmp,.-setjmp + + .text + .align 4 + .globl longjmp + .type longjmp, @function +longjmp: +#ifdef REGPARM + xchgl %eax,%edx +#else + movl 4(%esp),%edx # jmp_ptr address + movl 8(%esp),%eax # Return value +#endif + movl (%edx),%ebx + movl 4(%edx),%esp + movl 8(%edx),%ebp + movl 12(%edx),%esi + movl 16(%edx),%edi + jmp *20(%edx) + + .size longjmp,.-longjmp diff --git a/syslinux/com32/lib/snprintf.c b/syslinux/com32/lib/snprintf.c new file mode 100644 index 0000000..c642851 --- /dev/null +++ b/syslinux/com32/lib/snprintf.c @@ -0,0 +1,16 @@ +/* + * snprintf.c + */ + +#include <stdio.h> + +int snprintf(char *buffer, size_t n, const char *format, ...) +{ + va_list ap; + int rv; + + va_start(ap, format); + rv = vsnprintf(buffer, n, format, ap); + va_end(ap); + return rv; +} diff --git a/syslinux/com32/lib/sprintf.c b/syslinux/com32/lib/sprintf.c new file mode 100644 index 0000000..31f28af --- /dev/null +++ b/syslinux/com32/lib/sprintf.c @@ -0,0 +1,18 @@ +/* + * sprintf.c + */ + +#include <stdio.h> +#include <unistd.h> + +int sprintf(char *buffer, const char *format, ...) +{ + va_list ap; + int rv; + + va_start(ap, format); + rv = vsnprintf(buffer, ~(size_t)0, format, ap); + va_end(ap); + + return rv; +} diff --git a/syslinux/com32/lib/srand48.c b/syslinux/com32/lib/srand48.c new file mode 100644 index 0000000..a3df16d --- /dev/null +++ b/syslinux/com32/lib/srand48.c @@ -0,0 +1,16 @@ +/* + * srand48.c + */ + +#include <stdlib.h> +#include <stdint.h> + +extern unsigned short __rand48_seed[3]; + + +void srand48(long seedval) +{ + __rand48_seed[0] = 0x330e; + __rand48_seed[1] = (unsigned short)seedval; + __rand48_seed[2] = (unsigned short)((uint32_t)seedval >> 16); +} diff --git a/syslinux/com32/lib/sscanf.c b/syslinux/com32/lib/sscanf.c new file mode 100644 index 0000000..81aab9e --- /dev/null +++ b/syslinux/com32/lib/sscanf.c @@ -0,0 +1,17 @@ +/* + * sscanf() + */ + +#include <stdio.h> + +int sscanf(const char *str, const char *format, ...) +{ + va_list ap; + int rv; + + va_start(ap, format); + rv = vsscanf(str, format, ap); + va_end(ap); + + return rv; +} diff --git a/syslinux/com32/lib/stack.c b/syslinux/com32/lib/stack.c new file mode 100644 index 0000000..dd7d9d4 --- /dev/null +++ b/syslinux/com32/lib/stack.c @@ -0,0 +1,4 @@ +#include <stdlib.h> + +/* Default stack size 8 MB */ +size_t __stack_size = 8 << 20; diff --git a/syslinux/com32/lib/strcasecmp.c b/syslinux/com32/lib/strcasecmp.c new file mode 100644 index 0000000..fdc5795 --- /dev/null +++ b/syslinux/com32/lib/strcasecmp.c @@ -0,0 +1,24 @@ +/* + * strcasecmp.c + */ + +#include <string.h> +#include <ctype.h> + +int strcasecmp(const char *s1, const char *s2) +{ + const unsigned char *c1 = (const unsigned char *)s1; + const unsigned char *c2 = (const unsigned char *)s2; + unsigned char ch; + int d = 0; + + while ( 1 ) { + /* toupper() expects an unsigned char (implicitly cast to int) + as input, and returns an int, which is exactly what we want. */ + d = toupper(ch = *c1++) - toupper(*c2++); + if ( d || !ch ) + break; + } + + return d; +} diff --git a/syslinux/com32/lib/strcat.c b/syslinux/com32/lib/strcat.c new file mode 100644 index 0000000..a5f9477 --- /dev/null +++ b/syslinux/com32/lib/strcat.c @@ -0,0 +1,11 @@ +/* + * strcat.c + */ + +#include <string.h> + +char *strcat(char *dst, const char *src) +{ + strcpy(strchr(dst, '\0'), src); + return dst; +} diff --git a/syslinux/com32/lib/strchr.c b/syslinux/com32/lib/strchr.c new file mode 100644 index 0000000..192f836 --- /dev/null +++ b/syslinux/com32/lib/strchr.c @@ -0,0 +1,16 @@ +/* + * strchr.c + */ + +#include <string.h> + +char *strchr(const char *s, int c) +{ + while ( *s != (char)c ) { + if ( ! *s ) + return NULL; + s++; + } + + return (char *)s; +} diff --git a/syslinux/com32/lib/strcmp.c b/syslinux/com32/lib/strcmp.c new file mode 100644 index 0000000..63a391b --- /dev/null +++ b/syslinux/com32/lib/strcmp.c @@ -0,0 +1,21 @@ +/* + * strcmp.c + */ + +#include <string.h> + +int strcmp(const char *s1, const char *s2) +{ + const unsigned char *c1 = (const unsigned char *)s1; + const unsigned char *c2 = (const unsigned char *)s2; + unsigned char ch; + int d = 0; + + while ( 1 ) { + d = (int)(ch = *c1++) - (int)*c2++; + if ( d || !ch ) + break; + } + + return d; +} diff --git a/syslinux/com32/lib/strcpy.c b/syslinux/com32/lib/strcpy.c new file mode 100644 index 0000000..8372eba --- /dev/null +++ b/syslinux/com32/lib/strcpy.c @@ -0,0 +1,20 @@ +/* + * strcpy.c + * + * strcpy() + */ + +#include <string.h> + +char *strcpy(char *dst, const char *src) +{ + char *q = dst; + const char *p = src; + char ch; + + do { + *q++ = ch = *p++; + } while ( ch ); + + return dst; +} diff --git a/syslinux/com32/lib/strdup.c b/syslinux/com32/lib/strdup.c new file mode 100644 index 0000000..eb170c2 --- /dev/null +++ b/syslinux/com32/lib/strdup.c @@ -0,0 +1,17 @@ +/* + * strdup.c + */ + +#include <string.h> +#include <stdlib.h> + +char *strdup(const char *s) +{ + int l = strlen(s)+1; + char *d = malloc(l); + + if ( d ) + memcpy(d, s, l); + + return d; +} diff --git a/syslinux/com32/lib/strerror.c b/syslinux/com32/lib/strerror.c new file mode 100644 index 0000000..6270555 --- /dev/null +++ b/syslinux/com32/lib/strerror.c @@ -0,0 +1,24 @@ +/* + * strerror.c + */ + +#include <string.h> + +char *strerror(int errnum) +{ + static char message[32] = "error "; /* enough for error 2^63-1 */ + + char numbuf[32]; + char *p; + + p = numbuf+sizeof numbuf; + *--p = '\0'; + + do { + *--p = (errnum % 10) + '0'; + errnum /= 10; + } while ( errnum ); + + return (char *)memcpy(message+6, p, (numbuf+sizeof numbuf)-p); +} + diff --git a/syslinux/com32/lib/strlcat.c b/syslinux/com32/lib/strlcat.c new file mode 100644 index 0000000..6111445 --- /dev/null +++ b/syslinux/com32/lib/strlcat.c @@ -0,0 +1,31 @@ +/* + * strlcat.c + */ + +#include <string.h> +#include <klibc/compiler.h> + +size_t strlcat(char *dst, const char *src, size_t size) +{ + size_t bytes = 0; + char *q = dst; + const char *p = src; + char ch; + + while ( bytes < size && *q ) { + q++; + bytes++; + } + + while ( (ch = *p++) ) { + if ( bytes < size ) + *q++ = ch; + + bytes++; + } + + *q = '\0'; + return bytes; +} + + diff --git a/syslinux/com32/lib/strlcpy.c b/syslinux/com32/lib/strlcpy.c new file mode 100644 index 0000000..eb384c9 --- /dev/null +++ b/syslinux/com32/lib/strlcpy.c @@ -0,0 +1,26 @@ +/* + * strlcpy.c + */ + +#include <string.h> +#include <klibc/compiler.h> + +size_t strlcpy(char *dst, const char *src, size_t size) +{ + size_t bytes = 0; + char *q = dst; + const char *p = src; + char ch; + + while ( (ch = *p++) ) { + if ( bytes < size ) + *q++ = ch; + + bytes++; + } + + *q = '\0'; + return bytes; +} + + diff --git a/syslinux/com32/lib/strlen.c b/syslinux/com32/lib/strlen.c new file mode 100644 index 0000000..4d773f9 --- /dev/null +++ b/syslinux/com32/lib/strlen.c @@ -0,0 +1,14 @@ +/* + * strlen() + */ + +#include <string.h> + +size_t strlen(const char *s) +{ + const char *ss = s; + while ( *ss ) + ss++; + return ss-s; +} + diff --git a/syslinux/com32/lib/strncasecmp.c b/syslinux/com32/lib/strncasecmp.c new file mode 100644 index 0000000..c400124 --- /dev/null +++ b/syslinux/com32/lib/strncasecmp.c @@ -0,0 +1,24 @@ +/* + * strncasecmp.c + */ + +#include <string.h> +#include <ctype.h> + +int strncasecmp(const char *s1, const char *s2, size_t n) +{ + const unsigned char *c1 = (const unsigned char *)s1; + const unsigned char *c2 = (const unsigned char *)s2; + unsigned char ch; + int d = 0; + + while ( n-- ) { + /* toupper() expects an unsigned char (implicitly cast to int) + as input, and returns an int, which is exactly what we want. */ + d = toupper(ch = *c1++) - toupper(*c2++); + if ( d || !ch ) + break; + } + + return d; +} diff --git a/syslinux/com32/lib/strncat.c b/syslinux/com32/lib/strncat.c new file mode 100644 index 0000000..99d9575 --- /dev/null +++ b/syslinux/com32/lib/strncat.c @@ -0,0 +1,11 @@ +/* + * strncat.c + */ + +#include <string.h> + +char *strncat(char *dst, const char *src, size_t n) +{ + strncpy(strchr(dst, '\0'), src, n); + return dst; +} diff --git a/syslinux/com32/lib/strncmp.c b/syslinux/com32/lib/strncmp.c new file mode 100644 index 0000000..61f1fba --- /dev/null +++ b/syslinux/com32/lib/strncmp.c @@ -0,0 +1,21 @@ +/* + * strncmp.c + */ + +#include <string.h> + +int strncmp(const char *s1, const char *s2, size_t n) +{ + const unsigned char *c1 = (const unsigned char *)s1; + const unsigned char *c2 = (const unsigned char *)s2; + unsigned char ch; + int d = 0; + + while ( n-- ) { + d = (int)(ch = *c1++) - (int)*c2++; + if ( d || !ch ) + break; + } + + return d; +} diff --git a/syslinux/com32/lib/strncpy.c b/syslinux/com32/lib/strncpy.c new file mode 100644 index 0000000..a8fe45f --- /dev/null +++ b/syslinux/com32/lib/strncpy.c @@ -0,0 +1,22 @@ +/* + * strncpy.c + * + * strncpy() + */ + +#include <string.h> + +char *strncpy(char *dst, const char *src, size_t n) +{ + char *q = dst; + const char *p = src; + char ch; + + while ( n-- ) { + *q++ = ch = *p++; + if ( !ch ) + break; + } + + return dst; +} diff --git a/syslinux/com32/lib/strndup.c b/syslinux/com32/lib/strndup.c new file mode 100644 index 0000000..1b44e6f --- /dev/null +++ b/syslinux/com32/lib/strndup.c @@ -0,0 +1,17 @@ +/* + * strndup.c + */ + +#include <string.h> +#include <stdlib.h> + +char *strndup(const char *s, size_t n) +{ + int l = n > strlen(s) ? strlen(s)+1 : n+1; + char *d = malloc(l); + + if (d) + memcpy(d, s, l); + d[n] = '\0'; + return d; +} diff --git a/syslinux/com32/lib/strntoimax.c b/syslinux/com32/lib/strntoimax.c new file mode 100644 index 0000000..f53a266 --- /dev/null +++ b/syslinux/com32/lib/strntoimax.c @@ -0,0 +1,13 @@ +/* + * strntoimax.c + * + * strntoimax() + */ + +#include <stddef.h> +#include <inttypes.h> + +intmax_t strntoimax(const char *nptr, char **endptr, int base, size_t n) +{ + return (intmax_t) strntoumax(nptr, endptr, base, n); +} diff --git a/syslinux/com32/lib/strntoumax.c b/syslinux/com32/lib/strntoumax.c new file mode 100644 index 0000000..4e30637 --- /dev/null +++ b/syslinux/com32/lib/strntoumax.c @@ -0,0 +1,75 @@ +/* + * strntoumax.c + * + * The strntoumax() function and associated + */ + +#include <stddef.h> +#include <stdint.h> +#include <ctype.h> + +static inline int digitval(int ch) +{ + if ( ch >= '0' && ch <= '9' ) { + return ch-'0'; + } else if ( ch >= 'A' && ch <= 'Z' ) { + return ch-'A'+10; + } else if ( ch >= 'a' && ch <= 'z' ) { + return ch-'a'+10; + } else { + return -1; + } +} + +uintmax_t strntoumax(const char *nptr, char **endptr, int base, size_t n) +{ + int minus = 0; + uintmax_t v = 0; + int d; + + while ( n && isspace((unsigned char)*nptr) ) { + nptr++; + n--; + } + + /* Single optional + or - */ + if ( n && *nptr == '-' ) { + minus = 1; + nptr++; + n--; + } else if ( n && *nptr == '+' ) { + nptr++; + } + + if ( base == 0 ) { + if ( n >= 2 && nptr[0] == '0' && + (nptr[1] == 'x' || nptr[1] == 'X') ) { + n -= 2; + nptr += 2; + base = 16; + } else if ( n >= 1 && nptr[0] == '0' ) { + n--; + nptr++; + base = 8; + } else { + base = 10; + } + } else if ( base == 16 ) { + if ( n >= 2 && nptr[0] == '0' && + (nptr[1] == 'x' || nptr[1] == 'X') ) { + n -= 2; + nptr += 2; + } + } + + while ( n && (d = digitval(*nptr)) >= 0 && d < base ) { + v = v*base + d; + n--; + nptr++; + } + + if ( endptr ) + *endptr = (char *)nptr; + + return minus ? -v : v; +} diff --git a/syslinux/com32/lib/strrchr.c b/syslinux/com32/lib/strrchr.c new file mode 100644 index 0000000..3b42464 --- /dev/null +++ b/syslinux/com32/lib/strrchr.c @@ -0,0 +1,18 @@ +/* + * strrchr.c + */ + +#include <string.h> + +char *strrchr(const char *s, int c) +{ + const char *found = NULL; + + while ( *s ) { + if ( *s == (char) c ) + found = s; + s++; + } + + return (char *)found; +} diff --git a/syslinux/com32/lib/strsep.c b/syslinux/com32/lib/strsep.c new file mode 100644 index 0000000..58a7a07 --- /dev/null +++ b/syslinux/com32/lib/strsep.c @@ -0,0 +1,21 @@ +/* + * strsep.c + */ + +#include <string.h> + +char *strsep(char **stringp, const char *delim) +{ + char *s = *stringp; + char *e; + + if ( !s ) + return NULL; + + e = strpbrk(s, delim); + if (e) + *e++ = '\0'; + + *stringp = e; + return s; +} diff --git a/syslinux/com32/lib/strspn.c b/syslinux/com32/lib/strspn.c new file mode 100644 index 0000000..856a964 --- /dev/null +++ b/syslinux/com32/lib/strspn.c @@ -0,0 +1,67 @@ +/* + * strspn, strcspn + */ + +#include <string.h> +#include <stddef.h> +#include <inttypes.h> +#include <limits.h> + +#ifndef LONG_BIT +#define LONG_BIT (CHAR_BIT*sizeof(long)) +#endif + +static inline void +set_bit(unsigned long *bitmap, unsigned int bit) +{ + bitmap[bit/LONG_BIT] |= 1UL << (bit%LONG_BIT); +} + +static inline int +test_bit(unsigned long *bitmap, unsigned int bit) +{ + return (int)(bitmap[bit/LONG_BIT] >> (bit%LONG_BIT)) & 1; +} + +static size_t +strxspn(const char *s, const char *map, int parity) +{ + unsigned long matchmap[((1 << CHAR_BIT)+LONG_BIT-1)/LONG_BIT]; + size_t n = 0; + + /* Create bitmap */ + memset(matchmap, 0, sizeof matchmap); + while ( *map ) + set_bit(matchmap, (unsigned char) *map++); + + /* Make sure the null character never matches */ + if ( parity ) + set_bit(matchmap, 0); + + /* Calculate span length */ + while ( test_bit(matchmap, (unsigned char) *s++)^parity ) + n++; + + return n; +} + +size_t +strspn(const char *s, const char *accept) +{ + return strxspn(s, accept, 0); +} + +size_t +strcspn(const char *s, const char *reject) +{ + return strxspn(s, reject, 1); +} + +char * +strpbrk(const char *s, const char *accept) +{ + const char *ss = s+strxspn(s, accept, 1); + + return *ss ? (char *)ss : NULL; +} + diff --git a/syslinux/com32/lib/strstr.c b/syslinux/com32/lib/strstr.c new file mode 100644 index 0000000..10222df --- /dev/null +++ b/syslinux/com32/lib/strstr.c @@ -0,0 +1,10 @@ +/* + * strstr.c + */ + +#include <string.h> + +char *strstr(const char *haystack, const char *needle) +{ + return (char *)memmem(haystack, strlen(haystack), needle, strlen(needle)); +} diff --git a/syslinux/com32/lib/strtoimax.c b/syslinux/com32/lib/strtoimax.c new file mode 100644 index 0000000..0cdd088 --- /dev/null +++ b/syslinux/com32/lib/strtoimax.c @@ -0,0 +1,3 @@ +#define TYPE intmax_t +#define NAME strtoimax +#include "strtox.c" diff --git a/syslinux/com32/lib/strtok.c b/syslinux/com32/lib/strtok.c new file mode 100644 index 0000000..6e84f1d --- /dev/null +++ b/syslinux/com32/lib/strtok.c @@ -0,0 +1,16 @@ +/* + * strtok.c + */ + +#include <string.h> + +char *strtok(char *s, const char *delim) +{ + static char *holder; + + if ( s ) + holder = s; + + return strsep(&holder, delim); +} + diff --git a/syslinux/com32/lib/strtol.c b/syslinux/com32/lib/strtol.c new file mode 100644 index 0000000..9efc8b9 --- /dev/null +++ b/syslinux/com32/lib/strtol.c @@ -0,0 +1,3 @@ +#define TYPE signed long +#define NAME strtol +#include "strtox.c" diff --git a/syslinux/com32/lib/strtoll.c b/syslinux/com32/lib/strtoll.c new file mode 100644 index 0000000..a9428c7 --- /dev/null +++ b/syslinux/com32/lib/strtoll.c @@ -0,0 +1,3 @@ +#define TYPE signed long long +#define NAME strtoll +#include "strtox.c" diff --git a/syslinux/com32/lib/strtoul.c b/syslinux/com32/lib/strtoul.c new file mode 100644 index 0000000..3189aaa --- /dev/null +++ b/syslinux/com32/lib/strtoul.c @@ -0,0 +1,3 @@ +#define TYPE unsigned long +#define NAME strtoul +#include "strtox.c" diff --git a/syslinux/com32/lib/strtoull.c b/syslinux/com32/lib/strtoull.c new file mode 100644 index 0000000..83c14e9 --- /dev/null +++ b/syslinux/com32/lib/strtoull.c @@ -0,0 +1,3 @@ +#define TYPE unsigned long long +#define NAME strtoull +#include "strtox.c" diff --git a/syslinux/com32/lib/strtoumax.c b/syslinux/com32/lib/strtoumax.c new file mode 100644 index 0000000..a379710 --- /dev/null +++ b/syslinux/com32/lib/strtoumax.c @@ -0,0 +1,3 @@ +#define TYPE uintmax_t +#define NAME strtoumax +#include "strtox.c" diff --git a/syslinux/com32/lib/strtox.c b/syslinux/com32/lib/strtox.c new file mode 100644 index 0000000..7c228b6 --- /dev/null +++ b/syslinux/com32/lib/strtox.c @@ -0,0 +1,13 @@ +/* + * strtox.c + * + * strto...() functions, by macro definition + */ + +#include <stddef.h> +#include <inttypes.h> + +TYPE NAME (const char *nptr, char **endptr, int base) +{ + return (TYPE) strntoumax(nptr, endptr, base, ~(size_t)0); +} diff --git a/syslinux/com32/lib/sys/ansicon_write.c b/syslinux/com32/lib/sys/ansicon_write.c new file mode 100644 index 0000000..eaac667 --- /dev/null +++ b/syslinux/com32/lib/sys/ansicon_write.c @@ -0,0 +1,538 @@ +#ident "$Id: ansicon_write.c,v 1.9 2005/01/05 07:45:23 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * ansicon_write.c + * + * Write to the screen using ANSI control codes (about as capable as + * DOS' ANSI.SYS.) + */ + +#include <errno.h> +#include <string.h> +#include <com32.h> +#include <minmax.h> +#include <klibc/compiler.h> +#include "file.h" + +struct curxy { + uint8_t x, y; +} __attribute__((packed)); +#define BIOS_CURXY ((struct curxy *)0x450) /* Array for each page */ +#define BIOS_ROWS (*(uint8_t *)0x484) /* Minus one; if zero use 24 (= 25 lines) */ +#define BIOS_COLS (*(uint16_t *)0x44A) +#define BIOS_PAGE (*(uint8_t *)0x462) + +enum ansi_state { + st_init, /* Normal (no ESC seen) */ + st_esc, /* ESC seen */ + st_csi, /* CSI seen */ +}; + +#define MAX_PARMS 16 + +struct term_state { + int disabled; + int attr; /* Current display attribute */ + int vtgraphics; /* VT graphics on/off */ + int intensity; + int underline; + int blink; + int reverse; + int fg; + int bg; + int autocr; + struct curxy saved_xy; + uint16_t cursor_type; + enum ansi_state state; + int pvt; /* Private code? */ + int nparms; /* Number of parameters seen */ + int parms[MAX_PARMS]; +}; + +static const struct term_state default_state = +{ + .disabled = 0, + .attr = 0x07, /* Grey on black */ + .vtgraphics = 0, + .intensity = 1, + .underline = 0, + .blink = 0, + .reverse = 0, + .fg = 7, + .bg = 0, + .autocr = 0, + .saved_xy = { 0, 0 }, + .cursor_type = 0x0607, + .state = st_init, + .pvt = 0, + .nparms = 0, +}; + +static struct term_state st; + +/* DEC VT graphics to codepage 437 table (characters 0x60-0x7F only) */ +static const char decvt_to_cp437[] = + { 0004, 0261, 0007, 0007, 0007, 0007, 0370, 0361, 0007, 0007, 0331, 0277, 0332, 0300, 0305, 0304, + 0304, 0304, 0137, 0137, 0303, 0264, 0301, 0302, 0263, 0363, 0362, 0343, 0330, 0234, 0007, 00 }; + +/* Common setup */ +static void __constructor ansicon_init(void) +{ + static com32sys_t ireg; /* Auto-initalized to all zero */ + com32sys_t oreg; + + /* Initial state */ + memcpy(&st, &default_state, sizeof st); + + /* Are we disabled? */ + ireg.eax.w[0] = 0x000b; + __intcall(0x22, &ireg, &oreg); + + if ( (signed char)oreg.ebx.b[1] < 0 ) { + st.disabled = 1; + return; + } + + /* Force text mode */ + ireg.eax.w[0] = 0x0005; + __intcall(0x22, &ireg, NULL); + + /* Get cursor shape */ + ireg.eax.b[1] = 0x03; + ireg.ebx.b[1] = BIOS_PAGE; + __intcall(0x10, &ireg, &oreg); + st.cursor_type = oreg.ecx.w[0]; +} + +/* Erase a region of the screen */ +static void ansicon_erase(int x0, int y0, int x1, int y1) +{ + static com32sys_t ireg; + + ireg.eax.w[0] = 0x0600; /* Clear window */ + ireg.ebx.b[1] = st.attr; /* Fill with current attribute */ + ireg.ecx.b[0] = x0; + ireg.ecx.b[1] = y0; + ireg.edx.b[0] = x1; + ireg.edx.b[1] = y1; + __intcall(0x10, &ireg, NULL); +} + +/* Show or hide the cursor */ +static void showcursor(int yes) +{ + static com32sys_t ireg; + + ireg.eax.b[1] = 0x01; + ireg.ecx.w[0] = yes ? st.cursor_type : 0x2020; + __intcall(0x10, &ireg, NULL); +} + +static void ansicon_putchar(int ch) +{ + static com32sys_t ireg; + const int rows = BIOS_ROWS ? BIOS_ROWS+1 : 25; + const int cols = BIOS_COLS; + const int page = BIOS_PAGE; + struct curxy xy = BIOS_CURXY[page]; + + switch ( st.state ) { + case st_init: + switch ( ch ) { + case '\b': + if ( xy.x > 0 ) xy.x--; + break; + case '\t': + { + int nsp = 8 - (xy.x & 7); + while ( nsp-- ) + ansicon_putchar(' '); + } + return; /* Cursor already updated */ + case '\n': + case '\v': + case '\f': + xy.y++; + if ( st.autocr ) + xy.x = 0; + break; + case '\r': + xy.x = 0; + break; + case 127: + /* Ignore delete */ + break; + case 14: + st.vtgraphics = 1; + break; + case 15: + st.vtgraphics = 0; + break; + case 27: + st.state = st_esc; + break; + default: + /* Print character */ + if ( ch >= 32 ) { + if ( st.vtgraphics && (ch & 0xe0) == 0x60 ) + ch = decvt_to_cp437[ch - 0x60]; + + ireg.eax.b[1] = 0x09; + ireg.eax.b[0] = ch; + ireg.ebx.b[1] = page; + ireg.ebx.b[0] = st.attr; + ireg.ecx.w[0] = 1; + __intcall(0x10, &ireg, NULL); + xy.x++; + } + break; + } + break; + + case st_esc: + switch ( ch ) { + case '%': + case '(': + case ')': + case '#': + /* Ignore this plus the subsequent character, allows + compatibility with Linux sequence to set charset */ + break; + case '[': + st.state = st_csi; + st.nparms = st.pvt = 0; + memset(st.parms, 0, sizeof st.parms); + break; + case 'c': + /* Reset terminal */ + memcpy(&st, &default_state, sizeof st); + ansicon_erase(0, 0, cols-1, rows-1); + xy.x = xy.y = 1; + break; + default: + /* Ignore sequence */ + st.state = st_init; + break; + } + break; + + case st_csi: + { + int p0 = st.parms[0] ? st.parms[0] : 1; + + if ( ch >= '0' && ch <= '9' ) { + st.parms[st.nparms] = st.parms[st.nparms]*10 + (ch-'0'); + } else if ( ch == ';' ) { + st.nparms++; + if ( st.nparms >= MAX_PARMS ) + st.nparms = MAX_PARMS-1; + break; + } else if ( ch == '?' ) { + st.pvt = 1; + } else { + switch ( ch ) { + case 'A': + { + int y = xy.y - p0; + xy.y = (y < 0) ? 0 : y; + } + break; + case 'B': + { + int y = xy.y + p0; + xy.y = (y >= rows) ? rows-1 : y; + } + break; + case 'C': + { + int x = xy.x + p0; + xy.x = (x >= cols) ? cols-1 : x; + } + break; + case 'D': + { + int x = xy.x - p0; + xy.x = (x < 0) ? 0 : x; + } + break; + case 'E': + { + int y = xy.y + p0; + xy.y = (y >= rows) ? rows-1 : y; + xy.x = 0; + } + break; + case 'F': + { + int y = xy.y - p0; + xy.y = (y < 0) ? 0 : y; + xy.x = 0; + } + break; + case 'G': + case '\'': + { + int x = st.parms[0] - 1; + xy.x = (x >= cols) ? cols-1 : (x < 0) ? 0 : x; + } + break; + case 'H': + case 'f': + { + int y = st.parms[0] - 1; + int x = st.parms[1] - 1; + + xy.x = (x >= cols) ? cols-1 : (x < 0) ? 0 : x; + xy.y = (y >= rows) ? rows-1 : (y < 0) ? 0 : y; + } + break; + case 'J': + { + switch ( st.parms[0] ) { + case 0: + ansicon_erase(xy.x, xy.y, cols-1, xy.y); + if ( xy.y < rows-1 ) + ansicon_erase(0, xy.y+1, cols-1, rows-1); + break; + + case 1: + if ( xy.y > 0 ) + ansicon_erase(0, 0, cols-1, xy.y-1); + if ( xy.y > 0 ) + ansicon_erase(0, xy.y, xy.x-1, xy.y); + break; + + case 2: + ansicon_erase(0, 0, cols-1, rows-1); + break; + + default: + /* Ignore */ + break; + } + } + break; + case 'K': + { + switch ( st.parms[0] ) { + case 0: + ansicon_erase(xy.x, xy.y, cols-1, xy.y); + break; + + case 1: + if ( xy.x > 0 ) + ansicon_erase(0, xy.y, xy.x-1, xy.y); + break; + + case 2: + ansicon_erase(0, xy.y, cols-1, xy.y); + break; + + default: + /* Ignore */ + break; + } + } + break; + case 'h': + case 'l': + { + int set = (ch == 'h'); + switch ( st.parms[0] ) { + case 20: + st.autocr = set; + break; + case 25: + showcursor(set); + break; + default: + /* Ignore */ + break; + } + } + break; + case 'm': + { + static const int ansi2pc[8] = { 0, 4, 2, 6, 1, 5, 3, 7 }; + + int i; + for ( i = 0 ; i <= st.nparms ; i++ ) { + int a = st.parms[i]; + switch ( a ) { + case 0: + st.fg = 7; + st.bg = 0; + st.intensity = 1; + st.underline = 0; + st.blink = 0; + st.reverse = 0; + break; + case 1: + st.intensity = 2; + break; + case 2: + st.intensity = 0; + break; + case 4: + st.underline = 1; + break; + case 5: + st.blink = 1; + break; + case 7: + st.reverse = 1; + break; + case 21: + case 22: + st.intensity = 1; + break; + case 24: + st.underline = 0; + break; + case 25: + st.blink = 0; + break; + case 27: + st.reverse = 0; + break; + case 30 ... 37: + st.fg = ansi2pc[a-30]; + break; + case 38: + st.fg = 7; + st.underline = 1; + break; + case 39: + st.fg = 7; + st.underline = 0; + break; + case 40 ... 47: + st.bg = ansi2pc[a-40]; + break; + case 49: + st.bg = 7; + break; + default: + /* Do nothing */ + break; + } + } + + /* Turn into an attribute code */ + { + int bg = st.bg; + int fg; + + if ( st.underline ) + fg = 0x01; + else if ( st.intensity == 0 ) + fg = 0x08; + else + fg = st.fg; + + if ( st.reverse ) { + bg = fg & 0x07; + fg &= 0x08; + fg |= st.bg; + } + + if ( st.blink ) + bg ^= 0x08; + + if ( st.intensity == 2 ) + fg ^= 0x08; + + st.attr = (bg << 4) | fg; + } + } + break; + case 's': + st.saved_xy = xy; + break; + case 'u': + xy = st.saved_xy; + break; + default: /* Includes CAN and SUB */ + break; /* Drop unknown sequence */ + } + st.state = st_init; + } + } + break; + } + + /* If we fell off the end of the screen, adjust */ + if ( xy.x >= cols ) { + xy.x = 0; + xy.y++; + } + while ( xy.y >= rows ) { + xy.y--; + ireg.eax.w[0] = 0x0601; + ireg.ebx.b[1] = st.attr; + ireg.ecx.w[0] = 0; + ireg.edx.b[1] = rows-1; + ireg.edx.b[0] = cols-1; + __intcall(0x10, &ireg, NULL); /* Scroll */ + } + + /* Update cursor position */ + ireg.eax.b[1] = 0x02; + ireg.ebx.b[1] = page; + ireg.edx.b[1] = xy.y; + ireg.edx.b[0] = xy.x; + __intcall(0x10, &ireg, NULL); +} + + +ssize_t __ansicon_write(struct file_info *fp, const void *buf, size_t count) +{ + const unsigned char *bufp = buf; + size_t n = 0; + + (void)fp; + + if ( st.disabled ) + return n; /* Nothing to do */ + + while ( count-- ) { + ansicon_putchar(*bufp++); + n++; + } + + return n; +} + +const struct output_dev dev_ansicon_w = { + .dev_magic = __DEV_MAGIC, + .flags = __DEV_TTY | __DEV_OUTPUT, + .fileflags = O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, + .write = __ansicon_write, + .close = NULL, +}; diff --git a/syslinux/com32/lib/sys/ansiserial_write.c b/syslinux/com32/lib/sys/ansiserial_write.c new file mode 100644 index 0000000..106cd21 --- /dev/null +++ b/syslinux/com32/lib/sys/ansiserial_write.c @@ -0,0 +1,56 @@ +#ident "$Id: ansiserial_write.c,v 1.1 2004/11/30 22:09:56 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * ansiserial_write.c + * + * Write to both to the ANSI console and the serial port + */ + +#include <errno.h> +#include <string.h> +#include <com32.h> +#include <minmax.h> +#include "file.h" + +extern ssize_t __ansicon_write(struct file_info *, const void *, size_t); +extern ssize_t __serial_write(struct file_info *, const void *, size_t); + +static ssize_t __ansiserial_write(struct file_info *fp, const void *buf, size_t count) +{ + __ansicon_write(fp, buf, count); + return __serial_write(fp, buf, count); +} + +const struct output_dev dev_ansiserial_w = { + .dev_magic = __DEV_MAGIC, + .flags = __DEV_TTY | __DEV_OUTPUT, + .fileflags = O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, + .write = __ansiserial_write, + .close = NULL, +}; diff --git a/syslinux/com32/lib/sys/argv.c b/syslinux/com32/lib/sys/argv.c new file mode 100644 index 0000000..9e623c9 --- /dev/null +++ b/syslinux/com32/lib/sys/argv.c @@ -0,0 +1,98 @@ +#ident "$Id: argv.c,v 1.3 2004/12/21 02:47:08 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * argv.c + * + * Parse a single C string into argc and argv (argc is return value.) + * memptr points to available memory. + */ + +#include <inttypes.h> +#include <stddef.h> +#include <stdio.h> + +#define ALIGN_UP(p,t) ((t *)(((uintptr_t)(p) + (sizeof(t)-1)) & ~(sizeof(t)-1))) + +extern char _end[]; /* Symbol created by linker */ +void *__mem_end = &_end; /* Global variable for use by malloc() */ + +int __parse_argv(char ***argv, const char *str) +{ + char argv0[] = ""; + char *mem = __mem_end; + const char *p = str; + char *q = mem; + char *r; + char **arg; + int wasspace = 1; + int argc = 1; + + /* First copy the string, turning whitespace runs into nulls */ + for ( p = str ; ; p++ ) { + if ( *p <= ' ' ) { + if ( !wasspace ) { + wasspace = 1; + *q++ = '\0'; + } + } else { + if ( wasspace ) { + argc++; + wasspace = 0; + } + *q++ = *p; + } + + /* This test is AFTER we have processed the null byte; + we treat it as a whitespace character so it terminates + the last argument */ + if ( ! *p ) + break; + } + + /* Now create argv */ + arg = ALIGN_UP(q,char *); + *argv = arg; + *arg++ = argv0; /* argv[0] */ + + q--; /* Point q to final null */ + if ( mem < q ) + *arg++ = mem; /* argv[1] */ + + for ( r = mem ; r < q ; r++ ) { + if ( *r == '\0' ) { + *arg++ = r+1; + } + } + + *arg++ = NULL; /* Null pointer at the end */ + __mem_end = arg; /* End of memory we used */ + + return argc; +} + diff --git a/syslinux/com32/lib/sys/close.c b/syslinux/com32/lib/sys/close.c new file mode 100644 index 0000000..00f1ce0 --- /dev/null +++ b/syslinux/com32/lib/sys/close.c @@ -0,0 +1,62 @@ +#ident "$Id: close.c,v 1.4 2004/11/23 23:43:02 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * close.c + */ + +#include <errno.h> +#include <com32.h> +#include <string.h> +#include "file.h" + +int close(int fd) +{ + struct file_info *fp = &__file_info[fd]; + int rv = 0; + + if ( fd >= NFILES || !fp->iop || !fp->oop ) { + errno = EBADF; + return -1; + } + + if ( fp->iop->close ) { + rv = fp->iop->close(fp); + if ( rv ) + return rv; + } + + if ( fp->oop->close ) { + rv = fp->oop->close(fp); + if ( rv ) + return rv; + } + + memset(fp, 0, sizeof *fp); /* File structure unused */ + return 0; +} diff --git a/syslinux/com32/lib/sys/entry.S b/syslinux/com32/lib/sys/entry.S new file mode 100644 index 0000000..f6cc85c --- /dev/null +++ b/syslinux/com32/lib/sys/entry.S @@ -0,0 +1,90 @@ +#ident "$Id: entry.S,v 1.3 2004/12/21 02:47:08 hpa Exp $" +# ----------------------------------------------------------------------- +# +# Copyright 2003-2004 H. Peter Anvin - All Rights Reserved +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom +# the Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall +# be included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +# ----------------------------------------------------------------------- + +# COM32 start up code - must be linked first in the binary + + + .section ".init","ax" + .globl _start + .type _start, @function +_start: + # This first instruction acts as COM32 magic number + movl $0x21cd4cff,%eax + + # Upwards string operations + cld + + # Zero the .bss segment + xorl %eax,%eax + movl $__bss_start,%edi # Symbol provided by linker + movl $_end+3,%ecx # Symbol provided by linker + subl %edi,%ecx + shrl $2,%ecx + rep ; stosl + + # Copy COM32 invocation parameters + leal 4(%esp),%esi # Argument list + movl $__com32,%edi + movl $6,%ecx + movl %esp,-4(%edi) # Save the initial stack ptr + cmpl (%esi),%ecx + jbe 1f + movl (%esi),%ecx +1: rep ; movsl + + # Parse the command line (assumes REGPARM) + movl __com32+4,%edx # Command line + pushl %edx # Make space for argv + movl %esp,%eax + call __parse_argv + pushl %eax # Save argc + + # Look for library initialization functions + movl $__ctors_start, %esi +2: + cmpl $__ctors_end, %esi + jae 3f + call *(%esi) + addl $4,%esi + jmp 2b +# +# Actually run main. This assumes REGPARM is used!!!! +# +3: + popl %eax # argc + popl %edx # argv + call main + call *(__exit_handler) + hlt + .size _start, .-_start + + .bss + .globl __entry_esp +__entry_esp: .space 4 + .globl __com32 +__com32: .space 4*6 diff --git a/syslinux/com32/lib/sys/err_read.c b/syslinux/com32/lib/sys/err_read.c new file mode 100644 index 0000000..64bb8e9 --- /dev/null +++ b/syslinux/com32/lib/sys/err_read.c @@ -0,0 +1,54 @@ +#ident "$Id: err_read.c,v 1.1 2004/11/23 23:43:02 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * err_read.c + * + * Reading from a device which doesn't support reading + */ + +#include <errno.h> +#include <string.h> +#include <com32.h> +#include <minmax.h> +#include "file.h" + +static ssize_t __err_read(struct file_info *fp, void *buf, size_t count) +{ + (void)fp; (void)buf; (void)count; + errno = -EINVAL; + return -1; +} + +const struct input_dev dev_error_r = { + .dev_magic = __DEV_MAGIC, + .flags = __DEV_INPUT | __DEV_ERROR, + .fileflags = O_RDONLY, + .read = __err_read, + .close = NULL, +}; diff --git a/syslinux/com32/lib/sys/err_write.c b/syslinux/com32/lib/sys/err_write.c new file mode 100644 index 0000000..0cae16b --- /dev/null +++ b/syslinux/com32/lib/sys/err_write.c @@ -0,0 +1,54 @@ +#ident "$Id: err_write.c,v 1.1 2004/11/23 23:43:02 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * err_write.c + * + * Writing to a device which doesn't support writing + */ + +#include <errno.h> +#include <string.h> +#include <com32.h> +#include <minmax.h> +#include "file.h" + +static ssize_t __err_write(struct file_info *fp, const void *buf, size_t count) +{ + (void)fp; (void)buf; (void)count; + errno = -EINVAL; + return -1; +} + +const struct output_dev dev_error_w = { + .dev_magic = __DEV_MAGIC, + .flags = __DEV_OUTPUT | __DEV_ERROR, + .fileflags = O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, + .write = __err_write, + .close = NULL, +}; diff --git a/syslinux/com32/lib/sys/exit.S b/syslinux/com32/lib/sys/exit.S new file mode 100644 index 0000000..a2f8a1e --- /dev/null +++ b/syslinux/com32/lib/sys/exit.S @@ -0,0 +1,35 @@ +# $Id: exit.S,v 1.2 2004/12/17 19:40:41 hpa Exp $ +# +# Implementation of _exit() for com32 based on c32entry.S +# + .text + .globl _exit + .type _exit, @function +_exit: +#ifdef REGPARM + pushl %eax +#endif + + # Run any destructors + movl $__dtors_start, %esi +2: + cmpl $__dtors_end, %esi + jae 1f + call *(%esi) + addl $4,%esi + jmp 2b + +1: +#ifdef REGPARM + popl %eax +#else + movl 4(%esp),%eax # Exit code in %eax = return value +#endif + movl (__entry_esp),%esp # Return stack pointer to entry value + ret # Return to termination address + .size _exit, .-_exit + + .data +__exit_handler: + .globl __exit_handler + .long _exit diff --git a/syslinux/com32/lib/sys/file.h b/syslinux/com32/lib/sys/file.h new file mode 100644 index 0000000..2224f16 --- /dev/null +++ b/syslinux/com32/lib/sys/file.h @@ -0,0 +1,99 @@ +#ident "$Id: file.h,v 1.4 2004/11/23 23:43:02 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2003-2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * file.h + * + * Internal implementation of file I/O for COM32 + */ + +#ifndef _COM32_SYS_FILE_H +#define _COM32_SYS_FILE_H + +#include <inttypes.h> +#include <stdlib.h> +#include <sys/types.h> +#include <dev.h> +#include <fcntl.h> + +/* Device structure; contains the relevant operations */ + +struct file_info; + +#define __DEV_MAGIC 0xf4e7 +#define __DEV_TTY 0x0001 /* TTY - must be bit 0 */ +#define __DEV_FILE 0x0002 /* Ordinary file */ +#define __DEV_OUTPUT 0x0004 /* This is an output device */ +#define __DEV_INPUT 0 /* Dummy */ +#define __DEV_ERROR 0x0008 /* This is the error device */ +#define __DEV_NULL 0x0010 /* This is the null device */ + +struct input_dev { + uint16_t dev_magic; /* Magic number */ + uint16_t flags; /* Flags */ + int fileflags; /* Permitted file flags */ + ssize_t (*read)(struct file_info *, void *, size_t); + int (*close)(struct file_info *); +}; +struct output_dev { + uint16_t dev_magic; /* Magic number */ + uint16_t flags; /* Flags */ + int fileflags; + ssize_t (*write)(struct file_info *, const void *, size_t); + int (*close)(struct file_info *); +}; + +/* File structure */ + +#define NFILES 32 /* Number of files to support */ +#define MAXBLOCK 16384 /* Defined by ABI */ + +struct file_info { + const struct input_dev *iop; /* Input operations */ + const struct output_dev *oop; /* Output operations */ + + /* Structure used for input blocking */ + struct { + int blocklg2; /* Blocksize log 2 */ + size_t offset; /* Current file offset */ + size_t length; /* Total file length */ + uint16_t filedes; /* File descriptor */ + uint16_t _filler; /* Unused */ + size_t nbytes; /* Number of bytes available in buffer */ + char *datap; /* Current data pointer */ + char buf[MAXBLOCK]; + } i; +}; + +extern struct file_info __file_info[NFILES]; + +/* Line input discipline */ +ssize_t __line_input(struct file_info *fp, char *buf, size_t bufsize, + ssize_t (*get_char)(struct file_info *, void *, size_t)); + +#endif /* _COM32_SYS_FILE_H */ diff --git a/syslinux/com32/lib/sys/fileclose.c b/syslinux/com32/lib/sys/fileclose.c new file mode 100644 index 0000000..cb1c396 --- /dev/null +++ b/syslinux/com32/lib/sys/fileclose.c @@ -0,0 +1,53 @@ +#ident "$Id: fileclose.c,v 1.2 2004/11/23 23:43:02 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * fileclose.c + * + * Close an ordinary file + */ + +#include <errno.h> +#include <com32.h> +#include <string.h> +#include "file.h" + +int __file_close(struct file_info *fp) +{ + com32sys_t regs; + + if ( fp->i.filedes ) { + memset(®s, 0, sizeof regs); + regs.eax.w[0] = 0x0008; /* Close file */ + regs.esi.w[0] = fp->i.filedes; + + __com32.cs_intcall(0x22, ®s, NULL); + } + + return 0; +} diff --git a/syslinux/com32/lib/sys/fileinfo.c b/syslinux/com32/lib/sys/fileinfo.c new file mode 100644 index 0000000..a1fc7c9 --- /dev/null +++ b/syslinux/com32/lib/sys/fileinfo.c @@ -0,0 +1,3 @@ +#include "file.h" + +struct file_info __file_info[NFILES]; diff --git a/syslinux/com32/lib/sys/fileread.c b/syslinux/com32/lib/sys/fileread.c new file mode 100644 index 0000000..e0b92e5 --- /dev/null +++ b/syslinux/com32/lib/sys/fileread.c @@ -0,0 +1,86 @@ +#ident "$Id: fileread.c,v 1.2 2004/11/23 23:43:02 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * read.c + * + * Reading from a file + */ + +#include <errno.h> +#include <string.h> +#include <com32.h> +#include <minmax.h> +#include "file.h" + +ssize_t __file_read(struct file_info *fp, void *buf, size_t count) +{ + com32sys_t ireg, oreg; + char *bufp = buf; + size_t n = 0; + size_t ncopy; + + memset(&ireg, 0, sizeof ireg); + ireg.eax.w[0] = 0x0007; /* Read file */ + ireg.esi.w[0] = OFFS(__com32.cs_bounce); + ireg.es = SEG(__com32.cs_bounce); + + while ( count ) { + if ( fp->i.nbytes == 0 ) { + if ( fp->i.offset >= fp->i.length || !fp->i.filedes ) + return n; /* As good as it gets... */ + + ireg.esi.w[0] = fp->i.filedes; + ireg.ecx.w[0] = MAXBLOCK >> fp->i.blocklg2; + + __intcall(0x22, &ireg, &oreg); + + if ( oreg.eflags.l & EFLAGS_CF ) { + errno = EIO; + return -1; + } + + fp->i.filedes = ireg.esi.w[0]; + fp->i.nbytes = min(fp->i.length-fp->i.offset, (unsigned)MAXBLOCK); + fp->i.datap = fp->i.buf; + memcpy(fp->i.buf, __com32.cs_bounce, fp->i.nbytes); + } + + ncopy = min(count, fp->i.nbytes); + memcpy(bufp, fp->i.datap, ncopy); + + n += ncopy; + bufp += ncopy; + count -= ncopy; + fp->i.datap += ncopy; + fp->i.offset += ncopy; + fp->i.nbytes -= ncopy; + } + + return n; +} diff --git a/syslinux/com32/lib/sys/ftell.c b/syslinux/com32/lib/sys/ftell.c new file mode 100644 index 0000000..3db2814 --- /dev/null +++ b/syslinux/com32/lib/sys/ftell.c @@ -0,0 +1,18 @@ +/* + * sys/ftell.c + * + * We can't seek, but we can at least tell... + */ + +#include <stdio.h> +#include "sys/file.h" + +long ftell(FILE *stream) +{ + int fd = fileno(stream); + struct file_info *fp = &__file_info[fd]; + + return fp->i.offset; +} + + diff --git a/syslinux/com32/lib/sys/idle.c b/syslinux/com32/lib/sys/idle.c new file mode 100644 index 0000000..78a3713 --- /dev/null +++ b/syslinux/com32/lib/sys/idle.c @@ -0,0 +1,49 @@ +#ident "$Id: idle.c,v 1.1 2005/01/20 18:41:12 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2005 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * idle.c + * + * What to do in a busy loop... + */ + +#include <syslinux.h> +#include <stddef.h> +#include <com32.h> + +void syslinux_idle(void) +{ + static com32sys_t sys_idle = { + .eax.l = 0x0013, + }; + + /* This call isn't supported on SYSLINUX < 3.08, but all it does + is return an error, so we don't care. */ + + __intcall(0x22, &sys_idle, NULL); +} diff --git a/syslinux/com32/lib/sys/isatty.c b/syslinux/com32/lib/sys/isatty.c new file mode 100644 index 0000000..2a2d3e3 --- /dev/null +++ b/syslinux/com32/lib/sys/isatty.c @@ -0,0 +1,53 @@ +#ident "$Id: isatty.c,v 1.2 2004/11/23 23:43:02 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * isatty.c + * + * Return if this is a tty or not + */ + +#include <errno.h> +#include <string.h> +#include <com32.h> +#include <minmax.h> +#include <unistd.h> +#include <klibc/compiler.h> +#include "file.h" + +int isatty(int fd) +{ + struct file_info *fp = &__file_info[fd]; + + if ( fd >= NFILES || !fp->iop ) { + errno = EBADF; + return -1; + } + + return (fp->iop->flags & __DEV_TTY); +} diff --git a/syslinux/com32/lib/sys/line_input.c b/syslinux/com32/lib/sys/line_input.c new file mode 100644 index 0000000..e58ffc4 --- /dev/null +++ b/syslinux/com32/lib/sys/line_input.c @@ -0,0 +1,90 @@ +#ident "$Id: line_input.c,v 1.6 2005/01/20 18:41:12 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * line_input.c + * + * Line-oriented input discupline + */ + +#include "file.h" +#include <errno.h> +#include <syslinux.h> + +ssize_t __line_input(struct file_info *fp, char *buf, size_t bufsize, + ssize_t (*get_char)(struct file_info *, void *, size_t)) +{ + size_t n = 0; + char ch; + int rv; + ssize_t (* const Write)(struct file_info *, const void *, size_t) = + fp->oop->write; + + for(;;) { + rv = get_char(fp, &ch, 1); + + if ( rv != 1 ) { + syslinux_idle(); + continue; + } + + switch ( ch ) { + case '\n': /* Ignore incoming linefeed */ + break; + + case '\r': + *buf = '\n'; + Write(fp, "\n", 1); + return n+1; + + case '\b': + if ( n > 0 ) { + n--; buf--; + Write(fp, "\b \b", 3); + } + break; + + case '\x15': /* Ctrl-U */ + while ( n ) { + n--; buf--; + Write(fp, "\b \b", 3); + } + break; + + default: + if ( n < bufsize-1 ) { + *buf = ch; + Write(fp, buf, 1); + n++; + buf++; + } + break; + } + } +} + diff --git a/syslinux/com32/lib/sys/null_read.c b/syslinux/com32/lib/sys/null_read.c new file mode 100644 index 0000000..cac6b6f --- /dev/null +++ b/syslinux/com32/lib/sys/null_read.c @@ -0,0 +1,53 @@ +#ident "$Id: null_read.c,v 1.1 2004/11/23 23:43:02 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * null_read.c + * + * Reading null device + */ + +#include <errno.h> +#include <string.h> +#include <com32.h> +#include <minmax.h> +#include "file.h" + +static ssize_t __null_read(struct file_info *fp, void *buf, size_t count) +{ + (void)fp; (void)buf; (void)count; + return 0; +} + +const struct input_dev dev_null_r = { + .dev_magic = __DEV_MAGIC, + .flags = __DEV_INPUT | __DEV_NULL, + .fileflags = O_RDONLY, + .read = __null_read, + .close = NULL, +}; diff --git a/syslinux/com32/lib/sys/null_write.c b/syslinux/com32/lib/sys/null_write.c new file mode 100644 index 0000000..a057a90 --- /dev/null +++ b/syslinux/com32/lib/sys/null_write.c @@ -0,0 +1,53 @@ +#ident "$Id: null_write.c,v 1.1 2004/11/23 23:43:02 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * null_write.c + * + * Null writing device + */ + +#include <errno.h> +#include <string.h> +#include <com32.h> +#include <minmax.h> +#include "file.h" + +static ssize_t __null_write(struct file_info *fp, const void *buf, size_t count) +{ + (void)fp; (void)buf; (void)count; + return count; +} + +const struct output_dev dev_null_w = { + .dev_magic = __DEV_MAGIC, + .flags = __DEV_OUTPUT | __DEV_NULL, + .fileflags = O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, + .write = __null_write, + .close = NULL, +}; diff --git a/syslinux/com32/lib/sys/open.c b/syslinux/com32/lib/sys/open.c new file mode 100644 index 0000000..1cdaca8 --- /dev/null +++ b/syslinux/com32/lib/sys/open.c @@ -0,0 +1,90 @@ +#ident "$Id: open.c,v 1.4 2004/11/23 23:43:02 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2003-2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +#include <errno.h> +#include <com32.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include "file.h" + +/* + * open.c + * + * Open an ordinary file + */ + +extern ssize_t __file_read(struct file_info *, void *, size_t); +extern int __file_close(struct file_info *); + +static const struct input_dev file_dev = { + .dev_magic = __DEV_MAGIC, + .flags = __DEV_FILE | __DEV_INPUT, + .fileflags = O_RDONLY, + .read = __file_read, + .close = __file_close, +}; + +int open(const char *pathname, int flags, ...) +{ + com32sys_t regs; + int fd; + struct file_info *fp; + + fd = opendev(&file_dev, NULL, flags); + + if ( fd < 0 ) + return -1; + + fp = &__file_info[fd]; + + strlcpy(__com32.cs_bounce, pathname, __com32.cs_bounce_size); + + regs.eax.w[0] = 0x0006; + regs.esi.w[0] = OFFS(__com32.cs_bounce); + regs.es = SEG(__com32.cs_bounce); + + __com32.cs_intcall(0x22, ®s, ®s); + + if ( (regs.eflags.l & EFLAGS_CF) || regs.esi.w[0] == 0 ) { + errno = ENOENT; + return -1; + } + + { + uint16_t blklg2; + asm("bsrw %1,%0" : "=r" (blklg2) : "rm" (regs.ecx.w[0])); + fp->i.blocklg2 = blklg2; + } + fp->i.length = regs.eax.l; + fp->i.filedes = regs.esi.w[0]; + fp->i.offset = 0; + fp->i.nbytes = 0; + + return fd; +} diff --git a/syslinux/com32/lib/sys/openconsole.c b/syslinux/com32/lib/sys/openconsole.c new file mode 100644 index 0000000..4d5f3fc --- /dev/null +++ b/syslinux/com32/lib/sys/openconsole.c @@ -0,0 +1,52 @@ +#ident "$Id: openconsole.c,v 1.2 2004/11/23 23:43:02 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * openconsole.c + * + * Open the chosen console device + */ + +#include <unistd.h> +#include <console.h> +#include <fcntl.h> + +int openconsole(const struct input_dev *idev, const struct output_dev *odev) +{ + close(0); + if ( opendev(idev, odev, O_RDONLY) != 0 ) + return -1; + close(1); + if ( opendev(idev, odev, O_WRONLY) != 1 ) + return -1; + close(2); + if ( opendev(idev, odev, O_WRONLY) != 2 ) + return -1; + + return 0; +} diff --git a/syslinux/com32/lib/sys/opendev.c b/syslinux/com32/lib/sys/opendev.c new file mode 100644 index 0000000..2c5febf --- /dev/null +++ b/syslinux/com32/lib/sys/opendev.c @@ -0,0 +1,69 @@ +#ident "$Id: opendev.c,v 1.3 2004/11/23 23:43:02 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2003-2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +#include <errno.h> +#include <com32.h> +#include <string.h> +#include "file.h" + +/* + * opendev.c + * + * Open a special device + */ + +int opendev(const struct input_dev *idev, const struct output_dev *odev, int flags) +{ + int fd; + struct file_info *fp; + int okflags; + + okflags = (idev ? idev->fileflags : 0) | (odev ? odev->fileflags : 0); + + if ( !(flags & 3) || (flags & ~okflags) ) { + errno = EINVAL; + return -1; + } + + for ( fd = 0, fp = __file_info ; fd < NFILES ; fd++, fp++ ) + if ( !fp->iop && !fp->oop ) + break; + + if ( fd >= NFILES ) { + errno = EMFILE; + return -1; + } + + fp->iop = idev ? idev : &dev_error_r; + fp->oop = odev ? odev : &dev_error_w; + fp->i.offset = 0; + fp->i.nbytes = 0; + fp->i.datap = fp->i.buf; + + return fd; +} diff --git a/syslinux/com32/lib/sys/rawcon_read.c b/syslinux/com32/lib/sys/rawcon_read.c new file mode 100644 index 0000000..6abfe9f --- /dev/null +++ b/syslinux/com32/lib/sys/rawcon_read.c @@ -0,0 +1,80 @@ +#ident "$Id: rawcon_read.c,v 1.5 2005/01/20 18:41:12 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * rawcon_read.c + * + * Character-oriented reading from the console without echo; + * this is a NONBLOCKING device. + */ + +#include <errno.h> +#include <string.h> +#include <com32.h> +#include <minmax.h> +#include <sys/times.h> +#include "file.h" + +/* Global, since it's used by stdcon_read */ +ssize_t __rawcon_read(struct file_info *fp, void *buf, size_t count) +{ + com32sys_t ireg, oreg; + char *bufp = buf; + size_t n = 0; + clock_t start; + + (void)fp; + + memset(&ireg, 0, sizeof ireg); + + start = times(NULL); + + while ( n < count ) { + /* Poll */ + ireg.eax.b[1] = 0x0B; + __intcall(0x21, &ireg, &oreg); + if ( !oreg.eax.b[0] ) + break; + + /* We have data, go get it */ + ireg.eax.b[1] = 0x08; + __intcall(0x21, &ireg, &oreg); + *bufp++ = oreg.eax.b[0]; + n++; + } + + return n; +} + +const struct input_dev dev_rawcon_r = { + .dev_magic = __DEV_MAGIC, + .flags = __DEV_TTY | __DEV_INPUT, + .fileflags = O_RDONLY, + .read = __rawcon_read, + .close = NULL, +}; diff --git a/syslinux/com32/lib/sys/rawcon_write.c b/syslinux/com32/lib/sys/rawcon_write.c new file mode 100644 index 0000000..5c62398 --- /dev/null +++ b/syslinux/com32/lib/sys/rawcon_write.c @@ -0,0 +1,67 @@ +#ident "$Id: rawcon_write.c,v 1.2 2004/11/23 23:43:02 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * rawcon_write.c + * + * Raw writing to the console; no \n -> \r\n translation + */ + +#include <errno.h> +#include <string.h> +#include <com32.h> +#include <minmax.h> +#include "file.h" + +static ssize_t __rawcon_write(struct file_info *fp, const void *buf, size_t count) +{ + com32sys_t ireg; + const char *bufp = buf; + size_t n = 0; + + (void)fp; + + memset(&ireg, 0, sizeof ireg); + ireg.eax.b[1] = 0x02; + + while ( count-- ) { + ireg.edx.b[0] = *bufp++; + __intcall(0x21, &ireg, NULL); + n++; + } + + return n; +} + +const struct output_dev dev_rawcon_w = { + .dev_magic = __DEV_MAGIC, + .flags = __DEV_TTY | __DEV_OUTPUT, + .fileflags = O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, + .write = __rawcon_write, + .close = NULL, +}; diff --git a/syslinux/com32/lib/sys/read.c b/syslinux/com32/lib/sys/read.c new file mode 100644 index 0000000..7d7351a --- /dev/null +++ b/syslinux/com32/lib/sys/read.c @@ -0,0 +1,52 @@ +#ident "$Id: read.c,v 1.3 2004/11/23 23:43:02 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * read.c + * + * Reading from a file descriptor + */ + +#include <errno.h> +#include <string.h> +#include <com32.h> +#include <minmax.h> +#include <klibc/compiler.h> +#include "file.h" + +ssize_t read(int fd, void *buf, size_t count) +{ + struct file_info *fp = &__file_info[fd]; + + if ( fd >= NFILES || !fp->iop ) { + errno = EBADF; + return -1; + } + + return fp->iop->read(fp, buf, count); +} diff --git a/syslinux/com32/lib/sys/serial_write.c b/syslinux/com32/lib/sys/serial_write.c new file mode 100644 index 0000000..0f82862 --- /dev/null +++ b/syslinux/com32/lib/sys/serial_write.c @@ -0,0 +1,67 @@ +#ident "$Id: serial_write.c,v 1.2 2004/11/30 22:09:56 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * serial_write.c + * + * Raw writing to the serial port; no \n -> \r\n translation + */ + +#include <errno.h> +#include <string.h> +#include <com32.h> +#include <minmax.h> +#include "file.h" + +ssize_t __serial_write(struct file_info *fp, const void *buf, size_t count) +{ + com32sys_t ireg; + const char *bufp = buf; + size_t n = 0; + + (void)fp; + + memset(&ireg, 0, sizeof ireg); + ireg.eax.b[1] = 0x04; + + while ( count-- ) { + ireg.edx.b[0] = *bufp++; + __intcall(0x21, &ireg, NULL); + n++; + } + + return n; +} + +const struct output_dev dev_serial_w = { + .dev_magic = __DEV_MAGIC, + .flags = __DEV_TTY | __DEV_OUTPUT, + .fileflags = O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, + .write = __serial_write, + .close = NULL, +}; diff --git a/syslinux/com32/lib/sys/stdcon_read.c b/syslinux/com32/lib/sys/stdcon_read.c new file mode 100644 index 0000000..7ac8f98 --- /dev/null +++ b/syslinux/com32/lib/sys/stdcon_read.c @@ -0,0 +1,77 @@ +#ident "$Id: stdcon_read.c,v 1.3 2004/11/23 23:43:02 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * stdcon_read.c + * + * Line-oriented reading from the standard console + */ + +#include <errno.h> +#include <string.h> +#include <com32.h> +#include <minmax.h> +#include "file.h" + +extern ssize_t __rawcon_read(struct file_info *fp, void *buf, size_t count); + +static ssize_t __stdcon_read(struct file_info *fp, void *buf, size_t count) +{ + char *bufp = buf; + size_t n = 0; + char ch; + + (void)fp; + + while ( n < count ) { + if ( fp->i.nbytes ) { + ch = *bufp++ = *fp->i.datap++; + fp->i.nbytes--; + n++; + if ( ch == '\n' ) + return n; + } else { + fp->i.nbytes = __line_input(fp, fp->i.buf, MAXBLOCK, + __rawcon_read); + fp->i.datap = fp->i.buf; + + if ( fp->i.nbytes == 0 ) + return n; + } + } + + return n; +} + +const struct input_dev dev_stdcon_r = { + .dev_magic = __DEV_MAGIC, + .flags = __DEV_TTY | __DEV_INPUT, + .fileflags = O_RDONLY, + .read = __stdcon_read, + .close = NULL, +}; diff --git a/syslinux/com32/lib/sys/stdcon_write.c b/syslinux/com32/lib/sys/stdcon_write.c new file mode 100644 index 0000000..27202f1 --- /dev/null +++ b/syslinux/com32/lib/sys/stdcon_write.c @@ -0,0 +1,71 @@ +#ident "$Id: stdcon_write.c,v 1.3 2004/11/23 23:43:02 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * stdcon_write.c + * + * Writing to the console + */ + +#include <errno.h> +#include <string.h> +#include <com32.h> +#include <minmax.h> +#include "file.h" + +static ssize_t __stdcon_write(struct file_info *fp, const void *buf, size_t count) +{ + com32sys_t ireg; + const char *bufp = buf; + size_t n = 0; + + (void)fp; + + memset(&ireg, 0, sizeof ireg); + ireg.eax.b[1] = 0x02; + + while ( count-- ) { + if ( *bufp == '\n' ) { + ireg.edx.b[0] = '\r'; + __intcall(0x21, &ireg, NULL); + } + ireg.edx.b[0] = *bufp++; + __intcall(0x21, &ireg, NULL); + n++; + } + + return n; +} + +const struct output_dev dev_stdcon_w = { + .dev_magic = __DEV_MAGIC, + .flags = __DEV_TTY | __DEV_OUTPUT, + .fileflags = O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, + .write = __stdcon_write, + .close = NULL, +}; diff --git a/syslinux/com32/lib/sys/times.c b/syslinux/com32/lib/sys/times.c new file mode 100644 index 0000000..6fa0e68 --- /dev/null +++ b/syslinux/com32/lib/sys/times.c @@ -0,0 +1,45 @@ +#ident "$Id: times.c,v 1.1 2004/12/20 22:28:30 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * sys/times.c + * + * Returns something like a clock. + */ + +#include <sys/times.h> +#include <inttypes.h> +#include <com32.h> + +clock_t times(struct tms *buf) +{ + (void)buf; /* Ignored */ + + /* Should we get this via INT 1Ah? */ + return *(uint16_t *)0x46c; +} diff --git a/syslinux/com32/lib/sys/write.c b/syslinux/com32/lib/sys/write.c new file mode 100644 index 0000000..b1de461 --- /dev/null +++ b/syslinux/com32/lib/sys/write.c @@ -0,0 +1,52 @@ +#ident "$Id: write.c,v 1.3 2004/11/23 23:43:02 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * write.c + * + * Write to a file descriptor + */ + +#include <errno.h> +#include <string.h> +#include <com32.h> +#include <minmax.h> +#include <klibc/compiler.h> +#include "file.h" + +ssize_t write(int fd, void *buf, size_t count) +{ + struct file_info *fp = &__file_info[fd]; + + if ( fd >= NFILES || !fp->oop ) { + errno = EBADF; + return -1; + } + + return fp->oop->write(fp, buf, count); +} diff --git a/syslinux/com32/lib/vasprintf.c b/syslinux/com32/lib/vasprintf.c new file mode 100644 index 0000000..657bfdc --- /dev/null +++ b/syslinux/com32/lib/vasprintf.c @@ -0,0 +1,25 @@ +/* + * vasprintf.c + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> + +int vasprintf(char **bufp, const char *format, va_list ap) +{ + va_list ap1; + int bytes; + char *p; + + va_copy(ap1, ap); + + bytes = vsnprintf(NULL, 0, format, ap1) + 1; + va_end(ap1); + + *bufp = p = malloc(bytes); + if ( !p ) + return -1; + + return vsnprintf(p, bytes, format, ap); +} diff --git a/syslinux/com32/lib/vfprintf.c b/syslinux/com32/lib/vfprintf.c new file mode 100644 index 0000000..39cf983 --- /dev/null +++ b/syslinux/com32/lib/vfprintf.c @@ -0,0 +1,26 @@ +/* + * vfprintf.c + */ + +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <unistd.h> + +#define BUFFER_SIZE 32768 + +int vfprintf(FILE *file, const char *format, va_list ap) +{ + int rv; + char buffer[BUFFER_SIZE]; + + rv = vsnprintf(buffer, BUFFER_SIZE, format, ap); + + if ( rv < 0 ) + return rv; + + if ( rv > BUFFER_SIZE-1 ) + rv = BUFFER_SIZE-1; + + return _fwrite(buffer, rv, file); +} diff --git a/syslinux/com32/lib/vprintf.c b/syslinux/com32/lib/vprintf.c new file mode 100644 index 0000000..7d60665 --- /dev/null +++ b/syslinux/com32/lib/vprintf.c @@ -0,0 +1,11 @@ +/* + * vprintf.c + */ + +#include <stdio.h> +#include <stdarg.h> + +int vprintf(const char *format, va_list ap) +{ + return vfprintf(stdout, format, ap); +} diff --git a/syslinux/com32/lib/vsnprintf.c b/syslinux/com32/lib/vsnprintf.c new file mode 100644 index 0000000..5cb9331 --- /dev/null +++ b/syslinux/com32/lib/vsnprintf.c @@ -0,0 +1,433 @@ +/* + * vsnprintf.c + * + * vsnprintf(), from which the rest of the printf() + * family is built + */ + +#include <stdarg.h> +#include <stddef.h> +#include <inttypes.h> +#include <string.h> +#include <limits.h> +#include <stdio.h> + +enum flags { + FL_ZERO = 0x01, /* Zero modifier */ + FL_MINUS = 0x02, /* Minus modifier */ + FL_PLUS = 0x04, /* Plus modifier */ + FL_TICK = 0x08, /* ' modifier */ + FL_SPACE = 0x10, /* Space modifier */ + FL_HASH = 0x20, /* # modifier */ + FL_SIGNED = 0x40, /* Number is signed */ + FL_UPPER = 0x80 /* Upper case digits */ +}; + +/* These may have to be adjusted on certain implementations */ +enum ranks { + rank_char = -2, + rank_short = -1, + rank_int = 0, + rank_long = 1, + rank_longlong = 2 +}; + +#define MIN_RANK rank_char +#define MAX_RANK rank_longlong + +#define INTMAX_RANK rank_longlong +#define SIZE_T_RANK rank_long +#define PTRDIFF_T_RANK rank_long + +#define EMIT(x) ({ if (o<n){*q++ = (x);} o++; }) + +static size_t +format_int(char *q, size_t n, uintmax_t val, enum flags flags, + int base, int width, int prec) +{ + char *qq; + size_t o = 0, oo; + static const char lcdigits[] = "0123456789abcdef"; + static const char ucdigits[] = "0123456789ABCDEF"; + const char *digits; + uintmax_t tmpval; + int minus = 0; + int ndigits = 0, nchars; + int tickskip, b4tick; + + /* Select type of digits */ + digits = (flags & FL_UPPER) ? ucdigits : lcdigits; + + /* If signed, separate out the minus */ + if ( flags & FL_SIGNED && (intmax_t)val < 0 ) { + minus = 1; + val = (uintmax_t)(-(intmax_t)val); + } + + /* Count the number of digits needed. This returns zero for 0. */ + tmpval = val; + while ( tmpval ) { + tmpval /= base; + ndigits++; + } + + /* Adjust ndigits for size of output */ + + if ( flags & FL_HASH && base == 8 ) { + if ( prec < ndigits+1 ) + prec = ndigits+1; + } + + if ( ndigits < prec ) { + ndigits = prec; /* Mandatory number padding */ + } else if ( val == 0 ) { + ndigits = 1; /* Zero still requires space */ + } + + /* For ', figure out what the skip should be */ + if ( flags & FL_TICK ) { + tickskip = (base == 16) ? 4 : 3; + } else { + tickskip = ndigits; /* No tick marks */ + } + + /* Tick marks aren't digits, but generated by the number converter */ + ndigits += (ndigits-1)/tickskip; + + /* Now compute the number of nondigits */ + nchars = ndigits; + + if ( minus || (flags & (FL_PLUS|FL_SPACE)) ) + nchars++; /* Need space for sign */ + if ( (flags & FL_HASH) && base == 16 ) { + nchars += 2; /* Add 0x for hex */ + } + + /* Emit early space padding */ + if ( !(flags & (FL_MINUS|FL_ZERO)) && width > nchars ) { + while ( width > nchars ) { + EMIT(' '); + width--; + } + } + + /* Emit nondigits */ + if ( minus ) + EMIT('-'); + else if ( flags & FL_PLUS ) + EMIT('+'); + else if ( flags & FL_SPACE ) + EMIT(' '); + + if ( (flags & FL_HASH) && base == 16 ) { + EMIT('0'); + EMIT((flags & FL_UPPER) ? 'X' : 'x'); + } + + /* Emit zero padding */ + if ( (flags & (FL_MINUS|FL_ZERO)) == FL_ZERO && width > ndigits ) { + while ( width > nchars ) { + EMIT('0'); + width--; + } + } + + /* Generate the number. This is done from right to left. */ + q += ndigits; /* Advance the pointer to end of number */ + o += ndigits; + qq = q; oo = o; /* Temporary values */ + + b4tick = tickskip; + while ( ndigits > 0 ) { + if ( !b4tick-- ) { + qq--; oo--; ndigits--; + if ( oo < n ) *qq = '_'; + b4tick = tickskip-1; + } + qq--; oo--; ndigits--; + if ( oo < n ) *qq = digits[val%base]; + val /= base; + } + + /* Emit late space padding */ + while ( (flags & FL_MINUS) && width > nchars ) { + EMIT(' '); + width--; + } + + return o; +} + + +int vsnprintf(char *buffer, size_t n, const char *format, va_list ap) +{ + const char *p = format; + char ch; + char *q = buffer; + size_t o = 0; /* Number of characters output */ + uintmax_t val = 0; + int rank = rank_int; /* Default rank */ + int width = 0; + int prec = -1; + int base; + size_t sz; + enum flags flags = 0; + enum { + st_normal, /* Ground state */ + st_flags, /* Special flags */ + st_width, /* Field width */ + st_prec, /* Field precision */ + st_modifiers /* Length or conversion modifiers */ + } state = st_normal; + const char *sarg; /* %s string argument */ + char carg; /* %c char argument */ + int slen; /* String length */ + + while ( (ch = *p++) ) { + switch ( state ) { + case st_normal: + if ( ch == '%' ) { + state = st_flags; + flags = 0; rank = rank_int; width = 0; prec = -1; + } else { + EMIT(ch); + } + break; + + case st_flags: + switch ( ch ) { + case '-': + flags |= FL_MINUS; + break; + case '+': + flags |= FL_PLUS; + break; + case '\'': + flags |= FL_TICK; + break; + case ' ': + flags |= FL_SPACE; + break; + case '#': + flags |= FL_HASH; + break; + case '0': + flags |= FL_ZERO; + break; + default: + state = st_width; + p--; /* Process this character again */ + break; + } + break; + + case st_width: + if ( ch >= '0' && ch <= '9' ) { + width = width*10+(ch-'0'); + } else if ( ch == '*' ) { + width = va_arg(ap, int); + if ( width < 0 ) { + width = -width; + flags |= FL_MINUS; + } + } else if ( ch == '.' ) { + prec = 0; /* Precision given */ + state = st_prec; + } else { + state = st_modifiers; + p--; /* Process this character again */ + } + break; + + case st_prec: + if ( ch >= '0' && ch <= '9' ) { + prec = prec*10+(ch-'0'); + } else if ( ch == '*' ) { + prec = va_arg(ap, int); + if ( prec < 0 ) + prec = -1; + } else { + state = st_modifiers; + p--; /* Process this character again */ + } + break; + + case st_modifiers: + switch ( ch ) { + /* Length modifiers - nonterminal sequences */ + case 'h': + rank--; /* Shorter rank */ + break; + case 'l': + rank++; /* Longer rank */ + break; + case 'j': + rank = INTMAX_RANK; + break; + case 'z': + rank = SIZE_T_RANK; + break; + case 't': + rank = PTRDIFF_T_RANK; + break; + case 'L': + case 'q': + rank += 2; + break; + default: + /* Output modifiers - terminal sequences */ + state = st_normal; /* Next state will be normal */ + if ( rank < MIN_RANK ) /* Canonicalize rank */ + rank = MIN_RANK; + else if ( rank > MAX_RANK ) + rank = MAX_RANK; + + switch ( ch ) { + case 'P': /* Upper case pointer */ + flags |= FL_UPPER; + /* fall through */ + case 'p': /* Pointer */ + base = 16; + prec = (CHAR_BIT*sizeof(void *)+3)/4; + flags |= FL_HASH; + val = (uintmax_t)(uintptr_t)va_arg(ap, void *); + goto is_integer; + + case 'd': /* Signed decimal output */ + case 'i': + base = 10; + flags |= FL_SIGNED; + switch (rank) { + case rank_char: + /* Yes, all these casts are needed... */ + val = (uintmax_t)(intmax_t)(signed char)va_arg(ap, signed int); + break; + case rank_short: + val = (uintmax_t)(intmax_t)(signed short)va_arg(ap, signed int); + break; + case rank_int: + val = (uintmax_t)(intmax_t)va_arg(ap, signed int); + break; + case rank_long: + val = (uintmax_t)(intmax_t)va_arg(ap, signed long); + break; + case rank_longlong: + val = (uintmax_t)(intmax_t)va_arg(ap, signed long long); + break; + } + goto is_integer; + case 'o': /* Octal */ + base = 8; + goto is_unsigned; + case 'u': /* Unsigned decimal */ + base = 10; + goto is_unsigned; + case 'X': /* Upper case hexadecimal */ + flags |= FL_UPPER; + /* fall through */ + case 'x': /* Hexadecimal */ + base = 16; + goto is_unsigned; + + is_unsigned: + switch (rank) { + case rank_char: + val = (uintmax_t)(unsigned char)va_arg(ap, unsigned int); + break; + case rank_short: + val = (uintmax_t)(unsigned short)va_arg(ap, unsigned int); + break; + case rank_int: + val = (uintmax_t)va_arg(ap, unsigned int); + break; + case rank_long: + val = (uintmax_t)va_arg(ap, unsigned long); + break; + case rank_longlong: + val = (uintmax_t)va_arg(ap, unsigned long long); + break; + } + /* fall through */ + + is_integer: + sz = format_int(q, (o<n) ? n-o : 0, val, flags, base, width, prec); + q += sz; o += sz; + break; + + case 'c': /* Character */ + carg = (char)va_arg(ap, int); + sarg = &carg; + slen = 1; + goto is_string; + case 's': /* String */ + sarg = va_arg(ap, const char *); + sarg = sarg ? sarg : "(null)"; + slen = strlen(sarg); + goto is_string; + + is_string: + { + char sch; + int i; + + if ( prec != -1 && slen > prec ) + slen = prec; + + if ( width > slen && !(flags & FL_MINUS) ) { + char pad = (flags & FL_ZERO) ? '0' : ' '; + while ( width > slen ) { + EMIT(pad); + width--; + } + } + for ( i = slen ; i ; i-- ) { + sch = *sarg++; + EMIT(sch); + } + if ( width > slen && (flags & FL_MINUS) ) { + while ( width > slen ) { + EMIT(' '); + width--; + } + } + } + break; + + case 'n': /* Output the number of characters written */ + { + switch (rank) { + case rank_char: + *va_arg(ap, signed char *) = o; + break; + case rank_short: + *va_arg(ap, signed short *) = o; + break; + case rank_int: + *va_arg(ap, signed int *) = o; + break; + case rank_long: + *va_arg(ap, signed long *) = o; + break; + case rank_longlong: + *va_arg(ap, signed long long *) = o; + break; + } + } + break; + + default: /* Anything else, including % */ + EMIT(ch); + break; + } + } + } + } + + /* Null-terminate the string */ + if ( o<n ) + *q = '\0'; /* No overflow */ + else if ( n>0 ) + buffer[n-1] = '\0'; /* Overflow - terminate at end of buffer */ + + return o; +} diff --git a/syslinux/com32/lib/vsprintf.c b/syslinux/com32/lib/vsprintf.c new file mode 100644 index 0000000..4a6100e --- /dev/null +++ b/syslinux/com32/lib/vsprintf.c @@ -0,0 +1,11 @@ +/* + * vsprintf.c + */ + +#include <stdio.h> +#include <unistd.h> + +int vsprintf(char *buffer, const char *format, va_list ap) +{ + return vsnprintf(buffer, ~(size_t)0, format, ap); +} diff --git a/syslinux/com32/lib/vsscanf.c b/syslinux/com32/lib/vsscanf.c new file mode 100644 index 0000000..12a82b2 --- /dev/null +++ b/syslinux/com32/lib/vsscanf.c @@ -0,0 +1,365 @@ +/* + * vsscanf.c + * + * vsscanf(), from which the rest of the scanf() + * family is built + */ + +#include <ctype.h> +#include <stdarg.h> +#include <stddef.h> +#include <inttypes.h> +#include <string.h> +#include <limits.h> +#include <stdio.h> + +#ifndef LONG_BIT +#define LONG_BIT (CHAR_BIT*sizeof(long)) +#endif + +enum flags { + FL_SPLAT = 0x01, /* Drop the value, do not assign */ + FL_INV = 0x02, /* Character-set with inverse */ + FL_WIDTH = 0x04, /* Field width specified */ + FL_MINUS = 0x08, /* Negative number */ +}; + +enum ranks { + rank_char = -2, + rank_short = -1, + rank_int = 0, + rank_long = 1, + rank_longlong = 2, + rank_ptr = INT_MAX /* Special value used for pointers */ +}; + +#define MIN_RANK rank_char +#define MAX_RANK rank_longlong + +#define INTMAX_RANK rank_longlong +#define SIZE_T_RANK rank_long +#define PTRDIFF_T_RANK rank_long + +enum bail { + bail_none = 0, /* No error condition */ + bail_eof, /* Hit EOF */ + bail_err /* Conversion mismatch */ +}; + +static inline const char * +skipspace(const char *p) +{ + while ( isspace((unsigned char)*p) ) p++; + return p; +} + +#undef set_bit +static inline void +set_bit(unsigned long *bitmap, unsigned int bit) +{ + bitmap[bit/LONG_BIT] |= 1UL << (bit%LONG_BIT); +} + +#undef test_bit +static inline int +test_bit(unsigned long *bitmap, unsigned int bit) +{ + return (int)(bitmap[bit/LONG_BIT] >> (bit%LONG_BIT)) & 1; +} + +int vsscanf(const char *buffer, const char *format, va_list ap) +{ + const char *p = format; + char ch; + const char *q = buffer; + const char *qq; + uintmax_t val = 0; + int rank = rank_int; /* Default rank */ + unsigned int width = UINT_MAX; + int base; + enum flags flags = 0; + enum { + st_normal, /* Ground state */ + st_flags, /* Special flags */ + st_width, /* Field width */ + st_modifiers, /* Length or conversion modifiers */ + st_match_init, /* Initial state of %[ sequence */ + st_match, /* Main state of %[ sequence */ + st_match_range, /* After - in a %[ sequence */ + } state = st_normal; + char *sarg = NULL; /* %s %c or %[ string argument */ + enum bail bail = bail_none; + int sign; + int converted = 0; /* Successful conversions */ + unsigned long matchmap[((1 << CHAR_BIT)+(LONG_BIT-1))/LONG_BIT]; + int matchinv = 0; /* Is match map inverted? */ + unsigned char range_start = 0; + + while ( (ch = *p++) && !bail ) { + switch ( state ) { + case st_normal: + if ( ch == '%' ) { + state = st_flags; + flags = 0; rank = rank_int; width = UINT_MAX; + } else if ( isspace((unsigned char)ch) ) { + q = skipspace(q); + } else { + if ( *q == ch ) + q++; + else + bail = bail_err; /* Match failure */ + } + break; + + case st_flags: + switch ( ch ) { + case '*': + flags |= FL_SPLAT; + break; + case '0' ... '9': + width = (ch-'0'); + state = st_width; + flags |= FL_WIDTH; + break; + default: + state = st_modifiers; + p--; /* Process this character again */ + break; + } + break; + + case st_width: + if ( ch >= '0' && ch <= '9' ) { + width = width*10+(ch-'0'); + } else { + state = st_modifiers; + p--; /* Process this character again */ + } + break; + + case st_modifiers: + switch ( ch ) { + /* Length modifiers - nonterminal sequences */ + case 'h': + rank--; /* Shorter rank */ + break; + case 'l': + rank++; /* Longer rank */ + break; + case 'j': + rank = INTMAX_RANK; + break; + case 'z': + rank = SIZE_T_RANK; + break; + case 't': + rank = PTRDIFF_T_RANK; + break; + case 'L': + case 'q': + rank = rank_longlong; /* long double/long long */ + break; + + default: + /* Output modifiers - terminal sequences */ + state = st_normal; /* Next state will be normal */ + if ( rank < MIN_RANK ) /* Canonicalize rank */ + rank = MIN_RANK; + else if ( rank > MAX_RANK ) + rank = MAX_RANK; + + switch ( ch ) { + case 'P': /* Upper case pointer */ + case 'p': /* Pointer */ +#if 0 /* Enable this to allow null pointers by name */ + q = skipspace(q); + if ( !isdigit((unsigned char)*q) ) { + static const char * const nullnames[] = + { "null", "nul", "nil", "(null)", "(nul)", "(nil)", 0 }; + const char * const *np; + + /* Check to see if it's a null pointer by name */ + for ( np = nullnames ; *np ; np++ ) { + if ( !strncasecmp(q, *np, strlen(*np)) ) { + val = (uintmax_t)((void *)NULL); + goto set_integer; + } + } + /* Failure */ + bail = bail_err; + break; + } + /* else */ +#endif + rank = rank_ptr; + base = 0; sign = 0; + goto scan_int; + + case 'i': /* Base-independent integer */ + base = 0; sign = 1; + goto scan_int; + + case 'd': /* Decimal integer */ + base = 10; sign = 1; + goto scan_int; + + case 'o': /* Octal integer */ + base = 8; sign = 0; + goto scan_int; + + case 'u': /* Unsigned decimal integer */ + base = 10; sign = 0; + goto scan_int; + + case 'x': /* Hexadecimal integer */ + case 'X': + base = 16; sign = 0; + goto scan_int; + + case 'n': /* Number of characters consumed */ + val = (q-buffer); + goto set_integer; + + scan_int: + q = skipspace(q); + if ( !*q ) { + bail = bail_eof; + break; + } + val = strntoumax(q, (char **)&qq, base, width); + if ( qq == q ) { + bail = bail_err; + break; + } + q = qq; + converted++; + /* fall through */ + + set_integer: + if ( !(flags & FL_SPLAT) ) { + switch(rank) { + case rank_char: + *va_arg(ap, unsigned char *) = (unsigned char)val; + break; + case rank_short: + *va_arg(ap, unsigned short *) = (unsigned short)val; + break; + case rank_int: + *va_arg(ap, unsigned int *) = (unsigned int)val; + break; + case rank_long: + *va_arg(ap, unsigned long *) = (unsigned long)val; + break; + case rank_longlong: + *va_arg(ap, unsigned long long *) = (unsigned long long)val; + break; + case rank_ptr: + *va_arg(ap, void **) = (void *)(uintptr_t)val; + break; + } + } + break; + + case 'c': /* Character */ + width = (flags & FL_WIDTH) ? width : 1; /* Default width == 1 */ + sarg = va_arg(ap, char *); + while ( width-- ) { + if ( !*q ) { + bail = bail_eof; + break; + } + *sarg++ = *q++; + } + if ( !bail ) + converted++; + break; + + case 's': /* String */ + { + char *sp; + sp = sarg = va_arg(ap, char *); + while ( width-- && *q && !isspace((unsigned char)*q) ) { + *sp++ = *q++; + } + if ( sarg != sp ) { + *sp = '\0'; /* Terminate output */ + converted++; + } else { + bail = bail_eof; + } + } + break; + + case '[': /* Character range */ + sarg = va_arg(ap, char *); + state = st_match_init; + matchinv = 0; + memset(matchmap, 0, sizeof matchmap); + break; + + case '%': /* %% sequence */ + if ( *q == '%' ) + q++; + else + bail = bail_err; + break; + + default: /* Anything else */ + bail = bail_err; /* Unknown sequence */ + break; + } + } + break; + + case st_match_init: /* Initial state for %[ match */ + if ( ch == '^' && !(flags & FL_INV) ) { + matchinv = 1; + } else { + set_bit(matchmap, (unsigned char)ch); + state = st_match; + } + break; + + case st_match: /* Main state for %[ match */ + if ( ch == ']' ) { + goto match_run; + } else if ( ch == '-' ) { + range_start = (unsigned char)ch; + state = st_match_range; + } else { + set_bit(matchmap, (unsigned char)ch); + } + break; + + case st_match_range: /* %[ match after - */ + if ( ch == ']' ) { + set_bit(matchmap, (unsigned char)'-'); /* - was last character */ + goto match_run; + } else { + int i; + for ( i = range_start ; i < (unsigned char)ch ; i++ ) + set_bit(matchmap, i); + state = st_match; + } + break; + + match_run: /* Match expression finished */ + qq = q; + while ( width && *q && test_bit(matchmap, (unsigned char)*q)^matchinv ) { + *sarg++ = *q++; + } + if ( q != qq ) { + *sarg = '\0'; + converted++; + } else { + bail = *q ? bail_err : bail_eof; + } + break; + } + } + + if ( bail == bail_eof && !converted ) + converted = -1; /* Return EOF (-1) */ + + return converted; +} diff --git a/syslinux/com32/lib/zlib/FAQ b/syslinux/com32/lib/zlib/FAQ new file mode 100644 index 0000000..7115ec3 --- /dev/null +++ b/syslinux/com32/lib/zlib/FAQ @@ -0,0 +1,315 @@ + + Frequently Asked Questions about zlib + + +If your question is not there, please check the zlib home page +http://www.zlib.org which may have more recent information. +The lastest zlib FAQ is at http://www.gzip.org/zlib/zlib_faq.html + + + 1. Is zlib Y2K-compliant? + + Yes. zlib doesn't handle dates. + + 2. Where can I get a Windows DLL version? + + The zlib sources can be compiled without change to produce a DLL. + See the file win32/DLL_FAQ.txt in the zlib distribution. + Pointers to the precompiled DLL are found in the zlib web site at + http://www.zlib.org. + + 3. Where can I get a Visual Basic interface to zlib? + + See + * http://www.winimage.com/zLibDll/ + * http://www.dogma.net/markn/articles/zlibtool/zlibtool.htm + * contrib/visual-basic.txt in the zlib distribution + + 4. compress() returns Z_BUF_ERROR + + Make sure that before the call of compress, the length of the compressed + buffer is equal to the total size of the compressed buffer and not + zero. For Visual Basic, check that this parameter is passed by reference + ("as any"), not by value ("as long"). + + 5. deflate() or inflate() returns Z_BUF_ERROR + + Before making the call, make sure that avail_in and avail_out are not + zero. When setting the parameter flush equal to Z_FINISH, also make sure + that avail_out is big enough to allow processing all pending input. + Note that a Z_BUF_ERROR is not fatal--another call to deflate() or + inflate() can be made with more input or output space. A Z_BUF_ERROR + may in fact be unavoidable depending on how the functions are used, since + it is not possible to tell whether or not there is more output pending + when strm.avail_out returns with zero. + + 6. Where's the zlib documentation (man pages, etc.)? + + It's in zlib.h for the moment, and Francis S. Lin has converted it to a + web page zlib.html. Volunteers to transform this to Unix-style man pages, + please contact Jean-loup Gailly (jloup@gzip.org). Examples of zlib usage + are in the files example.c and minigzip.c. + + 7. Why don't you use GNU autoconf or libtool or ...? + + Because we would like to keep zlib as a very small and simple + package. zlib is rather portable and doesn't need much configuration. + + 8. I found a bug in zlib. + + Most of the time, such problems are due to an incorrect usage of + zlib. Please try to reproduce the problem with a small program and send + the corresponding source to us at zlib@gzip.org . Do not send + multi-megabyte data files without prior agreement. + + 9. Why do I get "undefined reference to gzputc"? + + If "make test" produces something like + + example.o(.text+0x154): undefined reference to `gzputc' + + check that you don't have old files libz.* in /usr/lib, /usr/local/lib or + /usr/X11R6/lib. Remove any old versions, then do "make install". + +10. I need a Delphi interface to zlib. + + See the contrib/delphi directory in the zlib distribution. + +11. Can zlib handle .zip archives? + + See the directory contrib/minizip in the zlib distribution. + +12. Can zlib handle .Z files? + + No, sorry. You have to spawn an uncompress or gunzip subprocess, or adapt + the code of uncompress on your own. + +13. How can I make a Unix shared library? + + make clean + ./configure -s + make + +14. How do I install a shared zlib library on Unix? + + make install + + However, many flavors of Unix come with a shared zlib already installed. + Before going to the trouble of compiling a shared version of zlib and + trying to install it, you may want to check if it's already there! If you + can #include <zlib.h>, it's there. The -lz option will probably link to it. + +15. I have a question about OttoPDF + + We are not the authors of OttoPDF. The real author is on the OttoPDF web + site Joel Hainley jhainley@myndkryme.com. + +16. Why does gzip give an error on a file I make with compress/deflate? + + The compress and deflate functions produce data in the zlib format, which + is different and incompatible with the gzip format. The gz* functions in + zlib on the other hand use the gzip format. Both the zlib and gzip + formats use the same compressed data format internally, but have different + headers and trailers around the compressed data. + +17. Ok, so why are there two different formats? + + The gzip format was designed to retain the directory information about + a single file, such as the name and last modification date. The zlib + format on the other hand was designed for in-memory and communication + channel applications, and has a much more compact header and trailer and + uses a faster integrity check than gzip. + +18. Well that's nice, but how do I make a gzip file in memory? + + You can request that deflate write the gzip format instead of the zlib + format using deflateInit2(). You can also request that inflate decode + the gzip format using inflateInit2(). Read zlib.h for more details. + + Note that you cannot specify special gzip header contents (e.g. a file + name or modification date), nor will inflate tell you what was in the + gzip header. If you need to customize the header or see what's in it, + you can use the raw deflate and inflate operations and the crc32() + function and roll your own gzip encoding and decoding. Read the gzip + RFC 1952 for details of the header and trailer format. + +19. Is zlib thread-safe? + + Yes. However any library routines that zlib uses and any application- + provided memory allocation routines must also be thread-safe. zlib's gz* + functions use stdio library routines, and most of zlib's functions use the + library memory allocation routines by default. zlib's Init functions allow + for the application to provide custom memory allocation routines. + + Of course, you should only operate on any given zlib or gzip stream from a + single thread at a time. + +20. Can I use zlib in my commercial application? + + Yes. Please read the license in zlib.h. + +21. Is zlib under the GNU license? + + No. Please read the license in zlib.h. + +22. The license says that altered source versions must be "plainly marked". So + what exactly do I need to do to meet that requirement? + + You need to change the ZLIB_VERSION and ZLIB_VERNUM #defines in zlib.h. In + particular, the final version number needs to be changed to "f", and an + identification string should be appended to ZLIB_VERSION. Version numbers + x.x.x.f are reserved for modifications to zlib by others than the zlib + maintainers. For example, if the version of the base zlib you are altering + is "1.2.3.4", then in zlib.h you should change ZLIB_VERNUM to 0x123f, and + ZLIB_VERSION to something like "1.2.3.f-zachary-mods-v3". You can also + update the version strings in deflate.c and inftrees.c. + + For altered source distributions, you should also note the origin and + nature of the changes in zlib.h, as well as in ChangeLog and README, along + with the dates of the alterations. The origin should include at least your + name (or your company's name), and an email address to contact for help or + issues with the library. + + Note that distributing a compiled zlib library along with zlib.h and + zconf.h is also a source distribution, and so you should change + ZLIB_VERSION and ZLIB_VERNUM and note the origin and nature of the changes + in zlib.h as you would for a full source distribution. + +23. Will zlib work on a big-endian or little-endian architecture, and can I + exchange compressed data between them? + + Yes and yes. + +24. Will zlib work on a 64-bit machine? + + It should. It has been tested on 64-bit machines, and has no dependence + on any data types being limited to 32-bits in length. If you have any + difficulties, please provide a complete problem report to zlib@gzip.org + +25. Will zlib decompress data from the PKWare Data Compression Library? + + No. The PKWare DCL uses a completely different compressed data format + than does PKZIP and zlib. However, you can look in zlib's contrib/blast + directory for a possible solution to your problem. + +26. Can I access data randomly in a compressed stream? + + No, not without some preparation. If when compressing you periodically + use Z_FULL_FLUSH, carefully write all the pending data at those points, + and keep an index of those locations, then you can start decompression + at those points. You have to be careful to not use Z_FULL_FLUSH too + often, since it can significantly degrade compression. + +27. Does zlib work on MVS, OS/390, CICS, etc.? + + We don't know for sure. We have heard occasional reports of success on + these systems. If you do use it on one of these, please provide us with + a report, instructions, and patches that we can reference when we get + these questions. Thanks. + +28. Is there some simpler, easier to read version of inflate I can look at + to understand the deflate format? + + First off, you should read RFC 1951. Second, yes. Look in zlib's + contrib/puff directory. + +29. Does zlib infringe on any patents? + + As far as we know, no. In fact, that was originally the whole point behind + zlib. Look here for some more information: + + http://www.gzip.org/#faq11 + +30. Can zlib work with greater than 4 GB of data? + + Yes. inflate() and deflate() will process any amount of data correctly. + Each call of inflate() or deflate() is limited to input and output chunks + of the maximum value that can be stored in the compiler's "unsigned int" + type, but there is no limit to the number of chunks. Note however that the + strm.total_in and strm_total_out counters may be limited to 4 GB. These + counters are provided as a convenience and are not used internally by + inflate() or deflate(). The application can easily set up its own counters + updated after each call of inflate() or deflate() to count beyond 4 GB. + compress() and uncompress() may be limited to 4 GB, since they operate in a + single call. gzseek() and gztell() may be limited to 4 GB depending on how + zlib is compiled. See the zlibCompileFlags() function in zlib.h. + + The word "may" appears several times above since there is a 4 GB limit + only if the compiler's "long" type is 32 bits. If the compiler's "long" + type is 64 bits, then the limit is 16 exabytes. + +31. Does zlib have any security vulnerabilities? + + The only one that we are aware of is potentially in gzprintf(). If zlib + is compiled to use sprintf() or vsprintf(), then there is no protection + against a buffer overflow of a 4K string space, other than the caller of + gzprintf() assuring that the output will not exceed 4K. On the other + hand, if zlib is compiled to use snprintf() or vsnprintf(), which should + normally be the case, then there is no vulnerability. The ./configure + script will display warnings if an insecure variation of sprintf() will + be used by gzprintf(). Also the zlibCompileFlags() function will return + information on what variant of sprintf() is used by gzprintf(). + + If you don't have snprintf() or vsnprintf() and would like one, you can + find a portable implementation here: + + http://www.ijs.si/software/snprintf/ + + Note that you should be using the most recent version of zlib. Versions + 1.1.3 and before were subject to a double-free vulnerability. + +32. Is there a Java version of zlib? + + Probably what you want is to use zlib in Java. zlib is already included + as part of the Java SDK in the java.util.zip package. If you really want + a version of zlib written in the Java language, look on the zlib home + page for links: http://www.zlib.org/ + +33. I get this or that compiler or source-code scanner warning when I crank it + up to maximally-pendantic. Can't you guys write proper code? + + Many years ago, we gave up attempting to avoid warnings on every compiler + in the universe. It just got to be a waste of time, and some compilers + were downright silly. So now, we simply make sure that the code always + works. + +34. Will zlib read the (insert any ancient or arcane format here) compressed + data format? + + Probably not. Look in the comp.compression FAQ for pointers to various + formats and associated software. + +35. How can I encrypt/decrypt zip files with zlib? + + zlib doesn't support encryption. The original PKZIP encryption is very weak + and can be broken with freely available programs. To get strong encryption, + use gpg ( http://www.gnupg.org/ ) which already includes zlib compression. + For PKZIP compatible "encryption", look at http://www.info-zip.org/ + +36. What's the difference between the "gzip" and "deflate" HTTP 1.1 encodings? + + "gzip" is the gzip format, and "deflate" is the zlib format. They should + probably have called the second one "zlib" instead to avoid confusion + with the raw deflate compressed data format. While the HTTP 1.1 RFC 2616 + correctly points to the zlib specification in RFC 1950 for the "deflate" + transfer encoding, there have been reports of servers and browsers that + incorrectly produce or expect raw deflate data per the deflate + specficiation in RFC 1951, most notably Microsoft. So even though the + "deflate" transfer encoding using the zlib format would be the more + efficient approach (and in fact exactly what the zlib format was designed + for), using the "gzip" transfer encoding is probably more reliable due to + an unfortunate choice of name on the part of the HTTP 1.1 authors. + + Bottom line: use the gzip format for HTTP 1.1 encoding. + +37. Does zlib support the new "Deflate64" format introduced by PKWare? + + No. PKWare has apparently decided to keep that format proprietary, since + they have not documented it as they have previous compression formats. + In any case, the compression improvements are so modest compared to other + more modern approaches, that it's not worth the effort to implement. + +38. Can you please sign these lengthy legal documents and fax them back to us + so that we can use your software in our product? + + No. Go away. Shoo. diff --git a/syslinux/com32/lib/zlib/README b/syslinux/com32/lib/zlib/README new file mode 100644 index 0000000..0f12054 --- /dev/null +++ b/syslinux/com32/lib/zlib/README @@ -0,0 +1,126 @@ +ZLIB DATA COMPRESSION LIBRARY + +zlib 1.2.1 is a general purpose data compression library. All the code is +thread safe. The data format used by the zlib library is described by RFCs +(Request for Comments) 1950 to 1952 in the files +http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format) +and rfc1952.txt (gzip format). These documents are also available in other +formats from ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html + +All functions of the compression library are documented in the file zlib.h +(volunteer to write man pages welcome, contact zlib@gzip.org). A usage example +of the library is given in the file example.c which also tests that the library +is working correctly. Another example is given in the file minigzip.c. The +compression library itself is composed of all source files except example.c and +minigzip.c. + +To compile all files and run the test program, follow the instructions given at +the top of Makefile. In short "make test; make install" should work for most +machines. For Unix: "./configure; make test; make install" For MSDOS, use one +of the special makefiles such as Makefile.msc. For VMS, use Make_vms.com or +descrip.mms. + +Questions about zlib should be sent to <zlib@gzip.org>, or to Gilles Vollant +<info@winimage.com> for the Windows DLL version. The zlib home page is +http://www.zlib.org or http://www.gzip.org/zlib/ Before reporting a problem, +please check this site to verify that you have the latest version of zlib; +otherwise get the latest version and check whether the problem still exists or +not. + +PLEASE read the zlib FAQ http://www.gzip.org/zlib/zlib_faq.html before asking +for help. + +Mark Nelson <markn@ieee.org> wrote an article about zlib for the Jan. 1997 +issue of Dr. Dobb's Journal; a copy of the article is available in +http://dogma.net/markn/articles/zlibtool/zlibtool.htm + +The changes made in version 1.2.1 are documented in the file ChangeLog. + +Unsupported third party contributions are provided in directory "contrib". + +A Java implementation of zlib is available in the Java Development Kit +http://java.sun.com/j2se/1.4.2/docs/api/java/util/zip/package-summary.html +See the zlib home page http://www.zlib.org for details. + +A Perl interface to zlib written by Paul Marquess <pmqs@cpan.org> is in the +CPAN (Comprehensive Perl Archive Network) sites +http://www.cpan.org/modules/by-module/Compress/ + +A Python interface to zlib written by A.M. Kuchling <amk@magnet.com> is +available in Python 1.5 and later versions, see +http://www.python.org/doc/lib/module-zlib.html + +A zlib binding for TCL written by Andreas Kupries <a.kupries@westend.com> is +availlable at http://www.oche.de/~akupries/soft/trf/trf_zip.html + +An experimental package to read and write files in .zip format, written on top +of zlib by Gilles Vollant <info@winimage.com>, is available in the +contrib/minizip directory of zlib. + + +Notes for some targets: + +- For Windows DLL versions, please see win32/DLL_FAQ.txt + +- For 64-bit Irix, deflate.c must be compiled without any optimization. With + -O, one libpng test fails. The test works in 32 bit mode (with the -n32 + compiler flag). The compiler bug has been reported to SGI. + +- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works + when compiled with cc. + +- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is + necessary to get gzprintf working correctly. This is done by configure. + +- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with + other compilers. Use "make test" to check your compiler. + +- gzdopen is not supported on RISCOS, BEOS and by some Mac compilers. + +- For PalmOs, see http://palmzlib.sourceforge.net/ + +- When building a shared, i.e. dynamic library on Mac OS X, the library must be + installed before testing (do "make install" before "make test"), since the + library location is specified in the library. + + +Acknowledgments: + + The deflate format used by zlib was defined by Phil Katz. The deflate + and zlib specifications were written by L. Peter Deutsch. Thanks to all the + people who reported problems and suggested various improvements in zlib; + they are too numerous to cite here. + +Copyright notice: + + (C) 1995-2003 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + +If you use the zlib library in a product, we would appreciate *not* +receiving lengthy legal documents to sign. The sources are provided +for free but without warranty of any kind. The library has been +entirely written by Jean-loup Gailly and Mark Adler; it does not +include third-party code. + +If you redistribute modified sources, we would appreciate that you include +in the file ChangeLog history information documenting your changes. Please +read the FAQ for more information on the distribution of modified source +versions. diff --git a/syslinux/com32/lib/zlib/adler32.c b/syslinux/com32/lib/zlib/adler32.c new file mode 100644 index 0000000..690f062 --- /dev/null +++ b/syslinux/com32/lib/zlib/adler32.c @@ -0,0 +1,74 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: adler32.c,v 1.1 2005/01/08 05:38:12 hpa Exp $ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +#define BASE 65521UL /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +#ifdef NO_DIVIDE +# define MOD(a) \ + do { \ + if (a >= (BASE << 16)) a -= (BASE << 16); \ + if (a >= (BASE << 15)) a -= (BASE << 15); \ + if (a >= (BASE << 14)) a -= (BASE << 14); \ + if (a >= (BASE << 13)) a -= (BASE << 13); \ + if (a >= (BASE << 12)) a -= (BASE << 12); \ + if (a >= (BASE << 11)) a -= (BASE << 11); \ + if (a >= (BASE << 10)) a -= (BASE << 10); \ + if (a >= (BASE << 9)) a -= (BASE << 9); \ + if (a >= (BASE << 8)) a -= (BASE << 8); \ + if (a >= (BASE << 7)) a -= (BASE << 7); \ + if (a >= (BASE << 6)) a -= (BASE << 6); \ + if (a >= (BASE << 5)) a -= (BASE << 5); \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int k; + + if (buf == Z_NULL) return 1L; + + while (len > 0) { + k = len < NMAX ? (int)len : NMAX; + len -= k; + while (k >= 16) { + DO16(buf); + buf += 16; + k -= 16; + } + if (k != 0) do { + s1 += *buf++; + s2 += s1; + } while (--k); + MOD(s1); + MOD(s2); + } + return (s2 << 16) | s1; +} diff --git a/syslinux/com32/lib/zlib/algorithm.txt b/syslinux/com32/lib/zlib/algorithm.txt new file mode 100644 index 0000000..b022dde --- /dev/null +++ b/syslinux/com32/lib/zlib/algorithm.txt @@ -0,0 +1,209 @@ +1. Compression algorithm (deflate) + +The deflation algorithm used by gzip (also zip and zlib) is a variation of +LZ77 (Lempel-Ziv 1977, see reference below). It finds duplicated strings in +the input data. The second occurrence of a string is replaced by a +pointer to the previous string, in the form of a pair (distance, +length). Distances are limited to 32K bytes, and lengths are limited +to 258 bytes. When a string does not occur anywhere in the previous +32K bytes, it is emitted as a sequence of literal bytes. (In this +description, `string' must be taken as an arbitrary sequence of bytes, +and is not restricted to printable characters.) + +Literals or match lengths are compressed with one Huffman tree, and +match distances are compressed with another tree. The trees are stored +in a compact form at the start of each block. The blocks can have any +size (except that the compressed data for one block must fit in +available memory). A block is terminated when deflate() determines that +it would be useful to start another block with fresh trees. (This is +somewhat similar to the behavior of LZW-based _compress_.) + +Duplicated strings are found using a hash table. All input strings of +length 3 are inserted in the hash table. A hash index is computed for +the next 3 bytes. If the hash chain for this index is not empty, all +strings in the chain are compared with the current input string, and +the longest match is selected. + +The hash chains are searched starting with the most recent strings, to +favor small distances and thus take advantage of the Huffman encoding. +The hash chains are singly linked. There are no deletions from the +hash chains, the algorithm simply discards matches that are too old. + +To avoid a worst-case situation, very long hash chains are arbitrarily +truncated at a certain length, determined by a runtime option (level +parameter of deflateInit). So deflate() does not always find the longest +possible match but generally finds a match which is long enough. + +deflate() also defers the selection of matches with a lazy evaluation +mechanism. After a match of length N has been found, deflate() searches for +a longer match at the next input byte. If a longer match is found, the +previous match is truncated to a length of one (thus producing a single +literal byte) and the process of lazy evaluation begins again. Otherwise, +the original match is kept, and the next match search is attempted only N +steps later. + +The lazy match evaluation is also subject to a runtime parameter. If +the current match is long enough, deflate() reduces the search for a longer +match, thus speeding up the whole process. If compression ratio is more +important than speed, deflate() attempts a complete second search even if +the first match is already long enough. + +The lazy match evaluation is not performed for the fastest compression +modes (level parameter 1 to 3). For these fast modes, new strings +are inserted in the hash table only when no match was found, or +when the match is not too long. This degrades the compression ratio +but saves time since there are both fewer insertions and fewer searches. + + +2. Decompression algorithm (inflate) + +2.1 Introduction + +The key question is how to represent a Huffman code (or any prefix code) so +that you can decode fast. The most important characteristic is that shorter +codes are much more common than longer codes, so pay attention to decoding the +short codes fast, and let the long codes take longer to decode. + +inflate() sets up a first level table that covers some number of bits of +input less than the length of longest code. It gets that many bits from the +stream, and looks it up in the table. The table will tell if the next +code is that many bits or less and how many, and if it is, it will tell +the value, else it will point to the next level table for which inflate() +grabs more bits and tries to decode a longer code. + +How many bits to make the first lookup is a tradeoff between the time it +takes to decode and the time it takes to build the table. If building the +table took no time (and if you had infinite memory), then there would only +be a first level table to cover all the way to the longest code. However, +building the table ends up taking a lot longer for more bits since short +codes are replicated many times in such a table. What inflate() does is +simply to make the number of bits in the first table a variable, and then +to set that variable for the maximum speed. + +For inflate, which has 286 possible codes for the literal/length tree, the size +of the first table is nine bits. Also the distance trees have 30 possible +values, and the size of the first table is six bits. Note that for each of +those cases, the table ended up one bit longer than the ``average'' code +length, i.e. the code length of an approximately flat code which would be a +little more than eight bits for 286 symbols and a little less than five bits +for 30 symbols. + + +2.2 More details on the inflate table lookup + +Ok, you want to know what this cleverly obfuscated inflate tree actually +looks like. You are correct that it's not a Huffman tree. It is simply a +lookup table for the first, let's say, nine bits of a Huffman symbol. The +symbol could be as short as one bit or as long as 15 bits. If a particular +symbol is shorter than nine bits, then that symbol's translation is duplicated +in all those entries that start with that symbol's bits. For example, if the +symbol is four bits, then it's duplicated 32 times in a nine-bit table. If a +symbol is nine bits long, it appears in the table once. + +If the symbol is longer than nine bits, then that entry in the table points +to another similar table for the remaining bits. Again, there are duplicated +entries as needed. The idea is that most of the time the symbol will be short +and there will only be one table look up. (That's whole idea behind data +compression in the first place.) For the less frequent long symbols, there +will be two lookups. If you had a compression method with really long +symbols, you could have as many levels of lookups as is efficient. For +inflate, two is enough. + +So a table entry either points to another table (in which case nine bits in +the above example are gobbled), or it contains the translation for the symbol +and the number of bits to gobble. Then you start again with the next +ungobbled bit. + +You may wonder: why not just have one lookup table for how ever many bits the +longest symbol is? The reason is that if you do that, you end up spending +more time filling in duplicate symbol entries than you do actually decoding. +At least for deflate's output that generates new trees every several 10's of +kbytes. You can imagine that filling in a 2^15 entry table for a 15-bit code +would take too long if you're only decoding several thousand symbols. At the +other extreme, you could make a new table for every bit in the code. In fact, +that's essentially a Huffman tree. But then you spend two much time +traversing the tree while decoding, even for short symbols. + +So the number of bits for the first lookup table is a trade of the time to +fill out the table vs. the time spent looking at the second level and above of +the table. + +Here is an example, scaled down: + +The code being decoded, with 10 symbols, from 1 to 6 bits long: + +A: 0 +B: 10 +C: 1100 +D: 11010 +E: 11011 +F: 11100 +G: 11101 +H: 11110 +I: 111110 +J: 111111 + +Let's make the first table three bits long (eight entries): + +000: A,1 +001: A,1 +010: A,1 +011: A,1 +100: B,2 +101: B,2 +110: -> table X (gobble 3 bits) +111: -> table Y (gobble 3 bits) + +Each entry is what the bits decode as and how many bits that is, i.e. how +many bits to gobble. Or the entry points to another table, with the number of +bits to gobble implicit in the size of the table. + +Table X is two bits long since the longest code starting with 110 is five bits +long: + +00: C,1 +01: C,1 +10: D,2 +11: E,2 + +Table Y is three bits long since the longest code starting with 111 is six +bits long: + +000: F,2 +001: F,2 +010: G,2 +011: G,2 +100: H,2 +101: H,2 +110: I,3 +111: J,3 + +So what we have here are three tables with a total of 20 entries that had to +be constructed. That's compared to 64 entries for a single table. Or +compared to 16 entries for a Huffman tree (six two entry tables and one four +entry table). Assuming that the code ideally represents the probability of +the symbols, it takes on the average 1.25 lookups per symbol. That's compared +to one lookup for the single table, or 1.66 lookups per symbol for the +Huffman tree. + +There, I think that gives you a picture of what's going on. For inflate, the +meaning of a particular symbol is often more than just a letter. It can be a +byte (a "literal"), or it can be either a length or a distance which +indicates a base value and a number of bits to fetch after the code that is +added to the base value. Or it might be the special end-of-block code. The +data structures created in inftrees.c try to encode all that information +compactly in the tables. + + +Jean-loup Gailly Mark Adler +jloup@gzip.org madler@alumni.caltech.edu + + +References: + +[LZ77] Ziv J., Lempel A., ``A Universal Algorithm for Sequential Data +Compression,'' IEEE Transactions on Information Theory, Vol. 23, No. 3, +pp. 337-343. + +``DEFLATE Compressed Data Format Specification'' available in +http://www.ietf.org/rfc/rfc1951.txt diff --git a/syslinux/com32/lib/zlib/compress.c b/syslinux/com32/lib/zlib/compress.c new file mode 100644 index 0000000..6846343 --- /dev/null +++ b/syslinux/com32/lib/zlib/compress.c @@ -0,0 +1,79 @@ +/* compress.c -- compress a memory buffer + * Copyright (C) 1995-2002 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: compress.c,v 1.1 2005/01/08 05:38:12 hpa Exp $ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ +int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; + int level; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; +#ifdef MAXSEG_64K + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +/* =========================================================================== + */ +int ZEXPORT compress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +uLong ZEXPORT compressBound (sourceLen) + uLong sourceLen; +{ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11; +} diff --git a/syslinux/com32/lib/zlib/crc32.c b/syslinux/com32/lib/zlib/crc32.c new file mode 100644 index 0000000..4e00c8c --- /dev/null +++ b/syslinux/com32/lib/zlib/crc32.c @@ -0,0 +1,312 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster + * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing + * tables for updating the shift register in one step with three exclusive-ors + * instead of four steps with four exclusive-ors. This results about a factor + * of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + */ + +/* @(#) $Id: crc32.c,v 1.1 2005/01/08 05:38:12 hpa Exp $ */ + +#ifdef MAKECRCH +# include <stdio.h> +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for STDC and FAR definitions */ + +#define local static + +/* Find a four-byte integer type for crc32_little() and crc32_big(). */ +#ifndef NOBYFOUR +# ifdef STDC /* need ANSI C limits.h to determine sizes */ +# include <limits.h> +# define BYFOUR +# if (UINT_MAX == 0xffffffffUL) + typedef unsigned int u4; +# else +# if (ULONG_MAX == 0xffffffffUL) + typedef unsigned long u4; +# else +# if (USHRT_MAX == 0xffffffffUL) + typedef unsigned short u4; +# else +# undef BYFOUR /* can't find a four-byte integer type! */ +# endif +# endif +# endif +# endif /* STDC */ +#endif /* !NOBYFOUR */ + +/* Definitions for doing the crc four data bytes at a time. */ +#ifdef BYFOUR +# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \ + (((w)&0xff00)<<8)+(((w)&0xff)<<24)) + local unsigned long crc32_little OF((unsigned long, + const unsigned char FAR *, unsigned)); + local unsigned long crc32_big OF((unsigned long, + const unsigned char FAR *, unsigned)); +# define TBLS 8 +#else +# define TBLS 1 +#endif /* BYFOUR */ + +#ifdef DYNAMIC_CRC_TABLE + +local int crc_table_empty = 1; +local unsigned long FAR crc_table[TBLS][256]; +local void make_crc_table OF((void)); +#ifdef MAKECRCH + local void write_table OF((FILE *, const unsigned long FAR *)); +#endif /* MAKECRCH */ + +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The first table is simply the CRC of all possible eight bit values. This is + all the information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. The remaining tables + allow for word-at-a-time CRC calculation for both big-endian and little- + endian machines, where a word is four bytes. +*/ +local void make_crc_table() +{ + unsigned long c; + unsigned int n; + int k; + unsigned long poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* make exclusive-or pattern from polynomial (0xedb88320UL) */ + poly = 0UL; + for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) + poly |= 1UL << (31 - p[n]); + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (unsigned long)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[0][n] = c; + } + +#ifdef BYFOUR + /* generate crc for each value followed by one, two, and three zeros, and + then the byte reversal of those as well as the first table */ + for (n = 0; n < 256; n++) { + c = crc_table[0][n]; + crc_table[4][n] = REV(c); + for (k = 1; k < 4; k++) { + c = crc_table[0][c & 0xff] ^ (c >> 8); + crc_table[k][n] = c; + crc_table[k + 4][n] = REV(c); + } + } +#endif /* BYFOUR */ + + crc_table_empty = 0; + +#ifdef MAKECRCH + /* write out CRC tables to crc32.h */ + { + FILE *out; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); + fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); + fprintf(out, "local const unsigned long FAR "); + fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); + write_table(out, crc_table[0]); +# ifdef BYFOUR + fprintf(out, "#ifdef BYFOUR\n"); + for (k = 1; k < 8; k++) { + fprintf(out, " },\n {\n"); + write_table(out, crc_table[k]); + } + fprintf(out, "#endif\n"); +# endif /* BYFOUR */ + fprintf(out, " }\n};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH +local void write_table(out, table) + FILE *out; + const unsigned long FAR *table; +{ + int n; + + for (n = 0; n < 256; n++) + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], + n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); +} +#endif /* MAKECRCH */ + +#else /* !DYNAMIC_CRC_TABLE */ +/* ======================================================================== + * Tables of CRC-32s of all single-byte values, made by make_crc_table(). + */ +#include "crc32.h" +#endif /* DYNAMIC_CRC_TABLE */ + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const unsigned long FAR * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + return (const unsigned long FAR *)crc_table; +} + +/* ========================================================================= */ +#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) +#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + if (buf == Z_NULL) return 0UL; + +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + +#ifdef BYFOUR + if (sizeof(void *) == sizeof(ptrdiff_t)) { + u4 endian; + + endian = 1; + if (*((unsigned char *)(&endian))) + return crc32_little(crc, buf, len); + else + return crc32_big(crc, buf, len); + } +#endif /* BYFOUR */ + crc = crc ^ 0xffffffffUL; + while (len >= 8) { + DO8; + len -= 8; + } + if (len) do { + DO1; + } while (--len); + return crc ^ 0xffffffffUL; +} + +#ifdef BYFOUR + +/* ========================================================================= */ +#define DOLIT4 c ^= *buf4++; \ + c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ + crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] +#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 + +/* ========================================================================= */ +local unsigned long crc32_little(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = (u4)crc; + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + len--; + } + + buf4 = (const u4 FAR *)buf; + while (len >= 32) { + DOLIT32; + len -= 32; + } + while (len >= 4) { + DOLIT4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + } while (--len); + c = ~c; + return (unsigned long)c; +} + +/* ========================================================================= */ +#define DOBIG4 c ^= *++buf4; \ + c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ + crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] +#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 + +/* ========================================================================= */ +local unsigned long crc32_big(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = REV((u4)crc); + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + len--; + } + + buf4 = (const u4 FAR *)buf; + buf4--; + while (len >= 32) { + DOBIG32; + len -= 32; + } + while (len >= 4) { + DOBIG4; + len -= 4; + } + buf4++; + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + } while (--len); + c = ~c; + return (unsigned long)(REV(c)); +} + +#endif /* BYFOUR */ diff --git a/syslinux/com32/lib/zlib/crc32.h b/syslinux/com32/lib/zlib/crc32.h new file mode 100644 index 0000000..8053b61 --- /dev/null +++ b/syslinux/com32/lib/zlib/crc32.h @@ -0,0 +1,441 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const unsigned long FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/syslinux/com32/lib/zlib/deflate.c b/syslinux/com32/lib/zlib/deflate.c new file mode 100644 index 0000000..982d03e --- /dev/null +++ b/syslinux/com32/lib/zlib/deflate.c @@ -0,0 +1,1502 @@ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in http://www.ietf.org/rfc/rfc1951.txt + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* @(#) $Id: deflate.c,v 1.1 2005/01/08 05:38:12 hpa Exp $ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.2.1 Copyright 1995-2003 Jean-loup Gailly "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +#ifndef FASTEST +local block_state deflate_slow OF((deflate_state *s, int flush)); +#endif +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +#ifndef FASTEST +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif +#endif +local uInt longest_match_fast OF((deflate_state *s, IPos cur_match)); + +#ifdef DEBUG +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +#ifndef NO_DUMMY_DECL +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ +#endif + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +int ZEXPORT deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int wrap = 1; + static const char my_version[] = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } +#ifdef GZIP + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } +#endif + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_RLE) { + return Z_STREAM_ERROR; + } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->wrap = wrap; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + s->status = FINISH_STATE; + strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt length = dictLength; + uInt n; + IPos hash_head = 0; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || + strm->state->wrap == 2 || + (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) + return Z_STREAM_ERROR; + + s = strm->state; + if (s->wrap) + strm->adler = adler32(strm->adler, dictionary, dictLength); + + if (length < MIN_MATCH) return Z_OK; + if (length > MAX_DIST(s)) { + length = MAX_DIST(s); +#ifndef USE_DICT_HEAD + dictionary += dictLength - length; /* use the tail of the dictionary */ +#endif + } + zmemcpy(s->window, dictionary, length); + s->strstart = length; + s->block_start = (long)length; + + /* Insert all strings in the hash table (except for the last two bytes). + * s->lookahead stays null, so s->ins_h will be recomputed at the next + * call of fill_window. + */ + s->ins_h = s->window[0]; + UPDATE_HASH(s, s->ins_h, s->window[1]); + for (n = 0; n <= length - MIN_MATCH; n++) { + INSERT_STRING(s, n, hash_head); + } + if (hash_head) hash_head = 0; /* to make compiler happy */ + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset (strm) + z_streamp strm; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { + return Z_STREAM_ERROR; + } + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->wrap < 0) { + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ + } + s->status = s->wrap ? INIT_STATE : BUSY_STATE; + strm->adler = +#ifdef GZIP + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : +#endif + adler32(0L, Z_NULL, 0); + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + lm_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePrime (strm, bits, value) + z_streamp strm; + int bits; + int value; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + strm->state->bi_valid = bits; + strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_RLE) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if (func != configuration_table[level].func && strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_PARTIAL_FLUSH); + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns + * a close to exact, as well as small, upper bound on the compressed size. + * They are coded as constants here for a reason--if the #define's are + * changed, then this function needs to be changed as well. The return + * value for 15 and 8 only works for those exact settings. + * + * For any setting other than those defaults for windowBits and memLevel, + * the value returned is a conservative worst case for the maximum expansion + * resulting from using fixed blocks instead of stored blocks, which deflate + * can emit on compressed data for some combinations of the parameters. + * + * This function could be more sophisticated to provide closer upper bounds + * for every combination of windowBits and memLevel, as well as wrap. + * But even the conservative upper bound of about 14% expansion does not + * seem onerous for output buffer allocation. + */ +uLong ZEXPORT deflateBound(strm, sourceLen) + z_streamp strm; + uLong sourceLen; +{ + deflate_state *s; + uLong destLen; + + /* conservative upper bound */ + destLen = sourceLen + + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11; + + /* if can't get parameters, return conservative bound */ + if (strm == Z_NULL || strm->state == Z_NULL) + return destLen; + + /* if not default parameters, return conservative bound */ + s = strm->state; + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return destLen; + + /* default settings: return tight bound for that case */ + return compressBound(sourceLen); +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + unsigned len = strm->state->pending; + + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, strm->state->pending_out, len); + strm->next_out += len; + strm->state->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + strm->state->pending -= len; + if (strm->state->pending == 0) { + strm->state->pending_out = strm->state->pending_buf; + } +} + +/* ========================================================================= */ +int ZEXPORT deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_FINISH || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the header */ + if (s->status == INIT_STATE) { +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, 255); + s->status = BUSY_STATE; + strm->adler = crc32(0L, Z_NULL, 0); + } + else +#endif + { + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + } + } + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && flush <= old_flush && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + + if (flush != Z_FINISH) return Z_OK; + if (s->wrap <= 0) return Z_STREAM_END; + + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else +#endif + { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd (strm) + z_streamp strm; +{ + int status; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + + status = strm->state->status; + if (status != INIT_STATE && status != BUSY_STATE && + status != FINISH_STATE) { + return Z_STREAM_ERROR; + } + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + *dest = *source; + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + *ds = *ss; + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif /* MAXSEG_64K */ +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf(strm, buf, size) + z_streamp strm; + Bytef *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, strm->next_in, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, strm->next_in, len); + } +#endif + zmemcpy(buf, strm->next_in, len); + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +} + +#ifndef FASTEST +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2: + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} +#endif /* ASMV */ +#endif /* FASTEST */ + +/* --------------------------------------------------------------------------- + * Optimized version for level == 1 or strategy == Z_RLE only + */ +local uInt longest_match_fast(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; +} + +#ifdef DEBUG +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif /* DEBUG */ + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy(s->window, s->window+wsize, (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif + more += wsize; + } + if (s->strm->avail_in == 0) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead >= MIN_MATCH) { + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, eof) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (eof)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, eof) { \ + FLUSH_BLOCK_ONLY(s, eof); \ + if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + ulg max_block_size = 0xffff; + ulg max_start; + + if (max_block_size > s->pending_buf_size - 5) { + max_block_size = s->pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; + if (s->strstart == 0 || (ulg)s->strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; + FLUSH_BLOCK(s, 0); + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ +#ifdef FASTEST + if ((s->strategy < Z_HUFFMAN_ONLY) || + (s->strategy == Z_RLE && s->strstart - hash_head == 1)) { + s->match_length = longest_match_fast (s, hash_head); + } +#else + if (s->strategy < Z_HUFFMAN_ONLY) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } +#endif + /* longest_match() or longest_match_fast() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +#ifndef FASTEST +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy < Z_HUFFMAN_ONLY) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } + /* longest_match() or longest_match_fast() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) +#endif + )) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + s->match_available = 0; + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif /* FASTEST */ diff --git a/syslinux/com32/lib/zlib/deflate.h b/syslinux/com32/lib/zlib/deflate.h new file mode 100644 index 0000000..9763003 --- /dev/null +++ b/syslinux/com32/lib/zlib/deflate.h @@ -0,0 +1,326 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2002 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id: deflate.h,v 1.1 2005/01/08 05:38:12 hpa Exp $ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + int pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + Byte data_type; /* UNKNOWN, BINARY or ASCII */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch _length_code[]; + extern uch _dist_code[]; +#else + extern const uch _length_code[]; + extern const uch _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/syslinux/com32/lib/zlib/example.c b/syslinux/com32/lib/zlib/example.c new file mode 100644 index 0000000..e528867 --- /dev/null +++ b/syslinux/com32/lib/zlib/example.c @@ -0,0 +1,567 @@ +/* example.c -- usage example of the zlib compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: example.c,v 1.1 2005/01/08 05:38:12 hpa Exp $ */ + +#include <stdio.h> +#include "zlib.h" + +#ifdef STDC +# include <string.h> +# include <stdlib.h> +#else + extern void exit OF((int)); +#endif + +#if defined(VMS) || defined(RISCOS) +# define TESTFILE "foo-gz" +#else +# define TESTFILE "foo.gz" +#endif + +#define CHECK_ERR(err, msg) { \ + if (err != Z_OK) { \ + fprintf(stderr, "%s error: %d\n", msg, err); \ + exit(1); \ + } \ +} + +const char hello[] = "hello, hello!"; +/* "hello world" would be more standard, but the repeated "hello" + * stresses the compression code better, sorry... + */ + +const char dictionary[] = "hello"; +uLong dictId; /* Adler32 value of the dictionary */ + +void test_compress OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_gzio OF((const char *fname, + Byte *uncompr, uLong uncomprLen)); +void test_deflate OF((Byte *compr, uLong comprLen)); +void test_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_large_deflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_large_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_flush OF((Byte *compr, uLong *comprLen)); +void test_sync OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_dict_deflate OF((Byte *compr, uLong comprLen)); +void test_dict_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +int main OF((int argc, char *argv[])); + +/* =========================================================================== + * Test compress() and uncompress() + */ +void test_compress(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + uLong len = (uLong)strlen(hello)+1; + + err = compress(compr, &comprLen, (const Bytef*)hello, len); + CHECK_ERR(err, "compress"); + + strcpy((char*)uncompr, "garbage"); + + err = uncompress(uncompr, &uncomprLen, compr, comprLen); + CHECK_ERR(err, "uncompress"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad uncompress\n"); + exit(1); + } else { + printf("uncompress(): %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Test read/write of .gz files + */ +void test_gzio(fname, uncompr, uncomprLen) + const char *fname; /* compressed file name */ + Byte *uncompr; + uLong uncomprLen; +{ +#ifdef NO_GZCOMPRESS + fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n"); +#else + int err; + int len = (int)strlen(hello)+1; + gzFile file; + z_off_t pos; + + file = gzopen(fname, "wb"); + if (file == NULL) { + fprintf(stderr, "gzopen error\n"); + exit(1); + } + gzputc(file, 'h'); + if (gzputs(file, "ello") != 4) { + fprintf(stderr, "gzputs err: %s\n", gzerror(file, &err)); + exit(1); + } + if (gzprintf(file, ", %s!", "hello") != 8) { + fprintf(stderr, "gzprintf err: %s\n", gzerror(file, &err)); + exit(1); + } + gzseek(file, 1L, SEEK_CUR); /* add one zero byte */ + gzclose(file); + + file = gzopen(fname, "rb"); + if (file == NULL) { + fprintf(stderr, "gzopen error\n"); + exit(1); + } + strcpy((char*)uncompr, "garbage"); + + if (gzread(file, uncompr, (unsigned)uncomprLen) != len) { + fprintf(stderr, "gzread err: %s\n", gzerror(file, &err)); + exit(1); + } + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad gzread: %s\n", (char*)uncompr); + exit(1); + } else { + printf("gzread(): %s\n", (char*)uncompr); + } + + pos = gzseek(file, -8L, SEEK_CUR); + if (pos != 6 || gztell(file) != pos) { + fprintf(stderr, "gzseek error, pos=%ld, gztell=%ld\n", + (long)pos, (long)gztell(file)); + exit(1); + } + + if (gzgetc(file) != ' ') { + fprintf(stderr, "gzgetc error\n"); + exit(1); + } + + if (gzungetc(' ', file) != ' ') { + fprintf(stderr, "gzungetc error\n"); + exit(1); + } + + gzgets(file, (char*)uncompr, (int)uncomprLen); + if (strlen((char*)uncompr) != 7) { /* " hello!" */ + fprintf(stderr, "gzgets err after gzseek: %s\n", gzerror(file, &err)); + exit(1); + } + if (strcmp((char*)uncompr, hello + 6)) { + fprintf(stderr, "bad gzgets after gzseek\n"); + exit(1); + } else { + printf("gzgets() after gzseek: %s\n", (char*)uncompr); + } + + gzclose(file); +#endif +} + +/* =========================================================================== + * Test deflate() with small buffers + */ +void test_deflate(compr, comprLen) + Byte *compr; + uLong comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + uLong len = (uLong)strlen(hello)+1; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_in = (Bytef*)hello; + c_stream.next_out = compr; + + while (c_stream.total_in != len && c_stream.total_out < comprLen) { + c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + } + /* Finish the stream, still forcing small buffers: */ + for (;;) { + c_stream.avail_out = 1; + err = deflate(&c_stream, Z_FINISH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "deflate"); + } + + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with small buffers + */ +void test_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = 0; + d_stream.next_out = uncompr; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) { + d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */ + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "inflate"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad inflate\n"); + exit(1); + } else { + printf("inflate(): %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Test deflate() with large buffers and dynamic change of compression level + */ +void test_large_deflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_BEST_SPEED); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_out = compr; + c_stream.avail_out = (uInt)comprLen; + + /* At this point, uncompr is still mostly zeroes, so it should compress + * very well: + */ + c_stream.next_in = uncompr; + c_stream.avail_in = (uInt)uncomprLen; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + if (c_stream.avail_in != 0) { + fprintf(stderr, "deflate not greedy\n"); + exit(1); + } + + /* Feed in already compressed data and switch to no compression: */ + deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY); + c_stream.next_in = compr; + c_stream.avail_in = (uInt)comprLen/2; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + + /* Switch back to compressing mode: */ + deflateParams(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED); + c_stream.next_in = uncompr; + c_stream.avail_in = (uInt)uncomprLen; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + fprintf(stderr, "deflate should report Z_STREAM_END\n"); + exit(1); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with large buffers + */ +void test_large_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = (uInt)comprLen; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + for (;;) { + d_stream.next_out = uncompr; /* discard the output */ + d_stream.avail_out = (uInt)uncomprLen; + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "large inflate"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (d_stream.total_out != 2*uncomprLen + comprLen/2) { + fprintf(stderr, "bad large inflate: %ld\n", d_stream.total_out); + exit(1); + } else { + printf("large_inflate(): OK\n"); + } +} + +/* =========================================================================== + * Test deflate() with full flush + */ +void test_flush(compr, comprLen) + Byte *compr; + uLong *comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + uInt len = (uInt)strlen(hello)+1; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_in = (Bytef*)hello; + c_stream.next_out = compr; + c_stream.avail_in = 3; + c_stream.avail_out = (uInt)*comprLen; + err = deflate(&c_stream, Z_FULL_FLUSH); + CHECK_ERR(err, "deflate"); + + compr[3]++; /* force an error in first compressed block */ + c_stream.avail_in = len - 3; + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + CHECK_ERR(err, "deflate"); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); + + *comprLen = c_stream.total_out; +} + +/* =========================================================================== + * Test inflateSync() + */ +void test_sync(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = 2; /* just read the zlib header */ + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + d_stream.next_out = uncompr; + d_stream.avail_out = (uInt)uncomprLen; + + inflate(&d_stream, Z_NO_FLUSH); + CHECK_ERR(err, "inflate"); + + d_stream.avail_in = (uInt)comprLen-2; /* read all compressed data */ + err = inflateSync(&d_stream); /* but skip the damaged part */ + CHECK_ERR(err, "inflateSync"); + + err = inflate(&d_stream, Z_FINISH); + if (err != Z_DATA_ERROR) { + fprintf(stderr, "inflate should report DATA_ERROR\n"); + /* Because of incorrect adler32 */ + exit(1); + } + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + printf("after inflateSync(): hel%s\n", (char *)uncompr); +} + +/* =========================================================================== + * Test deflate() with preset dictionary + */ +void test_dict_deflate(compr, comprLen) + Byte *compr; + uLong comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_BEST_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + err = deflateSetDictionary(&c_stream, + (const Bytef*)dictionary, sizeof(dictionary)); + CHECK_ERR(err, "deflateSetDictionary"); + + dictId = c_stream.adler; + c_stream.next_out = compr; + c_stream.avail_out = (uInt)comprLen; + + c_stream.next_in = (Bytef*)hello; + c_stream.avail_in = (uInt)strlen(hello)+1; + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + fprintf(stderr, "deflate should report Z_STREAM_END\n"); + exit(1); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with a preset dictionary + */ +void test_dict_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = (uInt)comprLen; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + d_stream.next_out = uncompr; + d_stream.avail_out = (uInt)uncomprLen; + + for (;;) { + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + if (err == Z_NEED_DICT) { + if (d_stream.adler != dictId) { + fprintf(stderr, "unexpected dictionary"); + exit(1); + } + err = inflateSetDictionary(&d_stream, (const Bytef*)dictionary, + sizeof(dictionary)); + } + CHECK_ERR(err, "inflate with dict"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad inflate with dict\n"); + exit(1); + } else { + printf("inflate with dictionary: %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Usage: example [output.gz [input.gz]] + */ + +int main(argc, argv) + int argc; + char *argv[]; +{ + Byte *compr, *uncompr; + uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */ + uLong uncomprLen = comprLen; + static const char* myVersion = ZLIB_VERSION; + + if (zlibVersion()[0] != myVersion[0]) { + fprintf(stderr, "incompatible zlib version\n"); + exit(1); + + } else if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) { + fprintf(stderr, "warning: different zlib version\n"); + } + + printf("zlib version %s = 0x%04x, compile flags = 0x%lx\n", + ZLIB_VERSION, ZLIB_VERNUM, zlibCompileFlags()); + + compr = (Byte*)calloc((uInt)comprLen, 1); + uncompr = (Byte*)calloc((uInt)uncomprLen, 1); + /* compr and uncompr are cleared to avoid reading uninitialized + * data and to ensure that uncompr compresses well. + */ + if (compr == Z_NULL || uncompr == Z_NULL) { + printf("out of memory\n"); + exit(1); + } + test_compress(compr, comprLen, uncompr, uncomprLen); + + test_gzio((argc > 1 ? argv[1] : TESTFILE), + uncompr, uncomprLen); + + test_deflate(compr, comprLen); + test_inflate(compr, comprLen, uncompr, uncomprLen); + + test_large_deflate(compr, comprLen, uncompr, uncomprLen); + test_large_inflate(compr, comprLen, uncompr, uncomprLen); + + test_flush(compr, &comprLen); + test_sync(compr, comprLen, uncompr, uncomprLen); + comprLen = uncomprLen; + + test_dict_deflate(compr, comprLen); + test_dict_inflate(compr, comprLen, uncompr, uncomprLen); + + free(compr); + free(uncompr); + + return 0; +} diff --git a/syslinux/com32/lib/zlib/gzio.c b/syslinux/com32/lib/zlib/gzio.c new file mode 100644 index 0000000..0658d86 --- /dev/null +++ b/syslinux/com32/lib/zlib/gzio.c @@ -0,0 +1,1018 @@ +/* gzio.c -- IO on .gz files + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. + */ + +/* @(#) $Id: gzio.c,v 1.1 2005/01/08 05:38:12 hpa Exp $ */ + +#include <stdio.h> + +#include "zutil.h" + +#ifdef NO_DEFLATE /* for compatiblity with old definition */ +# define NO_GZCOMPRESS +#endif + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#ifndef Z_BUFSIZE +# ifdef MAXSEG_64K +# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ +# else +# define Z_BUFSIZE 16384 +# endif +#endif +#ifndef Z_PRINTF_BUFSIZE +# define Z_PRINTF_BUFSIZE 4096 +#endif + +#ifdef __MVS__ +# pragma map (fdopen , "\174\174FDOPEN") + FILE *fdopen(int, const char *); +#endif + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern void free OF((voidpf ptr)); +#endif + +#define ALLOC(size) malloc(size) +#define TRYFREE(p) {if (p) free(p);} + +static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +typedef struct gz_stream { + z_stream stream; + int z_err; /* error code for last stream operation */ + int z_eof; /* set if end of input file */ + FILE *file; /* .gz file */ + Byte *inbuf; /* input buffer */ + Byte *outbuf; /* output buffer */ + uLong crc; /* crc32 of uncompressed data */ + char *msg; /* error message */ + char *path; /* path name for debugging only */ + int transparent; /* 1 if input file is not a .gz file */ + char mode; /* 'w' or 'r' */ + z_off_t start; /* start of compressed data in file (header skipped) */ + z_off_t in; /* bytes into deflate or inflate */ + z_off_t out; /* bytes out of deflate or inflate */ + int back; /* one character push-back */ + int last; /* true if push-back is last character */ +} gz_stream; + + +local gzFile gz_open OF((const char *path, const char *mode, int fd)); +local int do_flush OF((gzFile file, int flush)); +local int get_byte OF((gz_stream *s)); +local void check_header OF((gz_stream *s)); +local int destroy OF((gz_stream *s)); +local void putLong OF((FILE *file, uLong x)); +local uLong getLong OF((gz_stream *s)); + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb"). The file is given either by file descriptor + or path name (if fd == -1). + gz_open returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). +*/ +local gzFile gz_open (path, mode, fd) + const char *path; + const char *mode; + int fd; +{ + int err; + int level = Z_DEFAULT_COMPRESSION; /* compression level */ + int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ + char *p = (char*)mode; + gz_stream *s; + char fmode[80]; /* copy of mode, without the compression level */ + char *m = fmode; + + if (!path || !mode) return Z_NULL; + + s = (gz_stream *)ALLOC(sizeof(gz_stream)); + if (!s) return Z_NULL; + + s->stream.zalloc = (alloc_func)0; + s->stream.zfree = (free_func)0; + s->stream.opaque = (voidpf)0; + s->stream.next_in = s->inbuf = Z_NULL; + s->stream.next_out = s->outbuf = Z_NULL; + s->stream.avail_in = s->stream.avail_out = 0; + s->file = NULL; + s->z_err = Z_OK; + s->z_eof = 0; + s->in = 0; + s->out = 0; + s->back = EOF; + s->crc = crc32(0L, Z_NULL, 0); + s->msg = NULL; + s->transparent = 0; + + s->path = (char*)ALLOC(strlen(path)+1); + if (s->path == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + strcpy(s->path, path); /* do this early for debugging */ + + s->mode = '\0'; + do { + if (*p == 'r') s->mode = 'r'; + if (*p == 'w' || *p == 'a') s->mode = 'w'; + if (*p >= '0' && *p <= '9') { + level = *p - '0'; + } else if (*p == 'f') { + strategy = Z_FILTERED; + } else if (*p == 'h') { + strategy = Z_HUFFMAN_ONLY; + } else if (*p == 'R') { + strategy = Z_RLE; + } else { + *m++ = *p; /* copy the mode */ + } + } while (*p++ && m != fmode + sizeof(fmode)); + if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateInit2(&(s->stream), level, + Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); + /* windowBits is passed < 0 to suppress zlib header */ + + s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); +#endif + if (err != Z_OK || s->outbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } else { + s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); + + err = inflateInit2(&(s->stream), -MAX_WBITS); + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are + * present after the compressed stream. + */ + if (err != Z_OK || s->inbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } + s->stream.avail_out = Z_BUFSIZE; + + errno = 0; + s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); + + if (s->file == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + if (s->mode == 'w') { + /* Write a very simple .gz header: + */ + fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], + Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); + s->start = 10L; + /* We use 10L instead of ftell(s->file) to because ftell causes an + * fflush on some systems. This version of the library doesn't use + * start anyway in write mode, so this initialization is not + * necessary. + */ + } else { + check_header(s); /* skip the .gz header */ + s->start = ftell(s->file) - s->stream.avail_in; + } + + return (gzFile)s; +} + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. +*/ +gzFile ZEXPORT gzopen (path, mode) + const char *path; + const char *mode; +{ + return gz_open (path, mode, -1); +} + +/* =========================================================================== + Associate a gzFile with the file descriptor fd. fd is not dup'ed here + to mimic the behavio(u)r of fdopen. +*/ +gzFile ZEXPORT gzdopen (fd, mode) + int fd; + const char *mode; +{ + char name[20]; + + if (fd < 0) return (gzFile)Z_NULL; + sprintf(name, "<fd:%d>", fd); /* for debugging */ + + return gz_open (name, mode, fd); +} + +/* =========================================================================== + * Update the compression level and strategy + */ +int ZEXPORT gzsetparams (file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + /* Make room to allow flushing */ + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + } + s->stream.avail_out = Z_BUFSIZE; + } + + return deflateParams (&(s->stream), level, strategy); +} + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ +local int get_byte(s) + gz_stream *s; +{ + if (s->z_eof) return EOF; + if (s->stream.avail_in == 0) { + errno = 0; + s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + /* klibc hack */ + if (errno) s->z_err = Z_ERRNO; + return EOF; + } + s->stream.next_in = s->inbuf; + } + s->stream.avail_in--; + return *(s->stream.next_in)++; +} + +/* =========================================================================== + Check the gzip header of a gz_stream opened for reading. Set the stream + mode to transparent if the gzip magic header is not present; set s->err + to Z_DATA_ERROR if the magic header is present but the rest of the header + is incorrect. + IN assertion: the stream s has already been created sucessfully; + s->stream.avail_in is zero for the first time, but may be non-zero + for concatenated .gz files. +*/ +local void check_header(s) + gz_stream *s; +{ + int method; /* method byte */ + int flags; /* flags byte */ + uInt len; + int c; + + /* Assure two bytes in the buffer so we can peek ahead -- handle case + where first byte of header is at the end of the buffer after the last + gzip segment */ + len = s->stream.avail_in; + if (len < 2) { + if (len) s->inbuf[0] = s->stream.next_in[0]; + errno = 0; + len = fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); + /* klibc hack */ + if (len == 0 && errno) s->z_err = Z_ERRNO; + s->stream.avail_in += len; + s->stream.next_in = s->inbuf; + if (s->stream.avail_in < 2) { + s->transparent = s->stream.avail_in; + return; + } + } + + /* Peek ahead to check the gzip magic header */ + if (s->stream.next_in[0] != gz_magic[0] || + s->stream.next_in[1] != gz_magic[1]) { + s->transparent = 1; + return; + } + s->stream.avail_in -= 2; + s->stream.next_in += 2; + + /* Check the rest of the gzip header */ + method = get_byte(s); + flags = get_byte(s); + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + s->z_err = Z_DATA_ERROR; + return; + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) (void)get_byte(s); + + if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ + len = (uInt)get_byte(s); + len += ((uInt)get_byte(s))<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while (len-- != 0 && get_byte(s) != EOF) ; + } + if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ + for (len = 0; len < 2; len++) (void)get_byte(s); + } + s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; +} + + /* =========================================================================== + * Cleanup then free the given gz_stream. Return a zlib error code. + Try freeing in the reverse order of allocations. + */ +local int destroy (s) + gz_stream *s; +{ + int err = Z_OK; + + if (!s) return Z_STREAM_ERROR; + + TRYFREE(s->msg); + + if (s->stream.state != NULL) { + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateEnd(&(s->stream)); +#endif + } else if (s->mode == 'r') { + err = inflateEnd(&(s->stream)); + } + } + if (s->file != NULL && fclose(s->file)) { +#ifdef ESPIPE + if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ +#endif + err = Z_ERRNO; + } + if (s->z_err < 0) err = s->z_err; + + TRYFREE(s->inbuf); + TRYFREE(s->outbuf); + TRYFREE(s->path); + TRYFREE(s); + return err; +} + +/* =========================================================================== + Reads the given number of uncompressed bytes from the compressed file. + gzread returns the number of bytes actually read (0 for end of file). +*/ +int ZEXPORT gzread (file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + Bytef *start = (Bytef*)buf; /* starting point for crc computation */ + Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ + + if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; + + if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; + if (s->z_err == Z_STREAM_END) return 0; /* EOF */ + + next_out = (Byte*)buf; + s->stream.next_out = (Bytef*)buf; + s->stream.avail_out = len; + + if (s->stream.avail_out && s->back != EOF) { + *next_out++ = s->back; + s->stream.next_out++; + s->stream.avail_out--; + s->back = EOF; + s->out++; + if (s->last) { + s->z_err = Z_STREAM_END; + return 1; + } + } + + while (s->stream.avail_out != 0) { + + if (s->transparent) { + /* Copy first the lookahead bytes: */ + uInt n = s->stream.avail_in; + if (n > s->stream.avail_out) n = s->stream.avail_out; + if (n > 0) { + zmemcpy(s->stream.next_out, s->stream.next_in, n); + next_out += n; + s->stream.next_out = next_out; + s->stream.next_in += n; + s->stream.avail_out -= n; + s->stream.avail_in -= n; + } + if (s->stream.avail_out > 0) { + s->stream.avail_out -= fread(next_out, 1, s->stream.avail_out, + s->file); + } + len -= s->stream.avail_out; + s->in += len; + s->out += len; + if (len == 0) s->z_eof = 1; + return (int)len; + } + if (s->stream.avail_in == 0 && !s->z_eof) { + + errno = 0; + s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (errno) { + s->z_err = Z_ERRNO; + break; + } + } + s->stream.next_in = s->inbuf; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = inflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + + if (s->z_err == Z_STREAM_END) { + /* Check CRC and original size */ + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + start = s->stream.next_out; + + if (getLong(s) != s->crc) { + s->z_err = Z_DATA_ERROR; + } else { + (void)getLong(s); + /* The uncompressed length returned by above getlong() may be + * different from s->out in case of concatenated .gz files. + * Check for such files: + */ + check_header(s); + if (s->z_err == Z_OK) { + inflateReset(&(s->stream)); + s->crc = crc32(0L, Z_NULL, 0); + } + } + } + if (s->z_err != Z_OK || s->z_eof) break; + } + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + + return (int)(len - s->stream.avail_out); +} + + +/* =========================================================================== + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ +int ZEXPORT gzgetc(file) + gzFile file; +{ + unsigned char c; + + return gzread(file, &c, 1) == 1 ? c : -1; +} + + +/* =========================================================================== + Push one byte back onto the stream. +*/ +int ZEXPORT gzungetc(c, file) + int c; + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF; + s->back = c; + s->out--; + s->last = (s->z_err == Z_STREAM_END); + if (s->last) s->z_err = Z_OK; + s->z_eof = 0; + return c; +} + + +/* =========================================================================== + Reads bytes from the compressed file until len-1 characters are + read, or a newline character is read and transferred to buf, or an + end-of-file condition is encountered. The string is then terminated + with a null character. + gzgets returns buf, or Z_NULL in case of error. + + The current implementation is not optimized at all. +*/ +char * ZEXPORT gzgets(file, buf, len) + gzFile file; + char *buf; + int len; +{ + char *b = buf; + if (buf == Z_NULL || len <= 0) return Z_NULL; + + while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; + *buf = '\0'; + return b == buf && len > 0 ? Z_NULL : b; +} + + +#ifndef NO_GZCOMPRESS +/* =========================================================================== + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of bytes actually written (0 in case of error). +*/ +int ZEXPORT gzwrite (file, buf, len) + gzFile file; + voidpc buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.next_in = (Bytef*)buf; + s->stream.avail_in = len; + + while (s->stream.avail_in != 0) { + + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + break; + } + s->stream.avail_out = Z_BUFSIZE; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + if (s->z_err != Z_OK) break; + } + s->crc = crc32(s->crc, (const Bytef *)buf, len); + + return (int)(len - s->stream.avail_in); +} + + +/* =========================================================================== + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ +#ifdef STDC +#include <stdarg.h> + +int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) +{ + char buf[Z_PRINTF_BUFSIZE]; + va_list va; + int len; + + buf[sizeof(buf) - 1] = 0; + va_start(va, format); +#ifdef NO_vsnprintf +# ifdef HAS_vsprintf_void + (void)vsprintf(buf, format, va); + va_end(va); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = vsprintf(buf, format, va); + va_end(va); +# endif +#else +# ifdef HAS_vsnprintf_void + (void)vsnprintf(buf, sizeof(buf), format, va); + va_end(va); + len = strlen(buf); +# else + len = vsnprintf(buf, sizeof(buf), format, va); + va_end(va); +# endif +#endif + if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, (unsigned)len); +} +#else /* not ANSI C */ + +int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + gzFile file; + const char *format; + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; +{ + char buf[Z_PRINTF_BUFSIZE]; + int len; + + buf[sizeof(buf) - 1] = 0; +#ifdef NO_snprintf +# ifdef HAS_sprintf_void + sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#else +# ifdef HAS_snprintf_void + snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(buf); +# else + len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#endif + if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, len); +} +#endif + +/* =========================================================================== + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ +int ZEXPORT gzputc(file, c) + gzFile file; + int c; +{ + unsigned char cc = (unsigned char) c; /* required for big endian systems */ + + return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; +} + + +/* =========================================================================== + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ +int ZEXPORT gzputs(file, s) + gzFile file; + const char *s; +{ + return gzwrite(file, (char*)s, (unsigned)strlen(s)); +} + + +/* =========================================================================== + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. +*/ +local int do_flush (file, flush) + gzFile file; + int flush; +{ + uInt len; + int done = 0; + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.avail_in = 0; /* should be zero already anyway */ + + for (;;) { + len = Z_BUFSIZE - s->stream.avail_out; + + if (len != 0) { + if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { + s->z_err = Z_ERRNO; + return Z_ERRNO; + } + s->stream.next_out = s->outbuf; + s->stream.avail_out = Z_BUFSIZE; + } + if (done) break; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), flush); + s->out -= s->stream.avail_out; + + /* Ignore the second of two consecutive flushes: */ + if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; + + /* deflate has finished flushing only when it hasn't used up + * all the available space in the output buffer: + */ + done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); + + if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; + } + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} + +int ZEXPORT gzflush (file, flush) + gzFile file; + int flush; +{ + gz_stream *s = (gz_stream*)file; + int err = do_flush (file, flush); + + if (err) return err; + fflush(s->file); + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} +#endif /* NO_GZCOMPRESS */ + +/* =========================================================================== + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error. + SEEK_END is not implemented, returns error. + In this version of the library, gzseek can be extremely slow. +*/ +#if 0 /* COM32: seek not supported */ + +z_off_t ZEXPORT gzseek (file, offset, whence) + gzFile file; + z_off_t offset; + int whence; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || whence == SEEK_END || + s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { + return -1L; + } + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return -1L; +#else + if (whence == SEEK_SET) { + offset -= s->in; + } + if (offset < 0) return -1L; + + /* At this point, offset is the number of zero bytes to write. */ + if (s->inbuf == Z_NULL) { + s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ + if (s->inbuf == Z_NULL) return -1L; + zmemzero(s->inbuf, Z_BUFSIZE); + } + while (offset > 0) { + uInt size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (uInt)offset; + + size = gzwrite(file, s->inbuf, size); + if (size == 0) return -1L; + + offset -= size; + } + return s->in; +#endif + } + /* Rest of function is for reading only */ + + /* compute absolute position */ + if (whence == SEEK_CUR) { + offset += s->out; + } + if (offset < 0) return -1L; + + if (s->transparent) { + /* map to fseek */ + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; + + s->in = s->out = offset; + return offset; + } + + /* For a negative seek, rewind and use positive seek */ + if (offset >= s->out) { + offset -= s->out; + } else if (gzrewind(file) < 0) { + return -1L; + } + /* offset is now the number of bytes to skip. */ + + if (offset != 0 && s->outbuf == Z_NULL) { + s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); + if (s->outbuf == Z_NULL) return -1L; + } + if (offset && s->back != EOF) { + s->back = EOF; + s->out++; + offset--; + if (s->last) s->z_err = Z_STREAM_END; + } + while (offset > 0) { + int size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (int)offset; + + size = gzread(file, s->outbuf, (uInt)size); + if (size <= 0) return -1L; + offset -= size; + } + return s->out; +} + +#endif + +/* =========================================================================== + Rewinds input file. +*/ +#if 0 /* COM32: seek not supported */ + +int ZEXPORT gzrewind (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return -1; + + s->z_err = Z_OK; + s->z_eof = 0; + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + s->crc = crc32(0L, Z_NULL, 0); + if (!s->transparent) (void)inflateReset(&s->stream); + s->in = 0; + s->out = 0; + return fseek(s->file, s->start, SEEK_SET); +} +#endif + +/* =========================================================================== + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. +*/ +#if 0 /* COM32: seek not supported */ + +z_off_t ZEXPORT gztell (file) + gzFile file; +{ + return gzseek(file, 0L, SEEK_CUR); +} +#endif + +/* =========================================================================== + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ +int ZEXPORT gzeof (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + /* With concatenated compressed files that can have embedded + * crc trailers, z_eof is no longer the only/best indicator of EOF + * on a gz_stream. Handle end-of-stream error explicitly here. + */ + if (s == NULL || s->mode != 'r') return 0; + if (s->z_eof) return 1; + return s->z_err == Z_STREAM_END; +} + +/* =========================================================================== + Outputs a long in LSB order to the given file +*/ +local void putLong (file, x) + FILE *file; + uLong x; +{ + int n; + for (n = 0; n < 4; n++) { + fputc((int)(x & 0xff), file); + x >>= 8; + } +} + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets z_err in case + of error. +*/ +local uLong getLong (s) + gz_stream *s; +{ + uLong x = (uLong)get_byte(s); + int c; + + x += ((uLong)get_byte(s))<<8; + x += ((uLong)get_byte(s))<<16; + c = get_byte(s); + if (c == EOF) s->z_err = Z_DATA_ERROR; + x += ((uLong)c)<<24; + return x; +} + +/* =========================================================================== + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. +*/ +int ZEXPORT gzclose (file) + gzFile file; +{ + int err; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return Z_STREAM_ERROR; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return Z_STREAM_ERROR; +#else + err = do_flush (file, Z_FINISH); + if (err != Z_OK) return destroy((gz_stream*)file); + + putLong (s->file, s->crc); + putLong (s->file, (uLong)(s->in & 0xffffffff)); +#endif + } + return destroy((gz_stream*)file); +} + +/* =========================================================================== + Returns the error message for the last error which occured on the + given compressed file. errnum is set to zlib error number. If an + error occured in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ +const char * ZEXPORT gzerror (file, errnum) + gzFile file; + int *errnum; +{ + char *m; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) { + *errnum = Z_STREAM_ERROR; + return (const char*)ERR_MSG(Z_STREAM_ERROR); + } + *errnum = s->z_err; + if (*errnum == Z_OK) return (const char*)""; + + m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); + + if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); + + TRYFREE(s->msg); + s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); + if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR); + strcpy(s->msg, s->path); + strcat(s->msg, ": "); + strcat(s->msg, m); + return (const char*)s->msg; +} + +/* =========================================================================== + Clear the error and end-of-file flags, and do the same for the real file. +*/ +void ZEXPORT gzclearerr (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return; + if (s->z_err != Z_STREAM_END) s->z_err = Z_OK; + s->z_eof = 0; + /* klibc hack */ + /* clearerr(s->file); */ +} diff --git a/syslinux/com32/lib/zlib/infback.c b/syslinux/com32/lib/zlib/infback.c new file mode 100644 index 0000000..110b03b --- /dev/null +++ b/syslinux/com32/lib/zlib/infback.c @@ -0,0 +1,619 @@ +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + This code is largely copied from inflate.c. Normally either infback.o or + inflate.o would be linked into an application--not both. The interface + with inffast.c is retained so that optimized assembler-coded versions of + inflate_fast() can be used with either inflate.c or infback.c. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + windowBits is in the range 8..15, and window is a user-supplied + window and output buffer that is 2**windowBits bytes. + */ +int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) +z_stream FAR *strm; +int windowBits; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL || + windowBits < 8 || windowBits > 15) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (voidpf)state; + state->wbits = windowBits; + state->wsize = 1U << windowBits; + state->window = window; + state->write = 0; + state->whave = 0; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +/* Macros for inflateBack(): */ + +/* Load returned state from inflate_fast() */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Set state from registers for inflate_fast() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = state->window; \ + left = state->wsize; \ + state->whave = left; \ + if (out(out_desc, put, left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) +z_stream FAR *strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + state->mode = TYPE; + state->last = 0; + state->whave = 0; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = state->window; + left = state->wsize; + + /* Inflate until end of block marked as last */ + for (;;) + switch (state->mode) { + case TYPE: + /* determine and dispatch block type */ + if (state->last) { + BYTEBITS(); + state->mode = DONE; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + + /* copy stored block from input to output */ + while (state->length != 0) { + copy = state->length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + + case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= 6 && left >= 258) { + RESTORE(); + if (state->whave < state->wsize) + state->whave = state->wsize - left; + inflate_fast(strm, state->wsize); + LOAD(); + break; + } + + /* get a literal, length, or end-of-block code */ + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + + /* process literal */ + if (this.op == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + ROOM(); + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + } + + /* process end of block */ + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + + /* invalid code */ + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + + /* get distance code */ + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + + /* get distance extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->wsize - (state->whave < state->wsize ? + left : 0)) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = state->wsize - state->offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - state->offset; + copy = left; + } + if (copy > state->length) copy = state->length; + state->length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (state->length != 0); + break; + + case DONE: + /* inflate stream terminated properly -- write leftover output */ + ret = Z_STREAM_END; + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left)) + ret = Z_BUF_ERROR; + } + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Return unused input */ + inf_leave: + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBackEnd(strm) +z_stream FAR *strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/syslinux/com32/lib/zlib/inffast.c b/syslinux/com32/lib/zlib/inffast.c new file mode 100644 index 0000000..c716440 --- /dev/null +++ b/syslinux/com32/lib/zlib/inffast.c @@ -0,0 +1,305 @@ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifndef ASMINF + +/* Allow machine dependent optimization for post-increment or pre-increment. + Based on testing to date, + Pre-increment preferred for: + - PowerPC G3 (Adler) + - MIPS R5000 (Randers-Pehrson) + Post-increment preferred for: + - none + No measurable difference: + - Pentium III (Anderson) + - 68060 (Nikl) + */ +#ifdef POSTINC +# define OFF 0 +# define PUP(a) *(a)++ +#else +# define OFF 1 +# define PUP(a) *++(a) +#endif + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + unsigned char FAR *in; /* local strm->next_in */ + unsigned char FAR *last; /* while in < last, enough input available */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code this; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in - OFF; + last = in + (strm->avail_in - 5); + out = strm->next_out - OFF; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); + wsize = state->wsize; + whave = state->whave; + write = state->write; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = lcode[hold & lmask]; + dolen: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op == 0) { /* literal */ + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + PUP(out) = (unsigned char)(this.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = dcode[hold & dmask]; + dodist: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op & 16) { /* distance base */ + dist = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + from = window - OFF; + if (write == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (write < op) { /* wrap around window */ + from += wsize + write - op; + op -= write; + if (op < len) { /* some from end of window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = window - OFF; + if (write < len) { /* some from start of window */ + op = write; + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += write - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } while (len > 2); + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + this = dcode[this.val + (hold & ((1U << op) - 1))]; + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + this = lcode[this.val + (hold & ((1U << op) - 1))]; + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in + OFF; + strm->next_out = out + OFF; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and write == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/syslinux/com32/lib/zlib/inffast.h b/syslinux/com32/lib/zlib/inffast.h new file mode 100644 index 0000000..1e88d2d --- /dev/null +++ b/syslinux/com32/lib/zlib/inffast.h @@ -0,0 +1,11 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/syslinux/com32/lib/zlib/inffixed.h b/syslinux/com32/lib/zlib/inffixed.h new file mode 100644 index 0000000..75ed4b5 --- /dev/null +++ b/syslinux/com32/lib/zlib/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. It + is part of the implementation of the compression library and + is subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/syslinux/com32/lib/zlib/inflate.c b/syslinux/com32/lib/zlib/inflate.c new file mode 100644 index 0000000..a53b5c7 --- /dev/null +++ b/syslinux/com32/lib/zlib/inflate.c @@ -0,0 +1,1270 @@ +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common write == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); +local int updatewindow OF((z_streamp strm, unsigned out)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, + unsigned len)); + +int ZEXPORT inflateReset(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->wsize = 0; + state->whave = 0; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) +z_streamp strm; +int windowBits; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (voidpf)state; + if (windowBits < 0) { + state->wrap = 0; + windowBits = -windowBits; + } + else { + state->wrap = (windowBits >> 4) + 1; +#ifdef GUNZIP + if (windowBits < 48) windowBits &= 15; +#endif + } + if (windowBits < 8 || windowBits > 15) { + ZFREE(strm, state); + strm->state = Z_NULL; + return Z_STREAM_ERROR; + } + state->wbits = (unsigned)windowBits; + state->window = Z_NULL; + return inflateReset(strm); +} + +int ZEXPORT inflateInit_(strm, version, stream_size) +z_streamp strm; +const char *version; +int stream_size; +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include <stdio.h> + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, + state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(strm, out) +z_streamp strm; +unsigned out; +{ + struct inflate_state FAR *state; + unsigned copy, dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->write = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + copy = out - strm->avail_out; + if (copy >= state->wsize) { + zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); + state->write = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->write; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->write, strm->next_out - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, strm->next_out - copy, copy); + state->write = copy; + state->whave = state->wsize; + } + else { + state->write += dist; + if (state->write == state->wsize) state->write = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Reverse the bytes in a 32-bit value */ +#define REVERSE(q) \ + ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(strm, flush) +z_streamp strm; +int flush; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + state->flags = 0; /* expect zlib header */ + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + if (BITS(4) + 8 > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + case TIME: + NEEDBITS(32); + if (state->flags & 0x0200) CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + case OS: + NEEDBITS(16); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + } + state->mode = EXTRA; + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->mode = NAME; + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + } while (len && copy < have); + if (state->flags & 0x02000) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + state->mode = COMMENT; + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + } while (len && copy < have); + if (state->flags & 0x02000) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + state->mode = HCRC; + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if (hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = REVERSE(hold); + INITBITS(); + state->mode = DICT; + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + case TYPE: + if (flush == Z_BLOCK) goto inf_leave; + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY; + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + break; + } + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + if ((int)(this.op) == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + state->mode = LIT; + break; + } + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(this.op) & 15; + state->mode = LENEXT; + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->mode = DIST; + case DIST: + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + state->extra = (unsigned)(this.op) & 15; + state->mode = DISTEXT; + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->whave + out - left) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->write) { + copy -= state->write; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->write - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if (out) + strm->adler = state->check = + UPDATE(state->check, put - out, out); + out = left; + if (( +#ifdef GUNZIP + state->flags ? hold : +#endif + REVERSE(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if (hold != (state->total & 0xffffffffUL)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) + if (updatewindow(strm, out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if (state->wrap && out) + strm->adler = state->check = + UPDATE(state->check, strm->next_out - out, out); + strm->data_type = state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) +z_streamp strm; +const Bytef *dictionary; +uInt dictLength; +{ + struct inflate_state FAR *state; + unsigned long id; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->mode != DICT) return Z_STREAM_ERROR; + + /* check for correct dictionary id */ + id = adler32(0L, Z_NULL, 0); + id = adler32(id, dictionary, dictLength); + if (id != state->check) return Z_DATA_ERROR; + + /* copy dictionary to window */ + if (updatewindow(strm, strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + if (dictLength > state->wsize) { + zmemcpy(state->window, dictionary + dictLength - state->wsize, + state->wsize); + state->whave = state->wsize; + } + else { + zmemcpy(state->window + state->wsize - dictLength, dictionary, + dictLength); + state->whave = dictLength; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(have, buf, len) +unsigned FAR *have; +unsigned char FAR *buf; +unsigned len; +{ + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(strm) +z_streamp strm; +{ + unsigned len; /* number of bytes to look at or looked at */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(dest, source) +z_streamp dest; +z_streamp source; +{ + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + + /* check input */ + if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || + source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + *dest = *source; + *copy = *state; + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) + zmemcpy(window, state->window, 1U << state->wbits); + copy->window = window; + dest->state = (voidpf)copy; + return Z_OK; +} diff --git a/syslinux/com32/lib/zlib/inflate.h b/syslinux/com32/lib/zlib/inflate.h new file mode 100644 index 0000000..9a12c8f --- /dev/null +++ b/syslinux/com32/lib/zlib/inflate.h @@ -0,0 +1,117 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD, /* i: waiting for magic header */ +#ifdef GUNZIP + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ +#endif + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN, /* i: waiting for length/lit code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ +#ifdef GUNZIP + LENGTH, /* i: waiting for 32-bit length (gzip) */ +#endif + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to the BAD or MEM mode -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME + NAME -> COMMENT -> HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + Read deflate blocks: + TYPE -> STORED or TABLE or LEN or CHECK + STORED -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN + Read deflate codes: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 7K bytes. */ +struct inflate_state { + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ +}; diff --git a/syslinux/com32/lib/zlib/inftrees.c b/syslinux/com32/lib/zlib/inftrees.c new file mode 100644 index 0000000..3bb5639 --- /dev/null +++ b/syslinux/com32/lib/zlib/inftrees.c @@ -0,0 +1,321 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#define MAXBITS 15 + +const char inflate_copyright[] = + " inflate 1.2.1 Copyright 1995-2003 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int inflate_table(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code this; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + int end; /* use base and extra for symbol > end */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 76, 66}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) return -1; /* no codes! */ + for (min = 1; min <= MAXBITS; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || (codes - count[0] != 1))) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked when a LENS table is being made + against the space in *table, ENOUGH, minus the maximum space needed by + the worst case distance code, MAXD. This should never happen, but the + sufficiency of ENOUGH has not been proven exhaustively, hence the check. + This assumes that when type == LENS, bits == 9. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + end = 19; + break; + case LENS: + base = lbase; + base -= 257; + extra = lext; + extra -= 257; + end = 256; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + this.bits = (unsigned char)(len - drop); + if ((int)(work[sym]) < end) { + this.op = (unsigned char)0; + this.val = work[sym]; + } + else if ((int)(work[sym]) > end) { + this.op = (unsigned char)(extra[work[sym]]); + this.val = base[work[sym]]; + } + else { + this.op = (unsigned char)(32 + 64); /* end of block */ + this.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + do { + fill -= incr; + next[(huff >> drop) + fill] = this; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += 1U << curr; + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* + Fill in rest of table for incomplete codes. This loop is similar to the + loop above in incrementing huff for table indices. It is assumed that + len is equal to curr + drop, so there is no loop needed to increment + through high index bits. When the current sub-table is filled, the loop + drops back to the root table to fill in any remaining entries there. + */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)(len - drop); + this.val = (unsigned short)0; + while (huff != 0) { + /* when done with sub-table, drop back to root table */ + if (drop != 0 && (huff & mask) != low) { + drop = 0; + len = root; + next = *table; + curr = root; + this.bits = (unsigned char)len; + } + + /* put invalid code marker in table */ + next[huff >> drop] = this; + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/syslinux/com32/lib/zlib/inftrees.h b/syslinux/com32/lib/zlib/inftrees.h new file mode 100644 index 0000000..82d365a --- /dev/null +++ b/syslinux/com32/lib/zlib/inftrees.h @@ -0,0 +1,55 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1004 code structures (850 for length/literals + and 154 for distances, the latter actually the result of an + exhaustive search). The true maximum is not known, but the value + below is more than safe. */ +#define ENOUGH 1440 +#define MAXD 154 + +/* Type of code to build for inftable() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +extern int inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/syslinux/com32/lib/zlib/minigzip.c b/syslinux/com32/lib/zlib/minigzip.c new file mode 100644 index 0000000..744e3ab --- /dev/null +++ b/syslinux/com32/lib/zlib/minigzip.c @@ -0,0 +1,323 @@ +/* minigzip.c -- simulate gzip using the zlib compression library + * Copyright (C) 1995-2002 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * minigzip is a minimal implementation of the gzip utility. This is + * only an example of using zlib and isn't meant to replace the + * full-featured gzip. No attempt is made to deal with file systems + * limiting names to 14 or 8+3 characters, etc... Error checking is + * very limited. So use minigzip only for testing; use gzip for the + * real thing. On MSDOS, use only on file names without extension + * or in pipe mode. + */ + +/* @(#) $Id: minigzip.c,v 1.1 2005/01/08 05:38:13 hpa Exp $ */ + +#include <stdio.h> +#include "zlib.h" + +#ifdef STDC +# include <string.h> +# include <stdlib.h> +#else + extern void exit OF((int)); +#endif + +#ifdef USE_MMAP +# include <sys/types.h> +# include <sys/mman.h> +# include <sys/stat.h> +#endif + +#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__) +# include <fcntl.h> +# include <io.h> +# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif + +#ifdef VMS +# define unlink delete +# define GZ_SUFFIX "-gz" +#endif +#ifdef RISCOS +# define unlink remove +# define GZ_SUFFIX "-gz" +# define fileno(file) file->__file +#endif +#if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include <unix.h> /* for fileno */ +#endif + +#ifndef WIN32 /* unlink already in stdio.h for WIN32 */ + extern int unlink OF((const char *)); +#endif + +#ifndef GZ_SUFFIX +# define GZ_SUFFIX ".gz" +#endif +#define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1) + +#define BUFLEN 16384 +#define MAX_NAME_LEN 1024 + +#ifdef MAXSEG_64K +# define local static + /* Needed for systems with limitation on stack size. */ +#else +# define local +#endif + +char *prog; + +void error OF((const char *msg)); +void gz_compress OF((FILE *in, gzFile out)); +#ifdef USE_MMAP +int gz_compress_mmap OF((FILE *in, gzFile out)); +#endif +void gz_uncompress OF((gzFile in, FILE *out)); +void file_compress OF((char *file, char *mode)); +void file_uncompress OF((char *file)); +int main OF((int argc, char *argv[])); + +/* =========================================================================== + * Display error message and exit + */ +void error(msg) + const char *msg; +{ + fprintf(stderr, "%s: %s\n", prog, msg); + exit(1); +} + +/* =========================================================================== + * Compress input to output then close both files. + */ + +void gz_compress(in, out) + FILE *in; + gzFile out; +{ + local char buf[BUFLEN]; + int len; + int err; + +#ifdef USE_MMAP + /* Try first compressing with mmap. If mmap fails (minigzip used in a + * pipe), use the normal fread loop. + */ + if (gz_compress_mmap(in, out) == Z_OK) return; +#endif + for (;;) { + errno = 0; + len = (int)fread(buf, 1, sizeof(buf), in); + if (!len && errno) { + perror("fread"); + exit(1); + } + if (len == 0) break; + + if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err)); + } + fclose(in); + if (gzclose(out) != Z_OK) error("failed gzclose"); +} + +#ifdef USE_MMAP /* MMAP version, Miguel Albrecht <malbrech@eso.org> */ + +/* Try compressing the input file at once using mmap. Return Z_OK if + * if success, Z_ERRNO otherwise. + */ +int gz_compress_mmap(in, out) + FILE *in; + gzFile out; +{ + int len; + int err; + int ifd = fileno(in); + caddr_t buf; /* mmap'ed buffer for the entire input file */ + off_t buf_len; /* length of the input file */ + struct stat sb; + + /* Determine the size of the file, needed for mmap: */ + if (fstat(ifd, &sb) < 0) return Z_ERRNO; + buf_len = sb.st_size; + if (buf_len <= 0) return Z_ERRNO; + + /* Now do the actual mmap: */ + buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0); + if (buf == (caddr_t)(-1)) return Z_ERRNO; + + /* Compress the whole file at once: */ + len = gzwrite(out, (char *)buf, (unsigned)buf_len); + + if (len != (int)buf_len) error(gzerror(out, &err)); + + munmap(buf, buf_len); + fclose(in); + if (gzclose(out) != Z_OK) error("failed gzclose"); + return Z_OK; +} +#endif /* USE_MMAP */ + +/* =========================================================================== + * Uncompress input to output then close both files. + */ +void gz_uncompress(in, out) + gzFile in; + FILE *out; +{ + local char buf[BUFLEN]; + int len; + int err; + + for (;;) { + len = gzread(in, buf, sizeof(buf)); + if (len < 0) error (gzerror(in, &err)); + if (len == 0) break; + + if ((int)fwrite(buf, 1, (unsigned)len, out) != len) { + error("failed fwrite"); + } + } + if (fclose(out)) error("failed fclose"); + + if (gzclose(in) != Z_OK) error("failed gzclose"); +} + + +/* =========================================================================== + * Compress the given file: create a corresponding .gz file and remove the + * original. + */ +void file_compress(file, mode) + char *file; + char *mode; +{ + local char outfile[MAX_NAME_LEN]; + FILE *in; + gzFile out; + + strcpy(outfile, file); + strcat(outfile, GZ_SUFFIX); + + in = fopen(file, "rb"); + if (in == NULL) { + perror(file); + exit(1); + } + out = gzopen(outfile, mode); + if (out == NULL) { + fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile); + exit(1); + } + gz_compress(in, out); + + unlink(file); +} + + +/* =========================================================================== + * Uncompress the given file and remove the original. + */ +void file_uncompress(file) + char *file; +{ + local char buf[MAX_NAME_LEN]; + char *infile, *outfile; + FILE *out; + gzFile in; + uInt len = (uInt)strlen(file); + + strcpy(buf, file); + + if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) { + infile = file; + outfile = buf; + outfile[len-3] = '\0'; + } else { + outfile = file; + infile = buf; + strcat(infile, GZ_SUFFIX); + } + in = gzopen(infile, "rb"); + if (in == NULL) { + fprintf(stderr, "%s: can't gzopen %s\n", prog, infile); + exit(1); + } + out = fopen(outfile, "wb"); + if (out == NULL) { + perror(file); + exit(1); + } + + gz_uncompress(in, out); + + unlink(infile); +} + + +/* =========================================================================== + * Usage: minigzip [-d] [-f] [-h] [-r] [-1 to -9] [files...] + * -d : decompress + * -f : compress with Z_FILTERED + * -h : compress with Z_HUFFMAN_ONLY + * -r : compress with Z_RLE + * -1 to -9 : compression level + */ + +int main(argc, argv) + int argc; + char *argv[]; +{ + int uncompr = 0; + gzFile file; + char outmode[20]; + + strcpy(outmode, "wb6 "); + + prog = argv[0]; + argc--, argv++; + + while (argc > 0) { + if (strcmp(*argv, "-d") == 0) + uncompr = 1; + else if (strcmp(*argv, "-f") == 0) + outmode[3] = 'f'; + else if (strcmp(*argv, "-h") == 0) + outmode[3] = 'h'; + else if (strcmp(*argv, "-r") == 0) + outmode[3] = 'R'; + else if ((*argv)[0] == '-' && (*argv)[1] >= '1' && (*argv)[1] <= '9' && + (*argv)[2] == 0) + outmode[2] = (*argv)[1]; + else + break; + argc--, argv++; + } + if (argc == 0) { + SET_BINARY_MODE(stdin); + SET_BINARY_MODE(stdout); + if (uncompr) { + file = gzdopen(fileno(stdin), "rb"); + if (file == NULL) error("can't gzdopen stdin"); + gz_uncompress(file, stdout); + } else { + file = gzdopen(fileno(stdout), outmode); + if (file == NULL) error("can't gzdopen stdout"); + gz_compress(stdin, file); + } + } else { + do { + if (uncompr) { + file_uncompress(*argv); + } else { + file_compress(*argv, outmode); + } + } while (argv++, --argc); + } + return 0; +} diff --git a/syslinux/com32/lib/zlib/trees.c b/syslinux/com32/lib/zlib/trees.c new file mode 100644 index 0000000..2747100 --- /dev/null +++ b/syslinux/com32/lib/zlib/trees.c @@ -0,0 +1,1215 @@ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2003 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* @(#) $Id: trees.c,v 1.1 2005/01/08 05:38:13 hpa Exp $ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef DEBUG +# include <ctype.h> +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, ct_data *ltree, + ct_data *dtree)); +local void set_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (value << s->bi_valid); + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (val << s->bi_valid);\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG */ + + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1<<extra_lbits[code]); n++) { + _length_code[length++] = (uch)code; + } + } + Assert (length == 256, "tr_static_init: length != 256"); + /* Note that the length 255 (match length 258) can be represented + * in two different ways: code 284 + 5 bits or code 285, so we + * overwrite length_code[255] to use the best encoding: + */ + _length_code[length-1] = (uch)code; + + /* Initialize the mapping dist (0..32K) -> dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<<extra_dbits[code]); n++) { + _dist_code[dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: dist != 256"); + dist >>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Genererate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef DEBUG +# include <stdio.h> +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#ifdef DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if (tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1, + "inconsistent bit counts"); + Tracev((stderr,"\ngen_codes: max_code %d ", max_code)); + + for (n = 0; n <= max_code; n++) { + int len = tree[n].Len; + if (len == 0) continue; + /* Now reverse the bits */ + tree[n].Code = bi_reverse(next_code[len]++, len); + + Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ", + n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1)); + } +} + +/* =========================================================================== + * Construct one Huffman tree and assigns the code bit strings and lengths. + * Update the total bit length for the current block. + * IN assertion: the field freq is set for all tree elements. + * OUT assertions: the fields len and code are set to the optimal bit length + * and corresponding code. The length opt_len is updated; static_len is + * also updated if stree is not null. The field max_code is set. + */ +local void build_tree(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void _tr_stored_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ +#ifdef DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; +#endif + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; +#endif + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +void _tr_flush_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is ascii or binary */ + if (s->data_type == Z_UNKNOWN) set_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, eof); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+eof, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1)+eof, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (eof) { + bi_windup(s); +#ifdef DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*eof)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + +#ifdef TRUNCATE_BLOCK + /* Try to guess if it is profitable to stop the current block here */ + if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } +#endif + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + ct_data *ltree; /* literal tree */ + ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Set the data type to ASCII or BINARY, using a crude approximation: + * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. + * IN assertion: the fields freq of dyn_ltree are set and the total of all + * frequencies does not exceed 64K (to fit in an int on 16 bit machines). + */ +local void set_data_type(s) + deflate_state *s; +{ + int n = 0; + unsigned ascii_freq = 0; + unsigned bin_freq = 0; + while (n < 7) bin_freq += s->dyn_ltree[n++].Freq; + while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq; + while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq; + s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII); +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG + s->bits_sent += (ulg)len<<3; +#endif + while (len--) { + put_byte(s, *buf++); + } +} diff --git a/syslinux/com32/lib/zlib/trees.h b/syslinux/com32/lib/zlib/trees.h new file mode 100644 index 0000000..72facf9 --- /dev/null +++ b/syslinux/com32/lib/zlib/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/syslinux/com32/lib/zlib/uncompr.c b/syslinux/com32/lib/zlib/uncompr.c new file mode 100644 index 0000000..e95a8e9 --- /dev/null +++ b/syslinux/com32/lib/zlib/uncompr.c @@ -0,0 +1,61 @@ +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: uncompr.c,v 1.1 2005/01/08 05:38:13 hpa Exp $ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ +int ZEXPORT uncompress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) + return Z_DATA_ERROR; + return err; + } + *destLen = stream.total_out; + + err = inflateEnd(&stream); + return err; +} diff --git a/syslinux/com32/lib/zlib/zconf.in.h b/syslinux/com32/lib/zlib/zconf.in.h new file mode 100644 index 0000000..adfabdd --- /dev/null +++ b/syslinux/com32/lib/zlib/zconf.in.h @@ -0,0 +1,323 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zconf.in.h,v 1.1 2005/01/08 05:38:13 hpa Exp $ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflatePrime z_deflatePrime +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table + +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) +# define WIN32 +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include <windows.h> + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include <sys/types.h> /* for off_t */ +# include <unistd.h> /* for SEEK_* and off_t */ +# ifdef VMS +# include <unixio.h> /* for off_t */ +# endif +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +#define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/syslinux/com32/lib/zlib/zlib.3 b/syslinux/com32/lib/zlib/zlib.3 new file mode 100644 index 0000000..8900984 --- /dev/null +++ b/syslinux/com32/lib/zlib/zlib.3 @@ -0,0 +1,159 @@ +.TH ZLIB 3 "17 November 2003" +.SH NAME +zlib \- compression/decompression library +.SH SYNOPSIS +[see +.I zlib.h +for full description] +.SH DESCRIPTION +The +.I zlib +library is a general purpose data compression library. +The code is thread safe. +It provides in-memory compression and decompression functions, +including integrity checks of the uncompressed data. +This version of the library supports only one compression method (deflation) +but other algorithms will be added later +and will have the same stream interface. +.LP +Compression can be done in a single step if the buffers are large enough +(for example if an input file is mmap'ed), +or can be done by repeated calls of the compression function. +In the latter case, +the application must provide more input and/or consume the output +(providing more output space) before each call. +.LP +The library also supports reading and writing files in +.IR gzip (1) +(.gz) format +with an interface similar to that of stdio. +.LP +The library does not install any signal handler. +The decoder checks the consistency of the compressed data, +so the library should never crash even in case of corrupted input. +.LP +All functions of the compression library are documented in the file +.IR zlib.h . +The distribution source includes examples of use of the library +in the files +.I example.c +and +.IR minigzip.c . +.LP +Changes to this version are documented in the file +.I ChangeLog +that accompanies the source, +and are concerned primarily with bug fixes and portability enhancements. +.LP +A Java implementation of +.I zlib +is available in the Java Development Kit 1.1: +.IP +http://www.javasoft.com/products/JDK/1.1/docs/api/Package-java.util.zip.html +.LP +A Perl interface to +.IR zlib , +written by Paul Marquess (pmqs@cpan.org), +is available at CPAN (Comprehensive Perl Archive Network) sites, +including: +.IP +http://www.cpan.org/modules/by-module/Compress/ +.LP +A Python interface to +.IR zlib , +written by A.M. Kuchling (amk@magnet.com), +is available in Python 1.5 and later versions: +.IP +http://www.python.org/doc/lib/module-zlib.html +.LP +A +.I zlib +binding for +.IR tcl (1), +written by Andreas Kupries (a.kupries@westend.com), +is availlable at: +.IP +http://www.westend.com/~kupries/doc/trf/man/man.html +.LP +An experimental package to read and write files in .zip format, +written on top of +.I zlib +by Gilles Vollant (info@winimage.com), +is available at: +.IP +http://www.winimage.com/zLibDll/unzip.html +and also in the +.I contrib/minizip +directory of the main +.I zlib +web site. +.SH "SEE ALSO" +The +.I zlib +web site can be found at either of these locations: +.IP +http://www.zlib.org +.br +http://www.gzip.org/zlib/ +.LP +The data format used by the zlib library is described by RFC +(Request for Comments) 1950 to 1952 in the files: +.IP +http://www.ietf.org/rfc/rfc1950.txt (concerning zlib format) +.br +http://www.ietf.org/rfc/rfc1951.txt (concerning deflate format) +.br +http://www.ietf.org/rfc/rfc1952.txt (concerning gzip format) +.LP +These documents are also available in other formats from: +.IP +ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html +.LP +Mark Nelson (markn@ieee.org) wrote an article about +.I zlib +for the Jan. 1997 issue of Dr. Dobb's Journal; +a copy of the article is available at: +.IP +http://dogma.net/markn/articles/zlibtool/zlibtool.htm +.SH "REPORTING PROBLEMS" +Before reporting a problem, +please check the +.I zlib +web site to verify that you have the latest version of +.IR zlib ; +otherwise, +obtain the latest version and see if the problem still exists. +Please read the +.I zlib +FAQ at: +.IP +http://www.gzip.org/zlib/zlib_faq.html +.LP +before asking for help. +Send questions and/or comments to zlib@gzip.org, +or (for the Windows DLL version) to Gilles Vollant (info@winimage.com). +.SH AUTHORS +Version 1.2.1 +Copyright (C) 1995-2003 Jean-loup Gailly (jloup@gzip.org) +and Mark Adler (madler@alumni.caltech.edu). +.LP +This software is provided "as-is," +without any express or implied warranty. +In no event will the authors be held liable for any damages +arising from the use of this software. +See the distribution directory with respect to requirements +governing redistribution. +The deflate format used by +.I zlib +was defined by Phil Katz. +The deflate and +.I zlib +specifications were written by L. Peter Deutsch. +Thanks to all the people who reported problems and suggested various +improvements in +.IR zlib ; +who are too numerous to cite here. +.LP +UNIX manual page by R. P. C. Rodgers, +U.S. National Library of Medicine (rodgers@nlm.nih.gov). +.\" end of man page diff --git a/syslinux/com32/lib/zlib/zutil.c b/syslinux/com32/lib/zlib/zutil.c new file mode 100644 index 0000000..609c673 --- /dev/null +++ b/syslinux/com32/lib/zlib/zutil.c @@ -0,0 +1,319 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zutil.c,v 1.1 2005/01/08 05:38:13 hpa Exp $ */ + +#include "zutil.h" + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#ifndef STDC +extern void exit OF((int)); +#endif + +const char * const z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +uLong ZEXPORT zlibCompileFlags() +{ + uLong flags; + + flags = 0; + switch (sizeof(uInt)) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch (sizeof(uLong)) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch (sizeof(voidpf)) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch (sizeof(z_off_t)) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef DEBUG + flags += 1 << 8; +#endif +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1 << 16; +#endif +#ifdef NO_GZIP + flags += 1 << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1 << 20; +#endif +#ifdef FASTEST + flags += 1 << 21; +#endif +#ifdef STDC +# ifdef NO_vsnprintf + flags += 1 << 25; +# ifdef HAS_vsprintf_void + flags += 1 << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1 << 26; +# endif +# endif +#else + flags += 1 << 24; +# ifdef NO_snprintf + flags += 1 << 25; +# ifdef HAS_sprintf_void + flags += 1 << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1 << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef DEBUG + +# ifndef verbose +# define verbose 0 +# endif +int z_verbose = verbose; + +void z_error (m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(err) + int err; +{ + return ERR_MSG(err); +} + +#if defined(_WIN32_WCE) + /* does not exist on WCE */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void zmemcpy(dest, source, len) + Bytef* dest; + const Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + + +#ifdef SYS16BIT + +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ + +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + if (opaque) items += size - size; /* make compiler happy */ + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); +} + +void zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ diff --git a/syslinux/com32/lib/zlib/zutil.h b/syslinux/com32/lib/zlib/zutil.h new file mode 100644 index 0000000..560f95f --- /dev/null +++ b/syslinux/com32/lib/zlib/zutil.h @@ -0,0 +1,258 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id: zutil.h,v 1.1 2005/01/08 05:38:13 hpa Exp $ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#define ZLIB_INTERNAL +#include "zlib.h" + +#ifdef STDC +# include <stddef.h> +# include <string.h> +# include <stdlib.h> +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include <errno.h> +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include <alloc.h> +# endif +# else /* MSC or DJGPP */ +# include <malloc.h> +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include <unix.h> /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#ifdef WIN32 +# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ +# define OS_CODE 0x0b +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0f +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS + /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 + /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# define vsnprintf _vsnprintf +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +#endif + +#ifdef HAVE_STRERROR + extern char *strerror OF((int)); +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include <stdio.h> + extern int z_verbose; + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* ZUTIL_H */ diff --git a/syslinux/com32/libutil/Makefile b/syslinux/com32/libutil/Makefile new file mode 100644 index 0000000..cd4fdb2 --- /dev/null +++ b/syslinux/com32/libutil/Makefile @@ -0,0 +1,112 @@ +#ident "$Id: Makefile,v 1.8 2005/01/21 00:49:46 hpa Exp $" +## ----------------------------------------------------------------------- +## +## Copyright 2001-2004 H. Peter Anvin - All Rights Reserved +## +## Permission is hereby granted, free of charge, to any person +## obtaining a copy of this software and associated documentation +## files (the "Software"), to deal in the Software without +## restriction, including without limitation the rights to use, +## copy, modify, merge, publish, distribute, sublicense, and/or +## sell copies of the Software, and to permit persons to whom +## the Software is furnished to do so, subject to the following +## conditions: +## +## The above copyright notice and this permission notice shall +## be included in all copies or substantial portions of the Software. +## +## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +## OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +## HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +## WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +## FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +## OTHER DEALINGS IN THE SOFTWARE. +## +## ----------------------------------------------------------------------- + +## +## Utility companion library for the COM32 library +## + +gcc_ok = $(shell if gcc $(1) -c -x c /dev/null -o /dev/null 2>/dev/null; \ + then echo $(1); else echo $(2); fi) + +M32 := $(call gcc_ok,-m32,) + +CC = gcc +LD = ld -m elf_i386 +AR = ar +NASM = nasm +RANLIB = ranlib +CFLAGS = $(M32) -mregparm=3 -DREGPARM=3 -D__COM32__ -W -Wall -march=i386 -Os -fomit-frame-pointer -I./include -I../include +SFLAGS = $(M32) -D__COM32__ -march=i386 +LDFLAGS = -T ../lib/com32.ld +LNXCFLAGS = -I./include -W -Wall -O -g +LNXSFLAGS = -g +LNXLDFLAGS = -g +OBJCOPY = objcopy +LIBOBJS = ansiline.o ansiraw.o get_key.o idle.o sha1hash.o unbase64.o +LNXLIBOBJS = $(patsubst %.o,%.lo,$(LIBOBJS)) + +.SUFFIXES: .lss .c .lo .o .elf .c32 .lnx + +BINDIR = /usr/bin +LIBDIR = /usr/lib +AUXDIR = $(LIBDIR)/syslinux +INCDIR = /usr/include +COM32DIR = $(AUXDIR)/com32 + +all: libutil_com.a libutil_lnx.a + +libutil_com.a: $(LIBOBJS) + rm -f $@ + $(AR) cq $@ $(LIBOBJS) + $(RANLIB) $@ + +libutil_lnx.a: $(LNXLIBOBJS) + rm -f $@ + $(AR) cq $@ $(LNXLIBOBJS) + $(RANLIB) $@ + +.PRECIOUS: %.o +%.o: %.S + $(CC) $(SFLAGS) -c -o $@ $< + +.PRECIOUS: %.o +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +.PRECIOUS: %.elf +%.elf: %.o $(LIB) + $(LD) $(LDFLAGS) -o $@ $^ $(LIBGCC) + +.PRECIOUS: %.lo +%.lo: %.S + $(CC) $(LNXSFLAGS) -c -o $@ $< + +.PRECIOUS: %.lo +%.lo: %.c + $(CC) $(LNXCFLAGS) -c -o $@ $< + +.PRECIOUS: %.lnx +%.lnx: %.lo + $(CC) $(LNXCFLAGS) -o $@ $^ + +%.c32: %.elf + $(OBJCOPY) -O binary $< $@ + +tidy: + rm -f *.o *.lo *.lst *.elf + +clean: tidy + rm -f *.lss *.a *.c32 *.lnx *.com + +spotless: clean + rm -f *~ \#* + +install: all + mkdir -m 755 -p $(INSTALLROOT)$(COM32DIR) + install -m 644 libutil_com.a libutil_lnx.a $(INSTALLROOT)$(COM32DIR) + diff --git a/syslinux/com32/libutil/ansiline.c b/syslinux/com32/libutil/ansiline.c new file mode 100644 index 0000000..0b1fb51 --- /dev/null +++ b/syslinux/com32/libutil/ansiline.c @@ -0,0 +1,92 @@ +#ident "$Id: ansiline.c,v 1.1 2004/12/01 01:30:07 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * ansiline.c + * + * Configures the console for ANSI output in line mode; versions + * for COM32 and Linux support. + */ + +#ifdef __COM32__ + +#include <stdio.h> +#include <unistd.h> +#include <console.h> + +static void __attribute__((destructor)) console_cleanup(void) +{ + /* For the serial console, be nice and clean up */ + fputs("\033[0m\033[20l", stdout); +} + +void console_ansi_std(void) +{ + openconsole(&dev_stdcon_r, &dev_ansiserial_w); + fputs("\033[0m\033[20h", stdout); +} + +#else + +#include <stdio.h> +#include <termios.h> + +static struct termios original_termios_settings; + +static void __attribute__((constructor)) console_init(void) +{ + tcgetattr(0, &original_termios_settings); +} + +static void __attribute__((destructor)) console_cleanup(void) +{ + fputs("\033[0m\033[20l", stdout); + tcsetattr(0, TCSANOW, &original_termios_settings); +} + + +void console_ansi_std(void) +{ + struct termios tio; + + /* Disable stdio buffering */ + setbuf(stdin, NULL); + setbuf(stdout, NULL); + setbuf(stderr, NULL); + + /* Set the termios flag so we behave the same as libcom32 */ + tcgetattr(0, &tio); + tio.c_iflag &= ~ICRNL; + tio.c_iflag |= IGNCR; + tio.c_cflag |= ICANON|ECHO; + tcsetattr(0, TCSANOW, &tio); + fputs("\033[0m\033[20h", stdout); +} + +#endif + diff --git a/syslinux/com32/libutil/ansiraw.c b/syslinux/com32/libutil/ansiraw.c new file mode 100644 index 0000000..2e5af6f --- /dev/null +++ b/syslinux/com32/libutil/ansiraw.c @@ -0,0 +1,94 @@ +#ident "$Id: ansiraw.c,v 1.5 2004/12/21 01:37:43 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * ansiraw.c + * + * Configures the console for ANSI output in raw mode; versions + * for COM32 and Linux support. + */ + +#ifdef __COM32__ + +#include <stdio.h> +#include <unistd.h> +#include <console.h> + +static void __attribute__((destructor)) console_cleanup(void) +{ + /* For the serial console, be nice and clean up */ + fputs("\033[0m\033[20l", stdout); +} + +void console_ansi_raw(void) +{ + openconsole(&dev_rawcon_r, &dev_ansiserial_w); + fputs("\033[0m\033[20h", stdout); +} + +#else + +#include <stdio.h> +#include <termios.h> + +static struct termios original_termios_settings; + +static void __attribute__((constructor)) console_init(void) +{ + tcgetattr(0, &original_termios_settings); +} + +static void __attribute__((destructor)) console_cleanup(void) +{ + fputs("\033[0m\033[20l", stdout); + tcsetattr(0, TCSANOW, &original_termios_settings); +} + + +void console_ansi_raw(void) +{ + struct termios tio; + + /* Disable stdio buffering */ + setbuf(stdin, NULL); + setbuf(stdout, NULL); + setbuf(stderr, NULL); + + /* Set the termios flag so we behave the same as libcom32 */ + tcgetattr(0, &tio); + tio.c_iflag &= ~ICRNL; + tio.c_iflag |= IGNCR; + tio.c_lflag &= ~(ISIG|ICANON|ECHO); + tio.c_cc[VMIN] = 0; + tio.c_cc[VTIME] = 1; /* Don't 100% busy-wait in Linux */ + tcsetattr(0, TCSAFLUSH, &tio); + fputs("\033[0m\033[20h", stdout); +} + +#endif + diff --git a/syslinux/com32/libutil/get_key.c b/syslinux/com32/libutil/get_key.c new file mode 100644 index 0000000..d7a9713 --- /dev/null +++ b/syslinux/com32/libutil/get_key.c @@ -0,0 +1,172 @@ +#ident "$Id: get_key.c,v 1.7 2005/01/21 01:35:33 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * get_key.c + * + * Get a single key, and try to pick apart function key codes. + * This doesn't decode anywhere close to all possiblities, but + * hopefully is enough to be useful. + */ + +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <time.h> +#include <sys/times.h> +#include <getkey.h> +#include <libutil.h> + +struct keycode { + int code; + int seqlen; + const unsigned char *seq; +}; + +#define MAXLEN 8 +#define CODE(x,y) { x, (sizeof y)-1, (unsigned char *)y } + +static const struct keycode keycodes[] = { + /* First, the BIOS combined codes */ + CODE(KEY_F1, "\0\x3B"), + CODE(KEY_F2, "\0\x3C"), + CODE(KEY_F3, "\0\x3D"), + CODE(KEY_F4, "\0\x3E"), + CODE(KEY_F5, "\0\x3F"), + CODE(KEY_F6, "\0\x40"), + CODE(KEY_F7, "\0\x41"), + CODE(KEY_F8, "\0\x42"), + CODE(KEY_F9, "\0\x43"), + CODE(KEY_F10, "\0\x44"), + CODE(KEY_F11, "\0\x85"), + CODE(KEY_F12, "\0\x86"), + + CODE(KEY_UP, "\0\x48"), + CODE(KEY_DOWN, "\0\x50"), + CODE(KEY_LEFT, "\0\x4B"), + CODE(KEY_RIGHT,"\0\x4D"), + CODE(KEY_PGUP, "\0\x49"), + CODE(KEY_PGDN, "\0\x51"), + CODE(KEY_HOME, "\0\x47"), + CODE(KEY_END, "\0\x4F"), + CODE(KEY_INSERT, "\0\x52"), + CODE(KEY_DELETE, "\0\x53"), + + /* Now, VT/xterm/Linux codes */ + CODE(KEY_F1, "\033[[A"), + CODE(KEY_F1, "\033OP"), + CODE(KEY_F2, "\033[[B"), + CODE(KEY_F2, "\033OQ"), + CODE(KEY_F3, "\033[[C"), + CODE(KEY_F3, "\033OR"), + CODE(KEY_F4, "\033[[D"), + CODE(KEY_F4, "\033OS"), + CODE(KEY_F5, "\033[[E"), + CODE(KEY_F5, "\033[15~"), + CODE(KEY_F6, "\033[17~"), + CODE(KEY_F7, "\033[18~"), + CODE(KEY_F8, "\033[19~"), + CODE(KEY_F9, "\033[20~"), + CODE(KEY_F10, "\033[21~"), + CODE(KEY_F11, "\033[23~"), + CODE(KEY_F12, "\033[24~"), + + CODE(KEY_UP, "\033[A"), + CODE(KEY_DOWN, "\033[B"), + CODE(KEY_LEFT, "\033[D"), + CODE(KEY_RIGHT,"\033[C"), + CODE(KEY_PGUP, "\033[5~"), + CODE(KEY_PGUP, "\033[V"), + CODE(KEY_PGDN, "\033[6~"), + CODE(KEY_PGDN, "\033[U"), + CODE(KEY_HOME, "\033[1~"), + CODE(KEY_HOME, "\033[H"), + CODE(KEY_END, "\033[4~"), + CODE(KEY_END, "\033[F"), + CODE(KEY_END, "\033OF"), + CODE(KEY_INSERT, "\033[2~"), + CODE(KEY_INSERT, "\033[@"), + CODE(KEY_DELETE, "\033[3~"), +}; +#define NCODES ((int)(sizeof keycodes/sizeof(struct keycode))) + +int get_key(FILE *f, clock_t timeout) +{ + unsigned char buffer[MAXLEN]; + int nc, i, rv; + const struct keycode *kc; + int another; + unsigned char ch; + clock_t start; + + /* We typically start in the middle of a clock tick */ + if ( timeout ) + timeout++; + + nc = 0; + start = times(NULL); + do { + rv = read(fileno(f), &ch, 1); + if ( rv == 0 || (rv == -1 && errno == EAGAIN) ) { + clock_t lateness = times(NULL)-start; + if ( nc && lateness > 1+CLK_TCK/20 ) + return buffer[0]; /* timeout in sequence */ + else if ( !nc && timeout && lateness > timeout ) + return KEY_NONE; /* timeout before sequence */ + + do_idle(); + + another = 1; + continue; + } + + start = times(NULL); + + buffer[nc++] = ch; + + another = 0; + for ( i = 0, kc = keycodes ; i < NCODES ; i++, kc++ ) { + if ( nc == kc->seqlen && !memcmp(buffer, kc->seq, nc) ) + return kc->code; + else if ( nc < kc->seqlen && !memcmp(buffer, kc->seq, nc) ) { + another = 1; + break; + } + } + } while ( another ); + + /* We got an unrecognized sequence; return the first character */ + /* We really should remember this and return subsequent characters later */ + return buffer[0]; +} + + + + + diff --git a/syslinux/com32/libutil/idle.c b/syslinux/com32/libutil/idle.c new file mode 100644 index 0000000..1cc7738 --- /dev/null +++ b/syslinux/com32/libutil/idle.c @@ -0,0 +1,53 @@ +#ident "$Id: idle.c,v 1.1 2005/01/20 18:41:12 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2005 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * idle.c + * + * What to do in a busy loop... + */ + +#ifdef __COM32__ + +#include <syslinux.h> + +void do_idle(void) +{ + syslinux_idle(); +} + +#else + +#include <sched.h> + +void do_idle(void) +{ + sched_yield(); /* As good as we can get... */ +} + +#endif diff --git a/syslinux/com32/libutil/include/base64.h b/syslinux/com32/libutil/include/base64.h new file mode 100644 index 0000000..7da6078 --- /dev/null +++ b/syslinux/com32/libutil/include/base64.h @@ -0,0 +1,42 @@ +#ident "$Id: base64.h,v 1.1 2005/01/21 00:49:46 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2005 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * base64.h + * + * Simple routines for handing base64 text + */ + +#ifndef LIBUTIL_BASE64_H +#define LIBUTIL_BASE64_H + +#include <stddef.h> + +size_t unbase64(unsigned char *, size_t, const char *); + +#endif diff --git a/syslinux/com32/libutil/include/consoles.h b/syslinux/com32/libutil/include/consoles.h new file mode 100644 index 0000000..2eacf60 --- /dev/null +++ b/syslinux/com32/libutil/include/consoles.h @@ -0,0 +1,42 @@ +#ident "$Id: consoles.h,v 1.2 2004/12/01 02:44:34 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * consoles.h + * + * Utility functions for common console configurations + */ + +#ifndef LIBUTIL_CONSOLES_H +#define LIBUTIL_CONSOLES_H + +void console_ansi_std(void); +void console_ansi_raw(void); + +#endif /* LIBUTIL_CONSOLES_H */ + diff --git a/syslinux/com32/libutil/include/getkey.h b/syslinux/com32/libutil/include/getkey.h new file mode 100644 index 0000000..c9e19fd --- /dev/null +++ b/syslinux/com32/libutil/include/getkey.h @@ -0,0 +1,76 @@ +#ident "$Id: getkey.h,v 1.5 2005/01/21 01:35:33 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * getkey.h + * + * Function to get a key symbol and parse it + */ + +#ifndef LIBUTIL_GETKEY_H +#define LIBUTIL_GETKEY_H + +#include <stdio.h> +#include <sys/times.h> + +#define KEY_NONE (-1) + +#define KEY_CTRL(x) ((x) & 0x001f) +#define KEY_BACKSPACE 0x0008 +#define KEY_TAB 0x0009 +#define KEY_ENTER 0x000d +#define KEY_ESC 0x001b +#define KEY_DEL 0x007f + +#define KEY_F1 0x0100 +#define KEY_F2 0x0101 +#define KEY_F3 0x0102 +#define KEY_F4 0x0103 +#define KEY_F5 0x0104 +#define KEY_F6 0x0105 +#define KEY_F7 0x0106 +#define KEY_F8 0x0107 +#define KEY_F9 0x0108 +#define KEY_F10 0x0109 +#define KEY_F11 0x010A +#define KEY_F12 0x010B + +#define KEY_UP 0x0120 +#define KEY_DOWN 0x0121 +#define KEY_LEFT 0x0122 +#define KEY_RIGHT 0x0123 +#define KEY_PGUP 0x0124 +#define KEY_PGDN 0x0125 +#define KEY_HOME 0x0126 +#define KEY_END 0x0127 +#define KEY_INSERT 0x0128 +#define KEY_DELETE 0x0129 + +int get_key(FILE *, clock_t); + +#endif /* LIBUTIL_GETKEY_H */ diff --git a/syslinux/com32/libutil/include/libutil.h b/syslinux/com32/libutil/include/libutil.h new file mode 100644 index 0000000..1c3c17e --- /dev/null +++ b/syslinux/com32/libutil/include/libutil.h @@ -0,0 +1,40 @@ +#ident "$Id: libutil.h,v 1.1 2005/01/20 18:41:12 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2005 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * libutil.h + * + * Misc libutil functions + */ + +#ifndef LIBUTIL_LIBUTIL_H +#define LIBUTIL_LIBUTIL_H + +void do_idle(void); + +#endif diff --git a/syslinux/com32/libutil/include/minmax.h b/syslinux/com32/libutil/include/minmax.h new file mode 100644 index 0000000..0316b88 --- /dev/null +++ b/syslinux/com32/libutil/include/minmax.h @@ -0,0 +1,44 @@ +#ident "$Id: minmax.h,v 1.1 2004/12/20 23:19:36 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +#ifndef _MINMAX_H +#define _MINMAX_H + +/* + * minmax.h: Type-independent safe min/max macros + */ + +#define min(x,y) ({ __typeof(x) xx = (x); \ + __typeof(y) yy = (y); \ + xx < yy ? xx : yy; }) +#define max(x,y) ({ __typeof(x) xx = (x); \ + __typeof(y) yy = (y); \ + xx > yy ? xx : yy; }) + +#endif /* _MINMAX_H */ + diff --git a/syslinux/com32/libutil/include/sha1.h b/syslinux/com32/libutil/include/sha1.h new file mode 100644 index 0000000..ea324c7 --- /dev/null +++ b/syslinux/com32/libutil/include/sha1.h @@ -0,0 +1,18 @@ +#ifndef LIBUTIL_SHA1_H +#define LIBUTIL_SHA1_H + +#include <stdint.h> + +typedef struct { + uint32_t state[5]; + uint32_t count[2]; + unsigned char buffer[64]; +} SHA1_CTX; + +void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]); +void SHA1Init(SHA1_CTX* context); +void SHA1Update(SHA1_CTX* context, const unsigned char* data, uint32_t len); /* +JHB */ +void SHA1Final(unsigned char digest[20], SHA1_CTX* context); + +#endif /* LIBUTIL_SHA1_H */ diff --git a/syslinux/com32/libutil/sha1hash.c b/syslinux/com32/libutil/sha1hash.c new file mode 100644 index 0000000..fc5cc35 --- /dev/null +++ b/syslinux/com32/libutil/sha1hash.c @@ -0,0 +1,308 @@ +/* +SHA-1 in C +By Steve Reid <sreid@sea-to-sky.net> +100% Public Domain + +----------------- +Modified 7/98 +By James H. Brown <jbrown@burgoyne.com> +Still 100% Public Domain + +Corrected a problem which generated improper hash values on 16 bit machines +Routine SHA1Update changed from + void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int +len) +to + void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned +long len) + +The 'len' parameter was declared an int which works fine on 32 bit machines. +However, on 16 bit machines an int is too small for the shifts being done +against +it. This caused the hash function to generate incorrect values if len was +greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update(). + +Since the file IO in main() reads 16K at a time, any file 8K or larger would +be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million +"a"s). + +I also changed the declaration of variables i & j in SHA1Update to +unsigned long from unsigned int for the same reason. + +These changes should make no difference to any 32 bit implementations since +an +int and a long are the same size in those environments. + +-- +I also corrected a few compiler warnings generated by Borland C. +1. Added #include <process.h> for exit() prototype +2. Removed unused variable 'j' in SHA1Final +3. Changed exit(0) to return(0) at end of main. + +ALL changes I made can be located by searching for comments containing 'JHB' +----------------- +Modified 8/98 +By Steve Reid <sreid@sea-to-sky.net> +Still 100% public domain + +1- Removed #include <process.h> and used return() instead of exit() +2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall) +3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net + +----------------- +Modified 4/01 +By Saul Kravitz <Saul.Kravitz@celera.com> +Still 100% PD +Modified to run on Compaq Alpha hardware. + +----------------- +Modified 2/03 +By H. Peter Anvin <hpa@zytor.com> +Still 100% PD +Modified to run on any hardware with <inttypes.h> and <netinet/in.h> +Changed the driver program + +*/ + +/* +Test Vectors (from FIPS PUB 180-1) +"abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +/* #define SHA1HANDSOFF */ + +#include <stdio.h> +#include <string.h> +#include <inttypes.h> +#include <netinet/in.h> /* For htonl/ntohl/htons/ntohs */ + +#include "sha1.h" + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* blk0() and blk() perform the initial expand. */ +/* I got the idea of expanding during the round function from SSLeay */ +#define blk0(i) (block->l[i] = ntohl(block->l[i])) +#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ + ^block->l[(i+2)&15]^block->l[i&15],1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); +#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); +#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); + + +#ifdef VERBOSE /* SAK */ +void SHAPrintContext(SHA1_CTX *context, char *msg){ + printf("%s (%d,%d) %x %x %x %x %x\n", + msg, + context->count[0], context->count[1], + context->state[0], + context->state[1], + context->state[2], + context->state[3], + context->state[4]); +} +#endif + +/* Hash a single 512-bit block. This is the core of the algorithm. */ + +void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]) +{ +uint32_t a, b, c, d, e; +typedef union { + unsigned char c[64]; + uint32_t l[16]; +} CHAR64LONG16; +CHAR64LONG16* block; +#ifdef SHA1HANDSOFF +static unsigned char workspace[64]; + block = (CHAR64LONG16*)workspace; + memcpy(block, buffer, 64); +#else + block = (CHAR64LONG16*)buffer; +#endif + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + /* Wipe variables */ + a = b = c = d = e = 0; +} + + +/* SHA1Init - Initialize new context */ + +void SHA1Init(SHA1_CTX* context) +{ + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + + +/* Run your data through this. */ + +void SHA1Update(SHA1_CTX* context, const unsigned char* data, uint32_t len) /* +JHB */ +{ +uint32_t i, j; /* JHB */ + +#ifdef VERBOSE + SHAPrintContext(context, "before"); +#endif + j = (context->count[0] >> 3) & 63; + if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++; + context->count[1] += (len >> 29); + if ((j + len) > 63) { + memcpy(&context->buffer[j], data, (i = 64-j)); + SHA1Transform(context->state, context->buffer); + for ( ; i + 63 < len; i += 64) { + SHA1Transform(context->state, &data[i]); + } + j = 0; + } + else i = 0; + memcpy(&context->buffer[j], &data[i], len - i); +#ifdef VERBOSE + SHAPrintContext(context, "after "); +#endif +} + + +/* Add padding and return the message digest. */ + +void SHA1Final(unsigned char digest[20], SHA1_CTX* context) +{ +uint32_t i; /* JHB */ +unsigned char finalcount[8]; + + for (i = 0; i < 8; i++) { + finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] + >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ + } + SHA1Update(context, (unsigned char *)"\200", 1); + while ((context->count[0] & 504) != 448) { + SHA1Update(context, (unsigned char *)"\0", 1); + } + SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() +*/ + for (i = 0; i < 20; i++) { + digest[i] = (unsigned char) + ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); + } + /* Wipe variables */ + i = 0; /* JHB */ + memset(context->buffer, 0, 64); + memset(context->state, 0, 20); + memset(context->count, 0, 8); + memset(finalcount, 0, 8); /* SWR */ +#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */ + SHA1Transform(context->state, context->buffer); +#endif +} + +/*************************************************************/ + +/* This is not quite the MIME base64 algorithm: it uses _ instead of /, + and instead of padding the output with = characters we just make the + output shorter. */ +char *mybase64(uint8_t digest[20]) +{ + static const char charz[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_"; + uint8_t input[21]; + static char output[28]; + int i, j; + uint8_t *p; + char *q; + uint32_t bv; + + memcpy(input, digest, 20); + input[20] = 0; /* Pad to multiple of 3 bytes */ + + p = input; q = output; + for ( i = 0 ; i < 7 ; i++ ) { + bv = (p[0] << 16) | (p[1] << 8) | p[2]; + p += 3; + for ( j = 0 ; j < 4 ; j++ ) { + *q++ = charz[(bv >> 18) & 0x3f]; + bv <<= 6; + } + } + *--q = '\0'; /* The last character is not significant */ + return output; +} + +#ifdef FOR_TESTING_ONLY + +int main(int argc, char** argv) +{ + int i; + SHA1_CTX context; + uint8_t digest[20], buffer[16384]; + FILE* file; + + if (argc < 2) { + file = stdin; + } + else { + if (!(file = fopen(argv[1], "rb"))) { + fputs("Unable to open file.", stderr); + return(-1); + } + } + SHA1Init(&context); + while (!feof(file)) { /* note: what if ferror(file) */ + i = fread(buffer, 1, 16384, file); + SHA1Update(&context, buffer, i); + } + SHA1Final(digest, &context); + fclose(file); + + puts(mybase64(digest)); + + return 0; +} + +#endif diff --git a/syslinux/com32/libutil/unbase64.c b/syslinux/com32/libutil/unbase64.c new file mode 100644 index 0000000..0ac7539 --- /dev/null +++ b/syslinux/com32/libutil/unbase64.c @@ -0,0 +1,78 @@ +#ident "$Id: unbase64.c,v 1.1 2005/01/21 00:49:46 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2005 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * unbase64.c + * + * Convert a string in base64 format to a byte array. + */ + +#include <string.h> +#include <base64.h> + +static const unsigned char _base64chars[] = +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789./"; + +size_t unbase64(unsigned char *buffer, size_t bufsiz, const char *txt) +{ + unsigned int bits = 0; + int nbits = 0; + char base64tbl[256]; + int i; + char v; + size_t nbytes = 0; + + + memset(base64tbl, -1, sizeof base64tbl); + + for ( i = 0 ; _base64chars[i] ; i++ ) { + base64tbl[_base64chars[i]] = i; + } + + /* Also support filesystem safe alternate base64 encoding */ + base64tbl['-'] = 62; + base64tbl['_'] = 63; + + while ( *txt ) { + if ( (v = base64tbl[(unsigned char) *txt]) >= 0 ) { + bits <<= 6; + bits += v; + nbits += 6; + if ( nbits >= 8 ) { + if ( nbytes < bufsiz ) + *buffer++ = (bits >> (nbits-8)); + nbytes++; + nbits -= 8; + } + } + txt++; + } + + return nbytes; +} + diff --git a/syslinux/com32/modules/Makefile b/syslinux/com32/modules/Makefile new file mode 100644 index 0000000..cd3aee0 --- /dev/null +++ b/syslinux/com32/modules/Makefile @@ -0,0 +1,98 @@ +#ident "$Id: Makefile,v 1.21 2005/05/08 21:47:04 hpa Exp $" +## ----------------------------------------------------------------------- +## +## Copyright 2001-2004 H. Peter Anvin - All Rights Reserved +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, Inc., 53 Temple Place Ste 330, +## Boston MA 02111-1307, USA; either version 2 of the License, or +## (at your option) any later version; incorporated herein by reference. +## +## ----------------------------------------------------------------------- + +## +## samples for syslinux users +## + +gcc_ok = $(shell if gcc $(1) -c -x c /dev/null -o /dev/null 2>/dev/null; \ + then echo $(1); else echo $(2); fi) + +M32 := $(call gcc_ok,-m32,) + +CC = gcc +LD = ld -m elf_i386 +AR = ar +NASM = nasm +RANLIB = ranlib +CFLAGS = $(M32) -mregparm=3 -DREGPARM=3 -W -Wall -march=i386 -Os -fomit-frame-pointer -I../libutil/include -I../include -D__COM32__ +LNXCFLAGS = -W -Wall -O -g -I../libutil/include +LNXSFLAGS = -g +LNXLDFLAGS = -g +SFLAGS = -D__COM32__ -march=i386 +LDFLAGS = -T ../lib/com32.ld +OBJCOPY = objcopy +PPMTOLSS16 = ../ppmtolss16 +LIBGCC := $(shell $(CC) --print-libgcc) +LIBS = ../libutil/libutil_com.a ../lib/libcom32.a $(LIBGCC) +LNXLIBS = ../libutil/libutil_lnx.a + +.SUFFIXES: .lss .c .o .elf .c32 .lnx + +BINDIR = /usr/bin +LIBDIR = /usr/lib +AUXDIR = $(LIBDIR)/syslinux +INCDIR = /usr/include +COM32DIR = $(AUXDIR)/com32 + +MODULES = chain.c32 menu.c32 ethersel.c32 mboot.c32 +TESTFILES = menu.lnx + +all: $(MODULES) $(TESTFILES) + +.PRECIOUS: %.o +%.o: %.S + $(CC) $(SFLAGS) -c -o $@ $< + +.PRECIOUS: %.o +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +.PRECIOUS: %.elf +%.elf: %.o $(LIBS) + $(LD) $(LDFLAGS) -o $@ $^ + +.PRECIOUS: %.lo +%.lo: %.S + $(CC) $(LNXSFLAGS) -c -o $@ $< + +.PRECIOUS: %.lo +%.lo: %.c + $(CC) $(LNXCFLAGS) -c -o $@ $< + +.PRECIOUS: %.lnx +%.lnx: %.lo $(LNXLIBS) + $(CC) $(LNXLDFLAGS) -o $@ $^ + +%.c32: %.elf + $(OBJCOPY) -O binary $< $@ + +menu.elf : menu.o readconfig.o $(LIBS) + $(LD) $(LDFLAGS) -o $@ $^ + +menu.lnx : menu.lo readconfig.lo $(LNXLIBS) + $(CC) $(LNXLDFLAGS) -o $@ $^ + +tidy: + rm -f *.o *.lo *.a *.lst *.elf + +clean: tidy + rm -f *.lss *.c32 *.lnx *.com + +spotless: clean + rm -f *~ \#* + +install: all + mkdir -m 755 -p $(INSTALLROOT)$(AUXDIR) + install -m 644 $(MODULES) $(INSTALLROOT)$(AUXDIR) + diff --git a/syslinux/com32/modules/chain.c b/syslinux/com32/modules/chain.c new file mode 100644 index 0000000..59dcd43 --- /dev/null +++ b/syslinux/com32/modules/chain.c @@ -0,0 +1,377 @@ +#ident "$Id: chain.c,v 1.4 2005/01/12 00:34:54 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2003-2005 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * chain.c + * + * Chainload a hard disk (currently rather braindead.) + * + * Usage: chain hd<disk#> [<partition>] + * chain fd<disk#> + * + * ... e.g. "chain hd0 1" will boot the first partition on the first hard disk. + * + * Partitions 1-4 are primary, 5+ logical, 0 = boot MBR (default.) + */ + +#include <com32.h> +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <console.h> + +#define SECTOR 512 /* bytes/sector */ + +static inline void error(const char *msg) +{ + fputs(msg, stderr); +} + +/* + * Call int 13h, but with retry on failure. Especially floppies need this. + */ +int int13_retry(const com32sys_t *inreg, com32sys_t *outreg) +{ + int retry = 6; /* Number of retries */ + com32sys_t tmpregs; + + if ( !outreg ) outreg = &tmpregs; + + while ( retry-- ) { + __intcall(0x13, inreg, outreg); + if ( !(outreg->eflags.l & EFLAGS_CF) ) + return 0; /* CF=0, OK */ + } + + return -1; /* Error */ +} + +/* + * Query disk parameters and EBIOS availability for a particular disk. + */ +struct diskinfo { + int disk; + int ebios; /* EBIOS supported on this disk */ + int cbios; /* CHS geometry is valid */ + int head; + int sect; +} disk_info; + +int get_disk_params(int disk) +{ + static com32sys_t getparm, parm, getebios, ebios; + + disk_info.disk = disk; + + /* Get EBIOS support */ + getebios.eax.w[0] = 0x4100; + getebios.ebx.w[0] = 0x55aa; + getebios.edx.b[0] = disk; + getebios.eflags.b[0] = 0x3; /* CF set */ + + __intcall(0x13, &getebios, &ebios); + + if ( !(ebios.eflags.l & EFLAGS_CF) && + ebios.ebx.w[0] == 0xaa55 && + (ebios.ecx.b[0] & 1) ) { + disk_info.ebios = 1; + } + + /* Get disk parameters -- really only useful for + hard disks, but if we have a partitioned floppy + it's actually our best chance... */ + getparm.eax.b[1] = 0x08; + getparm.edx.b[0] = disk; + + __intcall(0x13, &getparm, &parm); + + if ( parm.eflags.l & EFLAGS_CF ) + return disk_info.ebios ? 0 : -1; + + disk_info.head = parm.edx.b[1]+1; + disk_info.sect = parm.ecx.b[0] & 0x3f; + if ( disk_info.sect == 0 ) { + disk_info.sect = 1; + } else { + disk_info.cbios = 1; /* Valid geometry */ + } + + return 0; +} + +/* + * Get a disk block; buf is REQUIRED TO BE IN LOW MEMORY. + */ +struct ebios_dapa { + uint16_t len; + uint16_t count; + uint16_t off; + uint16_t seg; + uint64_t lba; +} *dapa; + +int read_sector(void *buf, unsigned int lba) +{ + com32sys_t inreg; + + memset(&inreg, 0, sizeof inreg); + + if ( disk_info.ebios ) { + dapa->len = sizeof(*dapa); + dapa->count = 1; /* 1 sector */ + dapa->off = OFFS(buf); + dapa->seg = SEG(buf); + dapa->lba = lba; + + inreg.esi.w[0] = OFFS(dapa); + inreg.ds = SEG(dapa); + inreg.edx.b[0] = disk_info.disk; + inreg.eax.b[1] = 0x42; /* Extended read */ + } else { + unsigned int c, h, s, t; + + if ( !disk_info.cbios ) { + /* We failed to get the geometry */ + + if ( lba ) + return -1; /* Can only read MBR */ + + s = 1; h = 0; c = 0; + } else { + s = (lba % disk_info.sect) + 1; + t = lba / disk_info.sect; /* Track = head*cyl */ + h = t % disk_info.head; + c = t / disk_info.head; + } + + if ( s > 63 || h > 256 || c > 1023 ) + return -1; + + inreg.eax.w[0] = 0x0201; /* Read one sector */ + inreg.ecx.b[1] = c & 0xff; + inreg.ecx.b[0] = s + (c >> 6); + inreg.edx.b[1] = h; + inreg.edx.b[0] = disk_info.disk; + inreg.ebx.w[0] = OFFS(buf); + inreg.es = SEG(buf); + } + + return int13_retry(&inreg, NULL); +} + +/* A DOS partition table entry */ +struct part_entry { + uint8_t active_flag; /* 0x80 if "active" */ + uint8_t start_head; + uint8_t start_sect; + uint8_t start_cyl; + uint8_t ostype; + uint8_t end_head; + uint8_t end_sect; + uint8_t end_cyl; + uint32_t start_lba; + uint32_t length; +} __attribute__((packed)); + + +/* Search for a logical partition. Logical partitions are actually implemented + as recursive partition tables; theoretically they're supposed to form a linked + list, but other structures have been seen. + + To make things extra confusing: data partition offsets are relative to where + the data partition record is stored, whereas extended partition offsets + are relative to the beginning of the extended partition all the way back + at the MBR... but still not absolute! */ + +int nextpart; /* Number of the next logical partition */ + +struct part_entry *find_logical_partition(int whichpart, char *table, struct part_entry *self, struct part_entry *root) +{ + struct part_entry *ptab = (struct part_entry *)(table + 0x1be); + struct part_entry *found; + int i; + + if ( *(uint16_t *)(ptab + 0x1fe) != 0xaa55 ) + return NULL; /* Signature missing */ + + /* We are assumed to already having enumerated all the data partitions + in this table if this is the MBR. For MBR, self == NULL. */ + + if ( self ) { + /* Scan the data partitions. */ + + for ( i = 0 ; i < 4 ; i++ ) { + if ( ptab[i].ostype == 0x00 || ptab[i].ostype == 0x05 || + ptab[i].ostype == 0x0f || ptab[i].ostype == 0x85 ) + continue; /* Skip empty or extended partitions */ + + if ( !ptab[i].length ) + continue; + + /* Adjust the offset to account for the extended partition itself */ + ptab[i].start_lba += self->start_lba; + + /* Sanity check entry: must not extend outside the extended partition. + This is necessary since some OSes put crap in some entries. */ + if ( ptab[i].start_lba + ptab[i].length <= self->start_lba || + ptab[i].start_lba >= self->start_lba + self->length ) + continue; + + /* OK, it's a data partition. Is it the one we're looking for? */ + if ( nextpart++ == whichpart ) + return &ptab[i]; + } + } + + /* Scan the extended partitions. */ + for ( i = 0 ; i < 4 ; i++ ) { + if ( ptab[i].ostype != 0x05 && + ptab[i].ostype != 0x0f && ptab[i].ostype != 0x85 ) + continue; /* Skip empty or data partitions */ + + if ( !ptab[i].length ) + continue; + + /* Adjust the offset to account for the extended partition itself */ + if ( root ) + ptab[i].start_lba += root->start_lba; + + /* Sanity check entry: must not extend outside the extended partition. + This is necessary since some OSes put crap in some entries. */ + if ( root ) + if ( ptab[i].start_lba + ptab[i].length <= root->start_lba || + ptab[i].start_lba >= root->start_lba + root->length ) + continue; + + /* Process this partition */ + if ( read_sector(table+SECTOR, ptab[i].start_lba) ) + continue; /* Read error, must be invalid */ + + if ( (found = find_logical_partition(whichpart, table+SECTOR, &ptab[i], + root ? root : &ptab[i])) ) + return found; + } + + /* If we get here, there ain't nothing... */ + return NULL; +} + + +int main(int argc, char *argv[]) +{ + char *mbr, *boot_sector = NULL; + struct part_entry *partinfo; + char *drivename, *partition; + int hd, drive, whichpart; + static com32sys_t inreg; /* In bss, so zeroed automatically */ + + openconsole(&dev_null_r, &dev_stdcon_w); + + if ( argc < 2 ) { + error("Usage: chain.c32 (hd|fd)# [partition]\n"); + goto bail; + } + + drivename = argv[1]; + partition = argv[2]; /* Possibly null */ + + hd = 0; + if ( (drivename[0] == 'h' || drivename[0] == 'f') && + drivename[1] == 'd' ) { + hd = drivename[0] == 'h'; + drivename += 2; + } + drive = (hd ? 0x80 : 0) | strtoul(drivename, NULL, 0); + whichpart = 0; /* Default */ + + if ( partition ) + whichpart = strtoul(partition, NULL, 0); + + if ( !(drive & 0x80) && whichpart ) { + error("Warning: Partitions of floppy devices may not work\n"); + } + + /* Divvy up the bounce buffer. To keep things sector- + aligned, give the EBIOS DAPA the first sector, then + the MBR next, and the rest is used for the partition- + chasing stack. */ + dapa = (struct ebios_dapa *)__com32.cs_bounce; + mbr = (char *)__com32.cs_bounce + SECTOR; + + /* Get the disk geometry (not needed for MBR) */ + if ( get_disk_params(drive) && whichpart ) { + error("Cannot get disk parameters\n"); + goto bail; + } + + /* Get MBR */ + if ( read_sector(mbr, 0) ) { + error("Cannot read Master Boot Record\n"); + goto bail; + } + + if ( whichpart == 0 ) { + /* Boot the MBR */ + partinfo = NULL; + boot_sector = mbr; + } else if ( whichpart <= 4 ) { + /* Boot a primary partition */ + partinfo = &((struct part_entry *)(mbr + 0x1be))[whichpart-1]; + if ( partinfo->ostype == 0 ) { + error("Invalid primary partition\n"); + goto bail; + } + } else { + /* Boot a logical partition */ + + nextpart = 5; + partinfo = find_logical_partition(whichpart, mbr, NULL, NULL); + + if ( !partinfo || partinfo->ostype == 0 ) { + error("Requested logical partition not found\n"); + goto bail; + } + } + + /* Do the actual chainloading */ + if ( partinfo ) { + /* Actually read the boot sector */ + /* Pick the first buffer that isn't already in use */ + boot_sector = (char *)(((unsigned long)partinfo + 511) & ~511); + if ( read_sector(boot_sector, partinfo->start_lba) ) { + error("Cannot read boot sector\n"); + goto bail; + } + + /* 0x7BE is the canonical place for the first partition entry. */ + inreg.esi.w[0] = 0x7be; + memcpy((char *)0x7be, partinfo, sizeof(*partinfo)); + } + + fputs("Booting...\n", stdout); + + inreg.eax.w[0] = 0x000d; /* Clean up and chain boot */ + inreg.edx.w[0] = 0; /* Should be 3 for "keeppxe" */ + inreg.edi.l = (uint32_t)boot_sector; + inreg.ecx.l = SECTOR; /* One sector */ + inreg.ebx.b[0] = drive; /* DL = drive no */ + + __intcall(0x22, &inreg, NULL); + + /* If we get here, badness happened */ + error("Chainboot failed!\n"); + +bail: + return 255; +} diff --git a/syslinux/com32/modules/ethersel.c b/syslinux/com32/modules/ethersel.c new file mode 100644 index 0000000..5df9ee2 --- /dev/null +++ b/syslinux/com32/modules/ethersel.c @@ -0,0 +1,282 @@ +#ident "$Id: ethersel.c,v 1.3 2005/01/05 07:30:47 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2005 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * ethersel.c + * + * Search for an Ethernet card with a known PCI signature, and run + * the corresponding Ethernet module. + * + * To use this, set up a syslinux config file like this: + * + * PROMPT 0 + * DEFAULT ethersel.c32 + * # DEV [DID xxxx:yyyy[/mask]] [RID zz-zz] [SID uuuu:vvvv[/mask]] commandline + * # ... + * + * DID = PCI device ID + * RID = Revision ID (range) + * SID = Subsystem ID + */ + +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <console.h> +#include <sys/pci.h> +#include <com32.h> + +#ifdef DEBUG +# define dprintf printf +#else +# define dprintf(...) ((void)0) +#endif + +struct match { + struct match *next; + uint32_t did; + uint32_t did_mask; + uint32_t sid; + uint32_t sid_mask; + uint8_t rid_min, rid_max; + char *filename; +}; + +static const char * +get_config(void) +{ + static com32sys_t r; + + r.eax.w[0] = 0x000E; + __intcall(0x22, &r, &r); + + return MK_PTR(r.es, r.ebx.w[0]); +} + +static char * +skipspace(char *p) +{ + while ( *p && *p <= ' ' ) + p++; + + return p; +} + +#define MAX_LINE 512 + +/* Check to see if we are at a certain keyword (case insensitive) */ +static int looking_at(const char *line, const char *kwd) +{ + const char *p = line; + const char *q = kwd; + + while ( *p && *q && ((*p^*q) & ~0x20) == 0 ) { + p++; + q++; + } + + if ( *q ) + return 0; /* Didn't see the keyword */ + + return *p <= ' '; /* Must be EOL or whitespace */ +} + +static char * +get_did(char *p, uint32_t *idptr, uint32_t *maskptr) +{ + unsigned long vid, did, m1, m2; + + *idptr = -1; + *maskptr = 0xffffffff; + + vid = strtoul(p, &p, 16); + if ( *p != ':' ) + return p; /* Bogus ID */ + did = strtoul(p+1, &p, 16); + + *idptr = (did << 16) + vid; + + if ( *p == '/' ) { + m1 = strtoul(p+1, &p, 16); + if ( *p != ':' ) { + *maskptr = (m1 << 16) | 0xffff; + } else { + m2 = strtoul(p+1, &p, 16); + *maskptr = (m1 << 16) | m2; + } + } + + return p; +} + +static struct match * +parse_config(const char *filename) +{ + char line[MAX_LINE], *p; + FILE *f; + struct match *list = NULL; + struct match **ep = &list; + struct match *m; + + if ( !filename ) + filename = get_config(); + + f = fopen(filename, "r"); + if ( !f ) + return list; + + while ( fgets(line, sizeof line, f) ) { + p = skipspace(line); + + if ( !looking_at(p, "#") ) + continue; + p = skipspace(p+1); + + if ( !looking_at(p, "dev") ) + continue; + p = skipspace(p+3); + + m = malloc(sizeof(struct match)); + if ( !m ) + continue; + + memset(m, 0, sizeof *m); + m->rid_max = 0xff; + + for(;;) { + p = skipspace(p); + + if ( looking_at(p, "did") ) { + p = get_did(p+3, &m->did, &m->did_mask); + m->did_mask = 0xffffffff; + } else if ( looking_at(p, "sid") ) { + p = get_did(p+3, &m->sid, &m->sid_mask); + } else if ( looking_at(p, "rid") ) { + unsigned long r0, r1; + + p = skipspace(p+3); + + r0 = strtoul(p, &p, 16); + if ( *p == '-' ) { + r1 = strtoul(p+1, &p, 16); + } else { + r1 = r0; + } + + m->rid_min = r0; + m->rid_max = r1; + } else { + char *e; + + e = strchr(p, '\n'); + if ( *e ) *e = '\0'; + e = strchr(p, '\r'); + if ( *e ) *e = '\0'; + + m->filename = strdup(p); + if ( !m->filename ) + m->did = -1; + break; /* Done with this line */ + } + } + + dprintf("DEV DID %08x/%08x SID %08x/%08x RID %02x-%02x CMD %s\n", + m->did, m->did_mask, m->sid, m->sid_mask, + m->rid_min, m->rid_max, m->filename); + + *ep = m; + ep = &m->next; + } + + return list; +} + +static struct match * +pciscan(struct match *list) +{ + unsigned int bus, dev, func, maxfunc; + uint32_t did, sid; + uint8_t hdrtype, rid; + pciaddr_t a; + struct match *m; + + for ( bus = 0 ; bus <= 0xff ; bus++ ) { + for ( dev = 0 ; dev <= 0x1f ; dev++ ) { + maxfunc = 0; + for ( func = 0 ; func <= maxfunc ; func++ ) { + a = pci_mkaddr(bus, dev, func, 0); + + did = pci_readl(a); + + if ( did == 0xffffffff || did == 0xffff0000 || + did == 0x0000ffff || did == 0x00000000 ) + continue; + + hdrtype = pci_readb(a + 0x0e); + + if ( hdrtype & 0x80 ) + maxfunc = 7; /* Multifunction device */ + + if ( hdrtype & 0x7f ) + continue; /* Ignore bridge devices */ + + rid = pci_readb(a + 0x08); + sid = pci_readl(a + 0x2c); + + dprintf("Scanning: DID %08x SID %08x RID %02x\n", did, sid, rid); + + for ( m = list ; m ; m = m->next ) { + if ( ((did ^ m->did) & m->did_mask) == 0 && + ((sid ^ m->sid) & m->sid_mask) == 0 && + rid >= m->rid_min && rid <= m->rid_max ) + return m; + } + } + } + } + + return NULL; +} + +static void __attribute__((noreturn)) +execute(const char *cmdline) +{ + static com32sys_t ireg; + + strcpy(__com32.cs_bounce, cmdline); + ireg.eax.w[0] = 0x0003; /* Run command */ + ireg.ebx.w[0] = OFFS(__com32.cs_bounce); + ireg.es = SEG(__com32.cs_bounce); + __intcall(0x22, &ireg, NULL); + exit(255); /* Shouldn't return */ +} + +int main(int argc, char *argv[]) +{ + struct match *list, *match; + + openconsole(&dev_null_r, &dev_stdcon_w); + + list = parse_config(argc < 2 ? NULL : argv[1]); + + match = pciscan(list); + + if ( match ) + execute(match->filename); + + /* On error, return to the command line */ + fputs("Error: no recognized network card found!\n", stderr); + return 1; +} + diff --git a/syslinux/com32/modules/i386-elf.h b/syslinux/com32/modules/i386-elf.h new file mode 100644 index 0000000..7162e3d --- /dev/null +++ b/syslinux/com32/modules/i386-elf.h @@ -0,0 +1,237 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2001,2002 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* 32-bit data types */ + +typedef unsigned long Elf32_Addr; +typedef unsigned short Elf32_Half; +typedef unsigned long Elf32_Off; +typedef signed long Elf32_Sword; +typedef unsigned long Elf32_Word; +/* "unsigned char" already exists */ + +/* ELF header */ +typedef struct +{ + +#define EI_NIDENT 16 + + /* first four characters are defined below */ +#define EI_MAG0 0 +#define ELFMAG0 0x7f +#define EI_MAG1 1 +#define ELFMAG1 'E' +#define EI_MAG2 2 +#define ELFMAG2 'L' +#define EI_MAG3 3 +#define ELFMAG3 'F' + +#define EI_CLASS 4 /* data sizes */ +#define ELFCLASS32 1 /* i386 -- up to 32-bit data sizes present */ + +#define EI_DATA 5 /* data type and ordering */ +#define ELFDATA2LSB 1 /* i386 -- LSB 2's complement */ + +#define EI_VERSION 6 /* version number. "e_version" must be the same */ +#define EV_CURRENT 1 /* current version number */ + +#define EI_OSABI 7 /* operating system/ABI indication */ +#define ELFOSABI_FREEBSD 9 + +#define EI_ABIVERSION 8 /* ABI version */ + +#define EI_PAD 9 /* from here in is just padding */ + +#define EI_BRAND 8 /* start of OS branding (This is + obviously illegal against the ELF + standard.) */ + + unsigned char e_ident[EI_NIDENT]; /* basic identification block */ + +#define ET_EXEC 2 /* we only care about executable types */ + Elf32_Half e_type; /* file types */ + +#define EM_386 3 /* i386 -- obviously use this one */ + Elf32_Half e_machine; /* machine types */ + Elf32_Word e_version; /* use same as "EI_VERSION" above */ + Elf32_Addr e_entry; /* entry point of the program */ + Elf32_Off e_phoff; /* program header table file offset */ + Elf32_Off e_shoff; /* section header table file offset */ + Elf32_Word e_flags; /* flags */ + Elf32_Half e_ehsize; /* elf header size in bytes */ + Elf32_Half e_phentsize; /* program header entry size */ + Elf32_Half e_phnum; /* number of entries in program header */ + Elf32_Half e_shentsize; /* section header entry size */ + Elf32_Half e_shnum; /* number of entries in section header */ + +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xff00 +#define SHN_LOPROC 0xff00 +#define SHN_HIPROC 0xff1f +#define SHN_ABS 0xfff1 +#define SHN_COMMON 0xfff2 +#define SHN_HIRESERVE 0xffff + Elf32_Half e_shstrndx; /* section header table index */ +} +Elf32_Ehdr; + + +#define BOOTABLE_I386_ELF(h) \ + ((h.e_ident[EI_MAG0] == ELFMAG0) & (h.e_ident[EI_MAG1] == ELFMAG1) \ + & (h.e_ident[EI_MAG2] == ELFMAG2) & (h.e_ident[EI_MAG3] == ELFMAG3) \ + & (h.e_ident[EI_CLASS] == ELFCLASS32) & (h.e_ident[EI_DATA] == ELFDATA2LSB) \ + & (h.e_ident[EI_VERSION] == EV_CURRENT) & (h.e_type == ET_EXEC) \ + & (h.e_machine == EM_386) & (h.e_version == EV_CURRENT)) + +/* section table - ? */ +typedef struct +{ + Elf32_Word sh_name; /* Section name (string tbl index) */ + Elf32_Word sh_type; /* Section type */ + Elf32_Word sh_flags; /* Section flags */ + Elf32_Addr sh_addr; /* Section virtual addr at execution */ + Elf32_Off sh_offset; /* Section file offset */ + Elf32_Word sh_size; /* Section size in bytes */ + Elf32_Word sh_link; /* Link to another section */ + Elf32_Word sh_info; /* Additional section information */ + Elf32_Word sh_addralign; /* Section alignment */ + Elf32_Word sh_entsize; /* Entry size if section holds table */ +} +Elf32_Shdr; + +/* symbol table - page 4-25, figure 4-15 */ +typedef struct +{ + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Half st_shndx; +} +Elf32_Sym; + +/* symbol type and binding attributes - page 4-26 */ + +#define ELF32_ST_BIND(i) ((i) >> 4) +#define ELF32_ST_TYPE(i) ((i) & 0xf) +#define ELF32_ST_INFO(b,t) (((b)<<4)+((t)&0xf)) + +/* symbol binding - page 4-26, figure 4-16 */ + +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 +#define STB_LOPROC 13 +#define STB_HIPROC 15 + +/* symbol types - page 4-28, figure 4-17 */ + +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_LOPROC 13 +#define STT_HIPROC 15 + + +/* Macros to split/combine relocation type and symbol page 4-32 */ + +#define ELF32_R_SYM(__i) ((__i)>>8) +#define ELF32_R_TYPE(__i) ((unsigned char) (__i)) +#define ELF32_R_INFO(__s, __t) (((__s)<<8) + (unsigned char) (__t)) + + +/* program header - page 5-2, figure 5-1 */ + +typedef struct +{ + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +} +Elf32_Phdr; + +/* segment types - page 5-3, figure 5-2 */ + +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 + +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7fffffff + +/* segment permissions - page 5-6 */ + +#define PF_X 0x1 +#define PF_W 0x2 +#define PF_R 0x4 +#define PF_MASKPROC 0xf0000000 + + +/* dynamic structure - page 5-15, figure 5-9 */ + +typedef struct +{ + Elf32_Sword d_tag; + union + { + Elf32_Word d_val; + Elf32_Addr d_ptr; + } + d_un; +} +Elf32_Dyn; + +/* Dynamic array tags - page 5-16, figure 5-10. */ + +#define DT_NULL 0 +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 +#define DT_PLTGOT 3 +#define DT_HASH 4 +#define DT_STRTAB 5 +#define DT_SYMTAB 6 +#define DT_RELA 7 +#define DT_RELASZ 8 +#define DT_RELAENT 9 +#define DT_STRSZ 10 +#define DT_SYMENT 11 +#define DT_INIT 12 +#define DT_FINI 13 +#define DT_SONAME 14 +#define DT_RPATH 15 +#define DT_SYMBOLIC 16 +#define DT_REL 17 +#define DT_RELSZ 18 +#define DT_RELENT 19 +#define DT_PLTREL 20 +#define DT_DEBUG 21 +#define DT_TEXTREL 22 +#define DT_JMPREL 23 diff --git a/syslinux/com32/modules/mb_header.h b/syslinux/com32/modules/mb_header.h new file mode 100644 index 0000000..2193457 --- /dev/null +++ b/syslinux/com32/modules/mb_header.h @@ -0,0 +1,90 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * MultiBoot Header description + */ + +struct multiboot_header +{ + /* Must be MULTIBOOT_MAGIC - see below. */ + unsigned magic; + + /* Feature flags - see below. */ + unsigned flags; + + /* + * Checksum + * + * The above fields plus this one must equal 0 mod 2^32. + */ + unsigned checksum; + + /* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */ + unsigned header_addr; + unsigned load_addr; + unsigned load_end_addr; + unsigned bss_end_addr; + unsigned entry_addr; + + /* These are only valid if MULTIBOOT_VIDEO_MODE is set. */ + unsigned mode_type; + unsigned width; + unsigned height; + unsigned depth; +}; + +/* + * The entire multiboot_header must be contained + * within the first MULTIBOOT_SEARCH bytes of the kernel image. + */ +#define MULTIBOOT_SEARCH 8192 +#define MULTIBOOT_FOUND(addr, len) \ + (! ((addr) & 0x3) \ + && (len) >= 12 \ + && *((int *) (addr)) == MULTIBOOT_MAGIC \ + && ! (*((unsigned *) (addr)) + *((unsigned *) (addr + 4)) \ + + *((unsigned *) (addr + 8))) \ + && (! (MULTIBOOT_AOUT_KLUDGE & *((int *) (addr + 4))) || (len) >= 32) \ + && (! (MULTIBOOT_VIDEO_MODE & *((int *) (addr + 4))) || (len) >= 48)) + +/* Magic value identifying the multiboot_header. */ +#define MULTIBOOT_MAGIC 0x1BADB002 + +/* + * Features flags for 'flags'. + * If a boot loader sees a flag in MULTIBOOT_MUSTKNOW set + * and it doesn't understand it, it must fail. + */ +#define MULTIBOOT_MUSTKNOW 0x0000FFFF + +/* currently unsupported flags... this is a kind of version number. */ +#define MULTIBOOT_UNSUPPORTED 0x0000FFF8 + +/* Align all boot modules on i386 page (4KB) boundaries. */ +#define MULTIBOOT_PAGE_ALIGN 0x00000001 + +/* Must pass memory information to OS. */ +#define MULTIBOOT_MEMORY_INFO 0x00000002 + +/* Must pass video information to OS. */ +#define MULTIBOOT_VIDEO_MODE 0x00000004 + +/* This flag indicates the use of the address fields in the header. */ +#define MULTIBOOT_AOUT_KLUDGE 0x00010000 diff --git a/syslinux/com32/modules/mb_info.h b/syslinux/com32/modules/mb_info.h new file mode 100644 index 0000000..fb37f10 --- /dev/null +++ b/syslinux/com32/modules/mb_info.h @@ -0,0 +1,217 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * The structure type "mod_list" is used by the "multiboot_info" structure. + */ + +struct mod_list +{ + /* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */ + unsigned long mod_start; + unsigned long mod_end; + + /* Module command line */ + unsigned long cmdline; + + /* padding to take it to 16 bytes (must be zero) */ + unsigned long pad; +}; + + +/* + * INT-15, AX=E820 style "AddressRangeDescriptor" + * ...with a "size" parameter on the front which is the structure size - 4, + * pointing to the next one, up until the full buffer length of the memory + * map has been reached. + */ + +struct AddrRangeDesc +{ + unsigned long size; + unsigned long long BaseAddr; + unsigned long long Length; + unsigned long Type; + + /* unspecified optional padding... */ +}; + +/* usable memory "Type", all others are reserved. */ +#define MB_ARD_MEMORY 1 + + +/* Drive Info structure. */ +struct drive_info +{ + /* The size of this structure. */ + unsigned long size; + + /* The BIOS drive number. */ + unsigned char drive_number; + + /* The access mode (see below). */ + unsigned char drive_mode; + + /* The BIOS geometry. */ + unsigned short drive_cylinders; + unsigned char drive_heads; + unsigned char drive_sectors; + + /* The array of I/O ports used for the drive. */ + unsigned short drive_ports[0]; +}; + +/* Drive Mode. */ +#define MB_DI_CHS_MODE 0 +#define MB_DI_LBA_MODE 1 + + +/* APM BIOS info. */ +struct apm_info +{ + unsigned short version; + unsigned short cseg; + unsigned long offset; + unsigned short cseg_16; + unsigned short dseg_16; + unsigned short cseg_len; + unsigned short cseg_16_len; + unsigned short dseg_16_len; +}; + + +/* + * MultiBoot Info description + * + * This is the struct passed to the boot image. This is done by placing + * its address in the EAX register. + */ + +struct multiboot_info +{ + /* MultiBoot info version number */ + unsigned long flags; + + /* Available memory from BIOS */ + unsigned long mem_lower; + unsigned long mem_upper; + + /* "root" partition */ + unsigned long boot_device; + + /* Kernel command line */ + unsigned long cmdline; + + /* Boot-Module list */ + unsigned long mods_count; + unsigned long mods_addr; + + union + { + struct + { + /* (a.out) Kernel symbol table info */ + unsigned long tabsize; + unsigned long strsize; + unsigned long addr; + unsigned long pad; + } + a; + + struct + { + /* (ELF) Kernel section header table */ + unsigned long num; + unsigned long size; + unsigned long addr; + unsigned long shndx; + } + e; + } + syms; + + /* Memory Mapping buffer */ + unsigned long mmap_length; + unsigned long mmap_addr; + + /* Drive Info buffer */ + unsigned long drives_length; + unsigned long drives_addr; + + /* ROM configuration table */ + unsigned long config_table; + + /* Boot Loader Name */ + unsigned long boot_loader_name; + + /* APM table */ + unsigned long apm_table; + + /* Video */ + unsigned long vbe_control_info; + unsigned long vbe_mode_info; + unsigned short vbe_mode; + unsigned short vbe_interface_seg; + unsigned short vbe_interface_off; + unsigned short vbe_interface_len; +}; + +/* + * Flags to be set in the 'flags' parameter above + */ + +/* is there basic lower/upper memory information? */ +#define MB_INFO_MEMORY 0x00000001 +/* is there a boot device set? */ +#define MB_INFO_BOOTDEV 0x00000002 +/* is the command-line defined? */ +#define MB_INFO_CMDLINE 0x00000004 +/* are there modules to do something with? */ +#define MB_INFO_MODS 0x00000008 + +/* These next two are mutually exclusive */ + +/* is there a symbol table loaded? */ +#define MB_INFO_AOUT_SYMS 0x00000010 +/* is there an ELF section header table? */ +#define MB_INFO_ELF_SHDR 0x00000020 + +/* is there a full memory map? */ +#define MB_INFO_MEM_MAP 0x00000040 + +/* Is there drive info? */ +#define MB_INFO_DRIVE_INFO 0x00000080 + +/* Is there a config table? */ +#define MB_INFO_CONFIG_TABLE 0x00000100 + +/* Is there a boot loader name? */ +#define MB_INFO_BOOT_LOADER_NAME 0x00000200 + +/* Is there a APM table? */ +#define MB_INFO_APM_TABLE 0x00000400 + +/* Is there video information? */ +#define MB_INFO_VIDEO_INFO 0x00000800 + +/* + * The following value must be present in the EAX register. + */ + +#define MULTIBOOT_VALID 0x2BADB002 diff --git a/syslinux/com32/modules/mboot.c b/syslinux/com32/modules/mboot.c new file mode 100644 index 0000000..4238c5c --- /dev/null +++ b/syslinux/com32/modules/mboot.c @@ -0,0 +1,979 @@ +/* + * mboot.c + * + * Loader for Multiboot-compliant kernels and modules. + * + * Copyright (C) 2005 Tim Deegan <Tim.Deegan@cl.cam.ac.uk> + * Parts based on GNU GRUB, Copyright (C) 2000 Free Software Foundation, Inc. + * Parts based on SYSLINUX, Copyright (C) 1994-2005 H. Peter Anvin. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <string.h> +#include <malloc.h> +#include <consoles.h> +#include <zlib.h> +#include <com32.h> + +#include "i386-elf.h" +#include "mb_info.h" +#include "mb_header.h" + +#include <klibc/compiler.h> /* For __constructor */ + +#define MIN(_x, _y) (((_x)<(_y))?(_x):(_y)) +#define MAX(_x, _y) (((_x)>(_y))?(_x):(_y)) + +/* Define this for some more printout */ +#undef DEBUG + +/* Memory magic numbers */ +#define STACK_SIZE 0x20000 /* XXX Could be much smaller */ +#define MALLOC_SIZE 0x100000 /* XXX Could be much smaller */ +#define MIN_RUN_ADDR 0x10000 /* Lowest address we'll consider using */ +#define MEM_HOLE_START 0xa0000 /* Memory hole runs from 640k ... */ +#define MEM_HOLE_END 0x100000 /* ... to 1MB */ +#define X86_PAGE_SIZE 0x1000 + +size_t __stack_size = STACK_SIZE; /* How much stack we'll use */ +extern void *__mem_end; /* Start of malloc() heap */ +extern char _end[]; /* End of static data */ + +/* Pointer to free memory for loading into: load area is between here + * and section_addr */ +static char *next_load_addr; + +/* Memory map for run-time */ +typedef struct section section_t; +struct section { + size_t dest; /* Start of run-time allocation */ + char *src; /* Current location of data for memmove(), + * or NULL for bzero() */ + size_t size; /* Length of allocation */ +}; +static char *section_addr; +static int section_count; + +static size_t max_run_addr; /* Highest address we'll consider using */ +static size_t next_mod_run_addr; /* Where the next module will be put */ + +/* File loads are in units of this much */ +#define LOAD_CHUNK 0x20000 + +/* Layout of the input to the 32-bit lidt instruction */ +struct lidt_operand { + unsigned int limit:16; + unsigned int base:32; +} __attribute__((packed)); + +/* Magic strings */ +static const char version_string[] = "COM32 Multiboot loader v0.1"; +static const char copyright_string[] = "Copyright (C) 2005 Tim Deegan."; +static const char module_separator[] = "---"; + + +/* + * Start of day magic, run from __start during library init. + */ + +static void __constructor check_version(void) + /* Check the SYSLINUX version. Docs say we should be OK from v2.08, + * but in fact we crash on anything below v2.12 (when libc came in). */ +{ + com32sys_t regs_in, regs_out; + const char *p, *too_old = "Fatal: SYSLINUX image is too old; " + "mboot.c32 needs at least version 2.12.\r\n"; + + memset(®s_in, 0, sizeof(regs_in)); + regs_in.eax.l = 0x0001; /* "Get version" */ + __intcall(0x22, ®s_in, ®s_out); + if (regs_out.ecx.w[0] >= 0x020c) return; + + /* Pointless: on older versions this print fails too. :( */ + for (p = too_old ; *p ; p++) { + memset(®s_in, 0, sizeof(regs_in)); + regs_in.eax.b[1] = 0x02; /* "Write character" */ + regs_in.edx.b[0] = *p; + __intcall(0x21, ®s_in, ®s_out); + } + + __intcall(0x20, ®s_in, ®s_out); /* "Terminate program" */ +} + + +static void __constructor grab_memory(void) + /* Runs before init_memory_arena() (com32/lib/malloc.c) to let + * the malloc() code know how much space it's allowed to use. + * We don't use malloc() directly, but some of the library code + * does (zlib, for example). */ +{ + /* Find the stack pointer */ + register char * sp; + asm volatile("movl %%esp, %0" : "=r" (sp)); + + /* Initialize the allocation of *run-time* memory: don't let ourselves + * overwrite the stack during the relocation later. */ + max_run_addr = (size_t) sp - (MALLOC_SIZE + STACK_SIZE); + + /* Move the end-of-memory marker: malloc() will use only memory + * above __mem_end and below the stack. We will load files starting + * at the old __mem_end and working towards the new one, and allocate + * section descriptors at the top of that area, working down. */ + next_load_addr = __mem_end; + section_addr = sp - (MALLOC_SIZE + STACK_SIZE); + section_count = 0; + + /* But be careful not to move it the wrong direction if memory is + * tight. Instead we'll fail more gracefully later, when we try to + * load a file and find that next_load_addr > section_addr. */ + __mem_end = MAX(section_addr, next_load_addr); +} + + + + +/* + * Run-time memory map functions: allocating and recording allocations. + */ + +static int cmp_sections(const void *a, const void *b) + /* For sorting section descriptors by destination address */ +{ + const section_t *sa = a; + const section_t *sb = b; + if (sa->dest < sb->dest) return -1; + if (sa->dest > sb->dest) return 1; + return 0; +} + + +static void add_section(size_t dest, char *src, size_t size) + /* Adds something to the list of sections to relocate. */ +{ + section_t *sec; + +#ifdef DEBUG + printf("SECTION: %#8.8x --> %#8.8x (%#x)\n", (size_t) src, dest, size); +#endif + + section_addr -= sizeof (section_t); + if (section_addr < next_load_addr) { + printf("Fatal: out of memory allocating section descriptor.\n"); + exit(1); + } + sec = (section_t *) section_addr; + section_count++; + + sec->src = src; + sec->dest = dest; + sec->size = size; + + /* Keep the list sorted */ + qsort(sec, section_count, sizeof (section_t), cmp_sections); +} + + +static size_t place_low_section(size_t size, size_t align) + /* Find a space in the run-time memory map, below 640K */ +{ + int i; + size_t start; + section_t *sections = (section_t *) section_addr; + + start = MIN_RUN_ADDR; + start = (start + (align-1)) & ~(align-1); + + /* Section list is sorted by destination, so can do this in one pass */ + for (i = 0; i < section_count; i++) { + if (sections[i].dest < start + size) { + /* Hit the bottom of this section */ + start = sections[i].dest + sections[i].size; + start = (start + (align-1)) & ~(align-1); + } + } + if (start + size < MEM_HOLE_START) return start; + else return 0; +} + + +static size_t place_module_section(size_t size, size_t align) + /* Find a space in the run-time memory map for this module. */ +{ + /* Ideally we'd run through the sections looking for a free space + * like place_low_section() does, but some OSes (Xen, at least) + * assume that the bootloader has loaded all the modules + * consecutively, above the kernel. So, what we actually do is + * keep a pointer to the highest address allocated so far, and + * always allocate modules there. */ + + size_t start = next_mod_run_addr; + start = (start + (align-1)) & ~(align-1); + + if (start + size > max_run_addr) return 0; + + next_mod_run_addr = start + size; + return start; +} + + +static void place_kernel_section(size_t start, size_t size) + /* Allocate run-time space for part of the kernel, checking for + * sanity. We assume the kernel isn't broken enough to have + * overlapping segments. */ +{ + /* We always place modules above the kernel */ + next_mod_run_addr = MAX(next_mod_run_addr, start + size); + + if (start > max_run_addr || start + size > max_run_addr) { + /* Overruns the end of memory */ + printf("Fatal: kernel loads too high (%#8.8x+%#x > %#8.8x).\n", + start, size, max_run_addr); + exit(1); + } + if (start >= MEM_HOLE_END) { + /* Above the memory hole: easy */ +#ifdef DEBUG + printf("Placed kernel section (%#8.8x+%#x)\n", start, size); +#endif + return; + } + if (start >= MEM_HOLE_START) { + /* In the memory hole. Not so good */ + printf("Fatal: kernel load address (%#8.8x) is in the memory hole.\n", + start); + exit(1); + } + if (start + size > MEM_HOLE_START) { + /* Too big for low memory */ + printf("Fatal: kernel (%#8.8x+%#x) runs into the memory hole.\n", + start, size); + exit(1); + } + if (start < MIN_RUN_ADDR) { + /* Loads too low */ + printf("Fatal: kernel load address (%#8.8x) is too low (<%#8.8x).\n", + start, MIN_RUN_ADDR); + exit(1); + } + /* Kernel loads below the memory hole: OK */ +#ifdef DEBUG + printf("Placed kernel section (%#8.8x+%#x)\n", start, size); +#endif +} + + +static void reorder_sections(void) + /* Reorders sections into a safe order, where no relocation + * overwrites the source of a later one. */ +{ + section_t *secs = (section_t *) section_addr; + section_t tmp; + int i, j, tries; + +#ifdef DEBUG + printf("Relocations:\n"); + for (i = 0; i < section_count ; i++) { + printf(" %#8.8x --> %#8.8x (%#x)\n", + (size_t)secs[i].src, secs[i].dest, secs[i].size); + } +#endif + + for (i = 0; i < section_count; i++) { + tries = 0; + scan_again: + for (j = i + 1 ; j < section_count; j++) { + if (secs[j].src != NULL + && secs[i].dest + secs[i].size > (size_t) secs[j].src + && secs[i].dest < (size_t) secs[j].src + secs[j].size) { + /* Would overwrite the source of the later move */ + if (++tries > section_count) { + /* Deadlock! */ + /* XXX Try to break deadlocks? */ + printf("Fatal: circular dependence in relocations.\n"); + exit(1); + } + /* Swap these sections (using struct copies) */ + tmp = secs[i]; secs[i] = secs[j]; secs[j] = tmp; + /* Start scanning again from the new secs[i]... */ + goto scan_again; + } + } + } + +#ifdef DEBUG + printf("Relocations:\n"); + for (i = 0; i < section_count ; i++) { + printf(" %#8.8x --> %#8.8x (%#x)\n", + (size_t)secs[i].src, secs[i].dest, secs[i].size); + } +#endif +} + + +static void init_mmap(struct multiboot_info *mbi) + /* Get a full memory map from the BIOS to pass to the kernel. */ +{ + com32sys_t regs_in, regs_out; + struct AddrRangeDesc *e820; + int e820_slots; + size_t mem_lower, mem_upper, run_addr, mmap_size; + register size_t sp; + + /* Default values for mem_lower and mem_upper in case the BIOS won't + * tell us: 640K, and all memory up to the stack. */ + asm volatile("movl %%esp, %0" : "=r" (sp)); + mem_upper = (sp - MEM_HOLE_END) / 1024; + mem_lower = (MEM_HOLE_START) / 1024; + +#ifdef DEBUG + printf("Requesting memory map from BIOS:\n"); +#endif + + /* Ask the BIOS for the full memory map of the machine. We'll + * build it in Multiboot format (i.e. with size fields) in the + * bounce buffer, and then allocate some high memory to keep it in + * until boot time. */ + e820 = __com32.cs_bounce; + e820_slots = 0; + regs_out.ebx.l = 0; + + while(((void *)(e820 + 1)) < __com32.cs_bounce + __com32.cs_bounce_size) + { + + e820->size = sizeof(*e820) - sizeof(e820->size); + + /* Ask the BIOS to fill in this descriptor */ + regs_in.eax.l = 0xe820; /* "Get system memory map" */ + regs_in.ebx.l = regs_out.ebx.l; /* Continuation value from last call */ + regs_in.ecx.l = 20; /* Size of buffer to write into */ + regs_in.edx.l = 0x534d4150; /* "SMAP" */ + regs_in.es = SEG(&e820->BaseAddr); + regs_in.edi.w[0] = OFFS(&e820->BaseAddr); + __intcall(0x15, ®s_in, ®s_out); + + if ((regs_out.eflags.l & EFLAGS_CF) != 0 && regs_out.ebx.l != 0) + break; /* End of map */ + + if (((regs_out.eflags.l & EFLAGS_CF) != 0 && regs_out.ebx.l == 0) + || (regs_out.eax.l != 0x534d4150)) + { + /* Error */ + printf("Error %x reading E820 memory map: %s.\n", + (int) regs_out.eax.b[0], + (regs_out.eax.b[0] == 0x80) ? "invalid command" : + (regs_out.eax.b[0] == 0x86) ? "not supported" : + "unknown error"); + break; + } + + /* Success */ +#ifdef DEBUG + printf(" %#16.16Lx -- %#16.16Lx : ", + e820->BaseAddr, e820->BaseAddr + e820->Length); + switch (e820->Type) { + case 1: printf("Available\n"); break; + case 2: printf("Reserved\n"); break; + case 3: printf("ACPI Reclaim\n"); break; + case 4: printf("ACPI NVS\n"); break; + default: printf("? (Reserved)\n"); break; + } +#endif + + if (e820->Type == 1) { + if (e820->BaseAddr == 0) { + mem_lower = MIN(MEM_HOLE_START, e820->Length) / 1024; + } else if (e820->BaseAddr == MEM_HOLE_END) { + mem_upper = MIN(0xfff00000, e820->Length) / 1024; + } + } + + /* Move to next slot */ + e820++; + e820_slots++; + + /* Done? */ + if (regs_out.ebx.l == 0) + break; + } + + /* Record the simple information in the MBI */ + mbi->flags |= MB_INFO_MEMORY; + mbi->mem_lower = mem_lower; + mbi->mem_upper = mem_upper; + + /* Record the full memory map in the MBI */ + if (e820_slots != 0) { + mmap_size = e820_slots * sizeof(*e820); + /* Where will it live at run time? */ + run_addr = place_low_section(mmap_size, 1); + if (run_addr == 0) { + printf("Fatal: can't find space for the e820 mmap.\n"); + exit(1); + } + /* Where will it live now? */ + e820 = (struct AddrRangeDesc *) next_load_addr; + if (next_load_addr + mmap_size > section_addr) { + printf("Fatal: out of memory storing the e820 mmap.\n"); + exit(1); + } + next_load_addr += mmap_size; + /* Copy it out of the bounce buffer */ + memcpy(e820, __com32.cs_bounce, mmap_size); + /* Remember to copy it again at run time */ + add_section(run_addr, (char *) e820, mmap_size); + /* Record it in the MBI */ + mbi->flags |= MB_INFO_MEM_MAP; + mbi->mmap_length = mmap_size; + mbi->mmap_addr = run_addr; + } +} + + + + +/* + * Code for loading and parsing files. + */ + +static void load_file(char *filename, char **startp, size_t *sizep) + /* Load a file into memory. Returns where it is and how big via + * startp and sizep */ +{ + gzFile fp; + char *start; + int bsize; + + printf("Loading %s.", filename); + + start = next_load_addr; + startp[0] = start; + sizep[0] = 0; + + /* Open the file */ + if ((fp = gzopen(filename, "r")) == NULL) { + printf("\nFatal: cannot open %s\n", filename); + exit(1); + } + + while (next_load_addr + LOAD_CHUNK <= section_addr) { + bsize = gzread(fp, next_load_addr, LOAD_CHUNK); + printf("%s","."); + + if (bsize < 0) { + printf("\nFatal: read error in %s\n", filename); + gzclose(fp); + exit(1); + } + + next_load_addr += bsize; + sizep[0] += bsize; + + if (bsize < LOAD_CHUNK) { + printf("%s","\n"); + gzclose(fp); + return; + } + } + + /* Running out of memory. Try and use up the last bit */ + if (section_addr > next_load_addr) { + bsize = gzread(fp, next_load_addr, section_addr - next_load_addr); + printf("%s","."); + } else { + bsize = 0; + } + + if (bsize < 0) { + gzclose(fp); + printf("\nFatal: read error in %s\n", filename); + exit(1); + } + + next_load_addr += bsize; + sizep[0] += bsize; + + if (!gzeof(fp)) { + gzclose(fp); + printf("\nFatal: out of memory reading %s\n", filename); + exit(1); + } + + printf("%s","\n"); + gzclose(fp); + return; +} + + +static size_t load_kernel(char *cmdline) + /* Load a multiboot/elf32 kernel and allocate run-time memory for it. + * Returns the kernel's entry address. */ +{ + unsigned int i; + char *load_addr; /* Where the image was loaded */ + size_t load_size; /* How big it is */ + char *seg_addr; /* Where a segment was loaded */ + size_t seg_size, bss_size; /* How big it is */ + size_t run_addr, run_size; /* Where it should be put */ + char *p; + Elf32_Ehdr *ehdr; + Elf32_Phdr *phdr; + struct multiboot_header *mbh; + + printf("Kernel: %s\n", cmdline); + + load_addr = 0; + load_size = 0; + p = strchr(cmdline, ' '); + if (p != NULL) *p = 0; + load_file(cmdline, &load_addr, &load_size); + if (load_size < 12) { + printf("Fatal: %s is too short to be a multiboot kernel.", + cmdline); + exit(1); + } + if (p != NULL) *p = ' '; + + + /* Look for a multiboot header in the first 8k of the file */ + for (i = 0; i <= MIN(load_size - 12, MULTIBOOT_SEARCH - 12); i += 4) + { + mbh = (struct multiboot_header *)(load_addr + i); + if (mbh->magic != MULTIBOOT_MAGIC + || ((mbh->magic+mbh->flags+mbh->checksum) & 0xffffffff)) + { + /* Not a multiboot header */ + continue; + } + if (mbh->flags & (MULTIBOOT_UNSUPPORTED | MULTIBOOT_VIDEO_MODE)) { + /* Requires options we don't support */ + printf("Fatal: Kernel requires multiboot options " + "that I don't support: %#x.\n", + mbh->flags & (MULTIBOOT_UNSUPPORTED|MULTIBOOT_VIDEO_MODE)); + exit(1); + } + + /* This kernel will do: figure out where all the pieces will live */ + + if (mbh->flags & MULTIBOOT_AOUT_KLUDGE) { + + /* Use the offsets in the multiboot header */ +#ifdef DEBUG + printf("Using multiboot header.\n"); +#endif + + /* Where is the code in the loaded file? */ + seg_addr = ((char *)mbh) - (mbh->header_addr - mbh->load_addr); + + /* How much code is there? */ + run_addr = mbh->load_addr; + if (mbh->load_end_addr != 0) + seg_size = mbh->load_end_addr - mbh->load_addr; + else + seg_size = load_size - (seg_addr - load_addr); + + /* How much memory will it take up? */ + if (mbh->bss_end_addr != 0) + run_size = mbh->bss_end_addr - mbh->load_addr; + else + run_size = seg_size; + + if (seg_size > run_size) { + printf("Fatal: can't put %i bytes of kernel into %i bytes " + "of memory.\n", seg_size, run_size); + exit(1); + } + if (seg_addr + seg_size > load_addr + load_size) { + printf("Fatal: multiboot load segment runs off the " + "end of the file.\n"); + exit(1); + } + + /* Does it fit where it wants to be? */ + place_kernel_section(run_addr, run_size); + + /* Put it on the relocation list */ + if (seg_size < run_size) { + /* Set up the kernel BSS too */ + if (seg_size > 0) + add_section(run_addr, seg_addr, seg_size); + bss_size = run_size - seg_size; + add_section(run_addr + seg_size, NULL, bss_size); + } else { + /* No BSS */ + add_section(run_addr, seg_addr, run_size); + } + + /* Done. */ + return mbh->entry_addr; + + } else { + + /* Now look for an ELF32 header */ + ehdr = (Elf32_Ehdr *)load_addr; + if (*(unsigned long *)ehdr != 0x464c457f + || ehdr->e_ident[EI_DATA] != ELFDATA2LSB + || ehdr->e_ident[EI_CLASS] != ELFCLASS32 + || ehdr->e_machine != EM_386) + { + printf("Fatal: kernel has neither ELF32/x86 nor multiboot load" + " headers.\n"); + exit(1); + } + if (ehdr->e_phoff + ehdr->e_phnum*sizeof (*phdr) > load_size) { + printf("Fatal: malformed ELF header overruns EOF.\n"); + exit(1); + } + if (ehdr->e_phnum <= 0) { + printf("Fatal: ELF kernel has no program headers.\n"); + exit(1); + } + +#ifdef DEBUG + printf("Using ELF header.\n"); +#endif + + if (ehdr->e_type != ET_EXEC + || ehdr->e_version != EV_CURRENT + || ehdr->e_phentsize != sizeof (Elf32_Phdr)) { + printf("Warning: funny-looking ELF header.\n"); + } + phdr = (Elf32_Phdr *)(load_addr + ehdr->e_phoff); + + /* Obey the program headers to load the kernel */ + for(i = 0; i < ehdr->e_phnum; i++) { + + /* How much is in this segment? */ + run_size = phdr[i].p_memsz; + if (phdr[i].p_type != PT_LOAD) + seg_size = 0; + else + seg_size = (size_t)phdr[i].p_filesz; + + /* Where is it in the loaded file? */ + seg_addr = load_addr + phdr[i].p_offset; + if (seg_addr + seg_size > load_addr + load_size) { + printf("Fatal: ELF load segment runs off the " + "end of the file.\n"); + exit(1); + } + + /* Skip segments that don't take up any memory */ + if (run_size == 0) continue; + + /* Place the segment where it wants to be */ + run_addr = phdr[i].p_paddr; + place_kernel_section(run_addr, run_size); + + /* Put it on the relocation list */ + if (seg_size < run_size) { + /* Set up the kernel BSS too */ + if (seg_size > 0) + add_section(run_addr, seg_addr, seg_size); + bss_size = run_size - seg_size; + add_section(run_addr + seg_size, NULL, bss_size); + } else { + /* No BSS */ + add_section(run_addr, seg_addr, run_size); + } + } + + /* Done! */ + return ehdr->e_entry; + } + } + + /* This is not a multiboot kernel */ + printf("Fatal: not a multiboot kernel.\n"); + exit(1); +} + + + +static void load_module(struct mod_list *mod, char *cmdline) + /* Load a multiboot module and allocate a memory area for it */ +{ + char *load_addr, *p; + size_t load_size, run_addr; + + printf("Module: %s\n", cmdline); + + load_addr = 0; + load_size = 0; + p = strchr(cmdline, ' '); + if (p != NULL) *p = 0; + load_file(cmdline, &load_addr, &load_size); + if (p != NULL) *p = ' '; + + /* Decide where it's going to live */ + run_addr = place_module_section(load_size, X86_PAGE_SIZE); + if (run_addr == 0) { + printf("Fatal: can't find space for this module.\n"); + exit(1); + } + add_section(run_addr, load_addr, load_size); + + /* Remember where we put it */ + mod->mod_start = run_addr; + mod->mod_end = run_addr + load_size; + mod->pad = 0; + +#ifdef DEBUG + printf("Placed module (%#8.8x+%#x)\n", run_addr, load_size); +#endif +} + + + + +/* + * Code for shuffling sections into place and booting the new kernel + */ + +static void trampoline_start(section_t *secs, int sec_count, + size_t mbi_run_addr, size_t entry) + /* Final shuffle-and-boot code. Running on the stack; no external code + * or data can be relied on. */ +{ + int i; + struct lidt_operand idt; + + /* SYSLINUX has set up SS, DS and ES as 32-bit 0--4G data segments, + * but doesn't specify FS and GS. Multiboot wants them all to be + * the same, so we'd better do that before we overwrite the GDT. */ + asm volatile("movl %ds, %ecx; movl %ecx, %fs; movl %ecx, %gs"); + + /* Turn off interrupts */ + asm volatile("cli"); + + /* SYSLINUX has set up an IDT at 0x100000 that does all the + * comboot calls, and we're about to overwrite it. The Multiboot + * spec says that the kernel must set up its own IDT before turning + * on interrupts, but it's still entitled to use BIOS calls, so we'll + * put the IDT back to the BIOS one at the base of memory. */ + idt.base = 0; + idt.limit = 0x800; + asm volatile("lidt %0" : : "m" (idt)); + + /* Now, shuffle the sections */ + for (i = 0; i < sec_count; i++) { + if (secs[i].src == NULL) { + /* asm bzero() code from com32/lib/memset.c */ + char *q = (char *) secs[i].dest; + size_t nl = secs[i].size >> 2; + asm volatile("cld ; rep ; stosl ; movl %3,%0 ; rep ; stosb" + : "+c" (nl), "+D" (q) + : "a" (0x0U), "r" (secs[i].size & 3)); + } else { + /* asm memmove() code from com32/lib/memmove.c */ + const char *p = secs[i].src; + char *q = (char *) secs[i].dest; + size_t n = secs[i].size; + if ( q < p ) { + asm volatile("cld ; rep ; movsb" + : "+c" (n), "+S" (p), "+D" (q)); + } else { + p += (n-1); + q += (n-1); + asm volatile("std ; rep ; movsb" + : "+c" (n), "+S" (p), "+D" (q)); + } + } + } + + /* Now set up the last tiny bit of Multiboot environment... */ + + asm volatile( + + /* A20 is already enabled. + * CR0 already has PG cleared and PE set. + * EFLAGS already has VM and IF cleared. + * ESP is the kernels' problem. + * GDTR is the kernel's problem. + * CS is already a 32-bit, 0--4G code segments. + * DS, ES, FS and GS are already 32-bit, 0--4G data segments. + * EBX must point to the MBI: */ + + "movl %0, %%ebx;" + + /* EAX must be the Multiboot magic number. */ + + "movl $0x2badb002, %%eax;" + + /* Start the kernel. */ + + "jmp *%1" + + : : "m" (mbi_run_addr), "r" (entry)); + +} +static void trampoline_end(void) {} + + +static void boot(size_t mbi_run_addr, size_t entry) + /* Tidy up SYSLINUX, shuffle memory and boot the kernel */ +{ + com32sys_t regs; + section_t *tr_sections; + void (*trampoline)(section_t *, int, size_t, size_t); + size_t trampoline_size; + + /* Make sure the relocations are safe. */ + reorder_sections(); + + /* Copy the shuffle-and-boot code and the array of relocations + * onto the memory we previously used for malloc() heap. This is + * safe because it's not the source or the destination of any + * copies, and there'll be no more library calls after the copy. */ + + tr_sections = ((section_t *) section_addr) + section_count; + trampoline = (void *) (tr_sections + section_count); + trampoline_size = (void *)&trampoline_end - (void *)&trampoline_start; + +#ifdef DEBUG + printf("tr_sections: %p\n" + "trampoline: %p\n" + "trampoline_size: %#8.8x\n" + "max_run_addr: %#8.8x\n", + tr_sections, trampoline, trampoline_size, max_run_addr); +#endif + + printf("Booting: MBI=%#8.8x, entry=%#8.8x\n", mbi_run_addr, entry); + + memmove(tr_sections, section_addr, section_count * sizeof (section_t)); + memmove(trampoline, trampoline_start, trampoline_size); + + /* Tell SYSLINUX to clean up */ + regs.eax.l = 0x000c; /* "Perform final cleanup" */ + regs.edx.l = 0; /* "Normal cleanup" */ + __intcall(0x22, ®s, NULL); + + /* Into the unknown */ + trampoline(tr_sections, section_count, mbi_run_addr, entry); +} + + +int main(int argc, char **argv) + /* Parse the command-line and invoke loaders */ +{ + struct multiboot_info *mbi; + struct mod_list *modp; + int modules; + int mbi_reloc_offset; + char *p; + size_t mbi_run_addr, mbi_size, entry; + int i; + + /* Say hello */ + console_ansi_std(); + printf("%s. %s\n", version_string, copyright_string); + + if (argc < 2 || !strcmp(argv[1], module_separator)) { + printf("Fatal: No kernel filename!\n"); + exit(1); + } + +#ifdef DEBUG + printf("_end: %p\n" + "argv[1]: %p\n" + "next_load_addr: %p\n" + "section_addr %p\n" + "__mem_end: %p\n" + "argv[0]: %p\n", + &_end, argv[1], next_load_addr, section_addr, __mem_end, argv[0]); +#endif + + /* How much space will the MBI need? */ + modules = 0; + mbi_size = sizeof(struct multiboot_info) + strlen(version_string) + 5; + for (i = 1 ; i < argc ; i++) { + if (!strcmp(argv[i], module_separator)) { + modules++; + mbi_size += sizeof(struct mod_list) + 1; + } else { + mbi_size += strlen(argv[i]) + 1; + } + } + + /* Allocate space in the load buffer for the MBI, all the command + * lines, and all the module details. */ + mbi = (struct multiboot_info *)next_load_addr; + next_load_addr += mbi_size; + if (next_load_addr > section_addr) { + printf("Fatal: out of memory allocating for boot metadata.\n"); + exit(1); + } + memset(mbi, 0, sizeof (struct multiboot_info)); + p = (char *)(mbi + 1); + mbi->flags = MB_INFO_CMDLINE | MB_INFO_BOOT_LOADER_NAME; + + /* Figure out the memory map. + * N.B. Must happen before place_section() is called */ + init_mmap(mbi); + + mbi_run_addr = place_low_section(mbi_size, 4); + if (mbi_run_addr == 0) { + printf("Fatal: can't find space for the MBI!\n"); + exit(1); + } + mbi_reloc_offset = (size_t)mbi - mbi_run_addr; + add_section(mbi_run_addr, (void *)mbi, mbi_size); + + /* Module info structs */ + modp = (struct mod_list *) (((size_t)p + 3) & ~3); + if (modules > 0) mbi->flags |= MB_INFO_MODS; + mbi->mods_count = modules; + mbi->mods_addr = ((size_t)modp) - mbi_reloc_offset; + p = (char *)(modp + modules); + + /* Command lines: first kernel, then modules */ + mbi->cmdline = ((size_t)p) - mbi_reloc_offset; + modules = 0; + for (i = 1 ; i < argc ; i++) { + if (!strcmp(argv[i], module_separator)) { + *p++ = '\0'; + modp[modules++].cmdline = ((size_t)p) - mbi_reloc_offset; + } else { + strcpy(p, argv[i]); + p += strlen(argv[i]); + *p++ = ' '; + } + } + *p++ = '\0'; + + /* Bootloader ID */ + strcpy(p, version_string); + mbi->boot_loader_name = ((size_t)p) - mbi_reloc_offset; + p += strlen(version_string) + 1; + + /* Now, do all the loading, and boot it */ + entry = load_kernel((char *)(mbi->cmdline + mbi_reloc_offset)); + for (i=0; i<modules; i++) { + load_module(&(modp[i]), (char *)(modp[i].cmdline + mbi_reloc_offset)); + } + boot(mbi_run_addr, entry); + + return 1; +} + +/* + * EOF + */ diff --git a/syslinux/com32/modules/mboot.doc b/syslinux/com32/modules/mboot.doc new file mode 100644 index 0000000..006e46f --- /dev/null +++ b/syslinux/com32/modules/mboot.doc @@ -0,0 +1,27 @@ + +mboot.c32 +--------- + +mboot.c32 is a 32-bit comboot module that allows SYSLINUX and its +variants to load and boot kernels that use the Multiboot standard +(e.g. the Xen virtual machine monitor, and the Fiasco and GNU Mach +microkernels). + +To load a multiboot kernel and modules in SYSLINUX, put mboot.c32 (from +com32/modules) in the boot directory, and load it as the "kernel" in the +configuration file. The command-line to pass to mboot.c32 is the kernel +command-line, followed by all the module command lines, separated with +'---'. For example, to load a Xen VMM, xenlinux and an initrd: + +DEFAULT mboot.c32 xen.gz dom0_mem=15000 nosmp noacpi --- linux.gz console=tty0 root=/dev/hda1 --- initrd.img + +or, as a choice in a menu: + +LABEL Xen + KERNEL mboot.c32 + APPEND xen.gz dom0_mem=15000 nosmp noacpi --- linux.gz console=tty0 root=/dev/hda1 --- initrd.img + +mboot.c32 requires version 2.12 or later of SYSLINUX. + +Tim Deegan, May 2005 + diff --git a/syslinux/com32/modules/menu.c b/syslinux/com32/modules/menu.c new file mode 100644 index 0000000..06ff9ef --- /dev/null +++ b/syslinux/com32/modules/menu.c @@ -0,0 +1,631 @@ +#ident "$Id: menu.c,v 1.19 2005/04/06 09:53:28 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004-2005 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * menu.c + * + * Simple menu system which displays a list and allows the user to select + * a command line and/or edit it. + */ + +#define _GNU_SOURCE /* Needed for asprintf() on Linux */ +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <consoles.h> +#include <getkey.h> +#include <minmax.h> +#include <time.h> +#include <sys/times.h> +#include <unistd.h> +#include <sha1.h> +#include <base64.h> +#ifdef __COM32__ +#include <com32.h> +#endif + +#include "menu.h" + +#ifndef CLK_TCK +# define CLK_TCK sysconf(_SC_CLK_TCK) +#endif + +struct menu_attrib { + const char *border; /* Border area */ + const char *title; /* Title bar */ + const char *unsel; /* Unselected menu item */ + const char *hotkey; /* Unselected hotkey */ + const char *sel; /* Selected */ + const char *hotsel; /* Selected hotkey */ + const char *scrollbar; /* Scroll bar */ + const char *tabmsg; /* Press [Tab] message */ + const char *cmdmark; /* Command line marker */ + const char *cmdline; /* Command line */ + const char *screen; /* Rest of the screen */ + const char *pwdborder; /* Password box border */ + const char *pwdheader; /* Password box header */ + const char *pwdentry; /* Password box contents */ +}; + +static const struct menu_attrib default_attrib = { + .border = "\033[0;30;44m", + .title = "\033[1;36;44m", + .unsel = "\033[0;37;44m", + .hotkey = "\033[1;37;44m", + .sel = "\033[0;7;37;40m", + .hotsel = "\033[1;7;37;40m", + .scrollbar = "\033[0;30;44m", + .tabmsg = "\033[0;31;40m", + .cmdmark = "\033[1;36;40m", + .cmdline = "\033[0;37;40m", + .screen = "\033[0;37;40m", + .pwdborder = "\033[0;30;47m", + .pwdheader = "\033[0;31;47m", + .pwdentry = "\033[0;30;47m", +}; + +static const struct menu_attrib *menu_attrib = &default_attrib; + +#define WIDTH 80 +#define MARGIN 10 +#define PASSWD_MARGIN 3 +#define MENU_ROWS 12 +#define TABMSG_ROW 18 +#define CMDLINE_ROW 20 +#define END_ROW 24 +#define PASSWD_ROW 11 + +static char * +pad_line(const char *text, int align, int width) +{ + static char buffer[256]; + int n, p; + + if ( width >= (int) sizeof buffer ) + return NULL; /* Can't do it */ + + n = strlen(text); + if ( n >= width ) + n = width; + + memset(buffer, ' ', width); + buffer[width] = 0; + p = ((width-n)*align)>>1; + memcpy(buffer+p, text, n); + + return buffer; +} + +/* Display an entry, with possible hotkey highlight. Assumes + that the current attribute is the non-hotkey one, and will + guarantee that as an exit condition as well. */ +static void +display_entry(const struct menu_entry *entry, const char *attrib, + const char *hotattrib, int width) +{ + const char *p = entry->displayname; + + while ( width ) { + if ( *p ) { + if ( *p == '^' ) { + p++; + if ( *p && ((unsigned char)*p & ~0x20) == entry->hotkey ) { + fputs(hotattrib, stdout); + putchar(*p++); + fputs(attrib, stdout); + width--; + } + } else { + putchar(*p++); + width--; + } + } else { + putchar(' '); + width--; + } + } +} + +static void +draw_row(int y, int sel, int top, int sbtop, int sbbot) +{ + int i = (y-4)+top; + + printf("\033[%d;%dH%s\016x\017%s ", + y, MARGIN+1, menu_attrib->border, + (i == sel) ? menu_attrib->sel : menu_attrib->unsel); + + if ( i >= nentries ) { + fputs(pad_line("", 0, WIDTH-2*MARGIN-4), stdout); + } else { + display_entry(&menu_entries[i], + (i == sel) ? menu_attrib->sel : menu_attrib->unsel, + (i == sel) ? menu_attrib->hotsel : menu_attrib->hotkey, + WIDTH-2*MARGIN-4); + } + + if ( nentries <= MENU_ROWS ) { + printf(" %s\016x\017", menu_attrib->border); + } else if ( sbtop > 0 ) { + if ( y >= sbtop && y <= sbbot ) + printf(" %s\016a\017", menu_attrib->scrollbar); + else + printf(" %s\016x\017", menu_attrib->border); + } else { + putchar(' '); /* Don't modify the scrollbar */ + } +} + +static int +passwd_compare(const char *passwd, const char *entry) +{ + const char *p; + SHA1_CTX ctx; + unsigned char sha1[20], pwdsha1[20]; + + if ( passwd[0] != '$' ) /* Plaintext passwd, yuck! */ + return !strcmp(entry, passwd); + + if ( strncmp(passwd, "$4$", 3) ) + return 0; /* Only SHA-1 passwds supported */ + + SHA1Init(&ctx); + + if ( (p = strchr(passwd+3, '$')) ) { + SHA1Update(&ctx, passwd+3, p-(passwd+3)); + p++; + } else { + p = passwd+3; /* Assume no salt */ + } + + SHA1Update(&ctx, entry, strlen(entry)); + SHA1Final(sha1, &ctx); + + memset(pwdsha1, 0, 20); + unbase64(pwdsha1, 20, p); + + return !memcmp(sha1, pwdsha1, 20); +} + +static int +ask_passwd(const char *menu_entry) +{ + static const char title[] = "Password required"; + char user_passwd[WIDTH], *p; + int done; + int key; + int x; + + printf("\033[%d;%dH%s\016l", PASSWD_ROW, PASSWD_MARGIN+1, + menu_attrib->pwdborder); + for ( x = 2 ; x <= WIDTH-2*PASSWD_MARGIN-1 ; x++ ) + putchar('q'); + + printf("k\033[%d;%dHx", PASSWD_ROW+1, PASSWD_MARGIN+1); + for ( x = 2 ; x <= WIDTH-2*PASSWD_MARGIN-1 ; x++ ) + putchar(' '); + + printf("x\033[%d;%dHm", PASSWD_ROW+2, PASSWD_MARGIN+1); + for ( x = 2 ; x <= WIDTH-2*PASSWD_MARGIN-1 ; x++ ) + putchar('q'); + + printf("j\017\033[%d;%dH%s %s \033[%d;%dH%s", + PASSWD_ROW, (WIDTH-((int)sizeof(title)+1))/2, + menu_attrib->pwdheader, title, + PASSWD_ROW+1, PASSWD_MARGIN+3, menu_attrib->pwdentry); + + /* Actually allow user to type a password, then compare to the SHA1 */ + done = 0; + p = user_passwd; + + while ( !done ) { + key = get_key(stdin, 0); + + switch ( key ) { + case KEY_ENTER: + case KEY_CTRL('J'): + done = 1; + break; + + case KEY_ESC: + case KEY_CTRL('C'): + p = user_passwd; /* No password entered */ + done = 1; + break; + + case KEY_BACKSPACE: + case KEY_DEL: + case KEY_DELETE: + if ( p > user_passwd ) { + printf("\b \b"); + p--; + } + break; + + case KEY_CTRL('U'): + while ( p > user_passwd ) { + printf("\b \b"); + p--; + } + break; + + default: + if ( key >= ' ' && key <= 0xFF && + (p-user_passwd) < WIDTH-2*PASSWD_MARGIN-5 ) { + *p++ = key; + putchar('*'); + } + break; + } + } + + if ( p == user_passwd ) + return 0; /* No password entered */ + + *p = '\0'; + + return (menu_master_passwd && passwd_compare(menu_master_passwd, user_passwd)) + || (menu_entry && passwd_compare(menu_entry, user_passwd)); +} + + +static void +draw_menu(int sel, int top) +{ + int x, y; + int sbtop = 0, sbbot = 0; + + if ( nentries > MENU_ROWS ) { + int sblen = MENU_ROWS*MENU_ROWS/nentries; + sbtop = (MENU_ROWS-sblen+1)*top/(nentries-MENU_ROWS+1); + sbbot = sbtop + sblen - 1; + + sbtop += 4; sbbot += 4; /* Starting row of scrollbar */ + } + + printf("\033[1;%dH%s\016l", MARGIN+1, menu_attrib->border); + for ( x = 2 ; x <= WIDTH-2*MARGIN-1 ; x++ ) + putchar('q'); + + printf("k\033[2;%dH%sx\017%s %s %s\016x", + MARGIN+1, + menu_attrib->border, + menu_attrib->title, + pad_line(menu_title, 1, WIDTH-2*MARGIN-4), + menu_attrib->border); + + printf("\033[3;%dH%st", MARGIN+1, menu_attrib->border); + for ( x = 2 ; x <= WIDTH-2*MARGIN-1 ; x++ ) + putchar('q'); + fputs("u\017", stdout); + + for ( y = 4 ; y < 4+MENU_ROWS ; y++ ) + draw_row(y, sel, top, sbtop, sbbot); + + printf("\033[%d;%dH%s\016m", y, MARGIN+1, menu_attrib->border); + for ( x = 2 ; x <= WIDTH-2*MARGIN-1 ; x++ ) + putchar('q'); + fputs("j\017", stdout); + + if ( allowedit && !menu_master_passwd ) + printf("%s\033[%d;1H%s", menu_attrib->tabmsg, TABMSG_ROW, + pad_line("Press [Tab] to edit options", 1, WIDTH)); + + printf("%s\033[%d;1H", menu_attrib->screen, END_ROW); +} + +static const char * +edit_cmdline(char *input, int top) +{ + static char cmdline[MAX_CMDLINE_LEN]; + int key, len; + int redraw = 1; /* We enter with the menu already drawn */ + + strncpy(cmdline, input, MAX_CMDLINE_LEN); + cmdline[MAX_CMDLINE_LEN-1] = '\0'; + + len = strlen(cmdline); + + for (;;) { + if ( redraw > 1 ) { + /* Clear and redraw whole screen */ + /* Enable ASCII on G0 and DEC VT on G1; do it in this order + to avoid confusing the Linux console */ + printf("\033e\033%%@\033)0\033(B%s\033[?25l\033[2J", menu_attrib->screen); + draw_menu(-1, top); + } + + if ( redraw > 0 ) { + /* Redraw the command line */ + printf("\033[?25h\033[%d;1H%s> %s%s", + CMDLINE_ROW, menu_attrib->cmdmark, + menu_attrib->cmdline, pad_line(cmdline, 0, MAX_CMDLINE_LEN-1)); + printf("%s\033[%d;3H%s", + menu_attrib->cmdline, CMDLINE_ROW, cmdline); + redraw = 0; + } + + key = get_key(stdin, 0); + + /* FIX: should handle arrow keys and edit-in-middle */ + + switch( key ) { + case KEY_CTRL('L'): + redraw = 2; + break; + case KEY_ENTER: + case KEY_CTRL('J'): + return cmdline; + case KEY_ESC: + case KEY_CTRL('C'): + return NULL; + case KEY_BACKSPACE: + case KEY_DEL: + case KEY_DELETE: + if ( len ) { + cmdline[--len] = '\0'; + redraw = 1; + } + break; + case KEY_CTRL('U'): + if ( len ) { + len = 0; + cmdline[len] = '\0'; + redraw = 1; + } + break; + case KEY_CTRL('W'): + if ( len ) { + int wasbs = (cmdline[len-1] <= ' '); + while ( len && (cmdline[len-1] <= ' ' || !wasbs) ) { + len--; + wasbs = wasbs || (cmdline[len-1] <= ' '); + } + cmdline[len] = '\0'; + redraw = 1; + } + break; + default: + if ( key >= ' ' && key <= 0xFF && len < MAX_CMDLINE_LEN-1 ) { + cmdline[len] = key; + cmdline[++len] = '\0'; + putchar(key); + } + break; + } + } +} + +static void +clear_screen(void) +{ + printf("\033e\033%%@\033)0\033(B%s\033[?25l\033[2J", menu_attrib->screen); +} + +static const char * +run_menu(void) +{ + int key; + int done = 0; + int entry = defentry, prev_entry = -1; + int top = 0, prev_top = -1; + int clear = 1; + const char *cmdline = NULL; + clock_t key_timeout; + + /* Convert timeout from deciseconds to clock ticks */ + /* Note: for both key_timeout and timeout == 0 means no limit */ + key_timeout = (clock_t)(CLK_TCK*timeout+9)/10; + + while ( !done ) { + if ( entry < 0 ) + entry = 0; + else if ( entry >= nentries ) + entry = nentries-1; + + if ( top < 0 || top < entry-MENU_ROWS+1 ) + top = max(0, entry-MENU_ROWS+1); + else if ( top > entry || top > max(0,nentries-MENU_ROWS) ) + top = min(entry, max(0,nentries-MENU_ROWS)); + + /* Start with a clear screen */ + if ( clear ) { + /* Clear and redraw whole screen */ + /* Enable ASCII on G0 and DEC VT on G1; do it in this order + to avoid confusing the Linux console */ + clear_screen(); + clear = 0; + prev_entry = prev_top = -1; + } + + if ( top != prev_top ) { + draw_menu(entry, top); + } else if ( entry != prev_entry ) { + draw_row(prev_entry-top+4, entry, top, 0, 0); + draw_row(entry-top+4, entry, top, 0, 0); + } + + prev_entry = entry; prev_top = top; + + key = get_key(stdin, key_timeout); + switch ( key ) { + case KEY_NONE: /* Timeout */ + /* This is somewhat hacky, but this at least lets the user + know what's going on, and still deals with "phantom inputs" + e.g. on serial ports. + + Warning: a timeout will boot the default entry without any + password! */ + if ( entry != defentry ) + entry = defentry; + else { + cmdline = menu_entries[defentry].label; + done = 1; + } + break; + case KEY_CTRL('L'): + clear = 1; + break; + case KEY_ENTER: + case KEY_CTRL('J'): + if ( menu_entries[entry].passwd ) { + clear = 1; + done = ask_passwd(menu_entries[entry].passwd); + } else { + done = 1; + } + cmdline = menu_entries[entry].label; + break; + case 'P': + case 'p': + case KEY_UP: + if ( entry > 0 ) { + entry--; + if ( entry < top ) + top -= MENU_ROWS; + } + break; + case 'N': + case 'n': + case KEY_DOWN: + if ( entry < nentries-1 ) { + entry++; + if ( entry >= top+MENU_ROWS ) + top += MENU_ROWS; + } + break; + case KEY_CTRL('P'): + case KEY_PGUP: + case KEY_LEFT: + entry -= MENU_ROWS; + top -= MENU_ROWS; + break; + case KEY_CTRL('N'): + case KEY_PGDN: + case KEY_RIGHT: + case ' ': + entry += MENU_ROWS; + top += MENU_ROWS; + break; + case '-': + entry--; + top--; + break; + case '+': + entry++; + top++; + break; + case KEY_CTRL('A'): + case KEY_HOME: + top = entry = 0; + break; + case KEY_CTRL('E'): + case KEY_END: + entry = nentries - 1; + top = max(0, nentries-MENU_ROWS); + break; + case KEY_TAB: + if ( allowedit ) { + int ok = 1; + + draw_row(entry-top+4, -1, top, 0, 0); + + if ( menu_master_passwd ) { + ok = ask_passwd(NULL); + clear_screen(); + draw_menu(-1, top); + } + + if ( ok ) { + cmdline = edit_cmdline(menu_entries[entry].cmdline, top); + done = !!cmdline; + clear = 1; /* In case we hit [Esc] and done is null */ + } else { + draw_row(entry-top+4, entry, top, 0, 0); + } + } + break; + case KEY_CTRL('C'): /* Ctrl-C */ + case KEY_ESC: /* Esc */ + if ( allowedit ) { + done = 1; + clear = 1; + + draw_row(entry-top+4, -1, top, 0, 0); + + if ( menu_master_passwd ) + done = ask_passwd(NULL); + } + break; + default: + if ( key > 0 && key < 0xFF ) { + key &= ~0x20; /* Upper case */ + if ( menu_hotkeys[key] ) { + entry = menu_hotkeys[key] - menu_entries; + /* Should we commit at this point? */ + } + } + break; + } + } + + printf("\033[?25h"); /* Show cursor */ + + /* Return the label name so localboot and ipappend work */ + return cmdline; +} + + +static void __attribute__((noreturn)) +execute(const char *cmdline) +{ +#ifdef __COM32__ + static com32sys_t ireg; + + strcpy(__com32.cs_bounce, cmdline); + ireg.eax.w[0] = 0x0003; /* Run command */ + ireg.ebx.w[0] = OFFS(__com32.cs_bounce); + ireg.es = SEG(__com32.cs_bounce); + __intcall(0x22, &ireg, NULL); + exit(255); /* Shouldn't return */ +#else + /* For testing... */ + printf("\n>>> %s\n", cmdline); + exit(0); +#endif +} + +int main(int argc, char *argv[]) +{ + const char *cmdline = NULL; + int err = 0; + + (void)argc; + + console_ansi_raw(); + + parse_config(argv[1]); + + if ( !nentries ) { + fputs("No LABEL entries found in configuration file!\n", stdout); + err = 1; + } else { + cmdline = run_menu(); + } + + printf("\033[?25h\033[%d;1H\033[0m", END_ROW); + if ( cmdline ) + execute(cmdline); + else + return err; +} diff --git a/syslinux/com32/modules/menu.h b/syslinux/com32/modules/menu.h new file mode 100644 index 0000000..a4b1487 --- /dev/null +++ b/syslinux/com32/modules/menu.h @@ -0,0 +1,49 @@ +#ident "$Id: menu.h,v 1.5 2005/01/21 00:49:46 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * menu.h + * + * Header file for the simple menu system + */ + +#ifndef MENU_H +#define MENU_H + +struct menu_entry { + char *displayname; + char *label; + char *cmdline; + char *passwd; + unsigned char hotkey; +}; + +#define MAX_CMDLINE_LEN 256 + +#define MAX_ENTRIES 4096 /* Oughta be enough for anybody */ +extern struct menu_entry menu_entries[]; +extern struct menu_entry *menu_hotkeys[256]; + +extern int nentries; +extern int defentry; +extern int allowedit; +extern int timeout; + +extern char *menu_title; +extern char *ontimeout; +extern char *menu_master_passwd; + +void parse_config(const char *filename); + +#endif /* MENU_H */ + diff --git a/syslinux/com32/modules/readconfig.c b/syslinux/com32/modules/readconfig.c new file mode 100644 index 0000000..cc885df --- /dev/null +++ b/syslinux/com32/modules/readconfig.c @@ -0,0 +1,259 @@ +#ident "$Id: readconfig.c,v 1.7 2005/01/21 01:35:33 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#define _GNU_SOURCE /* Needed for asprintf() on Linux */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <minmax.h> +#include <alloca.h> +#ifdef __COM32__ +# include <com32.h> +#endif + +#include "menu.h" + +int nentries = 0; +int defentry = 0; +int allowedit = 1; /* Allow edits of the command line */ +int timeout = 0; + +char *menu_title = ""; +char *ontimeout = NULL; + +char *menu_master_passwd = NULL; + +struct menu_entry menu_entries[MAX_ENTRIES]; +struct menu_entry *menu_hotkeys[256]; + +#define astrdup(x) ({ char *__x = (x); \ + size_t __n = strlen(__x) + 1; \ + char *__p = alloca(__n); \ + if ( __p ) memcpy(__p, __x, __n); \ + __p; }) + +const char *ipappends[32]; + +static void +get_ipappend(void) +{ +#ifdef __COM32__ + static com32sys_t r; + uint16_t *ipp; + int i; + int nipappends; + + r.eax.w[0] = 0x000F; + __intcall(0x22, &r, &r); + + nipappends = min(r.ecx.w[0], 32); + ipp = MK_PTR(r.es, r.ebx.w[0]); + for ( i = 0 ; i < nipappends ; i++ ) { + ipappends[i] = MK_PTR(r.es, *ipp++); + } +#else + ipappends[0] = "ip=foo:bar:baz:quux"; + ipappends[1] = "BOOTIF=01-aa-bb-cc-dd-ee-ff"; +#endif +} + +static const char * +get_config(void) +{ +#ifdef __COM32__ + static com32sys_t r; + + r.eax.w[0] = 0x000E; + __intcall(0x22, &r, &r); + + return MK_PTR(r.es, r.ebx.w[0]); +#else + return "syslinux.cfg"; /* Dummy default name */ +#endif +} + +#define MAX_LINE 512 + +static char * +skipspace(char *p) +{ + while ( *p && *p <= ' ' ) + p++; + + return p; +} + +/* Check to see if we are at a certain keyword (case insensitive) */ +static int +looking_at(const char *line, const char *kwd) +{ + const char *p = line; + const char *q = kwd; + + while ( *p && *q && ((*p^*q) & ~0x20) == 0 ) { + p++; + q++; + } + + if ( *q ) + return 0; /* Didn't see the keyword */ + + return *p <= ' '; /* Must be EOL or whitespace */ +} + +struct labeldata { + char *label; + char *kernel; + char *append; + char *menulabel; + char *passwd; + unsigned int ipappend; + unsigned int menuhide; + unsigned int menudefault; +}; + +static void +record(struct labeldata *ld, char *append) +{ + char ipoptions[256], *ipp; + int i; + struct menu_entry *me = &menu_entries[nentries]; + + if ( ld->label ) { + char *a, *s; + me->displayname = ld->menulabel ? ld->menulabel : ld->label; + me->label = ld->label; + me->passwd = ld->passwd; + me->hotkey = 0; + + if ( ld->menulabel ) { + unsigned char *p = (unsigned char *)strchr(ld->menulabel, '^'); + if ( p && p[1] ) { + int hotkey = p[1] & ~0x20; + if ( !menu_hotkeys[hotkey] ) { + me->hotkey = hotkey; + } + } + } + + ipp = ipoptions; + *ipp = '\0'; + for ( i = 0 ; i < 32 ; i++ ) { + if ( (ld->ipappend & (1U << i)) && ipappends[i] ) + ipp += sprintf(ipp, " %s", ipappends[i]); + } + + a = ld->append; + if ( !a ) a = append; + if ( !a || (a[0] == '-' && !a[1]) ) a = ""; + s = a[0] ? " " : ""; + asprintf(&me->cmdline, "%s%s%s%s", ld->kernel, ipoptions, s, a); + + ld->label = NULL; + free(ld->kernel); + if ( ld->append ) + free(ld->append); + + if ( !ld->menuhide ) { + if ( me->hotkey ) + menu_hotkeys[me->hotkey] = me; + + if ( ld->menudefault ) + defentry = nentries; + + nentries++; + } + } +} + +void parse_config(const char *filename) +{ + char line[MAX_LINE], *p; + FILE *f; + char *append = NULL; + static struct labeldata ld; + + get_ipappend(); + + if ( !filename ) + filename = get_config(); + + f = fopen(filename, "r"); + if ( !f ) + return; + + while ( fgets(line, sizeof line, f) ) { + p = strchr(line, '\r'); + if ( p ) + *p = '\0'; + p = strchr(line, '\n'); + if ( p ) + *p = '\0'; + + p = skipspace(line); + + if ( looking_at(p, "menu") ) { + p = skipspace(p+4); + + if ( looking_at(p, "title") ) { + menu_title = strdup(skipspace(p+5)); + } else if ( looking_at(p, "label") ) { + if ( ld.label ) + ld.menulabel = strdup(skipspace(p+5)); + } else if ( looking_at(p, "default") ) { + ld.menudefault = 1; + } else if ( looking_at(p, "hide") ) { + ld.menuhide = 1; + } else if ( looking_at(p, "passwd") ) { + ld.passwd = strdup(skipspace(p+6)); + } else if ( looking_at(p, "master") ) { + p = skipspace(p+6); + if ( looking_at (p, "passwd") ) { + menu_master_passwd = strdup(skipspace(p+6)); + } + } else { + /* Unknown, ignore for now */ + } + } else if ( looking_at(p, "append") ) { + char *a = strdup(skipspace(p+6)); + if ( ld.label ) + ld.append = a; + else + append = a; + } else if ( looking_at(p, "label") ) { + p = skipspace(p+5); + record(&ld, append); + ld.label = strdup(p); + ld.kernel = strdup(p); + ld.append = NULL; + ld.menulabel = NULL; + ld.ipappend = ld.menudefault = ld.menuhide = 0; + } else if ( looking_at(p, "kernel") ) { + if ( ld.label ) { + free(ld.kernel); + ld.kernel = strdup(skipspace(p+6)); + } + } else if ( looking_at(p, "timeout") ) { + timeout = atoi(skipspace(p+7)); + } else if ( looking_at(p, "ontimeout") ) { + ontimeout = strdup(skipspace(p+9)); + } else if ( looking_at(p, "allowoptions") ) { + allowedit = atoi(skipspace(p+12)); + } else if ( looking_at(p, "ipappend") ) { + ld.ipappend = atoi(skipspace(p+8)); + } + } + + record(&ld, append); + fclose(f); +} diff --git a/syslinux/com32/samples/Makefile b/syslinux/com32/samples/Makefile new file mode 100644 index 0000000..1e9c15d --- /dev/null +++ b/syslinux/com32/samples/Makefile @@ -0,0 +1,82 @@ +#ident "$Id: Makefile,v 1.7 2005/01/04 03:05:17 hpa Exp $" +## ----------------------------------------------------------------------- +## +## Copyright 2001-2004 H. Peter Anvin - All Rights Reserved +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, Inc., 53 Temple Place Ste 330, +## Boston MA 02111-1307, USA; either version 2 of the License, or +## (at your option) any later version; incorporated herein by reference. +## +## ----------------------------------------------------------------------- + +## +## samples for syslinux users +## + +gcc_ok = $(shell if gcc $(1) -c -x c /dev/null -o /dev/null 2>/dev/null; \ + then echo $(1); else echo $(2); fi) + +M32 := $(call gcc_ok,-m32,) + +CC = gcc +LD = ld -m elf_i386 +AR = ar +NASM = nasm +RANLIB = ranlib +CFLAGS = $(M32) -mregparm=3 -DREGPARM=3 -W -Wall -march=i386 -Os -fomit-frame-pointer -I../libutil/include -I../include -D__COM32__ +LNXCFLAGS = -W -Wall -O -g -I../libutil/include +LNXSFLAGS = -g +LNXLDFLAGS = -g +SFLAGS = -D__COM32__ -march=i386 +LDFLAGS = -T ../lib/com32.ld +OBJCOPY = objcopy +PPMTOLSS16 = ../ppmtolss16 +LIBGCC := $(shell $(CC) --print-libgcc) +LIBS = ../libutil/libutil_com.a ../lib/libcom32.a $(LIBGCC) +LNXLIBS = ../libutil/libutil_lnx.a + +.SUFFIXES: .lss .c .o .elf .c32 .lnx + +all: hello.c32 cat.c32 resolv.c32 \ + fancyhello.c32 fancyhello.lnx \ + keytest.c32 keytest.lnx \ + +.PRECIOUS: %.o +%.o: %.S + $(CC) $(SFLAGS) -c -o $@ $< + +.PRECIOUS: %.o +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +.PRECIOUS: %.elf +%.elf: %.o $(LIBS) + $(LD) $(LDFLAGS) -o $@ $^ + +.PRECIOUS: %.lo +%.lo: %.S + $(CC) $(LNXSFLAGS) -c -o $@ $< + +.PRECIOUS: %.lo +%.lo: %.c + $(CC) $(LNXCFLAGS) -c -o $@ $< + +.PRECIOUS: %.lnx +%.lnx: %.lo $(LNXLIBS) + $(CC) $(LNXLDFLAGS) -o $@ $^ + +%.c32: %.elf + $(OBJCOPY) -O binary $< $@ + +tidy: + rm -f *.o *.lo *.a *.lst *.elf + +clean: tidy + rm -f *.lss *.c32 *.lnx *.com + +spotless: clean + rm -f *~ \#* + +install: # Don't install samples diff --git a/syslinux/com32/samples/cat.c b/syslinux/com32/samples/cat.c new file mode 100644 index 0000000..277427f --- /dev/null +++ b/syslinux/com32/samples/cat.c @@ -0,0 +1,31 @@ +#include <stdio.h> +#include <stdlib.h> +#include <console.h> + +int main(int argc, char *argv[]) +{ + FILE *f; + int ch; + int i; + + openconsole(&dev_stdcon_r, &dev_stdcon_w); + + printf("argv = %p\n", argv); + for ( i = 0 ; i <= argc ; i++ ) + printf("argv[%d] = %p = \"%s\"\n", i, argv[i], argv[i]); + + if ( argc < 2 ) { + fprintf(stderr, "Missing file name!\n"); + exit(1); + } + + printf("File = %s\n", argv[1]); + + f = fopen(argv[1], "r"); + while ( (ch = getc(f)) != EOF ) + putchar(ch); + + fclose(f); + + return 0; +} diff --git a/syslinux/com32/samples/fancyhello.c b/syslinux/com32/samples/fancyhello.c new file mode 100644 index 0000000..4ccccff --- /dev/null +++ b/syslinux/com32/samples/fancyhello.c @@ -0,0 +1,43 @@ + +#ident "$Id: fancyhello.c,v 1.2 2004/12/14 22:46:25 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * fancyhello.c + * + * Hello, World! using libcom32 and ANSI console; also possible to compile + * as a Linux application for testing. + */ + +#include <string.h> +#include <stdio.h> + +#include <consoles.h> /* Provided by libutil */ + +int main(void) +{ + char buffer[1024]; + + console_ansi_std(); + + printf("\033[1;33;44m *** \033[37mHello, World!\033[33m *** \033[0m\n"); + + for (;;) { + printf("\033[1;36m>\033[0m "); + fgets(buffer, sizeof buffer, stdin); + if ( !strncmp(buffer, "exit", 4) ) + break; + printf("\033[1m:\033[0m %s", buffer); + } + return 0; +} diff --git a/syslinux/com32/samples/hello.c b/syslinux/com32/samples/hello.c new file mode 100644 index 0000000..0a14665 --- /dev/null +++ b/syslinux/com32/samples/hello.c @@ -0,0 +1,41 @@ +#ident "$Id: hello.c,v 1.2 2004/12/14 22:46:25 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * hello.c + * + * Hello, World! using libcom32 + */ + +#include <string.h> +#include <stdio.h> +#include <console.h> + +int main(void) +{ + char buffer[1024]; + + openconsole(&dev_stdcon_r, &dev_stdcon_w); + + printf("Hello, World!\n"); + + for (;;) { + printf("> "); + fgets(buffer, sizeof buffer, stdin); + if ( !strncmp(buffer, "exit", 4) ) + break; + printf(": %s", buffer); + } + + return 0; +} diff --git a/syslinux/com32/samples/keytest.c b/syslinux/com32/samples/keytest.c new file mode 100644 index 0000000..9ba4a32 --- /dev/null +++ b/syslinux/com32/samples/keytest.c @@ -0,0 +1,82 @@ +#ident "$Id: keytest.c,v 1.4 2004/12/21 23:31:45 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * keytest.c + * + * Test the key parsing library + */ + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <sys/times.h> + +#include <consoles.h> /* Provided by libutil */ +#include <getkey.h> + +static void cooked_keys(void) +{ + int key; + + printf("[cooked]"); + + for(;;) { + key = get_key(stdin, 0); + + if ( key == 0x03 ) { + printf("[done]\n"); + exit(0); + } else if ( key == '?' ) + return; + + if ( key >= 0x20 && key < 0x100 ) { + putchar(key); + } else { + printf("[%04x]", key); + } + } +} + +static void raw_keys(void) +{ + int key; + + printf("[raw]"); + + for(;;) { + key = getc(stdin); + + if ( key == 0x03 ) { + printf("[done]\n"); + exit(0); + } else if ( key == '!' ) + return; + + printf("<%02x>", key); + } +} + +int main(void) +{ + console_ansi_raw(); + + printf("CLK_TCK = %d\n", (int)CLK_TCK); + printf("Press keys, end with Ctrl-C...\n"); + + for (;;) { + cooked_keys(); + raw_keys(); + } +} diff --git a/syslinux/com32/samples/resolv.c b/syslinux/com32/samples/resolv.c new file mode 100644 index 0000000..b58bbc5 --- /dev/null +++ b/syslinux/com32/samples/resolv.c @@ -0,0 +1,67 @@ +#ident "$Id: resolv.c,v 1.1 2004/12/28 23:49:43 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * resolv.c + * + * Resolve an IP address + */ + +#include <string.h> +#include <stdio.h> +#include <console.h> +#include <stdlib.h> +#include <com32.h> + +uint32_t resolv(const char *name) +{ + com32sys_t reg; + + strcpy((char *)__com32.cs_bounce, name); + + memset(®, 0, sizeof reg); + reg.eax.w[0] = 0x0010; + reg.ebx.w[0] = OFFS(__com32.cs_bounce); + reg.es = SEG(__com32.cs_bounce); + + __intcall(0x22, ®, ®); + + if ( reg.eflags.l & EFLAGS_CF ) + return 0; + else + return reg.eax.l; +} + +int main(int argc, char *argv[]) +{ + uint32_t ip; + + openconsole(&dev_null_r, &dev_stdcon_w); + + if ( argc < 2 ) { + fputs("Usage: resolv hostname\n", stderr); + exit(1); + } + + ip = resolv(argv[1]); + + if ( ip ) { + printf("%s = %u.%u.%u.%u\n", argv[1], + (ip & 0xff), (ip >> 8) & 0xff, + (ip >> 16) & 0xff, (ip >> 24) & 0xff); + } else { + printf("%s not found\n", argv[1]); + } + + return 0; +} diff --git a/syslinux/comboot.doc b/syslinux/comboot.doc new file mode 100644 index 0000000..57b976d --- /dev/null +++ b/syslinux/comboot.doc @@ -0,0 +1,585 @@ + $Id: comboot.doc,v 1.34 2005/01/20 18:43:22 hpa Exp $ + + COMBOOT and COM32 files + + +SYSLINUX supports simple standalone programs, using a file format +similar to DOS ".com" files. A 32-bit version, called COM32, is also +provided. A simple API provides access to a limited set of filesystem +and console functions. + + + ++++ COMBOOT file format ++++ + +A COMBOOT file is a raw binary file containing 16-bit code. It should +be linked to run at offset 0x100, and contain no absolute segment +references. It is run in 16-bit real mode. + +A COMBOOT image can be written to be compatible with MS-DOS. Such a +file will usually have extension ".com". A COMBOOT file which is not +compatible with MS-DOS will usually have extension ".cbt". + +Before running the program, SYSLINUX sets up the following fields in +the Program Segment Prefix (PSP), a structure at offset 0 in the +program segment: + + Offset Size Meaning + 0 word Contains an INT 20h instruction + 2 word Contains the paragraph (16-byte "segment" address) at + the end of memory available to the program. + 128 byte Length of the command line arguments, including the leading + space but not including the final CR character. + 129 127b Command line arguments, starting with a space and ending + with a CR character (ASCII 13). + +The program is allowed to use memory between the PSP paragraph (which +all the CS, DS, ES and SS registers point to at program start) and the +paragraph value given at offset 2. + +On startup, SP is set up to point to the end of the 64K segment, at +0xfffe. Under DOS it is possible for SP to contain a smaller +value if memory is very tight; this is never the case under SYSLINUX. + +The program should make no assumptions about what segment address it +will be loaded at; instead it should look at the segment registers on +program startup. Both DOS and SYSLINUX will guarantee CS == DS == ES +== SS on program start; the program should not assume anything about +the values of FS or GS. + +To exit, a program can either execute a near RET (which will jump to +offset 0 which contains an INT 20h instruction, terminating the +program), or execute INT 20h or INT 21h AH=00h or INT 21h AH=4Ch. +If compatiblity with SYSLINUX 1.xx is desired, use INT 20h. + + + ++++ COM32 file format ++++ + +A COM32 file is a raw binary file containing 32-bit code. It should +be linked to run at address 0x101000, and should not contain any +segment references. It will be run in flat-memory 32-bit protected +mode. Under SYSLINUX, it will be run in CPL 0, however, since it may +be possible to create a COM32 execution engine that would run under +something like Linux DOSEMU, it is recommended that the code does not +assume CPL 0 unless absolutely necessary. + +It is highly recommended that every COM32 program begins with the byte +sequence B8 FF 4C CD 21 (mov eax,21cd4cffh) as a magic number. + +A COM32 file should have extension ".c32". + +On startup, CS will be set up as a flat 32-bit code segment, and DS == +ES == SS will be set up as the equivalent flat 32-bit data segment. +FS and GS are reserved for future use and are currently initialized to +zero. A COM32 image should not assume any particular values of +segment selectors. + +ESP is set up at the end of available memory and also serves as +notification to the program how much memory is available. + +The following arguments are passed to the program on the stack: + + Address Size Meaning + [ESP] dword Return (termination) address + [ESP+4] dword Number of additional arguments (currently 5) + [ESP+8] dword Pointer to the command line arguments (null-terminated string) + [ESP+12] dword Pointer to INT call helper function + [ESP+16] dword Pointer to low memory bounce buffer + [ESP+20] dword Size of low memory bounce buffer + [ESP+24] dword Pointer to FAR call helper function (new in 2.05) + +This corresponds to the following C prototype, available in the file +com32/include/com32.h: + +/* The standard prototype for _start() */ +int _start(unsigned int __nargs, + char *__cmdline, + void (*__intcall)(uint8_t, com32sys_t *, com32sys_t *), + void *__bounce_ptr, + unsigned int __bounce_len, + void (*__farcall)(uint32_t, uint16_t, com32sys_t *, com32sys_t *)); + +The intcall helper function can be used to issue BIOS or SYSLINUX API +calls, and takes the interrupt number as first argument. The second +argument is a pointer to the input register definition, an instance of +the following structure (also available in com32.h): + +typedef union { + uint32_t l; + uint16_t w[2]; + uint8_t b[4]; +} reg32_t; + +typedef struct { + uint16_t gs; /* Offset 0 */ + uint16_t fs; /* Offset 2 */ + uint16_t es; /* Offset 4 */ + uint16_t ds; /* Offset 6 */ + + reg32_t edi; /* Offset 8 */ + reg32_t esi; /* Offset 12 */ + reg32_t ebp; /* Offset 16 */ + reg32_t _unused; /* Offset 20 */ + reg32_t ebx; /* Offset 24 */ + reg32_t edx; /* Offset 28 */ + reg32_t ecx; /* Offset 32 */ + reg32_t eax; /* Offset 36 */ + + reg32_t eflags; /* Offset 40 */ +} com32sys_t; + +The third argument is a pointer to the output register definition, an +instance of the same structure. The third argument can also be zero +(NULL). + +Since BIOS or SYSLINUX API calls can generally only manipulate data +below address 0x100000, a "bounce buffer" in low memory, at least 64K +in size, is available, to copy data in and out. + +The farcall helper function behaves similarly, but takes as its first +argument the CS:IP (in the form (CS << 16) + IP) of procedure to be +invoked via a FAR CALL. + + + ++++ SYSLINUX API CALLS +++ + +SYSLINUX provides the following API calls. SYSLINUX 1.xx only +supported INT 20h - terminate program. [] indicates the first version +of SYSLINUX which supported this feature (correctly.) + +NOTE: Most of the API functionality is still experimental. Expect to +find bugs. + + + ++++ DOS-COMPATIBLE API CALLS ++++ + +INT 20h [1.48] Terminate program +INT 21h AH=00h [2.00] Terminate program +INT 21h AH=4Ch [2.00] Terminate program + + All of these terminate the program. + +INT 21h AH=01h [2.01] Get Key with Echo + + Reads a key from the console input, with echo to the console + output. The read character is returned in AL. Extended + characters received from the keyboard are returned as NUL (00h) + + the extended character code. + +INT 21h AH=02h [2.01] Write Character + + Writes a character in DL to the console (video and serial) + output. + +INT 21h AH=04h [2.01] Write Character to Serial Port + + Writes a character in DL to the serial console output + (if enabled.) If no serial port is configured, this routine + does nothing. + +INT 21h AH=08h [2.09] Get Key without Echo + + Reads a key fron the console input, without echoing it to the + console output. The read character is returned in AL. + +INT 21h AH=09h [2.01] Write DOS String to Console + + Writes a DOS $-terminated string in DS:DX to the console. + +INT 21h AH=0Bh [2.00] Check Keyboard + + Returns AL=FFh if there is a keystroke waiting (which can then + be read with INT 21h, AH=01h or AH=08h), otherwise AL=00h. + +INT 21h AH=30h [2.00] Check DOS Version + + This function returns AX=BX=CX=DX=0, corresponding to a + hypothetical "DOS 0.0", but the high parts of EAX-EBX-ECX-EDX + spell "SYSLINUX": + + EAX=59530000h EBX=4C530000h ECX=4E490000h EDX=58550000h + + This function can thus be used to distinguish running on + SYSLINUX from running on DOS. + + + ++++ SYSLINUX-SPECIFIC API CALLS ++++ + +SYSLINUX-specific API calls are executed using INT 22h, with a +function number in AX. INT 22h is used by DOS for internal purposes; +do not execute INT 22h under DOS. + +DOS-compatible function INT 21h, AH=30h can be used to detect if the +SYSLINUX API calls are available. + +Any register not specifically listed as modified is preserved; +however, future versions of SYSLINUX may add additional output +registers to existing calls. + +All calls return CF=0 on success, CF=1 on failure. The noted outputs +apply if CF=0 only unless otherwise noted. All calls clobber the +arithmetric flags (CF, PF, AF, ZF, SF and OF) but leave all other +flags unchanged unless otherwise noted. + + +AX=0001h [2.00] Get Version + + Input: AX 0001h + Output: AX number of INT 22h API functions available + CH SYSLINUX major version number + CL SYSLINUX minor version number + DL SYSLINUX derivative ID (e.g. 32h = PXELINUX) + ES:SI SYSLINUX version string + ES:DI SYSLINUX copyright string + + This API call returns the SYSLINUX version and API + information. + + +AX=0002h [2.01] Write String + + Input: AX 0002h + ES:BX null-terminated string + Output: None + + Writes a null-terminated string on the console. + + +AX=0003h [2.01] Run command + + Input: AX 0003h + ES:BX null-terminated command string + Output: Does not return + + This API call terminates the program and executes the command + string as if the user had entered it at the SYSLINUX command + line. This API call does not return. + + +AX=0004h [2.01] Run default command + + Input: AX 0004h + Output: Does not return + + This API call terminates the program and executes the default + command string as if the user had pressed Enter alone on the + SYSLINUX command line. This API call does not return. + + +AX=0005h [2.00] Force text mode + + Input: AX 0005h + Output: None + + If the screen was in graphics mode (due to displaying a splash + screen using the <Ctrl-X> command in a message file, or + similar), return to text mode. + + +AX=0006h [2.08] Open file + + Input: AX 0006h + ES:SI null-terminated filename + Output: SI file handle + EAX length of file in bytes + CX file block size + + Open a file for reading. The exact syntax of the filenames + allowed depends on the particular SYSLINUX derivative. + + The SYSLINUX file system is block-oriented. The size of a + block will always be a power of two and no greater than 16K. + + Note: SYSLINUX considers a zero-length file to be nonexistent. + + +AX=0007h [2.08] Read file + + Input: AX 0007h + SI file handle + ES:BX buffer + CX number of blocks to read + Output: SI file handle, or 0 if EOF was reached + + Read blocks from a file. Note that the file handle that is + returned in SI may not be the same value that was passed in. + + If end of file was reached (SI=0), the file was automatically + closed. + + The address of the buffer (ES:BX) should be at least 512-byte + aligned. SYSLINUX guarantees at least this alignment for the + COMBOOT load segment or the COM32 bounce buffer. + + Keep in mind that a "file" may be a TFTP connection, and that + leaving a file open for an extended period of time may result + in a timeout. + + WARNING: Calling this function with an invalid file handle + will probably crash the system. + + +AX=0008h [2.08] Close file + + Input: AX 0008h + SI file handle + Output: None + + Close a file before reaching the end of file. + + WARNING: Calling this function with an invalid file handle + will probably crash the system. + + +AX=0009h [2.00] Call PXE Stack [PXELINUX ONLY] + + Input: AX 0009h + BX PXE function number + ES:DI PXE data buffer + Output: AX PXE return status code + + Invoke an arbitrary PXE stack function. On SYSLINUX/ISOLINUX, + this function returns with an error (CF=1) and no action is + taken. On PXELINUX, this function always returns with CF=0 + indicating that the PXE stack was successfully invoked; check + the status code in AX and in the first word of the data buffer + to determine if the PXE call succeeded or not. + + The PXE stack will have the UDP stack OPEN; if you change that + you cannot call any of the file-related API functions, and + must restore UDP OPEN before returning to PXELINUX. + + PXELINUX reserves UDP port numbers from 49152 to 65535 for its + own use; port numbers below that range is available. + + +AX=000Ah [2.00] Get Derivative-Specific Information + + [SYSLINUX, EXTLINUX] + Input: AX 000Ah + Output: AL 31h (SYSLINUX), 34h (EXTLINUX) + DL drive number + ES:BX pointer to partition table entry (if DL >= 80h) + + Note: This function was broken in EXTLINUX 3.00-3.02. + + + [PXELINUX] + Input: AX 000Ah + Output: AL 32h (PXELINUX) + DX PXE API version detected (DH=major, DL=minor) + ES:BX pointer to PXENV+ or !PXE structure + FS:SI pointer to original stack with invocation record + + Note: DX notes the API version detected by PXELINUX, + which may be more conservative than the actual version + available. For exact information examine the API + version entry in the PXENV+ structure, or the API + version entries in the ROMID structures pointed from + the !PXE structure. + + PXELINUX will use, and provide, the !PXE structure + over the PXENV+ structure. Examine the structure + signature to determine which particular structure was + provided. + + The FS:SI pointer points to the top of the original stack + provided by the PXE stack, with the following values + pushed at the time PXELINUX is started: + + [fs:si+0] GS <- top of stack + [fs:si+2] FS + [fs:si+4] ES + [fs:si+6] DS + [fs:si+8] EDI + [fs:si+12] ESI + [fs:si+16] EBP + [fs:si+20] - + [fs:si+24] EBX + [fs:si+28] EDX + [fs:si+32] ECX + [fs:si+36] EAX + [fs:si+40] EFLAGS + [fs:si+44] PXE return IP <- t.o.s. when PXELINUX invoked + [fs:si+46] PXE return CS + + + [ISOLINUX] + Input: AX 000Ah + Output: AL 33h (ISOLINUX) + DL drive number + ES:BX pointer to El Torito spec packet + + Note: Some very broken El Torito implementations do + not provide the spec packet information. If so, ES:BX + may point to all zeroes or to garbage. Call INT 13h, + AX=4B01h to obtain the spec packet directly from the + BIOS if necessary. + + This call gives information specific to a particular SYSLINUX + derivative. The value returned in AL is the same as is + returned in DL by INT 22h AX=0001h. + + +AX=000Bh [2.00] Get Serial Console Configuration + + Input: AX 000Bh + Output: DX serial port I/O base (e.g. 3F8h = COM1...) + CX baud rate divisor (1 = 115200 bps, 2 = 57600 bps...) + BX flow control configuration bits (see syslinux.doc) + -> bit 15 is set if the video console is disabled + + If no serial port is configured, DX will be set to 0 and the + other registers are undefined. + + +AX=000Ch [2.00] Perform final cleanup + Input: AX 000Ch + DX derivative-specific flags (0000h = clean up all) + Output: Does not return + + This routine performs any "final cleanup" the boot loader + would normally perform before loading a kernel, such as + unloading the PXE stack in the case of PXELINUX. AFTER + INVOKING THIS CALL, NO OTHER API CALLS MAY BE INVOKED, NOR MAY + THE PROGRAM TERMINATE AND RETURN TO THE BOOT LOADER. This + call basically tells the boot loader "get out of the way, I'll + handle it from here." + + For COM32 images, the boot loader will continue to provide + interrupt and BIOS call thunking services as long its memory + areas (0x0800-0xffff, 0x100000-0x100fff) are not overwritten. + MAKE SURE TO DISABLE INTERRUPTS, AND INSTALL NEW GDT AND IDTS + BEFORE OVERWRITING THESE MEMORY AREAS. + + The permissible values for DX is an OR of these values: + + SYSLINUX: 0000h Normal cleanup + + PXELINUX: 0000h Normal cleanup + 0003h Keep UNDI and PXE stacks loaded + + ISOLINUX: 0000h Normal cleanup + + All other values are undefined, and may have different + meanings in future versions of SYSLINUX. + + +AX=000Dh [2.08] Cleanup and replace bootstrap code + Input: AX 000Dh + DX derivative-specific flags (see previous function) + EDI bootstrap code (linear address, can be in high memory) + ECX bootstrap code length in bytes (must fit in low mem) + EBX(!) initial value of EDX after bootstrap + ESI initial value of ESI after bootstrap + DS initial value of DS after bootstrap + Output: Does not return + + This routine performs final cleanup, then takes a piece of + code, copies it over the primary bootstrap at address 7C00h, + and jumps to it. This can be used to chainload boot sectors, + MBRs, bootstraps, etc. + + Normal boot sectors expect DL to contain the drive number, + and, for hard drives (DL >= 80h) DS:SI to contain a pointer to + the 16-byte partition table entry. The memory between + 600h-7FFh is available to put the partition table entry in. + + For PXELINUX, if the PXE stack is not unloaded, all registers + (except DS, ESI and EDX) and the stack will be set up as they + were set up by the PXE ROM. + + +AX=000Eh [2.11] Get configuration file name + Input: AX 0000Eh + Output: ES:BX null-terminated file name string + + Returns the name of the configuration file. Note that it is + possible that the configuration file doesn't actually exist. + + +AX=000Fh [3.00] Get IPAPPEND strings [PXELINUX] + Input: AX 000Fh + Output: CX number of strings (currently 2) + ES:BX pointer to an array of NEAR pointers in + the same segment, one for each of the above + strings + + Returns the same strings that the "ipappend" option would have + added to the command line, one for each bit of the "ipappend" + flag value, so entry 0 is the "ip=" string and entry 1 is the + "BOOTIF=" string. + + +AX=0010h [3.00] Resolve hostname [PXELINUX] + Input: ES:BX pointer to null-terminated hostname + Output: EAX IP address of hostname (zero if not found) + + Queries the DNS server(s) for a specific hostname. If the + hostname does not contain a dot (.), the local domain name + is automatically appended. + + This function only return CF=1 if the function is not + supported. If the function is supported, but the hostname did + not resolve, it returns with CF=0, EAX=0. + + The IP address is returned in network byte order, i.e. if the + IP address is 1.2.3.4, EAX will contain 0x04030201. Note that + all uses of IP addresses in PXE are also in network byte order. + + +AX=0011h [3.05] Maximum number of shuffle descriptors + Input: AX 0011h + Output: CX maximum number of descriptors + + This routine reports the maximum number of shuffle descriptors + permitted in a call to function 0012h. + + Typical values are 682 and 1365. + + +AX=0012h [3.05] Cleanup, shuffle and boot + Input: AX 0012h + DX derivative-specific flags (see previous function) + ES:DI shuffle descriptor list (must be in low memory) + CX number of shuffle descriptors + EBX(!) initial value of EDX after bootstrap + ESI initial value of ESI after bootstrap + DS initial value of DS after bootstrap + EBP CS:IP of routine to jump to + Output: Does not return + (if CX is too large the routine returns with CF=1) + + This routine performs final cleanup, then performs a sequence + of copies, and jumps to a specified real mode entry point. + This is a more general version of function 000Dh, which can + also be used to load other types of programs. + + The copies must not touch memory below address 7C00h. + + ES:DI points to a list of CX descriptors each of the form: + + Offset Size Meaning + 0 dword destination address + 4 dword source address + 8 dword length in bytes + + The copies are overlap-safe, like memmove(). + + Normal boot sectors expect DL to contain the drive number, + and, for hard drives (DL >= 80h) DS:SI to contain a pointer to + the 16-byte partition table entry. The memory between + 600h-7FFh is available to put the partition table entry in. + + For PXELINUX, if the PXE stack is not unloaded, all registers + (except DS, ESI and EDX) and the stack will be set up as they + were set up by the PXE ROM. + + +AX=0013h [3.08] Idle loop call + Input: AX 0013h + Output: None + + Call this routine while sitting in an idle loop. It performs + any periodic activities required by the filesystem code. At + the moment, this is a no-op on all derivatives except + PXELINUX, where it executes PXE calls to answer ARP queries. diff --git a/syslinux/comboot.inc b/syslinux/comboot.inc new file mode 100644 index 0000000..afd2c24 --- /dev/null +++ b/syslinux/comboot.inc @@ -0,0 +1,693 @@ +;; $Id: comboot.inc,v 1.39 2005/01/20 18:43:22 hpa Exp $ +;; ----------------------------------------------------------------------- +;; +;; Copyright 1994-2005 H. Peter Anvin - All Rights Reserved +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +;; Boston MA 02111-1307, USA; either version 2 of the License, or +;; (at your option) any later version; incorporated herein by reference. +;; +;; ----------------------------------------------------------------------- + +;; +;; comboot.inc +;; +;; Common code for running a COMBOOT image +;; + + section .text + +; Parameter registers definition; this is the definition +; of the stack frame used by INT 21h and INT 22h. +%define P_FLAGS word [bp+44] +%define P_FLAGSL byte [bp+44] +%define P_FLAGSH byte [bp+45] +%define P_CS word [bp+42] +%define P_IP word [bp+40] +%define P_DS word [bp+38] +%define P_ES word [bp+36] +%define P_FS word [bp+34] +%define P_GS word [bp+32] +%define P_EAX dword [bp+28] +%define P_AX word [bp+28] +%define P_HAX word [bp+30] +%define P_AL byte [bp+28] +%define P_AH byte [bp+29] +%define P_ECX dword [bp+24] +%define P_CX word [bp+24] +%define P_HCX word [bp+26] +%define P_CL byte [bp+24] +%define P_CH byte [bp+25] +%define P_EDX dword [bp+20] +%define P_DX word [bp+20] +%define P_HDX word [bp+22] +%define P_DL byte [bp+20] +%define P_DH byte [bp+21] +%define P_EBX dword [bp+16] +%define P_BX word [bp+16] +%define P_HBX word [bp+18] +%define P_BL byte [bp+16] +%define P_BH byte [bp+17] +%define P_EBP dword [bp+8] +%define P_BP word [bp+8] +%define P_HBP word [bp+10] +%define P_ESI dword [bp+4] +%define P_SI word [bp+4] +%define P_HSI word [bp+6] +%define P_EDI dword [bp] +%define P_DI word [bp] +%define P_HDI word [bp+2] + +; Looks like a COMBOOT image but too large +comboot_too_large: + mov si,err_comlarge + call cwritestr + jmp enter_command + +; +; Load a COMBOOT image. A COMBOOT image is basically a DOS .COM file, +; except that it may, of course, not contain any DOS system calls. We +; do, however, allow the execution of INT 20h to return to SYSLINUX. +; +is_comboot_image: + and dx,dx + jnz comboot_too_large + cmp ax,0ff00h ; Max size in bytes + jae comboot_too_large + + push si ; Save file handle + + call make_plain_cmdline + + call comboot_setup_api + + mov cx,comboot_seg + mov es,cx + + xor di,di + mov cx,64 ; 256 bytes (size of PSP) + xor eax,eax ; Clear PSP + rep stosd + + mov word [es:0], 020CDh ; INT 20h instruction + ; First non-free paragraph + ; This is valid because comboot_seg == real_mode_seg + ; == the highest segment used by all derivatives + int 12h ; Get DOS memory size + shl ax,6 ; Kilobytes -> paragraphs + mov word [es:02h],ax + +%ifndef DEPEND +%if real_mode_seg != comboot_seg +%error "This code assumes real_mode_seg == comboot_seg" +%endif +%endif + ; Copy the command line from high memory + mov si,cmd_line_here + mov cx,125 ; Max cmdline len (minus space and CR) + mov di,081h ; Offset in PSP for command line + mov al,' ' ; DOS command lines begin with a space + stosb + +.loop: es lodsb + and al,al + jz .done + stosb + loop .loop +.done: + + mov al,0Dh ; CR after last character + stosb + mov ax,di + sub al,82h ; Include space but not CR + mov [es:80h],al ; Store command line length + + ; Now actually load the file... + pop si ; File handle + mov bx,100h ; Load at <seg>:0100h + mov cx,0FF00h >> SECTOR_SHIFT + ; Absolute maximum # of sectors + call getfssec + + ; And invoke the program... + mov [SavedSSSP],sp + mov [SavedSSSP+2],ss ; Save away SS:SP + + mov ax,es + mov ds,ax + mov ss,ax + xor sp,sp + push word 0 ; Return to address 0 -> exit + + jmp comboot_seg:100h ; Run it + +; Proper return vector +comboot_return: cli ; Don't trust anyone + xor ax,ax + jmp comboot_exit + +; +; Set up the COMBOOT API interrupt vectors. This is also used +; by the COM32 code. +; +comboot_setup_api: + mov di,4*0x20 ; DOS interrupt vectors + mov eax,comboot_return ; INT 20h = exit + stosd + mov ax,comboot_int21 ; INT 21h = DOS-compatible syscalls + stosd + mov ax,comboot_int22 ; INT 22h = proprietary syscalls + stosd + mov ax,comboot_bogus + mov cx,29 ; All remaining DOS vectors + rep stosd + ret + +; INT 21h: generic DOS system call +comboot_int21: cli + push ds + push es + push fs + push gs + pushad + cld + mov bp,cs + mov ds,bp + mov es,bp + mov bp,sp ; Set up stack frame + + call adjust_screen ; The COMBOOT program might have changed the screen + + mov cx,int21_count + mov si,int21_table +.again: lodsb + cmp al,P_AH + lodsw + loopne .again + ; The last function in the list is the + ; "no such function" function + clc + call ax ; Call the invoked function +comboot_resume: + setc P_FLAGSL ; Propagate CF->error + popad + pop gs + pop fs + pop es + pop ds + iret + +; Attempted to execute non-21h DOS system call +comboot_bogus: cli ; Don't trust anyone + mov ax,err_notdos +; +; Generic COMBOOT return to command line code +; AX -> message (if any) +; BX -> where to go next +; +comboot_exit: + mov bx,enter_command ; Normal return to command prompt +comboot_exit_special: + xor dx,dx + mov ds,dx + mov es,dx + lss sp,[SavedSSSP] + sti + cld + call adjust_screen ; The COMBOOT program might have changed the screen + and ax,ax + je .nomsg + mov si,KernelCName + call cwritestr + xchg si,ax + call cwritestr +.nomsg: jmp bx + +; +; INT 21h system calls +; +comboot_getkey: ; 01 = get key with echo + call vgashowcursor + call comboot_getchar + call vgahidecursor + call writechr + clc + ret + +comboot_writechr: ; 02 = writechr + mov al,P_DL + call writechr + clc + ret + +comboot_writeserial: ; 04 = write serial port + mov al,P_DL + call write_serial + clc + ret + +comboot_getkeynoecho: ; 08 = get key w/o echo + call comboot_getchar + clc + ret + +comboot_writestr: ; 09 = write DOS string + mov es,P_DS + mov si,P_DX +.loop: es lodsb + cmp al,'$' ; End string with $ - bizarre + je .done + call writechr + jmp short .loop +.done: clc + ret + +comboot_checkkey: ; 0B = check keyboard status + cmp byte [APIKeyFlag],00h + jnz .waiting + call pollchar +.waiting: setz al + dec al ; AL = 0FFh if present, 0 if not + mov P_AL,al + clc + ret + +comboot_checkver: ; 30 = check DOS version + ; We return 0 in all DOS-compatible version registers, + ; but the high part of eax-ebx-ecx-edx spell "SYSLINUX" + mov P_EAX,'SY' << 16 + mov P_EBX,'SL' << 16 + mov P_ECX,'IN' << 16 + mov P_EDX,'UX' << 16 + ret + +comboot_getchar: + cmp byte [APIKeyFlag],00h + jne .queued + call getchar ; If not queued get input + and al,al ; Function key? (CF <- 0) + jnz .done + mov [APIKeyWait],ah ; High part of key + inc byte [APIKeyFlag] ; Set flag +.done: mov P_AL,al + ret +.queued: mov al,[APIKeyWait] + dec byte [APIKeyFlag] + jmp .done + +; +; INT 22h - SYSLINUX-specific system calls +; System call number in ax +; +comboot_int22: + cli + push ds + push es + push fs + push gs + pushad + cld + mov bp,cs + mov ds,bp + mov es,bp + mov bp,sp ; Set up stack frame + + call adjust_screen ; The COMBOOT program might have changed the screen + + cmp ax,int22_count + jb .ok + xor ax,ax ; Function 0 -> unimplemented +.ok: + xchg ax,bx + add bx,bx ; CF <- 0 + call [bx+int22_table] + jmp comboot_resume ; On return + +; +; INT 22h AX=0000h Unimplemented call +; +comapi_err: + stc + ret + +; +; INT 22h AX=0001h Get SYSLINUX version +; +comapi_get_version: + ; Number of API functions supported + mov P_AX,int22_count + ; SYSLINUX version + mov P_CX,(VER_MAJOR << 8)+VER_MINOR + ; SYSLINUX derivative ID byte + mov P_DX,my_id + ; For future use + mov P_BX,cs ; cs == 0 + + mov P_ES,ds + ; ES:SI -> version banner + mov P_SI,syslinux_banner + ; ES:DI -> copyright string + mov P_DI,copyright_str + +comapi_nop: + clc + ret + +; +; INT 22h AX=0002h Write string +; +; Write null-terminated string in ES:BX +; +comapi_writestr: + mov ds,P_ES + mov si,P_BX + call writestr + clc + ret + +; +; INT 22h AX=0003h Run command +; +; Terminates the COMBOOT program and executes the command line in +; ES:BX as if it had been entered by the user. +; +comapi_run: + mov ds,P_ES + mov si,P_BX + mov di,command_line + call strcpy + xor ax,ax + mov bx,load_kernel ; Run a new kernel + jmp comboot_exit_special ; Terminate task, clean up + +; +; INT 22h AX=0004h Run default command +; +; Terminates the COMBOOT program and executes the default command line +; as if a timeout had happened or the user pressed <Enter>. +; +comapi_run_default: + mov bx,auto_boot + jmp comboot_exit_special + +; +; INT 22h AX=0005h Force text mode +; +; Puts the video in standard text mode +; +comapi_textmode: + call vgaclearmode + clc + ret + +; +; INT 22h AX=0006h Open file +; +comapi_open: + push ds + mov ds,P_ES + mov si,P_SI + mov di,InitRD + push di + call mangle_name + pop di + pop ds + call searchdir + jz .err + mov P_AX,ax + mov P_HAX,dx + mov P_CX,SECTOR_SIZE + mov P_SI,si + clc + ret +.err: + stc + ret + + +; +; INT 22h AX=0007h Read file +; +comapi_read: + mov es,P_ES + mov bx,P_BX + mov si,P_SI + mov cx,P_CX + call getfssec + jnc .noteof + xor si,si ; SI <- 0 on EOF, CF <- 0 +.noteof: mov P_SI,si + ret + +; +; INT 22h AX=0008h Close file +; +comapi_close: + ; Do nothing for now. Eventually implement + ; an internal API for this. + clc + ret + +; +; INT 22h AX=0009h Call PXE stack +; +%if IS_PXELINUX +comapi_pxecall: + mov bx,P_BX + mov es,P_ES + mov di,P_DI + call pxenv + mov P_AX,ax + clc + ret +%else +comapi_pxecall equ comapi_err ; Not available +%endif + +; +; INT 22h AX=000Ah Get Derivative-Specific Info +; +comapi_derinfo: + mov P_AL,my_id +%if IS_SYSLINUX || IS_MDSLINUX || IS_EXTLINUX + mov al,[DriveNumber] + mov P_DL,al + mov P_ES,cs + mov P_BX,PartInfo +%elif IS_PXELINUX + mov ax,[APIVer] + mov P_DX,ax + mov ax,[StrucPtr] + mov P_BX,ax + mov ax,[StrucPtr+2] + mov P_ES,ax + mov ax,[InitStack] + mov P_SI,ax + mov ax,[InitStack+2] + mov P_FS,ax +%elif IS_ISOLINUX + mov al,[DriveNo] + mov P_DL,al + mov P_ES,cs + mov P_BX,spec_packet +%endif + clc + ret + +; +; INT 22h AX=000Bh Get Serial Console Configuration +; +comapi_serialcfg: + mov ax,[SerialPort] + mov P_DX,ax + mov ax,[BaudDivisor] + mov P_CX,ax + mov ax,[FlowControl] + or al,ah + mov ah,[FlowIgnore] + shr ah,4 + test byte [DisplayCon],01h + jnz .normalconsole + or ah,80h +.normalconsole: + mov P_BX,ax + clc + ret + +; +; INT 22h AX=000Ch Perform final cleanup +; +comapi_cleanup: +%if IS_PXELINUX + ; Unload PXE if requested + test dl,3 + setnz [KeepPXE] + sub bp,sp ; unload_pxe may move the stack around + call unload_pxe + add bp,sp ; restore frame pointer... +%elif IS_SYSLINUX || IS_MDSLINUX || IS_EXTLINUX + ; Restore original FDC table + mov eax,[OrigFDCTabPtr] + mov [fdctab],eax +%endif + ; Reset the floppy disk subsystem + xor ax,ax + xor dx,dx + int 13h + clc + ret + +; +; INT 22h AX=000Dh Clean up then replace bootstrap +; +comapi_chainboot: + call comapi_cleanup + mov eax,P_EDI + mov [trackbuf+4],eax ; Copy from + mov eax,P_ECX + mov [trackbuf+8],eax ; Total bytes + mov eax,7C00h + mov [trackbuf],eax ; Copy to + mov [EntryPoint],eax ; CS:IP entry point + mov esi,P_ESI + mov edx,P_EBX + mov bx,P_DS + jmp replace_bootstrap_one + + +; +; INT 22h AX=000Eh Get configuration file name +; +comapi_configfile: + mov P_ES,cs + mov P_BX,ConfigName + clc + ret + +; +; INT 22h AX=000Fh Get IPAPPEND strings +; +%if IS_PXELINUX +comapi_ipappend: + mov P_ES,cs + mov P_CX,numIPAppends + mov P_BX,IPAppends + clc + ret + + section .data + alignb 2, db 0 +IPAppends dw IPOption + dw BOOTIFStr +numIPAppends equ ($-IPAppends)/2 + +%else +comapi_ipappend equ comapi_err +%endif + +; +; INT 22h AX=0010h Resolve hostname +; +%if IS_PXELINUX +comapi_dnsresolv: + mov ds,P_ES + mov si,P_BX + call dns_resolv + mov P_EAX,eax + ret +%else +comapi_dnsresolv equ comapi_err +%endif + + section .data +%macro int21 2 + db %1 + dw %2 +%endmacro + + +; +; INT 22h AX=0011h Maximum number of shuffle descriptors +; +comapi_maxshuffle: + mov P_CX,(2*trackbufsize)/12 + ret + +; +; INT 22h AX=0012h Cleanup, shuffle and boot +; +comapi_shuffle: + call comapi_cleanup + mov cx,P_CX + cmp cx,(2*trackbufsize)/12 + ja .error + + push cx ; On stack: descriptor count + + lea cx,[ecx+ecx*2] ; CX *= 3 + + mov fs,P_ES + mov si,P_DI + mov di,trackbuf + push di ; On stack: descriptor list address + fs rep movsd ; Copy the list + + mov eax,P_EBP + mov [EntryPoint],eax ; CS:IP entry point + mov esi,P_ESI + mov edx,P_EBX + mov bx,P_DS + jmp replace_bootstrap +.error: + stc + ret + +; +; INT 22h AX=0013h Idle call +; +comapi_idle: + DO_IDLE + clc + ret + +int21_table: + int21 00h, comboot_return + int21 01h, comboot_getkey + int21 02h, comboot_writechr + int21 04h, comboot_writeserial + int21 08h, comboot_getkeynoecho + int21 09h, comboot_writestr + int21 0Bh, comboot_checkkey + int21 30h, comboot_checkver + int21 4Ch, comboot_return + int21 -1, comboot_bogus +int21_count equ ($-int21_table)/3 + + align 2, db 0 +int22_table: + dw comapi_err ; 0000 unimplemented syscall + dw comapi_get_version ; 0001 get SYSLINUX version + dw comapi_writestr ; 0002 write string + dw comapi_run ; 0003 run specified command + dw comapi_run_default ; 0004 run default command + dw comapi_textmode ; 0005 force text mode + dw comapi_open ; 0006 open file + dw comapi_read ; 0007 read file + dw comapi_close ; 0008 close file + dw comapi_pxecall ; 0009 call PXE stack + dw comapi_derinfo ; 000A derivative-specific info + dw comapi_serialcfg ; 000B get serial port config + dw comapi_cleanup ; 000C perform final cleanup + dw comapi_chainboot ; 000D clean up then bootstrap + dw comapi_configfile ; 000E get name of config file + dw comapi_ipappend ; 000F get ipappend strings + dw comapi_dnsresolv ; 0010 resolve hostname + dw comapi_maxshuffle ; 0011 maximum shuffle descriptors + dw comapi_shuffle ; 0012 cleanup, shuffle and boot + dw comapi_idle ; 0013 idle call +int22_count equ ($-int22_table)/2 + +APIKeyWait db 0 +APIKeyFlag db 0 diff --git a/syslinux/config.inc b/syslinux/config.inc new file mode 100644 index 0000000..ba2127e --- /dev/null +++ b/syslinux/config.inc @@ -0,0 +1,44 @@ +;; $Id: config.inc,v 1.8 2005/05/08 21:47:03 hpa Exp $ +;; ----------------------------------------------------------------------- +;; +;; Copyright 2002-2005 H. Peter Anvin - All Rights Reserved +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +;; Boston MA 02111-1307, USA; either version 2 of the License, or +;; (at your option) any later version; incorporated herein by reference. +;; +;; ----------------------------------------------------------------------- + +;; +;; config.inc +;; +;; Common configuration options. Some of these are imposed by the kernel. +;; + +%ifndef _CONFIG_INC +%define _CONFIG_INC + +max_cmd_len equ 1023 ; Must be odd; 255 is the kernel limit +HIGHMEM_MAX equ 037FFFFFFh ; DEFAULT highest address for an initrd +DEFAULT_BAUD equ 9600 ; Default baud rate for serial port +BAUD_DIVISOR equ 115200 ; Serial port parameter + +%assign DO_WBINVD 0 ; Should we use WBINVD or not? + +; +; Version number definitinons +; +%ifndef DEPEND ; Generated file +%include "version.gen" +%endif + +; +; Should be updated with every release to avoid bootsector/SYS file mismatch +; +%define version_str VERSION ; Must be 4 characters long! +%define date DATE_STR ; Defined from the Makefile +%define year '2005' + +%endif ; _CONFIG_INC diff --git a/syslinux/conio.inc b/syslinux/conio.inc new file mode 100644 index 0000000..e2a87b0 --- /dev/null +++ b/syslinux/conio.inc @@ -0,0 +1,402 @@ +;; $Id: conio.inc,v 1.12 2005/01/04 22:17:17 hpa Exp $ +;; ----------------------------------------------------------------------- +;; +;; Copyright 1994-2005 H. Peter Anvin - All Rights Reserved +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +;; Boston MA 02111-1307, USA; either version 2 of the License, or +;; (at your option) any later version; incorporated herein by reference. +;; +;; ----------------------------------------------------------------------- + +;; +;; conio.inc +;; +;; Console I/O code, except: +;; writechr, writestr - module-dependent +;; cwritestr, crlf - writestr.inc +;; writehex* - writehex.inc +;; + +; +; loadkeys: Load a LILO-style keymap; SI and DX:AX set by searchdir +; + section .text + +loadkeys: + and dx,dx ; Should be 256 bytes exactly + jne loadkeys_ret + cmp ax,256 + jne loadkeys_ret + + mov bx,trackbuf + mov cx,1 ; 1 cluster should be >= 256 bytes + call getfssec + + mov si,trackbuf + mov di,KbdMap + mov cx,256 >> 2 + rep movsd + +loadkeys_ret: ret + +; +; get_msg_file: Load a text file and write its contents to the screen, +; interpreting color codes. Is called with SI and DX:AX +; set by routine searchdir +; +get_msg_file: + push es + shl edx,16 ; EDX <- DX:AX (length of file) + mov dx,ax + mov ax,xfer_buf_seg ; Use for temporary storage + mov es,ax + + mov byte [TextAttribute],07h ; Default grey on white + mov byte [DisplayMask],07h ; Display text in all modes + call msg_initvars + +get_msg_chunk: push edx ; EDX = length of file + xor bx,bx ; == xbs_textbuf + mov cx,[BufSafe] + call getfssec + pop edx + push si ; Save current cluster + xor si,si ; == xbs_textbuf + mov cx,[BufSafeBytes] ; Number of bytes left in chunk +print_msg_file: + push cx + push edx + es lodsb + cmp al,1Ah ; DOS EOF? + je msg_done_pop + push si + mov cl,[UsingVGA] + inc cl ; 01h = text mode, 02h = graphics + call [NextCharJump] ; Do what shall be done + pop si + pop edx + pop cx + dec edx + jz msg_done + loop print_msg_file + pop si + jmp short get_msg_chunk +msg_done_pop: + add sp,byte 6 ; Drop pushed EDX, CX +msg_done: + pop si + pop es + ret +msg_putchar: ; Normal character + cmp al,0Fh ; ^O = color code follows + je msg_ctrl_o + cmp al,0Dh ; Ignore <CR> + je msg_ignore + cmp al,0Ah ; <LF> = newline + je msg_newline + cmp al,0Ch ; <FF> = clear screen + je msg_formfeed + cmp al,19h ; <EM> = return to text mode + je msg_novga + cmp al,18h ; <CAN> = VGA filename follows + je msg_vga + jnb .not_modectl + cmp al,10h ; 10h to 17h are mode controls + jae msg_modectl +.not_modectl: + +msg_normal: call write_serial_displaymask ; Write to serial port + test [DisplayMask],cl + jz msg_ignore ; Not screen + test byte [DisplayCon],01h + jz msg_ignore + mov bl,[TextAttribute] + mov bh,[BIOS_page] + mov ah,09h ; Write character/attribute + mov cx,1 ; One character only + int 10h ; Write to screen + mov al,[CursorCol] + inc ax + cmp al,[VidCols] + ja msg_line_wrap ; Screen wraparound + mov [CursorCol],al + +msg_gotoxy: mov bh,[BIOS_page] + mov dx,[CursorDX] + mov ah,02h ; Set cursor position + int 10h +msg_ignore: ret +msg_ctrl_o: ; ^O = color code follows + mov word [NextCharJump],msg_setbg + ret +msg_newline: ; Newline char or end of line + mov si,crlf_msg + call write_serial_str_displaymask +msg_line_wrap: ; Screen wraparound + test [DisplayMask],cl + jz msg_ignore + mov byte [CursorCol],0 + mov al,[CursorRow] + inc ax + cmp al,[VidRows] + ja msg_scroll + mov [CursorRow],al + jmp short msg_gotoxy +msg_scroll: xor cx,cx ; Upper left hand corner + mov dx,[ScreenSize] + mov [CursorRow],dh ; New cursor at the bottom + mov bh,[ScrollAttribute] + mov ax,0601h ; Scroll up one line + int 10h + jmp short msg_gotoxy +msg_formfeed: ; Form feed character + mov si,crff_msg + call write_serial_str_displaymask + test [DisplayMask],cl + jz msg_ignore + xor cx,cx + mov [CursorDX],cx ; Upper lefthand corner + mov dx,[ScreenSize] + mov bh,[TextAttribute] + mov ax,0600h ; Clear screen region + int 10h + jmp msg_gotoxy +msg_setbg: ; Color background character + call unhexchar + jc msg_color_bad + shl al,4 + test [DisplayMask],cl + jz .dontset + mov [TextAttribute],al +.dontset: + mov word [NextCharJump],msg_setfg + ret +msg_setfg: ; Color foreground character + call unhexchar + jc msg_color_bad + test [DisplayMask],cl + jz .dontset + or [TextAttribute],al ; setbg set foreground to 0 +.dontset: + jmp short msg_putcharnext +msg_vga: + mov word [NextCharJump],msg_filename + mov di, VGAFileBuf + jmp short msg_setvgafileptr + +msg_color_bad: + mov byte [TextAttribute],07h ; Default attribute +msg_putcharnext: + mov word [NextCharJump],msg_putchar + ret + +msg_filename: ; Getting VGA filename + cmp al,0Ah ; <LF> = end of filename + je msg_viewimage + cmp al,' ' + jbe msg_ret ; Ignore space/control char + mov di,[VGAFilePtr] + cmp di,VGAFileBufEnd + jnb msg_ret + mov [di],al ; Can't use stosb (DS:) + inc di +msg_setvgafileptr: + mov [VGAFilePtr],di +msg_ret: ret + +msg_novga: + call vgaclearmode + jmp short msg_initvars + +msg_viewimage: + push es + push ds + pop es ; ES <- DS + mov si,VGAFileBuf + mov di,VGAFileMBuf + push di + call mangle_name + pop di + call searchdir + pop es + jz msg_putcharnext ; Not there + call vgadisplayfile + ; Fall through + + ; Subroutine to initialize variables, also needed + ; after loading a graphics file +msg_initvars: + pusha + mov bh,[BIOS_page] + mov ah,03h ; Read cursor position + int 10h + mov [CursorDX],dx + popa + jmp short msg_putcharnext ; Initialize state machine + +msg_modectl: + and al,07h + mov [DisplayMask],al + jmp short msg_putcharnext + +; +; write_serial: If serial output is enabled, write character on serial port +; write_serial_displaymask: d:o, but ignore if DisplayMask & 04h == 0 +; +write_serial_displaymask: + test byte [DisplayMask], 04h + jz write_serial.end +write_serial: + pushfd + pushad + mov bx,[SerialPort] + and bx,bx + je .noserial + push ax + mov ah,[FlowInput] +.waitspace: + ; Wait for space in transmit register + lea dx,[bx+5] ; DX -> LSR + in al,dx + test al,20h + jz .waitspace + + ; Wait for input flow control + inc dx ; DX -> MSR + in al,dx + and al,ah + cmp al,ah + jne .waitspace +.no_flow: + + xchg dx,bx ; DX -> THR + pop ax + call slow_out ; Send data +.noserial: popad + popfd +.end: ret + +; +; write_serial_str: write_serial for strings +; write_serial_str_displaymask: d:o, but ignore if DisplayMask & 04h == 0 +; +write_serial_str_displaymask: + test byte [DisplayMask], 04h + jz write_serial_str.end + +write_serial_str: +.loop lodsb + and al,al + jz .end + call write_serial + jmp short .loop +.end: ret + +; +; pollchar: check if we have an input character pending (ZF = 0) +; +pollchar: + pushad + mov ah,11h ; Poll keyboard + int 16h + jnz .done ; Keyboard response + mov dx,[SerialPort] + and dx,dx + jz .done ; No serial port -> no input + add dx,byte 5 ; DX -> LSR + in al,dx + test al,1 ; ZF = 0 if data pending + jz .done + inc dx ; DX -> MSR + mov ah,[FlowIgnore] ; Required status bits + in al,dx + and al,ah + cmp al,ah + setne al + dec al ; Set ZF = 0 if equal +.done: popad + ret + +; +; getchar: Read a character from keyboard or serial port +; +getchar: + RESET_IDLE +.again: + DO_IDLE + mov ah,11h ; Poll keyboard + int 16h + jnz .kbd ; Keyboard input? + mov bx,[SerialPort] + and bx,bx + jz .again + lea dx,[bx+5] ; DX -> LSR + in al,dx + test al,1 + jz .again + inc dx ; DX -> MSR + mov ah,[FlowIgnore] + in al,dx + and al,ah + cmp al,ah + jne .again +.serial: xor ah,ah ; Avoid confusion + xchg dx,bx ; Data port + in al,dx + ret +.kbd: mov ah,10h ; Get keyboard input + int 16h + cmp al,0E0h + jnz .not_ext + xor al,al +.not_ext: + and al,al + jz .func_key + mov bx,KbdMap ; Convert character sets + xlatb +.func_key: ret + +%ifdef DEBUG_TRACERS +; +; debug hack to print a character with minimal code impact +; +debug_tracer: pushad + pushfd + mov bp,sp + mov bx,[bp+9*4] ; Get return address + mov al,[cs:bx] ; Get data byte + inc word [bp+9*4] ; Return to after data byte + call writechr + popfd + popad + ret +%endif ; DEBUG_TRACERS + + section .data + ; This is a word to pc_setint16 can set it +DisplayCon dw 01h ; Console display enabled + +ScrollAttribute db 07h ; Grey on white (normal text color) + + section .bss + alignb 2 +NextCharJump resw 1 ; Routine to interpret next print char +CursorDX equ $ +CursorCol resb 1 ; Cursor column for message file +CursorRow resb 1 ; Cursor row for message file +ScreenSize equ $ +VidCols resb 1 ; Columns on screen-1 +VidRows resb 1 ; Rows on screen-1 + +; Serial console stuff... +BaudDivisor resw 1 ; Baud rate divisor +FlowControl equ $ +FlowOutput resb 1 ; Outputs to assert for serial flow +FlowInput resb 1 ; Input bits for serial flow +FlowIgnore resb 1 ; Ignore input unless these bits set + +TextAttribute resb 1 ; Text attribute for message file +DisplayMask resb 1 ; Display modes mask diff --git a/syslinux/copybs.asm b/syslinux/copybs.asm new file mode 100644 index 0000000..30eba47 --- /dev/null +++ b/syslinux/copybs.asm @@ -0,0 +1,272 @@ +; -*- fundamental -*- (asm-mode sucks) +; $Id: copybs.asm,v 1.4 2004/12/14 23:03:28 hpa Exp $ +; ----------------------------------------------------------------------- +; +; Copyright 1998-2004 H. Peter Anvin - All Rights Reserved +; +; This program is free software; you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +; Boston MA 02111-1307, USA; either version 2 of the License, or +; (at your option) any later version; incorporated herein by reference. +; +; ----------------------------------------------------------------------- + +; +; copybs.asm +; +; Small DOS program to copy the boot sector from a drive +; to a file +; +; Usage: copybs <drive>: <file> +; + + absolute 0 +pspInt20: resw 1 +pspNextParagraph: resw 1 + resb 1 ; reserved +pspDispatcher: resb 5 +pspTerminateVector: resd 1 +pspControlCVector: resd 1 +pspCritErrorVector: resd 1 + resw 11 ; reserved +pspEnvironment: resw 1 + resw 23 ; reserved +pspFCB_1: resb 16 +pspFCB_2: resb 16 + resd 1 ; reserved +pspCommandLen: resb 1 +pspCommandArg: resb 127 + + section .text + org 100h ; .COM format +_start: + mov ax,3000h ; Get DOS version + int 21h + xchg al,ah + mov [DOSVersion],ax + cmp ax,0200h ; DOS 2.00 minimum + jae dosver_ok + mov dx,msg_ancient_err + jmp die + + section .bss + alignb 2 +DOSVersion: resw 1 + + section .text +; +; Scan command line for a drive letter followed by a colon +; +dosver_ok: + xor cx,cx + mov si,pspCommandArg + mov cl,[pspCommandLen] + +cmdscan1: jcxz bad_usage ; End of command line? + lodsb ; Load character + dec cx + cmp al,' ' ; White space + jbe cmdscan1 + or al,020h ; -> lower case + cmp al,'a' ; Check for letter + jb bad_usage + cmp al,'z' + ja bad_usage + sub al,'a' ; Convert to zero-based index + mov [DriveNo],al ; Save away drive index + + section .bss +DriveNo: resb 1 + + section .text +; +; Got the leading letter, now the next character must be a colon +; +got_letter: jcxz bad_usage + lodsb + dec cx + cmp al,':' + jne bad_usage +; +; Got the colon; now we should have at least one whitespace +; followed by a filename +; +got_colon: jcxz bad_usage + lodsb + dec cx + cmp al,' ' + ja bad_usage + +skipspace: jcxz bad_usage + lodsb + dec cx + cmp al,' ' + jbe skipspace + + mov di,FileName +copyfile: stosb + jcxz got_cmdline + lodsb + dec cx + cmp al,' ' + ja copyfile + jmp short got_cmdline + +; +; We end up here if the command line doesn't parse +; +bad_usage: mov dx,msg_unfair + jmp die + + section .data +msg_unfair: db 'Usage: copybs <drive>: <filename>', 0Dh, 0Ah, '$' + + section .bss + alignb 4 +FileName resb 256 + +; +; Parsed the command line OK. Get device parameter block to get the +; sector size. +; + struc DPB +dpbDrive: resb 1 +dpbUnit: resb 1 +dpbSectorSize: resw 1 +dpbClusterMask: resb 1 +dpbClusterShift: resb 1 +dpbFirstFAT: resw 1 +dpbFATCount: resb 1 +dpbRootEntries: resw 1 +dpbFirstSector: resw 1 +dpbMaxCluster: resw 1 +dpbFATSize: resw 1 +dpbDirSector: resw 1 +dpbDriverAddr: resd 1 +dpbMedia: resb 1 +dpbFirstAccess: resb 1 +dpbNextDPB: resd 1 +dpbNextFree: resw 1 +dpbFreeCnt: resw 1 + endstruc + + section .bss + alignb 2 +SectorSize resw 1 + + section .text +got_cmdline: + xor al,al ; Zero-terminate filename + stosb + + mov dl,[DriveNo] + inc dl ; 1-based + mov ah,32h + int 21h ; Get Drive Parameter Block + + and al,al + jnz filesystem_error + + mov dx,[bx+dpbSectorSize] ; Save sector size +; +; Read the boot sector. +; + section .data + align 4, db 0 +DISKIO equ $ +diStartSector: dd 0 ; Absolute sector 0 +diSectors: dw 1 ; One sector +diBuffer: dw SectorBuffer ; Buffer offset + dw 0 ; Buffer segment + + section .text +read_bootsect: + mov ax,cs ; Set DS <- CS + mov ds,ax + + mov [SectorSize],dx ; Saved sector size from above + + cmp word [DOSVersion],0400h ; DOS 4.00 has a new interface + jae .new +.old: + mov bx,SectorBuffer + mov cx,1 ; One sector + jmp short .common +.new: + mov [diBuffer+2],ax ; == DS + mov bx,DISKIO + mov cx,-1 +.common: + xor dx,dx ; Absolute sector 0 + mov al,[DriveNo] + int 25h ; DOS absolute disk read + pop ax ; Remove flags from stack + jc disk_read_error + +; +; Open the file and write the boot sector to the file. +; + mov dx,FileName + mov cx,0020h ; Attribute = ARCHIVE + mov ah,3Ch ; Create file + int 21h + jc file_write_error + + mov bx,ax + push ax ; Handle + + mov cx,[SectorSize] + mov dx,SectorBuffer + mov ah,40h ; Write file + int 21h + jc file_write_error + cmp ax,[SectorSize] + jne file_write_error + + pop bx ; Handle + mov ah,3Eh ; Close file + int 21h + jc file_write_error +; +; We're done! +; + mov ax,4C00h ; exit(0) + int 21h + +; +; Error routine jump +; +filesystem_error: + mov dx,msg_filesystem_err + jmp short die +disk_read_error: + mov dx,msg_read_err + jmp short die +file_write_error: + mov dx,msg_write_err +die: + push cs + pop ds + push dx + mov dx,msg_error + mov ah,09h + int 21h + pop dx + + mov ah,09h ; Write string + int 21h + + mov ax,4C01h ; Exit error status + int 21h + + section .data +msg_error: db 'ERROR: $' +msg_ancient_err: db 'DOS version 2.00 or later required', 0Dh, 0Ah, '$' +msg_filesystem_err: db 'Filesystem not found on disk', 0Dh, 0Ah, '$' +msg_read_err: db 'Boot sector read failed', 0Dh, 0Ah, '$' +msg_write_err: db 'File write failed', 0Dh, 0Ah, '$' + + section .bss + alignb 4 +SectorBuffer: resb 4096 diff --git a/syslinux/cpuinit.inc b/syslinux/cpuinit.inc new file mode 100644 index 0000000..3c57cac --- /dev/null +++ b/syslinux/cpuinit.inc @@ -0,0 +1,76 @@ +;; $Id: cpuinit.inc,v 1.5 2004/12/27 07:04:08 hpa Exp $ +;; ----------------------------------------------------------------------- +;; +;; Copyright 1994-2002 H. Peter Anvin - All Rights Reserved +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +;; Boston MA 02111-1307, USA; either version 2 of the License, or +;; (at your option) any later version; incorporated herein by reference. +;; +;; ----------------------------------------------------------------------- + +;; +;; cpuinit.inc +;; +;; CPU-dependent initialization and related checks. +;; + +check_escapes: + mov ah,02h ; Check keyboard flags + int 16h + mov [KbdFlags],al ; Save for boot prompt check + test al,04h ; Ctrl->skip 386 check + jnz skip_checks + +; +; Now check that there is sufficient low (DOS) memory +; +; NOTE: Linux doesn't use all of real_mode_seg, but we use the same +; segment for COMBOOT images, which can use all 64K +; +dosram_k equ (real_mode_seg+0x1000) >> 6 ; Minimum DOS memory (K) + int 12h + cmp ax,dosram_k + jae enough_ram + mov si,err_noram + call writestr + jmp kaboom +enough_ram: +skip_checks: + +; +; Initialize the bcopy32 code in low memory +; + mov si,section..bcopy32.start + mov di,__bcopy_start + mov cx,__bcopy_size >> 2 + rep movsd + +; +; Check if we're 386 (as opposed to 486+); if so we need to blank out +; the WBINVD instruction +; +; We check for 486 by setting EFLAGS.AC +; +%if DO_WBINVD + pushfd ; Save the good flags + pushfd + pop eax + mov ebx,eax + xor eax,(1 << 18) ; AC bit + push eax + popfd + pushfd + pop eax + popfd ; Restore the original flags + xor eax,ebx + jnz is_486 +; +; 386 - Looks like we better blot out the WBINVD instruction +; + mov byte [try_wbinvd],0c3h ; Near RET +is_486: +%endif ; DO_WBINVD + diff --git a/syslinux/distrib.doc b/syslinux/distrib.doc new file mode 100644 index 0000000..e599d0e --- /dev/null +++ b/syslinux/distrib.doc @@ -0,0 +1,30 @@ +For creators of Linux distributions: + +SYSLINUX is a notoriously hard program to debug, since it runs outside +of any operating system, and has a tendency to expose BIOS and +hardware bugs on various systems. Therefore, I would appreciate if +you would resist the temptation of recompiling the SYSLINUX bootloader +itself (ldlinux.asm) if at all possible. If you do that, I will have +to refer any bug reports I receive back to the respective distributor. + +However, I have no such concerns about recompiling the installer +programs, and in fact, with both libc 5 and libc 6 in common use in +the Linux world today I understand if you wish to relink the +Linux-based installer against your system version of libc. Therefore +a special makefile targets "make installer" has been included with the +SYSLINUX distribution, starting with version 1.42. + +To rebuild the installer programs *only*, starting from a freshly +untarred distribution copy of SYSLINUX, do: + + make clean + make installer + +If you want to remove all intermediate files, including the ones +obtained from assembling ldlinux.asm and which are included in the +distribution, do "make spotless". + +I appreciate your assistance in this matter. + + H. Peter Anvin + diff --git a/syslinux/dnsresolv.inc b/syslinux/dnsresolv.inc new file mode 100644 index 0000000..05d0fff --- /dev/null +++ b/syslinux/dnsresolv.inc @@ -0,0 +1,378 @@ +; -*- fundamental -*- +; ----------------------------------------------------------------------- +; +; Copyright 2004 H. Peter Anvin - All Rights Reserved +; +; This program is free software; you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +; Bostom MA 02111-1307, USA; either version 2 of the License, or +; (at your option) any later version; incorporated herein by reference. +; +; ----------------------------------------------------------------------- + +; +; dnsresolv.inc +; +; Very simple DNS resolver (assumes recursion-enabled DNS server; +; this should be the normal thing for client-serving DNS servers.) +; + +DNS_PORT equ htons(53) ; Default DNS port +DNS_MAX_PACKET equ 512 ; Defined by protocol +; TFTP uses the range 49152-57343 +DNS_LOCAL_PORT equ htons(60053) ; All local DNS queries come from this port # +DNS_MAX_SERVERS equ 4 ; Max no of DNS servers + + section .text + +; +; Turn a string in DS:SI into a DNS "label set" in ES:DI. +; On return, DI points to the first byte after the label set, +; and SI to the terminating byte. +; +; On return, DX contains the number of dots encountered. +; +dns_mangle: + push ax + push bx + xor dx,dx +.isdot: + inc dx + xor al,al + mov bx,di + stosb +.getbyte: + lodsb + and al,al + jz .endstring + cmp al,':' + jz .endstring + cmp al,'.' + je .isdot + inc byte [es:bx] + stosb + jmp .getbyte +.endstring: + dec si + dec dx ; We always counted one high + cmp byte [es:bx],0 + jz .done + xor al,al + stosb +.done: + pop bx + pop ax + ret + +; +; Compare two sets of DNS labels, in DS:SI and ES:DI; the one in SI +; is allowed pointers relative to a packet in DNSRecvBuf. +; +; Assumes DS == ES. ZF = 1 if same; no registers changed. +; (Note: change reference to [di] to [es:di] to remove DS == ES assumption) +; +dns_compare: + pusha +%if 0 + +.label: + lodsb + cmp al,0C0h + jb .noptr + and al,03Fh ; Get pointer value + mov ah,al ; ... in network byte order! + lodsb + mov si,DNSRecvBuf + add si,ax + jmp .label +.noptr: + cmp al,[di] + jne .done ; Mismatch + inc di + movzx cx,al ; End label? + and cx,cx ; ZF = 1 if match + jz .done + + ; We have a string of bytes that need to match now + repe cmpsb + je .label + +.done: +%else + xor ax,ax +%endif + popa + ret + +; +; Skip past a DNS label set in DS:SI. +; +dns_skiplabel: + push ax + xor ax,ax ; AH == 0 +.loop: + lodsb + cmp al,0C0h ; Pointer? + jae .ptr + and al,al + jz .done + add si,ax + jmp .loop +.ptr: + inc si ; Pointer is two bytes +.done: + pop ax + ret + + ; DNS header format + struc dnshdr +.id: resw 1 +.flags: resw 1 +.qdcount: resw 1 +.ancount: resw 1 +.nscount: resw 1 +.arcount: resw 1 + endstruc + + ; DNS query + struc dnsquery +.qtype: resw 1 +.qclass: resw 1 + endstruc + + ; DNS RR + struc dnsrr +.type: resw 1 +.class: resw 1 +.ttl: resd 1 +.rdlength: resw 1 +.rdata: equ $ + endstruc + + section .bss + alignb 2, db 0 +DNSSendBuf resb DNS_MAX_PACKET +DNSRecvBuf resb DNS_MAX_PACKET +LocalDomain resb 256 ; Max possible length +DNSServers resd DNS_MAX_SERVERS + + section .data +pxe_udp_write_pkt_dns: +.status: dw 0 ; Status +.sip: dd 0 ; Server IP +.gip: dd 0 ; Gateway IP +.lport: dw DNS_LOCAL_PORT ; Local port +.rport: dw DNS_PORT ; Remote port +.buffersize: dw 0 ; Size of packet +.buffer: dw DNSSendBuf, 0 ; off, seg of buffer + +pxe_udp_read_pkt_dns: +.status: dw 0 ; Status +.sip: dd 0 ; Source IP +.dip: dd 0 ; Destination (our) IP +.rport: dw DNS_PORT ; Remote port +.lport: dw DNS_LOCAL_PORT ; Local port +.buffersize: dw DNS_MAX_PACKET ; Max packet size +.buffer: dw DNSRecvBuf, 0 ; off, seg of buffer + +LastDNSServer dw DNSServers + +; Actual resolver function +; Points to a null-terminated or :-terminated string in DS:SI +; and returns the name in EAX if it exists and can be found. +; If EAX = 0 on exit, the lookup failed. + + section .text +dns_resolv: + push ds + push es + push di + push cx + push dx + + push cs + pop es ; ES <- CS + + ; First, build query packet + mov di,DNSSendBuf+dnshdr.flags + inc word [es:di-2] ; New query ID + mov ax,htons(0100h) ; Recursion requested + stosw + mov ax,htons(1) ; One question + stosw + xor ax,ax ; No answers, NS or ARs + stosw + stosw + stosw + + call dns_mangle ; Convert name to DNS labels + + push cs ; DS <- CS + pop ds + + push si ; Save pointer to after DNS string + + ; Initialize... + mov eax,[MyIP] + mov [pxe_udp_read_pkt_dns.dip],eax + + and dx,dx + jnz .fqdn ; If we have dots, assume it's FQDN + dec di ; Remove final null + mov si,LocalDomain + call strcpy ; Uncompressed DNS label set so it ends in null +.fqdn: + + mov ax,htons(1) + stosw ; QTYPE = 1 = A + stosw ; QCLASS = 1 = IN + + sub di,DNSSendBuf + mov [pxe_udp_write_pkt_dns.buffersize],di + + ; Now, send it to the nameserver(s) + ; Outer loop: exponential backoff + ; Inner loop: scan the various DNS servers + + mov dx,PKT_TIMEOUT + mov cx,PKT_RETRY +.backoff: + mov si,DNSServers +.servers: + cmp si,[LastDNSServer] + jb .moreservers + +.nomoreservers: + add dx,dx ; Exponential backoff + loop .backoff + + xor eax,eax ; Nothing... +.done: + pop si + pop dx + pop cx + pop di + pop es + pop ds + ret + +.moreservers: + lodsd ; EAX <- next server + push si + push cx + push dx + + mov word [pxe_udp_write_pkt_dns.status],0 + + mov [pxe_udp_write_pkt_dns.sip],eax + mov [pxe_udp_read_pkt_dns.sip],eax + xor eax,[MyIP] + and eax,[Netmask] + jz .nogw + mov eax,[Gateway] +.nogw: + mov [pxe_udp_write_pkt_dns.gip],eax + + mov di,pxe_udp_write_pkt_dns + mov bx,PXENV_UDP_WRITE + call pxenv + jc .timeout ; Treat failed transmit as timeout + cmp word [pxe_udp_write_pkt_dns.status],0 + jne .timeout + + mov cx,[BIOS_timer] +.waitrecv: + mov ax,[BIOS_timer] + sub ax,cx + cmp ax,dx + jae .timeout + + mov word [pxe_udp_read_pkt_dns.status],0 + mov word [pxe_udp_read_pkt_dns.buffersize],DNS_MAX_PACKET + mov di,pxe_udp_read_pkt_dns + mov bx,PXENV_UDP_READ + call pxenv + and ax,ax + jnz .waitrecv + cmp [pxe_udp_read_pkt_dns.status],ax + jnz .waitrecv + + ; Got a packet, deal with it... + mov si,DNSRecvBuf + lodsw + cmp ax,[DNSSendBuf] ; ID + jne .waitrecv ; Not ours + + lodsw ; flags + xor al,80h ; Query#/Answer bit + test ax,htons(0F80Fh) + jnz .badness + + lodsw + xchg ah,al ; ntohs + mov cx,ax ; Questions echoed + lodsw + xchg ah,al ; ntohs + push ax ; Replies + lodsw ; NS records + lodsw ; Authority records + + jcxz .qskipped +.skipq: + call dns_skiplabel ; Skip name + add si,4 ; Skip question trailer + loop .skipq + +.qskipped: + pop cx ; Number of replies + jcxz .badness + +.parseanswer: + mov di,DNSSendBuf+dnshdr_size + call dns_compare + pushf + call dns_skiplabel + mov ax,[si+8] ; RDLENGTH + xchg ah,al ; ntohs + popf + jnz .notsame + cmp dword [si],htons(1)*0x10001 ; TYPE = A, CLASS = IN? + jne .notsame + cmp ax,4 ; RDLENGTH = 4? + jne .notsame + ; + ; We hit paydirt here... + ; + mov eax,[si+10] +.gotresult: + add sp,6 ; Drop timeout information + jmp .done + +.notsame: + add si,10 + add si,ax + loop .parseanswer + +.badness: + ; We got back no data from this server. Unfortunately, for a recursive, + ; non-authoritative query there is no such thing as an NXDOMAIN reply, + ; which technically means we can't draw any conclusions. However, + ; in practice that means the domain doesn't exist. If this turns out + ; to be a problem, we may want to add code to go through all the servers + ; before giving up. + + ; If the DNS server wasn't capable of recursion, and isn't capable + ; of giving us an authoritative reply (i.e. neither AA or RA set), + ; then at least try a different setver... + test word [DNSRecvBuf+dnshdr.flags],htons(0480h) + jz .timeout + + xor eax,eax + jmp .gotresult + +.timeout: + pop dx + pop cx + pop si + jmp .servers diff --git a/syslinux/dos/Makefile b/syslinux/dos/Makefile new file mode 100644 index 0000000..7da22fe --- /dev/null +++ b/syslinux/dos/Makefile @@ -0,0 +1,60 @@ +CC = gcc -m32 -mregparm=3 -DREGPARM=3 +LD = ld -m elf_i386 +OBJCOPY = objcopy +OPTFLAGS = -g -Os -march=i386 -falign-functions=0 -falign-jumps=0 -falign-loops=0 -fomit-frame-pointer +INCLUDES = -include code16.h -I. -I.. -I../libfat +CFLAGS = -W -Wall -ffreestanding -msoft-float $(OPTFLAGS) $(INCLUDES) +LDFLAGS = -T com16.ld +AR = ar +RANLIB = ranlib +LIBGCC := $(shell $(CC) --print-libgcc) + +SRCS = syslinux.c \ + ../syslxmod.c ../bootsect_bin.c ../ldlinux_bin.c ../mbr_bin.c \ + $(wildcard ../libfat/*.c) +OBJS = crt0.o $(patsubst %.c,%.o,$(notdir $(SRCS))) +LIBOBJS = conio.o memcpy.o memset.o skipatou.o atou.o malloc.o free.o \ + argv.o printf.o __divdi3.o __udivmoddi4.o + +.SUFFIXES: .c .o .i .s .S .elf .com + +VPATH = .:..:../libfat + +TARGETS = syslinux.com + +all: $(TARGETS) + +tidy: + -rm -f *.o *.i *.s *.a .*.d *.elf + +clean: tidy + +spotless: clean + -rm -f *~ $(TARGETS) + +installer: + +syslinux.elf: $(OBJS) libcom.a + $(LD) $(LDFLAGS) -o $@ $^ + +libcom.a: $(LIBOBJS) + -rm -f $@ + $(AR) cq $@ $^ + $(RANLIB) $@ + +syslinux.com: syslinux.elf + $(OBJCOPY) -O binary $< $@ + +%.o: %.c + $(CC) -Wp,-MT,$@,-MD,.$@.d $(CFLAGS) -c -o $@ $< +%.i: %.c + $(CC) $(CFLAGS) -E -o $@ $< +%.s: %.c + $(CC) $(CFLAGS) -S -o $@ $< +%.s: %.S + $(CC) $(CFLAGS) -D__ASSEMBLY__ -S -o $@ $< + +-include .*.d + + + diff --git a/syslinux/dos/__divdi3.c b/syslinux/dos/__divdi3.c new file mode 100644 index 0000000..be13cae --- /dev/null +++ b/syslinux/dos/__divdi3.c @@ -0,0 +1,29 @@ +/* + * arch/i386/libgcc/__divdi3.c + */ + +#include <stdint.h> +#include <stddef.h> + +extern uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t *rem); + +int64_t __divdi3(int64_t num, int64_t den) +{ + int minus = 0; + int64_t v; + + if ( num < 0 ) { + num = -num; + minus = 1; + } + if ( den < 0 ) { + den = -den; + minus ^= 1; + } + + v = __udivmoddi4(num, den, NULL); + if ( minus ) + v = -v; + + return v; +} diff --git a/syslinux/dos/__udivmoddi4.c b/syslinux/dos/__udivmoddi4.c new file mode 100644 index 0000000..57b20e2 --- /dev/null +++ b/syslinux/dos/__udivmoddi4.c @@ -0,0 +1,31 @@ +#include <stdint.h> + +uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t *rem_p) +{ + uint64_t quot = 0, qbit = 1; + + if ( den == 0 ) { + asm volatile("int $0"); + return 0; /* If trap returns... */ + } + + /* Left-justify denominator and count shift */ + while ( (int64_t)den >= 0 ) { + den <<= 1; + qbit <<= 1; + } + + while ( qbit ) { + if ( den <= num ) { + num -= den; + quot += qbit; + } + den >>= 1; + qbit >>= 1; + } + + if ( rem_p ) + *rem_p = num; + + return quot; +} diff --git a/syslinux/dos/argv.c b/syslinux/dos/argv.c new file mode 100644 index 0000000..26f2b8e --- /dev/null +++ b/syslinux/dos/argv.c @@ -0,0 +1,94 @@ +#ident "$Id: argv.c,v 1.3 2004/12/19 00:25:14 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * argv.c + * + * Parse a single C string into argc and argv (argc is return value.) + * memptr points to available memory. + */ + +#include <inttypes.h> +#include <stddef.h> +#include <stdio.h> + +#define ALIGN_UP(p,t) ((t *)(((uintptr_t)(p) + (sizeof(t)-1)) & ~(sizeof(t)-1))) + +extern char _end[]; /* Symbol created by linker */ +void *__mem_end = &_end; /* Global variable for use by malloc() */ + +int __parse_argv(char ***argv, const char *str) +{ + char *mem = __mem_end; + const char *p = str; + char *q = mem; + char *r; + char **arg; + int wasspace = 0; + int argc = 1; + + /* First copy the string, turning whitespace runs into nulls */ + for ( p = str ; ; p++ ) { + if ( *p <= ' ' ) { + if ( !wasspace ) { + wasspace = 1; + *q++ = '\0'; + } + } else { + if ( wasspace ) { + argc++; + wasspace = 0; + } + *q++ = *p; + } + + /* This test is AFTER we have processed the null byte; + we treat it as a whitespace character so it terminates + the last argument */ + if ( ! *p ) + break; + } + + /* Now create argv */ + arg = ALIGN_UP(q,char *); + *argv = arg; + *arg++ = mem; /* argv[0] */ + + q--; /* Point q to final null */ + for ( r = mem ; r < q ; r++ ) { + if ( *r == '\0' ) { + *arg++ = r+1; + } + } + + *arg++ = NULL; /* Null pointer at the end */ + __mem_end = arg; /* End of memory we used */ + + return argc; +} + diff --git a/syslinux/dos/atou.c b/syslinux/dos/atou.c new file mode 100644 index 0000000..6d65106 --- /dev/null +++ b/syslinux/dos/atou.c @@ -0,0 +1,10 @@ +#include "mystuff.h" + +unsigned int atou(const char *s) +{ + unsigned int i = 0; + while (isdigit(*s)) + i = i*10 + (*s++ - '0'); + return i; +} + diff --git a/syslinux/dos/code16.h b/syslinux/dos/code16.h new file mode 100644 index 0000000..ceb1600 --- /dev/null +++ b/syslinux/dos/code16.h @@ -0,0 +1,2 @@ +/* Must be included first of all */ +__asm__ (".code16gcc"); diff --git a/syslinux/dos/com16.ld b/syslinux/dos/com16.ld new file mode 100644 index 0000000..08a1e95 --- /dev/null +++ b/syslinux/dos/com16.ld @@ -0,0 +1,127 @@ +/* + * Linker script for COM16 binaries + */ + +/* Script for -z combreloc: combine and sort reloc sections */ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", + "elf32-i386") +OUTPUT_ARCH(i386) +EXTERN(_start) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x100; + PROVIDE (__executable_start = .); + + .init : + { + KEEP (*(.init)) + } =0x90909090 + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } =0x90909090 + .fini : + { + KEEP (*(.fini)) + } =0x90909090 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + + /* Ensure the __preinit_array_start label is properly aligned. We + could instead move the label definition inside the section, but + the linker would then create the section even if it turns out to + be empty, which isn't pretty. */ + . = ALIGN(4); + PROVIDE (__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE (__fini_array_end = .); + PROVIDE (__ctors_start = .); + .ctors : + { + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + PROVIDE (__ctors_end = .); + PROVIDE (__dtors_start = .); + .dtors : + { + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + PROVIDE (__dtors_end = .); + + /* Adjust the address for the data segment. Avoid mixing code and + data within same 128-byte chunk. */ + . = ALIGN(128); + + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN(32 / 8); + } + . = ALIGN(32 / 8); + _end = .; + PROVIDE (end = .); + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /DISCARD/ : { *(.note.GNU-stack) } +} diff --git a/syslinux/dos/conio.c b/syslinux/dos/conio.c new file mode 100644 index 0000000..7f6c416 --- /dev/null +++ b/syslinux/dos/conio.c @@ -0,0 +1,43 @@ +#ident "$Id: conio.c,v 1.3 2004/12/17 17:47:16 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2001-2004 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * conio.c + * + * Output to the screen + */ + +#include <stdarg.h> +#include "mystuff.h" + +int putchar(int ch) +{ + if ( ch == '\n' ) + putchar('\r'); + asm("movb $0x02,%%ah ; int $0x21" : : "d" (ch)); + return ch; +} + +/* Note: doesn't put '\n' like the stdc version does */ +int puts(const char *s) +{ + int count = 0; + + while ( *s ) { + putchar(*s); + count++; + s++; + } + + return count; +} diff --git a/syslinux/dos/crt0.S b/syslinux/dos/crt0.S new file mode 100644 index 0000000..af8b8ba --- /dev/null +++ b/syslinux/dos/crt0.S @@ -0,0 +1,53 @@ + .code16 + +#ifndef REGPARM +# error "This file assumes -mregparm=3 -DREGPARM=3" +#endif + + .section ".init","ax" + .globl _start + .type _start,@function +_start: + # Align the stack and make sure the high half is zero + andl $0xfff8,%esp + + # Clear the .bss + cld + xorl %eax,%eax + movw $__bss_start,%di + movw $_end+3,%cx + subw %di,%cx + shrw $2,%cx + rep ; stosl + + # Compute argc and argv (assumes REGPARM) + xorl %edx,%edx + movzbw 0x80,%bx + movb %dl,0x81(%bx) # Zero-terminate string + movb $0x81,%dl + pushl %eax # Make space for argv + movl %esp,%eax + calll __parse_argv + pushl %eax # argc + + # Initialize malloc + calll __init_memory_arena + + # Now call main... (NOTE: gcc forces main to be regparm 0) + popl %eax # argc + popl %edx # argv + calll main + + # Here %eax is the exit code, fall through into exit + + .size _start,.-_start + + .globl exit + .type exit,@function +exit: + # Exit code already in %eax + movb $0x4c,%ah # Terminate program + int $0x21 +1: hlt + jmp 1b + .size exit,.-exit diff --git a/syslinux/dos/errno.h b/syslinux/dos/errno.h new file mode 100644 index 0000000..30aa046 --- /dev/null +++ b/syslinux/dos/errno.h @@ -0,0 +1,7 @@ +#ifndef ERRNO_H +#define ERRNO_H + +int errno; +void perror(const char *); + +#endif /* ERRNO_H */ diff --git a/syslinux/dos/free.c b/syslinux/dos/free.c new file mode 100644 index 0000000..aa17080 --- /dev/null +++ b/syslinux/dos/free.c @@ -0,0 +1,78 @@ +/* + * free.c + * + * Very simple linked-list based malloc()/free(). + */ + +#include <stdlib.h> +#include "malloc.h" + +static struct free_arena_header * +__free_block(struct free_arena_header *ah) +{ + struct free_arena_header *pah, *nah; + + pah = ah->a.prev; + nah = ah->a.next; + if ( pah->a.type == ARENA_TYPE_FREE && + (char *)pah+pah->a.size == (char *)ah ) { + /* Coalesce into the previous block */ + pah->a.size += ah->a.size; + pah->a.next = nah; + nah->a.prev = pah; + +#ifdef DEBUG_MALLOC + ah->a.type = ARENA_TYPE_DEAD; +#endif + + ah = pah; + pah = ah->a.prev; + } else { + /* Need to add this block to the free chain */ + ah->a.type = ARENA_TYPE_FREE; + + ah->next_free = __malloc_head.next_free; + ah->prev_free = &__malloc_head; + __malloc_head.next_free = ah; + ah->next_free->prev_free = ah; + } + + /* In either of the previous cases, we might be able to merge + with the subsequent block... */ + if ( nah->a.type == ARENA_TYPE_FREE && + (char *)ah+ah->a.size == (char *)nah ) { + ah->a.size += nah->a.size; + + /* Remove the old block from the chains */ + nah->next_free->prev_free = nah->prev_free; + nah->prev_free->next_free = nah->next_free; + ah->a.next = nah->a.next; + nah->a.next->a.prev = ah; + +#ifdef DEBUG_MALLOC + nah->a.type = ARENA_TYPE_DEAD; +#endif + } + + /* Return the block that contains the called block */ + return ah; +} + +void free(void *ptr) +{ + struct free_arena_header *ah; + + if ( !ptr ) + return; + + ah = (struct free_arena_header *) + ((struct arena_header *)ptr - 1); + +#ifdef DEBUG_MALLOC + assert( ah->a.type == ARENA_TYPE_USED ); +#endif + + __free_block(ah); + + /* Here we could insert code to return memory to the system. */ +} diff --git a/syslinux/dos/malloc.c b/syslinux/dos/malloc.c new file mode 100644 index 0000000..499d551 --- /dev/null +++ b/syslinux/dos/malloc.c @@ -0,0 +1,114 @@ +/* + * malloc.c + * + * Very simple linked-list based malloc()/free(). + */ + +#include <stdlib.h> +#include "malloc.h" + +struct free_arena_header __malloc_head = +{ + { + ARENA_TYPE_HEAD, + 0, + &__malloc_head, + &__malloc_head, + }, + &__malloc_head, + &__malloc_head +}; + +/* This is extern so it can be overridden by the user application */ +const size_t __stack_size = 4096; + +static inline size_t sp(void) +{ + uint32_t sp; + asm volatile("movl %%esp,%0" : "=rm" (sp)); + return sp; +} + +extern void *__mem_end; + +void __init_memory_arena(void) +{ + struct free_arena_header *fp; + size_t start, total_space; + + start = (size_t)ARENA_ALIGN_UP(__mem_end); + total_space = sp() - start; + + fp = (struct free_arena_header *)start; + fp->a.type = ARENA_TYPE_FREE; + fp->a.size = total_space - __stack_size; + + /* Insert into chains */ + fp->a.next = fp->a.prev = &__malloc_head; + fp->next_free = fp->prev_free = &__malloc_head; + __malloc_head.a.next = __malloc_head.a.prev = fp; + __malloc_head.next_free = __malloc_head.prev_free = fp; +} + +static void *__malloc_from_block(struct free_arena_header *fp, size_t size) +{ + size_t fsize; + struct free_arena_header *nfp, *na; + + fsize = fp->a.size; + + /* We need the 2* to account for the larger requirements of a free block */ + if ( fsize >= size+2*sizeof(struct arena_header) ) { + /* Bigger block than required -- split block */ + nfp = (struct free_arena_header *)((char *)fp + size); + na = fp->a.next; + + nfp->a.type = ARENA_TYPE_FREE; + nfp->a.size = fsize-size; + fp->a.type = ARENA_TYPE_USED; + fp->a.size = size; + + /* Insert into all-block chain */ + nfp->a.prev = fp; + nfp->a.next = na; + na->a.prev = nfp; + fp->a.next = nfp; + + /* Replace current block on free chain */ + nfp->next_free = fp->next_free; + nfp->prev_free = fp->prev_free; + fp->next_free->prev_free = nfp; + fp->prev_free->next_free = nfp; + } else { + /* Allocate the whole block */ + fp->a.type = ARENA_TYPE_USED; + + /* Remove from free chain */ + fp->next_free->prev_free = fp->prev_free; + fp->prev_free->next_free = fp->next_free; + } + + return (void *)(&fp->a + 1); +} + +void *malloc(size_t size) +{ + struct free_arena_header *fp; + + if ( size == 0 ) + return NULL; + + /* Add the obligatory arena header, and round up */ + size = (size+2*sizeof(struct arena_header)-1) & ~ARENA_SIZE_MASK; + + for ( fp = __malloc_head.next_free ; fp->a.type != ARENA_TYPE_HEAD ; + fp = fp->next_free ) { + if ( fp->a.size >= size ) { + /* Found fit -- allocate out of this block */ + return __malloc_from_block(fp, size); + } + } + + /* Nothing found... need to request a block from the kernel */ + return NULL; /* No kernel to get stuff from */ +} diff --git a/syslinux/dos/malloc.h b/syslinux/dos/malloc.h new file mode 100644 index 0000000..70d0e63 --- /dev/null +++ b/syslinux/dos/malloc.h @@ -0,0 +1,54 @@ +/* + * malloc.h + * + * Internals for the memory allocator + */ + +#include <stdint.h> +#include <stddef.h> + +/* + * This is the minimum chunk size we will ask the kernel for; this should + * be a multiple of the page size on all architectures. + */ +#define MALLOC_CHUNK_SIZE 65536 +#define MALLOC_CHUNK_MASK (MALLOC_CHUNK_SIZE-1) + +/* + * This structure should be a power of two. This becomes the + * alignment unit. + */ +struct free_arena_header; + +struct arena_header { + size_t type; + size_t size; /* Also gives the location of the next entry */ + struct free_arena_header *next, *prev; +}; + +#ifdef DEBUG_MALLOC +#define ARENA_TYPE_USED 0x64e69c70 +#define ARENA_TYPE_FREE 0x012d610a +#define ARENA_TYPE_HEAD 0x971676b5 +#define ARENA_TYPE_DEAD 0xeeeeeeee +#else +#define ARENA_TYPE_USED 0 +#define ARENA_TYPE_FREE 1 +#define ARENA_TYPE_HEAD 2 +#endif + +#define ARENA_SIZE_MASK (sizeof(struct arena_header)-1) + +#define ARENA_ALIGN_UP(p) ((char *)(((uintptr_t)(p) + ARENA_SIZE_MASK) & ~ARENA_SIZE_MASK)) +#define ARENA_ALIGN_DOWN(p) ((char *)((uintptr_t)(p) & ~ARENA_SIZE_MASK)) + +/* + * This structure should be no more than twice the size of the + * previous structure. + */ +struct free_arena_header { + struct arena_header a; + struct free_arena_header *next_free, *prev_free; +}; + +extern struct free_arena_header __malloc_head; diff --git a/syslinux/dos/memcpy.S b/syslinux/dos/memcpy.S new file mode 100644 index 0000000..f586ae5 --- /dev/null +++ b/syslinux/dos/memcpy.S @@ -0,0 +1,24 @@ +# $Id: memcpy.S,v 1.2 2004/12/17 10:03:47 hpa Exp $ +# +# memcpy.S +# +# Simple 16-bit memcpy() implementation +# + + .text + .code16gcc + .globl memcpy + .type memcpy, @function +memcpy: + cld + pushw %di + pushw %si + movw %ax,%di + movw %dx,%si + # The third argument is already in cx + rep ; movsb + popw %si + popw %di + ret + + .size memcpy,.-memcpy diff --git a/syslinux/dos/memset.S b/syslinux/dos/memset.S new file mode 100644 index 0000000..6c6552a --- /dev/null +++ b/syslinux/dos/memset.S @@ -0,0 +1,22 @@ +# $Id: memset.S,v 1.2 2004/12/17 10:03:47 hpa Exp $ +# +# memset.S +# +# Minimal 16-bit memset() implementation +# + + .text + .code16gcc + .globl memset + .type memset, @function +memset: + cld + pushw %di + movw %ax,%di + movb %dl,%al + # The third argument is already in %cx + rep ; stosb + popw %di + retl + + .size memset,.-memset diff --git a/syslinux/dos/mystuff.h b/syslinux/dos/mystuff.h new file mode 100644 index 0000000..83f072f --- /dev/null +++ b/syslinux/dos/mystuff.h @@ -0,0 +1,15 @@ +#ifndef MYSTUFF_H +#define MYSTUFF_H + +#define NULL ((void *)0) + +unsigned int skip_atou(const char **s); +unsigned int atou(const char *s); + +static inline int +isdigit(int ch) +{ + return (ch >= '0') && (ch <= '9'); +} + +#endif /* MYSTUFF_H */ diff --git a/syslinux/dos/perror.c b/syslinux/dos/perror.c new file mode 100644 index 0000000..ff8d5f2 --- /dev/null +++ b/syslinux/dos/perror.c @@ -0,0 +1,8 @@ +#include <stdio.h> +#include <errno.h> + +void perror(const char *msg) +{ + printf("%s: error %s\n", msg, errno); +} + diff --git a/syslinux/dos/printf.c b/syslinux/dos/printf.c new file mode 100644 index 0000000..bea400d --- /dev/null +++ b/syslinux/dos/printf.c @@ -0,0 +1,298 @@ +/* + * Oh, it's a waste of space, but oh-so-yummy for debugging. It's just + * initialization code anyway, so it doesn't take up space when we're + * actually running. This version of printf() does not include 64-bit + * support. "Live with it." + * + * Most of this code was shamelessly snarfed from the Linux kernel, then + * modified. It's therefore GPL. + * + * printf() isn't actually needed to build syslinux.com, but during + * debugging it's handy. + */ + +#include <stdarg.h> +#include <stdio.h> +#include "mystuff.h" + +static int strnlen(const char *s, int maxlen) +{ + const char *es = s; + while ( *es && maxlen ) { + es++; maxlen--; + } + + return (es-s); +} + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SPECIAL 32 /* 0x */ +#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ + +#define do_div(n,base) ({ \ +int __res; \ +__res = ((unsigned long) n) % (unsigned) base; \ +n = ((unsigned long) n) / (unsigned) base; \ +__res; }) + +static char * number(char * str, long num, int base, int size, int precision + ,int type) +{ + char c,sign,tmp[66]; + const char *digits="0123456789abcdefghijklmnopqrstuvwxyz"; + int i; + + if (type & LARGE) + digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + if (type & LEFT) + type &= ~ZEROPAD; + if (base < 2 || base > 36) + return 0; + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) { + if (num < 0) { + sign = '-'; + num = -num; + size--; + } else if (type & PLUS) { + sign = '+'; + size--; + } else if (type & SPACE) { + sign = ' '; + size--; + } + } + if (type & SPECIAL) { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + i = 0; + if (num == 0) + tmp[i++]='0'; + else while (num != 0) + tmp[i++] = digits[do_div(num,base)]; + if (i > precision) + precision = i; + size -= precision; + if (!(type&(ZEROPAD+LEFT))) + while(size-->0) + *str++ = ' '; + if (sign) + *str++ = sign; + if (type & SPECIAL) { + if (base==8) + *str++ = '0'; + else if (base==16) { + *str++ = '0'; + *str++ = digits[33]; + } + } + if (!(type & LEFT)) + while (size-- > 0) + *str++ = c; + while (i < precision--) + *str++ = '0'; + while (i-- > 0) + *str++ = tmp[i]; + while (size-- > 0) + *str++ = ' '; + return str; +} + +/* Forward decl. needed for IP address printing stuff... */ +int sprintf(char * buf, const char *fmt, ...); + +int vsprintf(char *buf, const char *fmt, va_list args) +{ + int len; + unsigned long num; + int i, base; + char * str; + const char *s; + + int flags; /* flags to number() */ + + int field_width; /* width of output field */ + int precision; /* min. # of digits for integers; max + number of chars for from string */ + int qualifier; /* 'h', 'l', or 'L' for integer fields */ + + for (str=buf ; *fmt ; ++fmt) { + if (*fmt != '%') { + *str++ = *fmt; + continue; + } + + /* process flags */ + flags = 0; + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': flags |= LEFT; goto repeat; + case '+': flags |= PLUS; goto repeat; + case ' ': flags |= SPACE; goto repeat; + case '#': flags |= SPECIAL; goto repeat; + case '0': flags |= ZEROPAD; goto repeat; + } + + /* get field width */ + field_width = -1; + if (isdigit(*fmt)) + field_width = skip_atou(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt == '.') { + ++fmt; + if (isdigit(*fmt)) + precision = skip_atou(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { + qualifier = *fmt; + ++fmt; + } + + /* default base */ + base = 10; + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + *str++ = ' '; + *str++ = (unsigned char) va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + continue; + + case 's': + s = va_arg(args, char *); + len = strnlen(s, precision); + + if (!(flags & LEFT)) + while (len < field_width--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = *s++; + while (len < field_width--) + *str++ = ' '; + continue; + + case 'p': + if (field_width == -1) { + field_width = 2*sizeof(void *); + flags |= ZEROPAD; + } + str = number(str, + (unsigned long) va_arg(args, void *), 16, + field_width, precision, flags); + continue; + + + case 'n': + if (qualifier == 'l') { + long * ip = va_arg(args, long *); + *ip = (str - buf); + } else { + int * ip = va_arg(args, int *); + *ip = (str - buf); + } + continue; + + case '%': + *str++ = '%'; + continue; + + /* integer number formats - set up the flags and "break" */ + case 'o': + base = 8; + break; + + case 'X': + flags |= LARGE; + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + break; + + default: + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + continue; + } + if (qualifier == 'l') + num = va_arg(args, unsigned long); + else if (qualifier == 'h') { + num = (unsigned short) va_arg(args, int); + if (flags & SIGN) + num = (short) num; + } else if (flags & SIGN) + num = va_arg(args, int); + else + num = va_arg(args, unsigned int); + str = number(str, num, base, field_width, precision, flags); + } + *str = '\0'; + return str-buf; +} + +int sprintf(char * buf, const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i=vsprintf(buf,fmt,args); + va_end(args); + return i; +} + +int printf(const char *fmt, ...) +{ + char printf_buf[1024]; + va_list args; + int printed; + + va_start(args, fmt); + printed = vsprintf(printf_buf, fmt, args); + va_end(args); + + puts(printf_buf); + + return printed; +} + diff --git a/syslinux/dos/skipatou.c b/syslinux/dos/skipatou.c new file mode 100644 index 0000000..4c663f6 --- /dev/null +++ b/syslinux/dos/skipatou.c @@ -0,0 +1,10 @@ +#include "mystuff.h" + +unsigned int skip_atou(const char **s) +{ + int i=0; + + while (isdigit(**s)) + i = i*10 + *((*s)++) - '0'; + return i; +} diff --git a/syslinux/dos/stdio.h b/syslinux/dos/stdio.h new file mode 100644 index 0000000..ffc9b3f --- /dev/null +++ b/syslinux/dos/stdio.h @@ -0,0 +1,22 @@ +#ifndef STDIO_H +#define STDIO_H + +#include <stdarg.h> +#include <stdlib.h> + +typedef unsigned int off_t; + +int putchar(int); +int puts(const char *); +int sprintf(char * buf, const char *fmt, ...); +int vsprintf(char *buf, const char *fmt, va_list args); +int printf(const char *fmt, ...); + +#define stdin 0 +#define stdout 1 +#define stderr 2 + +#define fprintf(x, y, ...) printf(y, ## __VA_ARGS__) + +#endif /* STDIO_H */ + diff --git a/syslinux/dos/stdlib.h b/syslinux/dos/stdlib.h new file mode 100644 index 0000000..45b76a5 --- /dev/null +++ b/syslinux/dos/stdlib.h @@ -0,0 +1,12 @@ +#ifndef STDLIB_H +#define STDLIB_H + +typedef int ssize_t; +typedef unsigned int size_t; + +void __attribute__((noreturn)) exit(int); + +void *malloc(size_t); +void free(void *); + +#endif diff --git a/syslinux/dos/string.h b/syslinux/dos/string.h new file mode 100644 index 0000000..44f77da --- /dev/null +++ b/syslinux/dos/string.h @@ -0,0 +1,23 @@ +/* + * string.h + */ + +#ifndef _STRING_H +#define _STRING_H + +/* Standard routines */ +#define memcpy(a,b,c) __builtin_memcpy(a,b,c) +#define memset(a,b,c) __builtin_memset(a,b,c) +#define strcpy(a,b) __builtin_strcpy(a,b) +#define strlen(a) __builtin_strlen(a) + +/* This only returns true or false */ +static inline int memcmp(const void *__m1, const void *__m2, unsigned int __n) +{ + _Bool rv; + asm volatile("cld ; repe ; cmpsb ; setne %0" + : "=abd" (rv), "+D" (__m1), "+S" (__m2), "+c" (__n)); + return rv; +} + +#endif /* _STRING_H */ diff --git a/syslinux/dos/syslinux.c b/syslinux/dos/syslinux.c new file mode 100644 index 0000000..7301119 --- /dev/null +++ b/syslinux/dos/syslinux.c @@ -0,0 +1,594 @@ +#ident "$Id: syslinux.c,v 1.13 2004/12/28 22:51:44 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 1998-2004 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * syslinux.c - Linux installer program for SYSLINUX + * + * Hacked up for DOS. + */ + +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "mystuff.h" + +#include "syslinux.h" +#include "libfat.h" + +const char *program = "syslinux"; /* Name of program */ +uint16_t dos_version; + +#ifdef DEBUG +# define dprintf printf +#else +# define dprintf(...) ((void)0) +#endif + +void __attribute__((noreturn)) usage(void) +{ + puts("Usage: syslinux [-sfma] <drive>: [bootsecfile]\n"); + exit(1); +} + +void unlock_device(int); + +void __attribute__((noreturn)) die(const char *msg) +{ + unlock_device(0); + puts("syslinux: "); + puts(msg); + putchar('\n'); + exit(1); +} + +/* + * read/write wrapper functions + */ +int creat(const char *filename, int mode) +{ + uint16_t rv; + uint8_t err; + + dprintf("creat(\"%s\", 0x%x)\n", filename, mode); + + rv = 0x3C00; + asm volatile("int $0x21 ; setc %0" + : "=abcdm" (err), "+a" (rv) + : "c" (mode), "d" (filename)); + if ( err ) { + dprintf("rv = %d\n", rv); + die("cannot open ldlinux.sys"); + } + + return rv; +} + +void close(int fd) +{ + uint16_t rv = 0x3E00; + + dprintf("close(%d)\n", fd); + + asm volatile("int $0x21" + : "+a" (rv) + : "b" (fd)); + + /* The only error MS-DOS returns for close is EBADF, + and we really don't care... */ +} + +ssize_t write_file(int fd, const void *buf, size_t count) +{ + uint16_t rv; + ssize_t done = 0; + uint8_t err; + + dprintf("write_file(%d,%p,%u)\n", fd, buf, count); + + while ( count ) { + rv = 0x4000; + asm volatile("int $0x21 ; setc %0" + : "=abcdm" (err), "+a" (rv) + : "b" (fd), "c" (count), "d" (buf)); + if ( err || rv == 0 ) + die("file write error"); + + done += rv; + count -= rv; + } + + return done; +} + +struct diskio { + uint32_t startsector; + uint16_t sectors; + uint16_t bufoffs, bufseg; +} __attribute__((packed)); + +void write_device(int drive, const void *buf, size_t nsecs, unsigned int sector) +{ + uint8_t err; + struct diskio dio; + + dprintf("write_device(%d,%p,%u,%u)\n", drive, buf, nsecs, sector); + + dio.startsector = sector; + dio.sectors = nsecs; + dio.bufoffs = (uintptr_t)buf; + asm("movw %%ds,%0" : "=m" (dio.bufseg)); + + asm volatile("int $0x26 ; setc %0 ; popfw" + : "=abcdm" (err) + : "a" (drive-1), "b" (&dio), "c" (-1), "d" (buf)); + + if ( err ) + die("sector write error"); +} + +void read_device(int drive, const void *buf, size_t nsecs, unsigned int sector) +{ + uint8_t err; + struct diskio dio; + + dprintf("read_device(%d,%p,%u,%u)\n", drive, buf, nsecs, sector); + + dio.startsector = sector; + dio.sectors = nsecs; + dio.bufoffs = (uintptr_t)buf; + asm("movw %%ds,%0" : "=m" (dio.bufseg)); + + asm volatile("int $0x25 ; setc %0 ; popfw" + : "=abcdm" (err) + : "a" (drive-1), "b" (&dio), "c" (-1), "d" (buf)); + + if ( err ) + die("sector read error"); +} + +/* Both traditional DOS and FAT32 DOS return this structure, but + FAT32 return a lot more data, so make sure we have plenty of space */ +struct deviceparams { + uint8_t specfunc; + uint8_t devtype; + uint16_t devattr; + uint16_t cylinders; + uint8_t mediatype; + uint16_t bytespersec; + uint8_t secperclust; + uint16_t ressectors; + uint8_t fats; + uint16_t rootdirents; + uint16_t sectors; + uint8_t media; + uint16_t fatsecs; + uint16_t secpertrack; + uint16_t heads; + uint32_t hiddensecs; + uint32_t hugesectors; + uint8_t lotsofpadding[224]; +} __attribute__((packed)); + +uint32_t get_partition_offset(int drive) +{ + uint8_t err; + uint16_t rv; + struct deviceparams dp; + + dp.specfunc = 1; /* Get current information */ + + rv = 0x440d; + asm volatile("int $0x21 ; setc %0" + : "=abcdm" (err), "+a" (rv) + : "b" (drive), "c" (0x0860), "d" (&dp)); + + if ( !err ) + return dp.hiddensecs; + + rv = 0x440d; + asm volatile("int $0x21 ; setc %0" + : "=abcdm" (err), "+a" (rv) + : "b" (drive), "c" (0x4860), "d" (&dp)); + + if ( !err ) + return dp.hiddensecs; + + die("could not find partition start offset"); +} + +struct rwblock { + uint8_t special; + uint16_t head; + uint16_t cylinder; + uint16_t firstsector; + uint16_t sectors; + uint16_t bufferoffset; + uint16_t bufferseg; +} __attribute__((packed)); + +static struct rwblock mbr = { + .special = 0, + .head = 0, + .cylinder = 0, + .firstsector = 0, /* MS-DOS, unlike the BIOS, zero-base sectors */ + .sectors = 1, + .bufferoffset = 0, + .bufferseg = 0 +}; + +void write_mbr(int drive, const void *buf) +{ + uint16_t rv; + uint8_t err; + + dprintf("write_mbr(%d,%p)\n", drive, buf); + + mbr.bufferoffset = (uintptr_t)buf; + asm("movw %%ds,%0" : "=m" (mbr.bufferseg)); + + rv = 0x440d; + asm volatile("int $0x21 ; setc %0" + : "=abcdm" (err), "+a" (rv) + : "c" (0x0841), "d" (&mbr), "b" (drive)); + + if ( !err ) + return; + + rv = 0x440d; + asm volatile("int $0x21 ; setc %0" + : "=abcdm" (err), "+a" (rv) + : "c" (0x4841), "d" (&mbr), "b" (drive)); + + if ( err ) + die("mbr write error"); +} + +void read_mbr(int drive, const void *buf) +{ + uint16_t rv; + uint8_t err; + + dprintf("read_mbr(%d,%p)\n", drive, buf); + + mbr.bufferoffset = (uintptr_t)buf; + asm("movw %%ds,%0" : "=m" (mbr.bufferseg)); + + rv = 0x440d; + asm volatile("int $0x21 ; setc %0" + : "=abcdm" (err), "+a" (rv) + : "c" (0x0861), "d" (&mbr), "b" (drive)); + + if ( !err ) + return; + + rv = 0x440d; + asm volatile("int $0x21 ; setc %0" + : "=abcdm" (err), "+a" (rv) + : "c" (0x4861), "d" (&mbr), "b" (drive)); + + if ( err ) + die("mbr read error"); +} + +/* This call can legitimately fail, and we don't care, so ignore error return */ +void set_attributes(const char *file, int attributes) +{ + uint16_t rv = 0x4301; + + dprintf("set_attributes(\"%s\", 0x%02x)\n", file, attributes); + + asm volatile("int $0x21" + : "+a" (rv) + : "c" (attributes), "d" (file)); +} + +/* + * Version of the read_device function suitable for libfat + */ +int libfat_xpread(intptr_t pp, void *buf, size_t secsize, libfat_sector_t sector) +{ + read_device(pp, buf, 1, sector); + return secsize; +} + +static inline void get_dos_version(void) +{ + uint16_t ver = 0x3001; + asm("int $0x21 ; xchgb %%ah,%%al" : "+a" (ver) : : "ebx", "ecx"); + dos_version = ver; + dprintf("DOS version %d.%d\n", (dos_version >> 8), dos_version & 0xff); +} + +/* The locking interface relies on static variables. A massive hack :( */ +static uint16_t lock_level; + +static inline void set_lock_device(uint8_t device) +{ + lock_level = device; +} + +void lock_device(int level) +{ + uint16_t rv; + uint8_t err; + uint16_t lock_call; + + if ( dos_version < 0x0700 ) + return; /* Win9x/NT only */ + +#if 0 + /* DOS 7.10 = Win95 OSR2 = first version with FAT32 */ + lock_call = (dos_version >= 0x0710) ? 0x484A : 0x084A; +#else + lock_call = 0x084A; /* MSDN says this is OK for all filesystems */ +#endif + + while ( (lock_level >> 8) < level ) { + uint16_t new_level = lock_level + 0x0100; + dprintf("Trying lock %04x...\n", new_level); + rv = 0x444d; + asm volatile("int $0x21 ; setc %0" + : "=abcdm" (err), "+a" (rv) + : "b" (new_level), "c" (lock_call), "d"(0x0001)); + if ( err ) { + /* rv == 0x0001 means this call is not supported, if so we + assume locking isn't needed (e.g. Win9x in DOS-only mode) */ + if ( rv == 0x0001 ) + return; + else + die("could not lock device"); + } + + lock_level = new_level; + } + return; +} + +void unlock_device(int level) +{ + uint16_t rv; + uint8_t err; + uint16_t unlock_call; + + if ( dos_version < 0x0700 ) + return; /* Win9x/NT only */ + +#if 0 + /* DOS 7.10 = Win95 OSR2 = first version with FAT32 */ + unlock_call = (dos_version >= 0x0710) ? 0x486A : 0x086A; +#else + unlock_call = 0x086A; /* MSDN says this is OK for all filesystems */ +#endif + + while ( (lock_level >> 8) > level ) { + uint16_t new_level = lock_level - 0x0100; + rv = 0x440d; + asm volatile("int $0x21 ; setc %0" + : "=abcdm" (err), "+a" (rv) + : "b" (new_level), "c" (unlock_call)); + lock_level = new_level; + } +} + + +/* + * This function does any desired MBR manipulation; called with the device lock held. + */ +struct mbr_entry { + uint8_t active; /* Active flag */ + uint8_t bhead; /* Begin head */ + uint8_t bsector; /* Begin sector */ + uint8_t bcylinder; /* Begin cylinder */ + uint8_t filesystem; /* Filesystem value */ + uint8_t ehead; /* End head */ + uint8_t esector; /* End sector */ + uint8_t ecylinder; /* End cylinder */ + uint32_t startlba; /* Start sector LBA */ + uint32_t sectors; /* Length in sectors */ +} __attribute__((packed)); + +static void adjust_mbr(int device, int writembr, int set_active) +{ + static unsigned char sectbuf[512]; + int i; + + if ( !writembr && !set_active ) + return; /* Nothing to do */ + + read_mbr(device, sectbuf); + + if ( writembr ) { + memcpy(sectbuf, syslinux_mbr, syslinux_mbr_len); + *(uint16_t *)(sectbuf+510) = 0xaa55; + } + + if ( set_active ) { + uint32_t offset = get_partition_offset(device); + struct mbr_entry *me = (struct mbr_entry *)(sectbuf+446); + int found = 0; + + for ( i = 0 ; i < 4 ; i++ ) { + if ( me->startlba == offset ) { + me->active = 0x80; + found++; + } else { + me->active = 0; + } + me++; + } + + if ( found < 1 ) { + die("partition not found"); + } else if ( found > 1 ) { + die("multiple aliased partitions found"); + } + } + + write_mbr(device, sectbuf); +} + +int main(int argc, char *argv[]) +{ + static unsigned char sectbuf[512]; + int dev_fd, fd; + static char ldlinux_name[] = "@:\\LDLINUX.SYS"; + char **argp, *opt; + int force = 0; /* -f (force) option */ + struct libfat_filesystem *fs; + libfat_sector_t s, *secp, sectors[65]; /* 65 is maximum possible */ + int32_t ldlinux_cluster; + int nsectors; + const char *device = NULL, *bootsecfile = NULL; + const char *errmsg; + int i; + int writembr = 0; /* -m (write MBR) option */ + int set_active = 0; /* -a (set partition active) option */ + + dprintf("argv = %p\n", argv); + for ( i = 0 ; i <= argc ; i++ ) + dprintf("argv[%d] = %p = \"%s\"\n", i, argv[i], argv[i]); + + (void)argc; /* Unused */ + + get_dos_version(); + + for ( argp = argv+1 ; *argp ; argp++ ) { + if ( **argp == '-' ) { + opt = *argp + 1; + if ( !*opt ) + usage(); + + while ( *opt ) { + switch ( *opt ) { + case 's': /* Use "safe, slow and stupid" code */ + syslinux_make_stupid(); + break; + case 'f': /* Force install */ + force = 1; + break; + case 'm': /* Write MBR */ + writembr = 1; + break; + case 'a': /* Set partition active */ + set_active = 1; + break; + default: + usage(); + } + opt++; + } + } else { + if ( bootsecfile ) + usage(); + else if ( device ) + bootsecfile = *argp; + else + device = *argp; + } + } + + if ( !device ) + usage(); + + /* + * Figure out which drive we're talking to + */ + dev_fd = (device[0] & ~0x20) - 0x40; + if ( dev_fd < 1 || dev_fd > 26 || device[1] != ':' || device[2] ) + usage(); + + set_lock_device(dev_fd); + + lock_device(2); /* Make sure we can lock the device */ + read_device(dev_fd, sectbuf, 1, 0); + unlock_device(1); + + /* + * Check to see that what we got was indeed an MS-DOS boot sector/superblock + */ + if( (errmsg = syslinux_check_bootsect(sectbuf)) ) { + unlock_device(0); + puts(errmsg); + putchar('\n'); + exit(1); + } + + ldlinux_name[0] = dev_fd | 0x40; + + set_attributes(ldlinux_name, 0); + fd = creat(ldlinux_name, 0x07); /* SYSTEM HIDDEN READONLY */ + write_file(fd, syslinux_ldlinux, syslinux_ldlinux_len); + close(fd); + + /* + * Now, use libfat to create a block map. This probably + * should be changed to use ioctl(...,FIBMAP,...) since + * this is supposed to be a simple, privileged version + * of the installer. + */ + lock_device(2); + fs = libfat_open(libfat_xpread, dev_fd); + ldlinux_cluster = libfat_searchdir(fs, 0, "LDLINUX SYS", NULL); + secp = sectors; + nsectors = 0; + s = libfat_clustertosector(fs, ldlinux_cluster); + while ( s && nsectors < 65 ) { + *secp++ = s; + nsectors++; + s = libfat_nextsector(fs, s); + } + libfat_close(fs); + + /* + * Patch ldlinux.sys and the boot sector + */ + syslinux_patch(sectors, nsectors); + + /* + * Write the now-patched first sector of ldlinux.sys + */ + lock_device(3); + write_device(dev_fd, syslinux_ldlinux, 1, sectors[0]); + + /* + * Muck with the MBR, if desired, while we hold the lock + */ + adjust_mbr(dev_fd, writembr, set_active); + + /* + * To finish up, write the boot sector + */ + + /* Read the superblock again since it might have changed while mounted */ + read_device(dev_fd, sectbuf, 1, 0); + + /* Copy the syslinux code into the boot sector */ + syslinux_make_bootsect(sectbuf); + + /* Write new boot sector */ + if ( bootsecfile ) { + unlock_device(0); + fd = creat(bootsecfile, 0x20); /* ARCHIVE */ + write_file(fd, sectbuf, 512); + close(fd); + } else { + write_device(dev_fd, sectbuf, 1, 0); + unlock_device(0); + } + + /* Done! */ + + return 0; +} + diff --git a/syslinux/dos/syslinux.com b/syslinux/dos/syslinux.com new file mode 100755 index 0000000000000000000000000000000000000000..bc45134704e5a02e1af5dd99a564cad321c61ea9 GIT binary patch literal 16620 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 literal 0 HcmV?d00001 diff --git a/syslinux/ext2_fs.inc b/syslinux/ext2_fs.inc new file mode 100644 index 0000000..0813e6b --- /dev/null +++ b/syslinux/ext2_fs.inc @@ -0,0 +1,163 @@ +; $Id: ext2_fs.inc,v 1.3 2005/01/06 22:34:06 hpa Exp $ +; ----------------------------------------------------------------------- +; +; Copyright 1998-1999 H. Peter Anvin - All Rights Reserved +; +; This program is free software; you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139, +; USA; either version 2 of the License, or (at your option) any later +; version; incorporated herein by reference. +; +; ----------------------------------------------------------------------- + +; +; ext2_fs.inc +; +; NASM include file for ext2fs data structures +; + +%define EXT2_SUPER_MAGIC 0xEF53 + +%define EXT2_GOOD_OLD_REV 0 ; The good old (original) format +%define EXT2_DYNAMIC_REV 1 ; V2 format w/ dynamic inode sizes +%define EXT2_GOOD_OLD_INODE_SIZE 128 + +; Special inode numbers +%define EXT2_BAD_INO 1 ; Bad blocks inode +%define EXT2_ROOT_INO 2 ; Root inode +%define EXT2_BOOT_LOADER_INO 5 ; Boot loader inode +%define EXT2_UNDEL_DIR_INO 6 ; Undelete directory inode +%define EXT3_RESIZE_INO 7 ; Reserved group descriptors inode +%define EXT3_JOURNAL_INO 8 ; Journal inode + +; We're readonly, so we only care about incompat features. +%define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001 +%define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002 +%define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 +%define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 +%define EXT2_FEATURE_INCOMPAT_META_BG 0x0010 +%define EXT2_FEATURE_INCOMPAT_ANY 0xffffffff + +%define EXT2_NDIR_BLOCKS 12 +%define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS +%define EXT2_DIND_BLOCK (EXT2_IND_BLOCK+1) +%define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK+1) +%define EXT2_N_BLOCKS (EXT2_TIND_BLOCK+1) + +; +; Structure definition for the ext2 superblock +; + struc ext2_super_block +s_inodes_count resd 1 ; Inodes count +s_blocks_count resd 1 ; Blocks count +s_r_blocks_count resd 1 ; Reserved blocks count +s_free_blocks_count resd 1 ; Free blocks count +s_free_inodes_count resd 1 ; Free inodes count +s_first_data_block resd 1 ; First Data Block +s_log_block_size resd 1 ; Block size +s_log_frag_size resd 1 ; Fragment size +s_blocks_per_group resd 1 ; # Blocks per group +s_frags_per_group resd 1 ; # Fragments per group +s_inodes_per_group resd 1 ; # Inodes per group +s_mtime resd 1 ; Mount time +s_wtime resd 1 ; Write time +s_mnt_count resw 1 ; Mount count +s_max_mnt_count resw 1 ; Maximal mount count +s_magic resw 1 ; Magic signature +s_state resw 1 ; File system state +s_errors resw 1 ; Behaviour when detecting errors +s_minor_rev_level resw 1 ; minor revision level +s_lastcheck resd 1 ; time of last check +s_checkinterval resd 1 ; max. time between checks +s_creator_os resd 1 ; OS +s_rev_level resd 1 ; Revision level +s_def_resuid resw 1 ; Default uid for reserved blocks +s_def_resgid resw 1 ; Default gid for reserved blocks +s_first_ino resd 1 ; First non-reserved inode +s_inode_size resw 1 ; size of inode structure +s_block_group_nr resw 1 ; block group # of this superblock +s_feature_compat resd 1 ; compatible feature set +s_feature_incompat resd 1 ; incompatible feature set +s_feature_ro_compat resd 1 ; readonly-compatible feature set +s_uuid resb 16 ; 128-bit uuid for volume +s_volume_name resb 16 ; volume name +s_last_mounted resb 64 ; directory where last mounted +s_algorithm_usage_bitmap resd 1 ; For compression +s_prealloc_blocks resb 1 ; Nr of blocks to try to preallocate +s_prealloc_dir_blocks resb 1 ; Nr to preallocate for dirs +s_padding1 resw 1 +s_reserved resd 204 ; Padding to the end of the block + endstruc + +%ifndef DEPEND +%if ext2_super_block_size != 1024 +%error "ext2_super_block definition bogus" +%endif +%endif + +; +; Structure definition for the ext2 inode +; + struc ext2_inode +i_mode resw 1 ; File mode +i_uid resw 1 ; Owner Uid +i_size resd 1 ; Size in bytes +i_atime resd 1 ; Access time +i_ctime resd 1 ; Creation time +i_mtime resd 1 ; Modification time +i_dtime resd 1 ; Deletion Time +i_gid resw 1 ; Group Id +i_links_count resw 1 ; Links count +i_blocks resd 1 ; Blocks count +i_flags resd 1 ; File flags +l_i_reserved1 resd 1 +i_block resd EXT2_N_BLOCKS ; Pointer to blocks +i_version resd 1 ; File version (for NFS) +i_file_acl resd 1 ; File ACL +i_dir_acl resd 1 ; Directory ACL +i_faddr resd 1 ; Fragment address +l_i_frag resb 1 ; Fragment number +l_i_fsize resb 1 ; Fragment size +i_pad1 resw 1 +l_i_reserved2 resd 2 + endstruc + +%ifndef DEPEND +%if ext2_inode_size != 128 +%error "ext2_inode definition bogus" +%endif +%endif + +; +; Structure definition for ext2 block group descriptor +; + struc ext2_group_desc +bg_block_bitmap resd 1 ; Block bitmap block +bg_inode_bitmap resd 1 ; Inode bitmap block +bg_inode_table resd 1 ; Inode table block +bg_free_blocks_count resw 1 ; Free blocks count +bg_free_inodes_count resw 1 ; Free inodes count +bg_used_dirs_count resw 1 ; Used inodes count +bg_pad resw 1 +bg_reserved resd 3 + endstruc + +%ifndef DEPEND +%if ext2_group_desc_size != 32 +%error "ext2_group_desc definition bogus" +%endif +%endif + +%define ext2_group_desc_lg2size 5 + +; +; Structure definition for ext2 directory entry +; + struc ext2_dir_entry +d_inode resd 1 ; Inode number +d_rec_len resw 1 ; Directory entry length +d_name_len resb 1 ; Name length +d_file_type resb 1 ; File type +d_name equ $ + endstruc diff --git a/syslinux/extlinux.asm b/syslinux/extlinux.asm new file mode 100644 index 0000000..be8363e --- /dev/null +++ b/syslinux/extlinux.asm @@ -0,0 +1,1500 @@ +; -*- fundamental -*- (asm-mode sucks) +; $Id: extlinux.asm,v 1.21 2005/04/03 00:00:36 hpa Exp $ +; **************************************************************************** +; +; extlinux.asm +; +; A program to boot Linux kernels off an ext2/ext3 filesystem. +; +; Copyright (C) 1994-2005 H. Peter Anvin +; +; This program is free software; you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +; Boston MA 02111-1307, USA; either version 2 of the License, or +; (at your option) any later version; incorporated herein by reference. +; +; **************************************************************************** + +%define IS_EXTLINUX 1 +%include "macros.inc" +%include "config.inc" +%include "kernel.inc" +%include "bios.inc" +%include "tracers.inc" +%include "layout.inc" + +%include "ext2_fs.inc" + +; +; Some semi-configurable constants... change on your own risk. +; +my_id equ extlinux_id +; NASM 0.98.38 croaks if these are equ's rather than macros... +FILENAME_MAX_LG2 equ 8 ; log2(Max filename size Including final null) +FILENAME_MAX equ (1 << FILENAME_MAX_LG2) ; Max mangled filename size +NULLFILE equ 0 ; Null character == empty filename +NULLOFFSET equ 0 ; Position in which to look +retry_count equ 6 ; How patient are we with the disk? +%assign HIGHMEM_SLOP 0 ; Avoid this much memory near the top +LDLINUX_MAGIC equ 0x3eb202fe ; A random number to identify ourselves with + +MAX_OPEN_LG2 equ 6 ; log2(Max number of open files) +MAX_OPEN equ (1 << MAX_OPEN_LG2) + +SECTOR_SHIFT equ 9 +SECTOR_SIZE equ (1 << SECTOR_SHIFT) + +; +; This is what we need to do when idle +; +%macro RESET_IDLE 0 + ; Nothing +%endmacro +%macro DO_IDLE 0 + ; Nothing +%endmacro + +; +; The following structure is used for "virtual kernels"; i.e. LILO-style +; option labels. The options we permit here are `kernel' and `append +; Since there is no room in the bottom 64K for all of these, we +; stick them at vk_seg:0000 and copy them down before we need them. +; + struc vkernel +vk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!** +vk_rname: resb FILENAME_MAX ; Real name +vk_appendlen: resw 1 + alignb 4 +vk_append: resb max_cmd_len+1 ; Command line + alignb 4 +vk_end: equ $ ; Should be <= vk_size + endstruc + +; +; Segment assignments in the bottom 640K +; Stick to the low 512K in case we're using something like M-systems flash +; which load a driver into low RAM (evil!!) +; +; 0000h - main code/data segment (and BIOS segment) +; +real_mode_seg equ 4000h +cache_seg equ 3000h ; 64K area for metadata cache +vk_seg equ 2000h ; Virtual kernels +xfer_buf_seg equ 1000h ; Bounce buffer for I/O to high mem +comboot_seg equ real_mode_seg ; COMBOOT image loading zone + +; +; File structure. This holds the information for each currently open file. +; + struc open_file_t +file_left resd 1 ; Number of sectors left (0 = free) +file_sector resd 1 ; Next linear sector to read +file_in_sec resd 1 ; Sector where inode lives +file_in_off resw 1 +file_mode resw 1 + endstruc + +%ifndef DEPEND +%if (open_file_t_size & (open_file_t_size-1)) +%error "open_file_t is not a power of 2" +%endif +%endif + +; --------------------------------------------------------------------------- +; BEGIN CODE +; --------------------------------------------------------------------------- + +; +; Memory below this point is reserved for the BIOS and the MBR +; + section .earlybss +trackbufsize equ 8192 +trackbuf resb trackbufsize ; Track buffer goes here +getcbuf resb trackbufsize + ; ends at 4800h + + section .bss +SuperBlock resb 1024 ; ext2 superblock +SuperInfo resq 16 ; DOS superblock expanded +ClustSize resd 1 ; Bytes/cluster ("block") +SecPerClust resd 1 ; Sectors/cluster +ClustMask resd 1 ; Sectors/cluster - 1 +PtrsPerBlock1 resd 1 ; Pointers/cluster +PtrsPerBlock2 resd 1 ; (Pointers/cluster)^2 +DriveNumber resb 1 ; BIOS drive number +ClustShift resb 1 ; Shift count for sectors/cluster +ClustByteShift resb 1 ; Shift count for bytes/cluster + + alignb open_file_t_size +Files resb MAX_OPEN*open_file_t_size + +; +; Constants for the xfer_buf_seg +; +; The xfer_buf_seg is also used to store message file buffers. We +; need two trackbuffers (text and graphics), plus a work buffer +; for the graphics decompressor. +; +xbs_textbuf equ 0 ; Also hard-coded, do not change +xbs_vgabuf equ trackbufsize +xbs_vgatmpbuf equ 2*trackbufsize + + + section .text +; +; Some of the things that have to be saved very early are saved +; "close" to the initial stack pointer offset, in order to +; reduce the code size... +; +StackBuf equ $-44-32 ; Start the stack here (grow down - 4K) +PartInfo equ StackBuf ; Saved partition table entry +FloppyTable equ PartInfo+16 ; Floppy info table (must follow PartInfo) +OrigFDCTabPtr equ StackBuf-4 ; The high dword on the stack + +; +; Primary entry point. Tempting as though it may be, we can't put the +; initial "cli" here; the jmp opcode in the first byte is part of the +; "magic number" (using the term very loosely) for the DOS superblock. +; +bootsec equ $ + jmp short start ; 2 bytes + nop ; 1 byte +; +; "Superblock" follows -- it's in the boot sector, so it's already +; loaded and ready for us +; +bsOemName db 'EXTLINUX' ; The SYS command sets this, so... +; +; These are the fields we actually care about. We end up expanding them +; all to dword size early in the code, so generate labels for both +; the expanded and unexpanded versions. +; +%macro superb 1 +bx %+ %1 equ SuperInfo+($-superblock)*8+4 +bs %+ %1 equ $ + zb 1 +%endmacro +%macro superw 1 +bx %+ %1 equ SuperInfo+($-superblock)*8 +bs %+ %1 equ $ + zw 1 +%endmacro +%macro superd 1 +bx %+ %1 equ $ ; no expansion for dwords +bs %+ %1 equ $ + zd 1 +%endmacro +superblock equ $ + superw BytesPerSec + superb SecPerClust + superw ResSectors + superb FATs + superw RootDirEnts + superw Sectors + superb Media + superw FATsecs + superw SecPerTrack + superw Heads +superinfo_size equ ($-superblock)-1 ; How much to expand + superd Hidden + superd HugeSectors + ; + ; This is as far as FAT12/16 and FAT32 are consistent + ; + zb 54 ; FAT12/16 need 26 more bytes, + ; FAT32 need 54 more bytes +superblock_len equ $-superblock + +; +; Note we don't check the constraints above now; we did that at install +; time (we hope!) +; +start: + cli ; No interrupts yet, please + cld ; Copy upwards +; +; Set up the stack +; + xor ax,ax + mov ss,ax + mov sp,StackBuf ; Just below BSS + mov es,ax +; +; DS:SI may contain a partition table entry. Preserve it for us. +; + mov cx,8 ; Save partition info + mov di,sp + rep movsw + + mov ds,ax ; Now we can initialize DS... + +; +; Now sautee the BIOS floppy info block to that it will support decent- +; size transfers; the floppy block is 11 bytes and is stored in the +; INT 1Eh vector (brilliant waste of resources, eh?) +; +; Of course, if BIOSes had been properly programmed, we wouldn't have +; had to waste precious space with this code. +; + mov bx,fdctab + lfs si,[bx] ; FS:SI -> original fdctab + push fs ; Save on stack in case we need to bail + push si + + ; Save the old fdctab even if hard disk so the stack layout + ; is the same. The instructions above do not change the flags + mov [DriveNumber],dl ; Save drive number in DL + and dl,dl ; If floppy disk (00-7F), assume no + ; partition table + js harddisk + +floppy: + mov cl,6 ; 12 bytes (CX == 0) + ; es:di -> FloppyTable already + ; This should be safe to do now, interrupts are off... + mov [bx],di ; FloppyTable + mov [bx+2],ax ; Segment 0 + fs rep movsw ; Faster to move words + mov cl,[bsSecPerTrack] ; Patch the sector count + mov [di-8],cl + ; AX == 0 here + int 13h ; Some BIOSes need this + + jmp short not_harddisk +; +; The drive number and possibly partition information was passed to us +; by the BIOS or previous boot loader (MBR). Current "best practice" is to +; trust that rather than what the superblock contains. +; +; Would it be better to zero out bsHidden if we don't have a partition table? +; +; Note: di points to beyond the end of PartInfo +; +harddisk: + test byte [di-16],7Fh ; Sanity check: "active flag" should + jnz no_partition ; be 00 or 80 + mov eax,[di-8] ; Partition offset (dword) + mov [bsHidden],eax +no_partition: +; +; Get disk drive parameters (don't trust the superblock.) Don't do this for +; floppy drives -- INT 13:08 on floppy drives will (may?) return info about +; what the *drive* supports, not about the *media*. Fortunately floppy disks +; tend to have a fixed, well-defined geometry which is stored in the superblock. +; + ; DL == drive # still + mov ah,08h + int 13h + jc no_driveparm + and ah,ah + jnz no_driveparm + shr dx,8 + inc dx ; Contains # of heads - 1 + mov [bsHeads],dx + and cx,3fh + mov [bsSecPerTrack],cx +no_driveparm: +not_harddisk: +; +; Ready to enable interrupts, captain +; + sti + + +; +; Do we have EBIOS (EDD)? +; +eddcheck: + mov bx,55AAh + mov ah,41h ; EDD existence query + mov dl,[DriveNumber] + int 13h + jc .noedd + cmp bx,0AA55h + jne .noedd + test cl,1 ; Extended disk access functionality set + jz .noedd + ; + ; We have EDD support... + ; + mov byte [getlinsec.jmp+1],getlinsec_ebios-(getlinsec.jmp+2) +.noedd: + +; +; Load the first sector of LDLINUX.SYS; this used to be all proper +; with parsing the superblock and root directory; it doesn't fit +; together with EBIOS support, unfortunately. +; + mov eax,[FirstSector] ; Sector start + mov bx,ldlinux_sys ; Where to load it + call getonesec + + ; Some modicum of integrity checking + cmp dword [ldlinux_magic],LDLINUX_MAGIC + jne kaboom + cmp dword [ldlinux_magic+4],HEXDATE + jne kaboom + + ; Go for it... + jmp ldlinux_ent + +; +; kaboom: write a message and bail out. +; +kaboom: + xor si,si + mov ss,si + mov sp,StackBuf-4 ; Reset stack + mov ds,si ; Reset data segment + pop dword [fdctab] ; Restore FDC table +.patch: mov si,bailmsg + call writestr ; Returns with AL = 0 + cbw ; AH <- 0 + int 16h ; Wait for keypress + int 19h ; And try once more to boot... +.norge: jmp short .norge ; If int 19h returned; this is the end + +; +; +; writestr: write a null-terminated string to the console +; This assumes we're on page 0. This is only used for early +; messages, so it should be OK. +; +writestr: +.loop: lodsb + and al,al + jz .return + mov ah,0Eh ; Write to screen as TTY + mov bx,0007h ; Attribute + int 10h + jmp short .loop +.return: ret + +; +; xint13: wrapper for int 13h which will retry 6 times and then die, +; AND save all registers except BP +; +xint13: +.again: + mov bp,retry_count +.loop: pushad + int 13h + popad + jnc writestr.return + dec bp + jnz .loop +.disk_error: + jmp strict near kaboom ; Patched + + +; +; getonesec: get one disk sector +; +getonesec: + mov bp,1 ; One sector + ; Fall through + +; +; getlinsec: load a sequence of BP floppy sector given by the linear sector +; number in EAX into the buffer at ES:BX. We try to optimize +; by loading up to a whole track at a time, but the user +; is responsible for not crossing a 64K boundary. +; (Yes, BP is weird for a count, but it was available...) +; +; On return, BX points to the first byte after the transferred +; block. +; +; This routine assumes CS == DS, and trashes most registers. +; +; Stylistic note: use "xchg" instead of "mov" when the source is a register +; that is dead from that point; this saves space. However, please keep +; the order to dst,src to keep things sane. +; +getlinsec: + add eax,[bsHidden] ; Add partition offset +.jmp: jmp strict short getlinsec_cbios ; This is patched + +; +; getlinsec_ebios: +; +; getlinsec implementation for EBIOS (EDD) +; +getlinsec_ebios: + mov si,dapa ; Load up the DAPA + mov [si+4],bx + mov [si+6],es + mov [si+8],eax +.loop: + push bp ; Sectors left + call maxtrans ; Enforce maximum transfer size +.bp_ok: + mov [si+2],bp + mov dl,[DriveNumber] + mov ah,42h ; Extended Read + call xint13 + pop bp + movzx eax,word [si+2] ; Sectors we read + add [si+8],eax ; Advance sector pointer + sub bp,ax ; Sectors left + shl ax,9 ; 512-byte sectors + add [si+4],ax ; Advance buffer pointer + and bp,bp + jnz .loop + mov eax,[si+8] ; Next sector + mov bx,[si+4] ; Buffer pointer + ret + +; +; getlinsec_cbios: +; +; getlinsec implementation for legacy CBIOS +; +getlinsec_cbios: +.loop: + push eax + push bp + push bx + + movzx esi,word [bsSecPerTrack] + movzx edi,word [bsHeads] + ; + ; Dividing by sectors to get (track,sector): we may have + ; up to 2^18 tracks, so we need to use 32-bit arithmetric. + ; + xor edx,edx ; Zero-extend LBA to 64 bits + div esi + xor cx,cx + xchg cx,dx ; CX <- sector index (0-based) + ; EDX <- 0 + ; eax = track # + div edi ; Convert track to head/cyl + ; + ; Now we have AX = cyl, DX = head, CX = sector (0-based), + ; BP = sectors to transfer, SI = bsSecPerTrack, + ; ES:BX = data target + ; + + call maxtrans ; Enforce maximum transfer size + + ; Must not cross track boundaries, so BP <= SI-CX + sub si,cx + cmp bp,si + jna .bp_ok + mov bp,si +.bp_ok: + + shl ah,6 ; Because IBM was STOOPID + ; and thought 8 bits were enough + ; then thought 10 bits were enough... + inc cx ; Sector numbers are 1-based, sigh + or cl,ah + mov ch,al + mov dh,dl + mov dl,[DriveNumber] + xchg ax,bp ; Sector to transfer count + mov ah,02h ; Read sectors + call xint13 + movzx ecx,al + shl ax,9 ; Convert sectors in AL to bytes in AX + pop bx + add bx,ax + pop bp + pop eax + add eax,ecx + sub bp,cx + jnz .loop + ret + +; +; Truncate BP to MaxTransfer +; +maxtrans: + cmp bp,[MaxTransfer] + jna .ok + mov bp,[MaxTransfer] +.ok: ret + +; +; Error message on failure +; +bailmsg: db 'Boot failed', 0Dh, 0Ah, 0 + +; +; EBIOS disk address packet +; + align 4, db 0 +dapa: + dw 16 ; Packet size +.count: dw 0 ; Block count +.off: dw 0 ; Offset of buffer +.seg: dw 0 ; Segment of buffer +.lba: dd 0 ; LBA (LSW) + dd 0 ; LBA (MSW) + + +%if 1 +bs_checkpt_off equ ($-$$) +%ifndef DEPEND +%if bs_checkpt_off > 1F8h +%error "Boot sector overflow" +%endif +%endif + + zb 1F8h-($-$$) +%endif +FirstSector dd 0xDEADBEEF ; Location of sector 1 +MaxTransfer dw 0x007F ; Max transfer size +bootsignature dw 0AA55h + +; +; =========================================================================== +; End of boot sector +; =========================================================================== +; Start of LDLINUX.SYS +; =========================================================================== + +ldlinux_sys: + +syslinux_banner db 0Dh, 0Ah + db 'EXTLINUX ' + db version_str, ' ', date, ' ', 0 + db 0Dh, 0Ah, 1Ah ; EOF if we "type" this in DOS + + align 8, db 0 +ldlinux_magic dd LDLINUX_MAGIC + dd HEXDATE + +; +; This area is patched by the installer. It is found by looking for +; LDLINUX_MAGIC, plus 8 bytes. +; +patch_area: +LDLDwords dw 0 ; Total dwords starting at ldlinux_sys +LDLSectors dw 0 ; Number of sectors - (bootsec+this sec) +CheckSum dd 0 ; Checksum starting at ldlinux_sys + ; value = LDLINUX_MAGIC - [sum of dwords] +CurrentDir dd 2 ; "Current" directory inode number + +; Space for up to 64 sectors, the theoretical maximum +SectorPtrs times 64 dd 0 + +ldlinux_ent: +; +; Note that some BIOSes are buggy and run the boot sector at 07C0:0000 +; instead of 0000:7C00 and the like. We don't want to add anything +; more to the boot sector, so it is written to not assume a fixed +; value in CS, but we don't want to deal with that anymore from now +; on. +; + jmp 0:.next +.next: + +; +; Tell the user we got this far +; + mov si,syslinux_banner + call writestr + +; +; Patch disk error handling +; + mov word [xint13.disk_error+1],do_disk_error-(xint13.disk_error+3) + +; +; Now we read the rest of LDLINUX.SYS. Don't bother loading the first +; sector again, though. +; +load_rest: + mov si,SectorPtrs + mov bx,7C00h+2*SECTOR_SIZE ; Where we start loading + mov cx,[LDLSectors] + +.get_chunk: + jcxz .done + xor bp,bp + lodsd ; First sector of this chunk + + mov edx,eax + +.make_chunk: + inc bp + dec cx + jz .chunk_ready + inc edx ; Next linear sector + cmp [esi],edx ; Does it match + jnz .chunk_ready ; If not, this is it + add esi,4 ; If so, add sector to chunk + jmp short .make_chunk + +.chunk_ready: + call getlinsecsr + shl bp,SECTOR_SHIFT + add bx,bp + jmp .get_chunk + +.done: + +; +; All loaded up, verify that we got what we needed. +; Note: the checksum field is embedded in the checksum region, so +; by the time we get to the end it should all cancel out. +; +verify_checksum: + mov si,ldlinux_sys + mov cx,[LDLDwords] + mov edx,-LDLINUX_MAGIC +.checksum: + lodsd + add edx,eax + loop .checksum + + and edx,edx ; Should be zero + jz all_read ; We're cool, go for it! + +; +; Uh-oh, something went bad... +; + mov si,checksumerr_msg + call writestr + jmp kaboom + +; +; ----------------------------------------------------------------------------- +; Subroutines that have to be in the first sector +; ----------------------------------------------------------------------------- + +; +; getlinsecsr: save registers, call getlinsec, restore registers +; +getlinsecsr: pushad + call getlinsec + popad + ret + +; +; This routine captures disk errors, and tries to decide if it is +; time to reduce the transfer size. +; +do_disk_error: + cmp ah,42h + je .ebios + shr al,1 ; Try reducing the transfer size + mov [MaxTransfer],al + jz kaboom ; If we can't, we're dead... + jmp xint13 ; Try again +.ebios: + push ax + mov ax,[si+2] + shr ax,1 + mov [MaxTransfer],ax + mov [si+2],ax + pop ax + jmp xint13 + +; +; Checksum error message +; +checksumerr_msg db 'Load error - ', 0 ; Boot failed appended + +; +; Debug routine +; +%ifdef debug +safedumpregs: + cmp word [Debug_Magic],0D00Dh + jnz nc_return + jmp dumpregs +%endif + +rl_checkpt equ $ ; Must be <= 8000h + +rl_checkpt_off equ ($-$$) +%if 0 ; ndef DEPEND +%if rl_checkpt_off > 400h +%error "Sector 1 overflow" +%endif +%endif + +; ---------------------------------------------------------------------------- +; End of code and data that have to be in the first sector +; ---------------------------------------------------------------------------- + +all_read: +; +; Let the user (and programmer!) know we got this far. This used to be +; in Sector 1, but makes a lot more sense here. +; + mov si,copyright_str + call writestr + +; +; Insane hack to expand the DOS superblock to dwords +; +expand_super: + xor eax,eax + mov si,superblock + mov di,SuperInfo + mov cx,superinfo_size +.loop: + lodsw + dec si + stosd ; Store expanded word + xor ah,ah + stosd ; Store expanded byte + loop .loop + +; +; Load the real (ext2) superblock; 1024 bytes long at offset 1024 +; + mov bx,SuperBlock + mov eax,1024 >> SECTOR_SHIFT + mov bp,ax + call getlinsec + +; +; Compute some values... +; + xor edx,edx + inc edx + + ; s_log_block_size = log2(blocksize) - 10 + mov cl,[SuperBlock+s_log_block_size] + add cl,10 + mov [ClustByteShift],cl + mov eax,edx + shl eax,cl + mov [ClustSize],eax + + sub cl,SECTOR_SHIFT + mov [ClustShift],cl + shr eax,SECTOR_SHIFT + mov [SecPerClust],eax + dec eax + mov [ClustMask],eax + + add cl,SECTOR_SHIFT-2 ; 4 bytes/pointer + shl edx,cl + mov [PtrsPerBlock1],edx + shl edx,cl + mov [PtrsPerBlock2],edx + +; +; Common initialization code +; +%include "init.inc" +%include "cpuinit.inc" + +; +; Initialize the metadata cache +; + call initcache + +; +; Now, everything is "up and running"... patch kaboom for more +; verbosity and using the full screen system +; + ; E9 = JMP NEAR + mov dword [kaboom.patch],0e9h+((kaboom2-(kaboom.patch+3)) << 8) + +; +; Now we're all set to start with our *real* business. First load the +; configuration file (if any) and parse it. +; +; In previous versions I avoided using 32-bit registers because of a +; rumour some BIOSes clobbered the upper half of 32-bit registers at +; random. I figure, though, that if there are any of those still left +; they probably won't be trying to install Linux on them... +; +; The code is still ripe with 16-bitisms, though. Not worth the hassle +; to take'm out. In fact, we may want to put them back if we're going +; to boot ELKS at some point. +; + +; +; Load configuration file +; +load_config: + mov di,ConfigName + call open + jz no_config_file + +; +; Now we have the config file open. Parse the config file and +; run the user interface. +; +%include "ui.inc" + +; +; Linux kernel loading code is common. +; +%include "runkernel.inc" + +; +; COMBOOT-loading code +; +%include "comboot.inc" +%include "com32.inc" +%include "cmdline.inc" + +; +; Boot sector loading code +; +%include "bootsect.inc" + + +; +; getlinsec_ext: same as getlinsec, except load any sector from the zero +; block as all zeros; use to load any data derived +; from an ext2 block pointer, i.e. anything *except the +; superblock.* +; +getonesec_ext: + mov bp,1 + +getlinsec_ext: + cmp eax,[SecPerClust] + jae getlinsec ; Nothing fancy + + ; If we get here, at least part of what we want is in the + ; zero block. Zero one sector at a time and loop. + push eax + push cx + xchg di,bx + xor eax,eax + mov cx,SECTOR_SIZE >> 2 + rep stosd + xchg di,bx + pop cx + pop eax + inc eax + dec bp + jnz getlinsec_ext + ret + +; +; abort_check: let the user abort with <ESC> or <Ctrl-C> +; +abort_check: + call pollchar + jz ac_ret1 + pusha + call getchar + cmp al,27 ; <ESC> + je ac_kill + cmp al,3 ; <Ctrl-C> + jne ac_ret2 +ac_kill: mov si,aborted_msg + +; +; abort_load: Called by various routines which wants to print a fatal +; error message and return to the command prompt. Since this +; may happen at just about any stage of the boot process, assume +; our state is messed up, and just reset the segment registers +; and the stack forcibly. +; +; SI = offset (in _text) of error message to print +; +abort_load: + mov ax,cs ; Restore CS = DS = ES + mov ds,ax + mov es,ax + cli + mov sp,StackBuf-2*3 ; Reset stack + mov ss,ax ; Just in case... + sti + call cwritestr ; Expects SI -> error msg +al_ok: jmp enter_command ; Return to command prompt +; +; End of abort_check +; +ac_ret2: popa +ac_ret1: ret + +; +; allocate_file: Allocate a file structure +; +; If successful: +; ZF set +; BX = file pointer +; In unsuccessful: +; ZF clear +; +allocate_file: + TRACER 'a' + push cx + mov bx,Files + mov cx,MAX_OPEN +.check: cmp dword [bx], byte 0 + je .found + add bx,open_file_t_size ; ZF = 0 + loop .check + ; ZF = 0 if we fell out of the loop +.found: pop cx + ret +; +; open_inode: +; Open a file indicated by an inode number in EAX +; +; NOTE: This file considers finding a zero-length file an +; error. This is so we don't have to deal with that special +; case elsewhere in the program (most loops have the test +; at the end). +; +; If successful: +; ZF clear +; SI = file pointer +; DX:AX = EAX = file length in bytes +; If unsuccessful +; ZF set +; +open_inode.allocate_failure: + xor eax,eax + ret + +open_inode: + call allocate_file + jnz .allocate_failure + + push gs + ; First, get the appropriate inode group and index + dec eax ; There is no inode 0 + xor edx,edx + mov [bx+file_sector],edx + div dword [SuperBlock+s_inodes_per_group] + ; EAX = inode group; EDX = inode within group + push edx + + ; Now, we need the block group descriptor. + ; To get that, we first need the relevant descriptor block. + + shl eax, ext2_group_desc_lg2size ; Get byte offset in desc table + xor edx,edx + div dword [ClustSize] + ; eax = block #, edx = offset in block + add eax,dword [SuperBlock+s_first_data_block] + inc eax ; s_first_data_block+1 + mov cl,[ClustShift] + shl eax,cl + push edx + shr edx,SECTOR_SHIFT + add eax,edx + pop edx + and dx,SECTOR_SIZE-1 + call getcachesector ; Get the group descriptor + add si,dx + mov esi,[gs:si+bg_inode_table] ; Get inode table block # + pop eax ; Get inode within group + movzx edx, word [SuperBlock+s_inode_size] + mul edx + ; edx:eax = byte offset in inode table + div dword [ClustSize] + ; eax = block # versus inode table, edx = offset in block + add eax,esi + shl eax,cl ; Turn into sector + push dx + shr edx,SECTOR_SHIFT + add eax,edx + mov [bx+file_in_sec],eax + pop dx + and dx,SECTOR_SIZE-1 + mov [bx+file_in_off],dx + + call getcachesector + add si,dx + mov ax,[gs:si+i_mode] + mov [bx+file_mode],ax + mov eax,[gs:si+i_size] + push eax + add eax,SECTOR_SIZE-1 + shr eax,SECTOR_SHIFT + mov [bx+file_left],eax + pop eax + mov si,bx + mov edx,eax + shr edx,16 ; 16-bitism, sigh + and eax,eax ; ZF clear unless zero-length file + pop gs + ret + +; +; close: +; Deallocates a file structure (pointer in SI) +; Assumes CS == DS. +; +close: + mov dword [si],0 ; First dword == file_left + ret + +; +; searchdir: +; Search the root directory for a pre-mangled filename in DS:DI. +; +; NOTE: This file considers finding a zero-length file an +; error. This is so we don't have to deal with that special +; case elsewhere in the program (most loops have the test +; at the end). +; +; If successful: +; ZF clear +; SI = file pointer +; DX:AX = EAX = file length in bytes +; If unsuccessful +; ZF set +; +; Assumes CS == DS == ES; *** IS THIS CORRECT ***? +; +searchdir: + push bx + push cx + push di + mov eax,[CurrentDir] +.leadingslash: + cmp byte [di],'/' ; Absolute filename? + jne .searchloop + mov eax,EXT2_ROOT_INO + inc di ; Skip slash + +.searchloop: + ; At this point, EAX contains the directory inode, + ; and DS:DI contains a pathname tail. + call open_inode + +.readdir: + mov bx,trackbuf + push bx + mov cx,[SecPerClust] + call getfssec + pop bx + pushf ; Save EOF flag + push si ; Save filesystem pointer +.getent: + cmp dword [bx+d_inode],0 + je .endblock + + push di + movzx cx,byte [bx+d_name_len] + lea si,[bx+d_name] + repe cmpsb + je .maybe +.nope: + pop di + + add bx,[bx+d_rec_len] + jmp .getent + +.endblock: + pop si + popf + jnc .readdir ; There is more +.failure: + xor eax,eax + jmp .done +.maybe: + mov eax,[bx+d_inode] + + cmp byte [di],0 + je .finish ; It's a real file; done + cmp byte [di],'/' + jne .nope ; False alarm + + ; It's a match, but it's a directory. + ; Repeat operation. + pop bx ; Adjust stack (di) + pop si + call close + pop bx ; Adjust stack (flags) + inc di ; Skip slash + jmp .searchloop + + +.finish: ; We found it; now we need to open the file + pop bx ; Adjust stack (di) + pop si + call close ; Close directory + pop bx ; Adjust stack (flags) + call open_inode +.done: + pop di + pop cx + pop bx + ret +; +; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed +; to by ES:DI; ends on encountering any whitespace. +; +; This verifies that a filename is < FILENAME_MAX characters, +; doesn't contain whitespace, zero-pads the output buffer, +; and removes redundant slashes, +; so "repe cmpsb" can do a compare, and the +; path-searching routine gets a bit of an easier job. +; +; FIX: we may want to support \-escapes here (and this would +; be the place.) +; +mangle_name: + push bx + xor ax,ax + mov cx,FILENAME_MAX-1 + mov bx,di + +.mn_loop: + lodsb + cmp al,' ' ; If control or space, end + jna .mn_end + cmp al,ah ; Repeated slash? + je .mn_skip + xor ah,ah + cmp al,'/' + jne .mn_ok + mov ah,al +.mn_ok stosb +.mn_skip: loop .mn_loop +.mn_end: + cmp bx,di ; At the beginning of the buffer? + jbe .mn_zero + cmp byte [di-1],'/' ; Terminal slash? + jne .mn_zero +.mn_kill: dec di ; If so, remove it + inc cx + jmp short .mn_end +.mn_zero: + inc cx ; At least one null byte + xor ax,ax ; Zero-fill name + rep stosb + pop bx + ret ; Done + +; +; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled +; filename to the conventional representation. This is needed +; for the BOOT_IMAGE= parameter for the kernel. +; NOTE: A 13-byte buffer is mandatory, even if the string is +; known to be shorter. +; +; DS:SI -> input mangled file name +; ES:DI -> output buffer +; +; On return, DI points to the first byte after the output name, +; which is set to a null byte. +; +unmangle_name: call strcpy + dec di ; Point to final null byte + ret + +; +; writechr: Write a single character in AL to the console without +; mangling any registers; handle video pages correctly. +; +writechr: + call write_serial ; write to serial port if needed + pushfd + test byte [cs:DisplayCon],01h + jz .nothing + pushad + mov ah,0Eh + mov bl,07h ; attribute + mov bh,[cs:BIOS_page] ; current page + int 10h + popad +.nothing: + popfd + ret + +; +; +; kaboom2: once everything is loaded, replace the part of kaboom +; starting with "kaboom.patch" with this part + +kaboom2: + mov si,err_bootfailed + call cwritestr + call getchar + call vgaclearmode + int 19h ; And try once more to boot... +.norge: jmp short .norge ; If int 19h returned; this is the end + + +; +; linsector: Convert a linear sector index in a file to a linear sector number +; EAX -> linear sector number +; DS:SI -> open_file_t +; +; Returns next sector number in EAX; CF on EOF (not an error!) +; +linsector: + push gs + push ebx + push esi + push edi + push ecx + push edx + push ebp + + push eax ; Save sector index + mov cl,[ClustShift] + shr eax,cl ; Convert to block number + push eax + mov eax,[si+file_in_sec] + mov bx,si + call getcachesector ; Get inode + add si,[bx+file_in_off] ; Get *our* inode + pop eax + lea ebx,[i_block+4*eax] + cmp eax,EXT2_NDIR_BLOCKS + jb .direct + mov ebx,i_block+4*EXT2_IND_BLOCK + sub eax,EXT2_NDIR_BLOCKS + mov ebp,[PtrsPerBlock1] + cmp eax,ebp + jb .ind1 + mov ebx,i_block+4*EXT2_DIND_BLOCK + sub eax,ebp + mov ebp,[PtrsPerBlock2] + cmp eax,ebp + jb .ind2 + mov ebx,i_block+4*EXT2_TIND_BLOCK + sub eax,ebp + +.ind3: + ; Triple indirect; eax contains the block no + ; with respect to the start of the tind area; + ; ebx contains the pointer to the tind block. + xor edx,edx + div dword [PtrsPerBlock2] + ; EAX = which dind block, EDX = pointer within dind block + push ax + shr eax,SECTOR_SHIFT-2 + mov ebp,[gs:si+bx] + shl ebp,cl + add eax,ebp + call getcachesector + pop bx + and bx,(SECTOR_SIZE >> 2)-1 + shl bx,2 + mov eax,edx ; The ind2 code wants the remainder... + +.ind2: + ; Double indirect; eax contains the block no + ; with respect to the start of the dind area; + ; ebx contains the pointer to the dind block. + xor edx,edx + div dword [PtrsPerBlock1] + ; EAX = which ind block, EDX = pointer within ind block + push ax + shr eax,SECTOR_SHIFT-2 + mov ebp,[gs:si+bx] + shl ebp,cl + add eax,ebp + call getcachesector + pop bx + and bx,(SECTOR_SIZE >> 2)-1 + shl bx,2 + mov eax,edx ; The int1 code wants the remainder... + +.ind1: + ; Single indirect; eax contains the block no + ; with respect to the start of the ind area; + ; ebx contains the pointer to the ind block. + push ax + shr eax,SECTOR_SHIFT-2 + mov ebp,[gs:si+bx] + shl ebp,cl + add eax,ebp + call getcachesector + pop bx + and bx,(SECTOR_SIZE >> 2)-1 + shl bx,2 + +.direct: + mov ebx,[gs:bx+si] ; Get the pointer + + pop eax ; Get the sector index again + shl ebx,cl ; Convert block number to sector + and eax,[ClustMask] ; Add offset within block + add eax,ebx + + pop ebp + pop edx + pop ecx + pop edi + pop esi + pop ebx + pop gs + ret + +; +; getfssec: Get multiple sectors from a file +; +; Same as above, except SI is a pointer to a open_file_t +; +; ES:BX -> Buffer +; DS:SI -> Pointer to open_file_t +; CX -> Sector count (0FFFFh = until end of file) +; Must not exceed the ES segment +; Returns CF=1 on EOF (not necessarily error) +; All arguments are advanced to reflect data read. +; +getfssec: + push ebp + push eax + push edx + push edi + + movzx ecx,cx + cmp ecx,[si] ; Number of sectors left + jbe .lenok + mov cx,[si] +.lenok: +.getfragment: + mov eax,[si+file_sector] ; Current start index + mov edi,eax + call linsector + push eax ; Fragment start sector + mov edx,eax + xor ebp,ebp ; Fragment sector count +.getseccnt: + inc bp + dec cx + jz .do_read + xor eax,eax + mov ax,es + shl ax,4 + add ax,bx ; Now DI = how far into 64K block we are + not ax ; Bytes left in 64K block + inc eax + shr eax,SECTOR_SHIFT ; Sectors left in 64K block + cmp bp,ax + jnb .do_read ; Unless there is at least 1 more sector room... + inc edi ; Sector index + inc edx ; Linearly next sector + mov eax,edi + call linsector + ; jc .do_read + cmp edx,eax + je .getseccnt +.do_read: + pop eax ; Linear start sector + pushad + call getlinsec_ext + popad + push bp + shl bp,9 + add bx,bp ; Adjust buffer pointer + pop bp + add [si+file_sector],ebp ; Next sector index + sub [si],ebp ; Sectors consumed + jcxz .done + jnz .getfragment + ; Fall through +.done: + cmp dword [si],1 ; Did we run out of file? + ; CF set if [SI] < 1, i.e. == 0 + pop edi + pop edx + pop eax + pop ebp + ret + +; ----------------------------------------------------------------------------- +; Common modules +; ----------------------------------------------------------------------------- + +%include "getc.inc" ; getc et al +%include "conio.inc" ; Console I/O +%include "writestr.inc" ; String output +%include "parseconfig.inc" ; High-level config file handling +%include "parsecmd.inc" ; Low-level config file handling +%include "bcopy32.inc" ; 32-bit bcopy +%include "loadhigh.inc" ; Load a file into high memory +%include "font.inc" ; VGA font stuff +%include "graphics.inc" ; VGA graphics +%include "highmem.inc" ; High memory sizing +%include "strcpy.inc" ; strcpy() +%include "cache.inc" + +; ----------------------------------------------------------------------------- +; Begin data section +; ----------------------------------------------------------------------------- + + section .data +copyright_str db ' Copyright (C) 1994-', year, ' H. Peter Anvin' + db CR, LF, 0 +boot_prompt db 'boot: ', 0 +wipe_char db BS, ' ', BS, 0 +err_notfound db 'Could not find kernel image: ',0 +err_notkernel db CR, LF, 'Invalid or corrupt kernel image.', CR, LF, 0 +err_noram db 'It appears your computer has less than ' + asciidec dosram_k + db 'K of low ("DOS")' + db CR, LF + db 'RAM. Linux needs at least this amount to boot. If you get' + db CR, LF + db 'this message in error, hold down the Ctrl key while' + db CR, LF + db 'booting, and I will take your word for it.', CR, LF, 0 +err_badcfg db 'Unknown keyword in extlinux.conf.', CR, LF, 0 +err_noparm db 'Missing parameter in extlinux.conf.', CR, LF, 0 +err_noinitrd db CR, LF, 'Could not find ramdisk image: ', 0 +err_nohighmem db 'Not enough memory to load specified kernel.', CR, LF, 0 +err_highload db CR, LF, 'Kernel transfer failure.', CR, LF, 0 +err_oldkernel db 'Cannot load a ramdisk with an old kernel image.' + db CR, LF, 0 +err_notdos db ': attempted DOS system call', CR, LF, 0 +err_comlarge db 'COMBOOT image too large.', CR, LF, 0 +err_bssimage db 'BSS images not supported.', CR, LF, 0 +err_a20 db CR, LF, 'A20 gate not responding!', CR, LF, 0 +err_bootfailed db CR, LF, 'Boot failed: please change disks and press ' + db 'a key to continue.', CR, LF, 0 +ready_msg db 'Ready.', CR, LF, 0 +crlfloading_msg db CR, LF +loading_msg db 'Loading ', 0 +dotdot_msg db '.' +dot_msg db '.', 0 +aborted_msg db ' aborted.' ; Fall through to crlf_msg! +crlf_msg db CR, LF +null_msg db 0 +crff_msg db CR, FF, 0 +ConfigName db 'extlinux.conf',0 ; Unmangled form + +; +; Command line options we'd like to take a look at +; +; mem= and vga= are handled as normal 32-bit integer values +initrd_cmd db 'initrd=' +initrd_cmd_len equ 7 + +; +; Config file keyword table +; +%include "keywords.inc" + +; +; Extensions to search for (in *forward* order). +; + align 4, db 0 +exten_table: db '.cbt' ; COMBOOT (specific) + db '.img' ; Disk image + db '.bs', 0 ; Boot sector + db '.com' ; COMBOOT (same as DOS) + db '.c32' ; COM32 +exten_table_end: + dd 0, 0 ; Need 8 null bytes here + +; +; Misc initialized (data) variables +; +%ifdef debug ; This code for debugging only +debug_magic dw 0D00Dh ; Debug code sentinel +%endif + + alignb 4, db 0 +BufSafe dw trackbufsize/SECTOR_SIZE ; Clusters we can load into trackbuf +BufSafeSec dw trackbufsize/SECTOR_SIZE ; = how many sectors? +BufSafeBytes dw trackbufsize ; = how many bytes? +EndOfGetCBuf dw getcbuf+trackbufsize ; = getcbuf+BufSafeBytes +%ifndef DEPEND +%if ( trackbufsize % SECTOR_SIZE ) != 0 +%error trackbufsize must be a multiple of SECTOR_SIZE +%endif +%endif diff --git a/syslinux/extlinux.bin b/syslinux/extlinux.bin new file mode 100644 index 0000000000000000000000000000000000000000..dbb45d62683bc6872a9f55c7d7b0219855800c78 GIT binary patch literal 9832 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 ZHj*|eU6X!1{dhW;{-5dl)5ZS`{SP)Z7?=P6 literal 0 HcmV?d00001 diff --git a/syslinux/extlinux.bss b/syslinux/extlinux.bss new file mode 100644 index 0000000000000000000000000000000000000000..2fd44aead0a68e577e04ea9cb87138535b3faec9 GIT binary patch literal 512 zcmaDIF~Kz=#K+SwG=hP;;MX6+1AQ0vY^m-$u#<zK^ZDnceK&SjFz|0N=U))kAvVQd z;ZlX@Mz&7-PIso1&r7@bBx*W*f1DM5t^UpRLwzYnTDR+uw8b(tTR6@N7YQpoDdj)- zio>Z>Osb~&p?xQxM9uHrt3tOpc8N{#KPy}$(D*xaRVmlEgN!At$JiWd8PXR1sNKy_ z_acNLt<g@Q?jO@8yHdWiMmv?dQ@`IkmNLJzU^4vHcWuvx>b`qv{cIHs`)<^}U}u<d zR_v_g>wjw$4wP_i;oHs5a8}^;r^9>M7}65X3a2F&fAKB-`ts=iy^IWL%xp3>udVmJ zsO^kl>2YC8>vZ7=eNoNOnZpEf(-x-}C;rE#@o#rwN@H~4&^&tZ0Vksii{jhTTWQ@c z9NjT2htmQ=gVXr8n@QB9@o%@2s!21vl=l6b;mP(>Y2UxUFl5j?XZf{^sq^cBCv1)! z4?B)_Tmu<Abqmvry#HzZ+fE#Oz!}YWI5sUJjq!x$+0qS%t@ZxYma%l}{i!|dl%HRs ckd~O4lbXWI#lXNIfEKy$_pQBG&k(u_00El3pa1{> literal 0 HcmV?d00001 diff --git a/syslinux/extlinux.doc b/syslinux/extlinux.doc new file mode 100644 index 0000000..0bf7487 --- /dev/null +++ b/syslinux/extlinux.doc @@ -0,0 +1,89 @@ +EXTLINUX is a new syslinux derivative, which boots from a Linux +ext2/ext3 filesystem. + +It works the same way as SYSLINUX, with a few slight modifications. + +1. The installer is run on a *mounted* filesystem. Run the extlinux + installer on the directory in which you want extlinux installed: + + extlinux /boot + + NOTE: this doesn't have to be the root directory of a filesystem. + If /boot is a filesystem, you can do: + + mkdir -p /boot/extlinux + extlinux /boot/extlinux + + ... to create a subdirectory and install extlinux in it. + + +2. The configuration file is called "extlinux.conf", and is expected + to be found in the same directory as extlinux is installed in. + + +3. Pathnames can be absolute or relative; if absolute (with a leading + slash), they are relative to the root of the filesystem on which + extlinux is installed (/boot in the example above), if relative, + they are relative to the extlinux directory. + + extlinux supports subdirectories, but the total path length is + limited to 255 characters. + + +4. EXTLINUX currently doesn't support symlinks it does, however, + support hard links. This will be fixed in a future version. + + + +Note that EXTLINUX installs in the filesystem partition like a +well-behaved bootloader :) Thus, it needs a master boot record in the +partition table; the mbr.bin shipped with SYSLINUX should work well. +To install it just do: + + cat mbr.bin > /dev/XXX + +... where /dev/XXX is the appropriate master device, e.g. /dev/hda, +and make sure the correct partition in set active. + + +If you have multiple disks in a software RAID configuration, the +preferred way to boot is: + +- Create a separate RAID-1 partition for /boot. Note that the Linux + RAID-1 driver can span as many disks as you wish. + +- Install the MBR on *each disk*, and mark the RAID-1 partition + active. + +- Run "extlinux /boot" to install extlinux. This will install it on + all the drives in the RAID-1 set, which means you can boot any + combination of drives in any order. + + + +It is not required to re-run the extlinux installer after installing +new kernels. If you are using ext3 journalling, however, it might be +desirable to do so, since running the extlinux installer will flush +the log. Otherwise a dirty shutdown could cause some of the new +kernel image to still be in the log. This is a general problem for +boot loaders on journalling filesystems; it is not specific to +extlinux. The "sync" command does not flush the log on the ext3 +filesystem. + + +The SYSLINUX series boot loaders support chain loading other operating +systems via a separate module, chain.c32 (located in +com32/modules/chain.c32). To use it, specify a LABEL in the +configuration file with KERNEL chain.c32 and +APPEND [hd|fd]<number> [<partition>] + +For example: + +# Windows CE/ME/NT, a very dense operating system. +# Second partition (2) on the first hard disk (hd0); +# Linux would *typically* call this /dev/hda2 or /dev/sda2. +LABEL cement + KERNEL chain.c32 + APPEND hd0 2 + +See also README.menu. diff --git a/syslinux/extlinux.sys b/syslinux/extlinux.sys new file mode 100644 index 0000000000000000000000000000000000000000..19e762fae7e8422d2f1c40d19c85aba25d506705 GIT binary patch literal 9320 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 JOZ=aq{|BXrTj~G+ literal 0 HcmV?d00001 diff --git a/syslinux/extlinux/Makefile b/syslinux/extlinux/Makefile new file mode 100644 index 0000000..3358f5a --- /dev/null +++ b/syslinux/extlinux/Makefile @@ -0,0 +1,40 @@ +CC = gcc +OPTFLAGS = -g -Os +INCLUDES = -I. -I.. -I../libfat +CFLAGS = -W -Wall -Wno-sign-compare -D_FILE_OFFSET_BITS=64 $(OPTFLAGS) $(INCLUDES) +LDFLAGS = -s + +SRCS = extlinux.c ../extlinux_bss_bin.c ../extlinux_sys_bin.c +OBJS = $(patsubst %.c,%.o,$(notdir $(SRCS))) + +.SUFFIXES: .c .o .i .s .S + +VPATH = .:.. + +all: installer + +tidy: + -rm -f *.o *.i *.s *.a .*.d + +clean: tidy + -rm -f extlinux + +spotless: clean + -rm -f *~ + +installer: extlinux + +extlinux: $(OBJS) + $(CC) $(LDFLAGS) -o $@ $^ + +%.o: %.c + $(CC) -Wp,-MT,$@,-MMD,.$@.d $(CFLAGS) -c -o $@ $< +%.i: %.c + $(CC) $(CFLAGS) -E -o $@ $< +%.s: %.c + $(CC) $(CFLAGS) -S -o $@ $< + +-include .*.d + + + diff --git a/syslinux/extlinux/ext2_fs.h b/syslinux/extlinux/ext2_fs.h new file mode 100644 index 0000000..6355d92 --- /dev/null +++ b/syslinux/extlinux/ext2_fs.h @@ -0,0 +1,508 @@ +/* + * linux/include/linux/ext2_fs.h + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/include/linux/minix_fs.h + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* Private copy for extlinux */ + +#ifndef _LINUX_EXT2_FS_H +#define _LINUX_EXT2_FS_H + +#include <linux/types.h> + +/* + * The second extended filesystem constants/structures + */ + +/* + * Define EXT2FS_DEBUG to produce debug messages + */ +#undef EXT2FS_DEBUG + +/* + * Define EXT2_PREALLOCATE to preallocate data blocks for expanding files + */ +#define EXT2_PREALLOCATE +#define EXT2_DEFAULT_PREALLOC_BLOCKS 8 + +/* + * The second extended file system version + */ +#define EXT2FS_DATE "95/08/09" +#define EXT2FS_VERSION "0.5b" + +/* + * Debug code + */ +#ifdef EXT2FS_DEBUG +# define ext2_debug(f, a...) { \ + printk ("EXT2-fs DEBUG (%s, %d): %s:", \ + __FILE__, __LINE__, __FUNCTION__); \ + printk (f, ## a); \ + } +#else +# define ext2_debug(f, a...) /**/ +#endif + +/* + * Special inode numbers + */ +#define EXT2_BAD_INO 1 /* Bad blocks inode */ +#define EXT2_ROOT_INO 2 /* Root inode */ +#define EXT2_ACL_IDX_INO 3 /* ACL inode */ +#define EXT2_ACL_DATA_INO 4 /* ACL inode */ +#define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */ +#define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */ + +/* First non-reserved inode for old ext2 filesystems */ +#define EXT2_GOOD_OLD_FIRST_INO 11 + +/* + * The second extended file system magic number + */ +#define EXT2_SUPER_MAGIC 0xEF53 + +/* + * Maximal count of links to a file + */ +#define EXT2_LINK_MAX 32000 + +/* + * Macro-instructions used to manage several block sizes + */ +#define EXT2_MIN_BLOCK_SIZE 1024 +#define EXT2_MAX_BLOCK_SIZE 4096 +#define EXT2_MIN_BLOCK_LOG_SIZE 10 +# define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size) +#define EXT2_ACLE_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_acl_entry)) +#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (__u32)) +# define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10) +#define EXT2_INODE_SIZE(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \ + EXT2_GOOD_OLD_INODE_SIZE : \ + (s)->s_inode_size) +#define EXT2_FIRST_INO(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \ + EXT2_GOOD_OLD_FIRST_INO : \ + (s)->s_first_ino) + +/* + * Macro-instructions used to manage fragments + */ +#define EXT2_MIN_FRAG_SIZE 1024 +#define EXT2_MAX_FRAG_SIZE 4096 +#define EXT2_MIN_FRAG_LOG_SIZE 10 +# define EXT2_FRAG_SIZE(s) (EXT2_MIN_FRAG_SIZE << (s)->s_log_frag_size) +# define EXT2_FRAGS_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s)) + +/* + * ACL structures + */ +struct ext2_acl_header /* Header of Access Control Lists */ +{ + __u32 aclh_size; + __u32 aclh_file_count; + __u32 aclh_acle_count; + __u32 aclh_first_acle; +}; + +struct ext2_acl_entry /* Access Control List Entry */ +{ + __u32 acle_size; + __u16 acle_perms; /* Access permissions */ + __u16 acle_type; /* Type of entry */ + __u16 acle_tag; /* User or group identity */ + __u16 acle_pad1; + __u32 acle_next; /* Pointer on next entry for the */ + /* same inode or on next free entry */ +}; + +/* + * Structure of a blocks group descriptor + */ +struct ext2_group_desc +{ + __u32 bg_block_bitmap; /* Blocks bitmap block */ + __u32 bg_inode_bitmap; /* Inodes bitmap block */ + __u32 bg_inode_table; /* Inodes table block */ + __u16 bg_free_blocks_count; /* Free blocks count */ + __u16 bg_free_inodes_count; /* Free inodes count */ + __u16 bg_used_dirs_count; /* Directories count */ + __u16 bg_pad; + __u32 bg_reserved[3]; +}; + +/* + * Macro-instructions used to manage group descriptors + */ +# define EXT2_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group) +# define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc)) +# define EXT2_INODES_PER_GROUP(s) ((s)->s_inodes_per_group) + +/* + * Constants relative to the data blocks + */ +#define EXT2_NDIR_BLOCKS 12 +#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS +#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1) +#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1) +#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1) + +/* + * Inode flags + */ +#define EXT2_SECRM_FL 0x00000001 /* Secure deletion */ +#define EXT2_UNRM_FL 0x00000002 /* Undelete */ +#define EXT2_COMPR_FL 0x00000004 /* Compress file */ +#define EXT2_SYNC_FL 0x00000008 /* Synchronous updates */ +#define EXT2_IMMUTABLE_FL 0x00000010 /* Immutable file */ +#define EXT2_APPEND_FL 0x00000020 /* writes to file may only append */ +#define EXT2_NODUMP_FL 0x00000040 /* do not dump file */ +#define EXT2_NOATIME_FL 0x00000080 /* do not update atime */ +/* Reserved for compression usage... */ +#define EXT2_DIRTY_FL 0x00000100 +#define EXT2_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */ +#define EXT2_NOCOMP_FL 0x00000400 /* Don't compress */ +#define EXT2_ECOMPR_FL 0x00000800 /* Compression error */ +/* End compression flags --- maybe not all used */ +#define EXT2_BTREE_FL 0x00001000 /* btree format dir */ +#define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */ + +#define EXT2_FL_USER_VISIBLE 0x00001FFF /* User visible flags */ +#define EXT2_FL_USER_MODIFIABLE 0x000000FF /* User modifiable flags */ + +/* + * ioctl commands + */ +#define EXT2_IOC_GETFLAGS _IOR('f', 1, long) +#define EXT2_IOC_SETFLAGS _IOW('f', 2, long) +#define EXT2_IOC_GETVERSION _IOR('v', 1, long) +#define EXT2_IOC_SETVERSION _IOW('v', 2, long) + +/* + * Structure of an inode on the disk + */ +struct ext2_inode { + __u16 i_mode; /* File mode */ + __u16 i_uid; /* Low 16 bits of Owner Uid */ + __u32 i_size; /* Size in bytes */ + __u32 i_atime; /* Access time */ + __u32 i_ctime; /* Creation time */ + __u32 i_mtime; /* Modification time */ + __u32 i_dtime; /* Deletion Time */ + __u16 i_gid; /* Low 16 bits of Group Id */ + __u16 i_links_count; /* Links count */ + __u32 i_blocks; /* Blocks count */ + __u32 i_flags; /* File flags */ + union { + struct { + __u32 l_i_reserved1; + } linux1; + struct { + __u32 h_i_translator; + } hurd1; + struct { + __u32 m_i_reserved1; + } masix1; + } osd1; /* OS dependent 1 */ + __u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */ + __u32 i_generation; /* File version (for NFS) */ + __u32 i_file_acl; /* File ACL */ + __u32 i_dir_acl; /* Directory ACL */ + __u32 i_faddr; /* Fragment address */ + union { + struct { + __u8 l_i_frag; /* Fragment number */ + __u8 l_i_fsize; /* Fragment size */ + __u16 i_pad1; + __u16 l_i_uid_high; /* these 2 fields */ + __u16 l_i_gid_high; /* were reserved2[0] */ + __u32 l_i_reserved2; + } linux2; + struct { + __u8 h_i_frag; /* Fragment number */ + __u8 h_i_fsize; /* Fragment size */ + __u16 h_i_mode_high; + __u16 h_i_uid_high; + __u16 h_i_gid_high; + __u32 h_i_author; + } hurd2; + struct { + __u8 m_i_frag; /* Fragment number */ + __u8 m_i_fsize; /* Fragment size */ + __u16 m_pad1; + __u32 m_i_reserved2[2]; + } masix2; + } osd2; /* OS dependent 2 */ +}; + +#define i_size_high i_dir_acl + +#if defined(__KERNEL__) || defined(__linux__) +#define i_reserved1 osd1.linux1.l_i_reserved1 +#define i_frag osd2.linux2.l_i_frag +#define i_fsize osd2.linux2.l_i_fsize +#define i_uid_low i_uid +#define i_gid_low i_gid +#define i_uid_high osd2.linux2.l_i_uid_high +#define i_gid_high osd2.linux2.l_i_gid_high +#define i_reserved2 osd2.linux2.l_i_reserved2 +#endif + +#ifdef __hurd__ +#define i_translator osd1.hurd1.h_i_translator +#define i_frag osd2.hurd2.h_i_frag; +#define i_fsize osd2.hurd2.h_i_fsize; +#define i_uid_high osd2.hurd2.h_i_uid_high +#define i_gid_high osd2.hurd2.h_i_gid_high +#define i_author osd2.hurd2.h_i_author +#endif + +#ifdef __masix__ +#define i_reserved1 osd1.masix1.m_i_reserved1 +#define i_frag osd2.masix2.m_i_frag +#define i_fsize osd2.masix2.m_i_fsize +#define i_reserved2 osd2.masix2.m_i_reserved2 +#endif + +/* + * File system states + */ +#define EXT2_VALID_FS 0x0001 /* Unmounted cleanly */ +#define EXT2_ERROR_FS 0x0002 /* Errors detected */ + +/* + * Mount flags + */ +#define EXT2_MOUNT_CHECK 0x0001 /* Do mount-time checks */ +#define EXT2_MOUNT_GRPID 0x0004 /* Create files with directory's group */ +#define EXT2_MOUNT_DEBUG 0x0008 /* Some debugging messages */ +#define EXT2_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */ +#define EXT2_MOUNT_ERRORS_RO 0x0020 /* Remount fs ro on errors */ +#define EXT2_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */ +#define EXT2_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */ +#define EXT2_MOUNT_NO_UID32 0x0200 /* Disable 32-bit UIDs */ + +#define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt +#define set_opt(o, opt) o |= EXT2_MOUNT_##opt +#define test_opt(sb, opt) ((sb)->u.ext2_sb.s_mount_opt & \ + EXT2_MOUNT_##opt) +/* + * Maximal mount counts between two filesystem checks + */ +#define EXT2_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */ +#define EXT2_DFL_CHECKINTERVAL 0 /* Don't use interval check */ + +/* + * Behaviour when detecting errors + */ +#define EXT2_ERRORS_CONTINUE 1 /* Continue execution */ +#define EXT2_ERRORS_RO 2 /* Remount fs read-only */ +#define EXT2_ERRORS_PANIC 3 /* Panic */ +#define EXT2_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE + +/* + * Structure of the super block + */ +struct ext2_super_block { + __u32 s_inodes_count; /* Inodes count */ + __u32 s_blocks_count; /* Blocks count */ + __u32 s_r_blocks_count; /* Reserved blocks count */ + __u32 s_free_blocks_count; /* Free blocks count */ + __u32 s_free_inodes_count; /* Free inodes count */ + __u32 s_first_data_block; /* First Data Block */ + __u32 s_log_block_size; /* Block size */ + __s32 s_log_frag_size; /* Fragment size */ + __u32 s_blocks_per_group; /* # Blocks per group */ + __u32 s_frags_per_group; /* # Fragments per group */ + __u32 s_inodes_per_group; /* # Inodes per group */ + __u32 s_mtime; /* Mount time */ + __u32 s_wtime; /* Write time */ + __u16 s_mnt_count; /* Mount count */ + __s16 s_max_mnt_count; /* Maximal mount count */ + __u16 s_magic; /* Magic signature */ + __u16 s_state; /* File system state */ + __u16 s_errors; /* Behaviour when detecting errors */ + __u16 s_minor_rev_level; /* minor revision level */ + __u32 s_lastcheck; /* time of last check */ + __u32 s_checkinterval; /* max. time between checks */ + __u32 s_creator_os; /* OS */ + __u32 s_rev_level; /* Revision level */ + __u16 s_def_resuid; /* Default uid for reserved blocks */ + __u16 s_def_resgid; /* Default gid for reserved blocks */ + /* + * These fields are for EXT2_DYNAMIC_REV superblocks only. + * + * Note: the difference between the compatible feature set and + * the incompatible feature set is that if there is a bit set + * in the incompatible feature set that the kernel doesn't + * know about, it should refuse to mount the filesystem. + * + * e2fsck's requirements are more strict; if it doesn't know + * about a feature in either the compatible or incompatible + * feature set, it must abort and not try to meddle with + * things it doesn't understand... + */ + __u32 s_first_ino; /* First non-reserved inode */ + __u16 s_inode_size; /* size of inode structure */ + __u16 s_block_group_nr; /* block group # of this superblock */ + __u32 s_feature_compat; /* compatible feature set */ + __u32 s_feature_incompat; /* incompatible feature set */ + __u32 s_feature_ro_compat; /* readonly-compatible feature set */ + __u8 s_uuid[16]; /* 128-bit uuid for volume */ + char s_volume_name[16]; /* volume name */ + char s_last_mounted[64]; /* directory where last mounted */ + __u32 s_algorithm_usage_bitmap; /* For compression */ + /* + * Performance hints. Directory preallocation should only + * happen if the EXT2_COMPAT_PREALLOC flag is on. + */ + __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ + __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ + __u16 s_padding1; + __u32 s_reserved[204]; /* Padding to the end of the block */ +}; + +/* Assume that user mode programs are passing in an ext2fs superblock, not + * a kernel struct super_block. This will allow us to call the feature-test + * macros from user land. */ +#define EXT2_SB(sb) (sb) + +/* + * Codes for operating systems + */ +#define EXT2_OS_LINUX 0 +#define EXT2_OS_HURD 1 +#define EXT2_OS_MASIX 2 +#define EXT2_OS_FREEBSD 3 +#define EXT2_OS_LITES 4 + +/* + * Revision levels + */ +#define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */ +#define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */ + +#define EXT2_CURRENT_REV EXT2_GOOD_OLD_REV +#define EXT2_MAX_SUPP_REV EXT2_DYNAMIC_REV + +#define EXT2_GOOD_OLD_INODE_SIZE 128 + +/* + * Feature set definitions + */ + +#define EXT2_HAS_COMPAT_FEATURE(sb,mask) \ + ( EXT2_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) ) +#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask) \ + ( EXT2_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) ) +#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \ + ( EXT2_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) ) +#define EXT2_SET_COMPAT_FEATURE(sb,mask) \ + EXT2_SB(sb)->s_es->s_feature_compat |= cpu_to_le32(mask) +#define EXT2_SET_RO_COMPAT_FEATURE(sb,mask) \ + EXT2_SB(sb)->s_es->s_feature_ro_compat |= cpu_to_le32(mask) +#define EXT2_SET_INCOMPAT_FEATURE(sb,mask) \ + EXT2_SB(sb)->s_es->s_feature_incompat |= cpu_to_le32(mask) +#define EXT2_CLEAR_COMPAT_FEATURE(sb,mask) \ + EXT2_SB(sb)->s_es->s_feature_compat &= ~cpu_to_le32(mask) +#define EXT2_CLEAR_RO_COMPAT_FEATURE(sb,mask) \ + EXT2_SB(sb)->s_es->s_feature_ro_compat &= ~cpu_to_le32(mask) +#define EXT2_CLEAR_INCOMPAT_FEATURE(sb,mask) \ + EXT2_SB(sb)->s_es->s_feature_incompat &= ~cpu_to_le32(mask) + +#define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001 +#define EXT2_FEATURE_COMPAT_IMAGIC_INODES 0x0002 +#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004 +#define EXT2_FEATURE_COMPAT_EXT_ATTR 0x0008 +#define EXT2_FEATURE_COMPAT_RESIZE_INO 0x0010 +#define EXT2_FEATURE_COMPAT_DIR_INDEX 0x0020 +#define EXT2_FEATURE_COMPAT_ANY 0xffffffff + +#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 +#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 +#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 +#define EXT2_FEATURE_RO_COMPAT_ANY 0xffffffff + +#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001 +#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002 +#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 +#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 +#define EXT2_FEATURE_INCOMPAT_ANY 0xffffffff + +#define EXT2_FEATURE_COMPAT_SUPP 0 +#define EXT2_FEATURE_INCOMPAT_SUPP EXT2_FEATURE_INCOMPAT_FILETYPE +#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \ + EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \ + EXT2_FEATURE_RO_COMPAT_BTREE_DIR) +#define EXT2_FEATURE_RO_COMPAT_UNSUPPORTED ~EXT2_FEATURE_RO_COMPAT_SUPP +#define EXT2_FEATURE_INCOMPAT_UNSUPPORTED ~EXT2_FEATURE_INCOMPAT_SUPP + +/* + * Default values for user and/or group using reserved blocks + */ +#define EXT2_DEF_RESUID 0 +#define EXT2_DEF_RESGID 0 + +/* + * Structure of a directory entry + */ +#define EXT2_NAME_LEN 255 + +struct ext2_dir_entry { + __u32 inode; /* Inode number */ + __u16 rec_len; /* Directory entry length */ + __u16 name_len; /* Name length */ + char name[EXT2_NAME_LEN]; /* File name */ +}; + +/* + * The new version of the directory entry. Since EXT2 structures are + * stored in intel byte order, and the name_len field could never be + * bigger than 255 chars, it's safe to reclaim the extra byte for the + * file_type field. + */ +struct ext2_dir_entry_2 { + __u32 inode; /* Inode number */ + __u16 rec_len; /* Directory entry length */ + __u8 name_len; /* Name length */ + __u8 file_type; + char name[EXT2_NAME_LEN]; /* File name */ +}; + +/* + * Ext2 directory file types. Only the low 3 bits are used. The + * other bits are reserved for now. + */ +enum { + EXT2_FT_UNKNOWN, + EXT2_FT_REG_FILE, + EXT2_FT_DIR, + EXT2_FT_CHRDEV, + EXT2_FT_BLKDEV, + EXT2_FT_FIFO, + EXT2_FT_SOCK, + EXT2_FT_SYMLINK, + EXT2_FT_MAX +}; + +/* + * EXT2_DIR_PAD defines the directory entries boundaries + * + * NOTE: It must be a multiple of 4 + */ +#define EXT2_DIR_PAD 4 +#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1) +#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \ + ~EXT2_DIR_ROUND) + + +#endif /* _LINUX_EXT2_FS_H */ diff --git a/syslinux/extlinux/extlinux.c b/syslinux/extlinux/extlinux.c new file mode 100644 index 0000000..24fbdf0 --- /dev/null +++ b/syslinux/extlinux/extlinux.c @@ -0,0 +1,756 @@ +#ident "$Id: extlinux.c,v 1.15 2005/04/03 00:00:36 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 1998-2005 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * extlinux.c + * + * Install the extlinux boot block on an ext2/3 filesystem + */ + +#define _GNU_SOURCE /* Enable everything */ +#include <inttypes.h> +/* This is needed to deal with the kernel headers imported into glibc 3.3.3. */ +typedef uint64_t u64; +#include <alloca.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <unistd.h> +#include <mntent.h> +#include <stdlib.h> +#include <string.h> +#include <getopt.h> +#include <sysexits.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/mount.h> + +#include <linux/fd.h> /* Floppy geometry */ +#include <linux/hdreg.h> /* Hard disk geometry */ +#include <linux/fs.h> /* FIGETBSZ, FIBMAP */ + +#include "ext2_fs.h" +#include "../version.h" + +#ifdef DEBUG +# define dprintf printf +#else +# define dprintf(...) ((void)0) +#endif + +/* Global option handling */ + +const char *program; + +/* These are the options we can set and their values */ +struct my_options { + unsigned int sectors; + unsigned int heads; +} opt = { + .sectors = 0, + .heads = 0, +}; + +static void __attribute__((noreturn)) usage(int rv) +{ + fprintf(stderr, + "Usage: %s [options] directory\n" + " --zip -z Force zipdrive geometry (-H 64 -S 32)\n" + " --sectors=# -S Force the number of sectors per track\n" + " --heads=# -H Force number of heads\n" + "\n" + " Note: geometry is determined at boot time for devices which\n" + " are considered hard disks by the BIOS. Unfortunately, this is\n" + " not possible for devices which are considered floppy disks,\n" + " which includes zipdisks and LS-120 superfloppies.\n" + "\n" + " The -z option is useful for USB devices which are considered\n" + " hard disks by some BIOSes and zipdrives by other BIOSes.\n", + program); + + exit(rv); +} + +static const struct option long_options[] = { + { "zipdrive", 0, NULL, 'z' }, + { "sectors", 1, NULL, 'S' }, + { "heads", 1, NULL, 'H' }, + { "version", 0, NULL, 'v' }, + { "help", 0, NULL, 'h' }, + { 0, 0, 0, 0 } +}; + +static const char short_options[] = "zS:H:vh"; + + + +#if defined(__linux__) && !defined(BLKGETSIZE64) +/* This takes a u64, but the size field says size_t. Someone screwed big. */ +# define BLKGETSIZE64 _IOR(0x12,114,size_t) +#endif + +#define LDLINUX_MAGIC 0x3eb202fe + +enum bs_offsets { + bsJump = 0x00, + bsOemName = 0x03, + bsBytesPerSec = 0x0b, + bsSecPerClust = 0x0d, + bsResSectors = 0x0e, + bsFATs = 0x10, + bsRootDirEnts = 0x11, + bsSectors = 0x13, + bsMedia = 0x15, + bsFATsecs = 0x16, + bsSecPerTrack = 0x18, + bsHeads = 0x1a, + bsHiddenSecs = 0x1c, + bsHugeSectors = 0x20, + + /* FAT12/16 only */ + bs16DriveNumber = 0x24, + bs16Reserved1 = 0x25, + bs16BootSignature = 0x26, + bs16VolumeID = 0x27, + bs16VolumeLabel = 0x2b, + bs16FileSysType = 0x36, + bs16Code = 0x3e, + + /* FAT32 only */ + bs32FATSz32 = 36, + bs32ExtFlags = 40, + bs32FSVer = 42, + bs32RootClus = 44, + bs32FSInfo = 48, + bs32BkBootSec = 50, + bs32Reserved = 52, + bs32DriveNumber = 64, + bs32Reserved1 = 65, + bs32BootSignature = 66, + bs32VolumeID = 67, + bs32VolumeLabel = 71, + bs32FileSysType = 82, + bs32Code = 90, + + bsSignature = 0x1fe +}; + +#define bsHead bsJump +#define bsHeadLen (bsOemName-bsHead) +#define bsCode bs32Code /* The common safe choice */ +#define bsCodeLen (bsSignature-bs32Code) + +/* + * Access functions for littleendian numbers, possibly misaligned. + */ +static inline uint8_t get_8(const unsigned char *p) +{ + return *(const uint8_t *)p; +} + +static inline uint16_t get_16(const unsigned char *p) +{ +#if defined(__i386__) || defined(__x86_64__) + /* Littleendian and unaligned-capable */ + return *(const uint16_t *)p; +#else + return (uint16_t)p[0] + ((uint16_t)p[1] << 8); +#endif +} + +static inline uint32_t get_32(const unsigned char *p) +{ +#if defined(__i386__) || defined(__x86_64__) + /* Littleendian and unaligned-capable */ + return *(const uint32_t *)p; +#else + return (uint32_t)p[0] + ((uint32_t)p[1] << 8) + + ((uint32_t)p[2] << 16) + ((uint32_t)p[3] << 24); +#endif +} + +static inline void set_16(unsigned char *p, uint16_t v) +{ +#if defined(__i386__) || defined(__x86_64__) + /* Littleendian and unaligned-capable */ + *(uint16_t *)p = v; +#else + p[0] = (v & 0xff); + p[1] = ((v >> 8) & 0xff); +#endif +} + +static inline void set_32(unsigned char *p, uint32_t v) +{ +#if defined(__i386__) || defined(__x86_64__) + /* Littleendian and unaligned-capable */ + *(uint32_t *)p = v; +#else + p[0] = (v & 0xff); + p[1] = ((v >> 8) & 0xff); + p[2] = ((v >> 16) & 0xff); + p[3] = ((v >> 24) & 0xff); +#endif +} + +#ifndef EXT2_SUPER_OFFSET +#define EXT2_SUPER_OFFSET 1024 +#endif + +#define SECTOR_SHIFT 9 /* 512-byte sectors */ +#define SECTOR_SIZE (1 << SECTOR_SHIFT) + +const char *program; + +/* + * Boot block + */ +extern unsigned char extlinux_bootsect[]; +extern unsigned int extlinux_bootsect_len; +#define boot_block extlinux_bootsect +#define boot_block_len extlinux_bootsect_len + +/* + * Image file + */ +extern unsigned char extlinux_image[]; +extern unsigned int extlinux_image_len; +#define boot_image extlinux_image +#define boot_image_len extlinux_image_len + +/* + * Common abort function + */ +void __attribute__((noreturn)) die(const char *msg) +{ + fputs(msg, stderr); + exit(1); +} + +/* + * read/write wrapper functions + */ +ssize_t xpread(int fd, void *buf, size_t count, off_t offset) +{ + char *bufp = (char *)buf; + ssize_t rv; + ssize_t done = 0; + + while ( count ) { + rv = pread(fd, bufp, count, offset); + if ( rv == 0 ) { + die("short read"); + } else if ( rv == -1 ) { + if ( errno == EINTR ) { + continue; + } else { + die(strerror(errno)); + } + } else { + bufp += rv; + offset += rv; + done += rv; + count -= rv; + } + } + + return done; +} + +ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset) +{ + const char *bufp = (const char *)buf; + ssize_t rv; + ssize_t done = 0; + + while ( count ) { + rv = pwrite(fd, bufp, count, offset); + if ( rv == 0 ) { + die("short write"); + } else if ( rv == -1 ) { + if ( errno == EINTR ) { + continue; + } else { + die(strerror(errno)); + } + } else { + bufp += rv; + offset += rv; + done += rv; + count -= rv; + } + } + + return done; +} + +/* + * Produce file map + */ +int +sectmap(int fd, uint32_t *sectors, int nsectors) +{ + unsigned int blksize, blk, nblk; + unsigned int i; + + /* Get block size */ + if ( ioctl(fd, FIGETBSZ, &blksize) ) + return -1; + + /* Number of sectors per block */ + blksize >>= SECTOR_SHIFT; + + nblk = 0; + while ( nsectors ) { + + blk = nblk++; + dprintf("querying block %u\n", blk); + if ( ioctl(fd, FIBMAP, &blk) ) + return -1; + + blk *= blksize; + for ( i = 0 ; i < blksize ; i++ ) { + if ( !nsectors ) + return 0; + + dprintf("Sector: %10u\n", blk); + *sectors++ = blk++; + nsectors--; + } + } + + return 0; +} + +/* + * Get the size of a block device + */ +uint64_t get_size(int devfd) +{ + uint64_t bytes; + uint32_t sects; + struct stat st; + +#ifdef BLKGETSIZE64 + if ( !ioctl(devfd, BLKGETSIZE64, &bytes) ) + return bytes; +#endif + if ( !ioctl(devfd, BLKGETSIZE, §s) ) + return (uint64_t)sects << 9; + else if ( !fstat(devfd, &st) && st.st_size ) + return st.st_size; + else + return 0; +} + + +/* + * Get device geometry and partition offset + */ +struct geometry_table { + uint64_t bytes; + struct hd_geometry g; +}; + +/* Standard floppy disk geometries, plus LS-120. Zipdisk geometry + (x/64/32) is the final fallback. I don't know what LS-240 has + as its geometry, since I don't have one and don't know anyone that does, + and Google wasn't helpful... */ +static const struct geometry_table standard_geometries[] = { + { 360*1024, { 2, 9, 40, 0 } }, + { 720*1024, { 2, 9, 80, 0 } }, + { 1200*1024, { 2, 15, 80, 0 } }, + { 1440*1024, { 2, 18, 80, 0 } }, + { 1680*1024, { 2, 21, 80, 0 } }, + { 1722*1024, { 2, 21, 80, 0 } }, + { 2880*1024, { 2, 36, 80, 0 } }, + { 3840*1024, { 2, 48, 80, 0 } }, + { 123264*1024, { 8, 32, 963, 0 } }, /* LS120 */ + { 0, {0,0,0,0} } +}; + +int +get_geometry(int devfd, uint64_t totalbytes, struct hd_geometry *geo) +{ + struct floppy_struct fd_str; + const struct geometry_table *gp; + + memset(geo, 0, sizeof *geo); + + if ( !ioctl(devfd, HDIO_GETGEO, &geo) ) { + return 0; + } else if ( !ioctl(devfd, FDGETPRM, &fd_str) ) { + geo->heads = fd_str.head; + geo->sectors = fd_str.sect; + geo->cylinders = fd_str.track; + geo->start = 0; + return 0; + } + + /* Didn't work. Let's see if this is one of the standard geometries */ + for ( gp = standard_geometries ; gp->bytes ; gp++ ) { + if ( gp->bytes == totalbytes ) { + memcpy(geo, &gp->g, sizeof *geo); + return 0; + } + } + + /* Didn't work either... assign a geometry of 64 heads, 32 sectors; this is + what zipdisks use, so this would help if someone has a USB key that + they're booting in USB-ZIP mode. */ + + geo->heads = opt.heads ?: 64; + geo->sectors = opt.sectors ?: 32; + geo->cylinders = totalbytes/(geo->heads*geo->sectors << SECTOR_SHIFT); + geo->start = 0; + + if ( !opt.sectors && !opt.heads ) + fprintf(stderr, "Warning: unable to obtain device geometry (defaulting to %d heads, %d sectors)\n" + " (on hard disks, this is usually harmless.)\n", + geo->heads, geo->sectors); + + return 1; +} + +/* + * Query the device geometry and put it into the boot sector. + * Map the file and put the map in the boot sector and file. + * Stick the "current directory" inode number into the file. + */ +void +patch_file_and_bootblock(int fd, int dirfd, int devfd) +{ + struct stat dirst; + struct hd_geometry geo; + uint32_t *sectp; + uint64_t totalbytes, totalsectors; + int nsect; + unsigned char *p, *patcharea; + int i, dw; + uint32_t csum; + + if ( fstat(dirfd, &dirst) ) { + perror("fstat dirfd"); + exit(255); /* This should never happen */ + } + + totalbytes = get_size(devfd); + get_geometry(devfd, totalbytes, &geo); + + if ( opt.heads ) + geo.heads = opt.heads; + if ( opt.sectors ) + geo.sectors = opt.sectors; + + /* Patch this into a fake FAT superblock. This isn't because + FAT is a good format in any way, it's because it lets the + early bootstrap share code with the FAT version. */ + dprintf("heads = %u, sect = %u\n", geo.heads, geo.sectors); + + totalsectors = totalbytes >> SECTOR_SHIFT; + if ( totalsectors >= 65536 ) { + set_16(boot_block+bsSectors, 0); + } else { + set_16(boot_block+bsSectors, totalsectors); + } + set_32(boot_block+bsHugeSectors, totalsectors); + + set_16(boot_block+bsBytesPerSec, SECTOR_SIZE); + set_16(boot_block+bsSecPerTrack, geo.sectors); + set_16(boot_block+bsHeads, geo.heads); + set_32(boot_block+bsHiddenSecs, geo.start); + + /* Construct the boot file */ + + dprintf("directory inode = %lu\n", (unsigned long) dirst.st_ino); + nsect = (boot_image_len+SECTOR_SIZE-1) >> SECTOR_SHIFT; + sectp = alloca(sizeof(uint32_t)*nsect); + if ( sectmap(fd, sectp, nsect) ) { + perror("bmap"); + exit(1); + } + + /* First sector need pointer in boot sector */ + set_32(boot_block+0x1F8, *sectp++); + nsect--; + + /* Search for LDLINUX_MAGIC to find the patch area */ + for ( p = boot_image ; get_32(p) != LDLINUX_MAGIC ; p += 4 ); + patcharea = p+8; + + /* Set up the totals */ + dw = boot_image_len >> 2; /* COMPLETE dwords! */ + set_16(patcharea, dw); + set_16(patcharea+2, nsect); /* Does not include the first sector! */ + set_32(patcharea+8, dirst.st_ino); /* "Current" directory */ + + /* Set the sector pointers */ + p = patcharea+12; + + memset(p, 0, 64*4); + while ( nsect-- ) { + set_32(p, *sectp++); + p += 4; + } + + /* Now produce a checksum */ + set_32(patcharea+4, 0); + + csum = LDLINUX_MAGIC; + for ( i = 0, p = boot_image ; i < dw ; i++, p += 4 ) + csum -= get_32(p); /* Negative checksum */ + + set_32(patcharea+4, csum); +} + +/* + * Install the boot block on the specified device. + * Must be run AFTER install_file()! + */ +int +install_bootblock(int fd, const char *device) +{ + struct ext2_super_block sb; + + if ( xpread(fd, &sb, sizeof sb, EXT2_SUPER_OFFSET) != sizeof sb ) { + perror("reading superblock"); + return 1; + } + + if ( sb.s_magic != EXT2_SUPER_MAGIC ) { + fprintf(stderr, "no ext2/ext3 superblock found on %s\n", device); + return 1; + } + + if ( xpwrite(fd, boot_block, boot_block_len, 0) != boot_block_len ) { + perror("writing bootblock"); + return 1; + } + + return 0; +} + +int +install_file(const char *path, int devfd, struct stat *rst) +{ + char *file; + int fd = -1, dirfd = -1, flags; + struct stat st; + + asprintf(&file, "%s%sextlinux.sys", + path, + path[0] && path[strlen(path)-1] == '/' ? "" : "/"); + if ( !file ) { + perror(program); + return 1; + } + + dirfd = open(path, O_RDONLY|O_DIRECTORY); + if ( dirfd < 0 ) { + perror(path); + goto bail; + } + + fd = open(file, O_RDONLY); + if ( fd < 0 ) { + if ( errno != ENOENT ) { + perror(file); + goto bail; + } + } else { + /* If file exist, remove the immutable flag and set u+w mode */ + if ( !ioctl(fd, EXT2_IOC_GETFLAGS, &flags) ) { + flags &= ~EXT2_IMMUTABLE_FL; + ioctl(fd, EXT2_IOC_SETFLAGS, &flags); + } + if ( !fstat(fd, &st) ) { + fchmod(fd, st.st_mode | S_IWUSR); + } + } + close(fd); + + fd = open(file, O_WRONLY|O_TRUNC|O_CREAT, S_IRUSR|S_IRGRP|S_IROTH); + if ( fd < 0 ) { + perror(file); + goto bail; + } + + /* Write it the first time */ + if ( xpwrite(fd, boot_image, boot_image_len, 0) != boot_image_len ) { + fprintf(stderr, "%s: write failure on %s\n", program, file); + goto bail; + } + + /* Map the file, and patch the initial sector accordingly */ + patch_file_and_bootblock(fd, dirfd, devfd); + + /* Write it again - this relies on the file being overwritten in place! */ + if ( xpwrite(fd, boot_image, boot_image_len, 0) != boot_image_len ) { + fprintf(stderr, "%s: write failure on %s\n", program, file); + goto bail; + } + + /* Attempt to set immutable flag and remove all write access */ + /* Only set immutable flag if file is owned by root */ + if ( !fstat(fd, &st) ) { + fchmod(fd, st.st_mode & (S_IRUSR|S_IRGRP|S_IROTH)); + if ( st.st_uid == 0 && !ioctl(fd, EXT2_IOC_GETFLAGS, &flags) ) { + flags |= EXT2_IMMUTABLE_FL; + ioctl(fd, EXT2_IOC_SETFLAGS, &flags); + } + } + + if ( fstat(fd, rst) ) { + perror(file); + goto bail; + } + + close(dirfd); + close(fd); + return 0; + + bail: + if ( dirfd >= 0 ) + close(dirfd); + if ( fd >= 0 ) + close(fd); + + return 1; +} + +int +install_loader(const char *path) +{ + struct stat st, dst, fst; + struct mntent *mnt = NULL; + int devfd, rv; + FILE *mtab; + + if ( stat(path, &st) || !S_ISDIR(st.st_mode) ) { + fprintf(stderr, "%s: Not a directory: %s\n", program, path); + return 1; + } + + devfd = -1; + + if ( (mtab = setmntent("/proc/mounts", "r")) ) { + while ( (mnt = getmntent(mtab)) ) { + if ( (!strcmp(mnt->mnt_type, "ext2") || + !strcmp(mnt->mnt_type, "ext3")) && + !stat(mnt->mnt_fsname, &dst) && + dst.st_rdev == st.st_dev ) { + fprintf(stderr, "%s is device %s\n", path, mnt->mnt_fsname); + if ( (devfd = open(mnt->mnt_fsname, O_RDWR|O_SYNC)) < 0 ) { + fprintf(stderr, "%s: cannot open device %s\n", program, mnt->mnt_fsname); + return 1; + } + break; + } + } + } + + if ( devfd < 0 ) { + /* Didn't find it in /proc/mounts, try /etc/mtab */ + if ( (mtab = setmntent("/etc/mtab", "r")) ) { + while ( (mnt = getmntent(mtab)) ) { + if ( (!strcmp(mnt->mnt_type, "ext2") || + !strcmp(mnt->mnt_type, "ext3")) && + !stat(mnt->mnt_fsname, &dst) && + dst.st_rdev == st.st_dev ) { + fprintf(stderr, "%s is device %s\n", path, mnt->mnt_fsname); + if ( (devfd = open(mnt->mnt_fsname, O_RDWR|O_SYNC)) < 0 ) { + fprintf(stderr, "%s: cannot open device %s\n", program, mnt->mnt_fsname); + return 1; + } + break; + } + } + } + } + + if ( devfd < 0 ) { + fprintf(stderr, "%s: cannot find device for path %s\n", program, path); + return 1; + } + + install_file(path, devfd, &fst); + + if ( fst.st_dev != st.st_dev ) { + fprintf(stderr, "%s: file system changed under us - aborting!\n", + program); + return 1; + } + + sync(); + rv = install_bootblock(devfd, mnt->mnt_fsname); + close(devfd); + sync(); + + endmntent(mtab); + + if ( rv ) return rv; + + return 0; +} + +int +main(int argc, char *argv[]) +{ + int o; + const char *directory; + + program = argv[0]; + + while ( (o = getopt_long(argc, argv, short_options, + long_options, NULL)) != EOF ) { + switch ( o ) { + case 'z': + opt.heads = 64; + opt.sectors = 32; + break; + case 'S': + opt.sectors = strtoul(optarg, NULL, 0); + if ( opt.sectors < 1 || opt.sectors > 63 ) { + fprintf(stderr, "%s: invalid number of sectors: %u (must be 1-63)\n", + program, opt.sectors); + exit(EX_USAGE); + } + break; + case 'H': + opt.heads = strtoul(optarg, NULL, 0); + if ( opt.heads < 1 || opt.heads > 256 ) { + fprintf(stderr, "%s: invalid number of heads: %u (must be 1-256)\n", + program, opt.heads); + exit(EX_USAGE); + } + break; + case 'h': + usage(0); + break; + case 'v': + fputs("extlinux " VERSION "\n", stderr); + exit(0); + default: + fprintf(stderr, "%s: Unknown option: %c\n", program, optopt); + exit(EX_USAGE); + } + } + + directory = argv[optind]; + + if ( !directory ) + usage(EX_USAGE); + + return install_loader(directory); +} diff --git a/syslinux/font.inc b/syslinux/font.inc new file mode 100644 index 0000000..a0f0668 --- /dev/null +++ b/syslinux/font.inc @@ -0,0 +1,131 @@ +;; $Id: font.inc,v 1.7 2004/12/27 07:04:08 hpa Exp $ +;; ----------------------------------------------------------------------- +;; +;; Copyright 1994-2004 H. Peter Anvin - All Rights Reserved +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +;; Boston MA 02111-1307, USA; either version 2 of the License, or +;; (at your option) any later version; incorporated herein by reference. +;; +;; ----------------------------------------------------------------------- + +;; +;; font.inc +;; +;; VGA font handling code +;; + + section .text + +; +; loadfont: Load a .psf font file and install it onto the VGA console +; (if we're not on a VGA screen then ignore.) It is called with +; SI and DX:AX set by routine searchdir +; +loadfont: + mov bx,trackbuf ; The trackbuf is >= 16K; the part + mov cx,[BufSafe] ; of a PSF file we care about is no + call getfssec ; more than 8K+4 bytes + + mov ax,[trackbuf] ; Magic number + cmp ax,0436h + jne lf_ret + + mov al,[trackbuf+2] ; File mode + cmp al,5 ; Font modes 0-5 supported + ja lf_ret + + mov bh,byte [trackbuf+3] ; Height of font + cmp bh,2 ; VGA minimum + jb lf_ret + cmp bh,32 ; VGA maximum + ja lf_ret + + ; Copy to font buffer + mov si,trackbuf+4 ; Start of font data + mov [VGAFontSize],bh + mov di,vgafontbuf + mov cx,(32*256) >> 2 ; Maximum size + rep movsd + + mov [UserFont], byte 1 ; Set font flag + + ; Fall through to use_font + +; +; use_font: +; This routine activates whatever font happens to be in the +; vgafontbuf, and updates the adjust_screen data. +; Must be called with CS = DS = ES +; +use_font: + test [UserFont], byte 1 ; Are we using a user-specified font? + jz adjust_screen ; If not, just do the normal stuff + + mov bp,vgafontbuf + mov bh,[VGAFontSize] + + xor bl,bl ; Needed by both INT 10h calls + cmp [UsingVGA], byte 1 ; Are we in graphics mode? + jne .text + +.graphics: + xor cx,cx + mov cl,bh ; CX = bytes/character + mov ax,480 + div cl ; Compute char rows per screen + mov dl,al + dec al + mov [VidRows],al + mov ax,1121h ; Set user character table + int 10h + mov [VidCols], byte 79 ; Always 80 bytes/line +.lf_ret: ret ; No need to call adjust_screen + +.text: + mov cx,256 + xor dx,dx + mov ax,1110h + int 10h ; Load into VGA RAM + + xor bl,bl + mov ax,1103h ; Select page 0 + int 10h + + ; Fall through to adjust_screen + +lf_ret equ use_font.lf_ret + +; +; adjust_screen: Set the internal variables associated with the screen size. +; This is a subroutine in case we're loading a custom font. +; +adjust_screen: + pusha + mov al,[BIOS_vidrows] + and al,al + jnz vidrows_ok + mov al,24 ; No vidrows in BIOS, assume 25 + ; (Remember: vidrows == rows-1) +vidrows_ok: mov [VidRows],al + mov ah,0fh + int 10h ; Read video state + dec ah ; Store count-1 (same as rows) + mov [VidCols],ah + popa + ret + + +; VGA font buffer at the end of memory (so loading a font works even +; in graphics mode, but don't put too much pressure on the .bss) + section .latebss +vgafontbuf resb 8192 + + section .data + align 2, db 0 +VGAFontSize dw 16 ; Defaults to 16 byte font +UserFont db 0 ; Using a user-specified font + + diff --git a/syslinux/genhash.pl b/syslinux/genhash.pl new file mode 100755 index 0000000..b1b4cc0 --- /dev/null +++ b/syslinux/genhash.pl @@ -0,0 +1,26 @@ +#!/usr/bin/perl +# +# Generate hash values for keywords +# + +eval { use bytes; }; + +while ( defined($keywd = <STDIN>) ) { + chomp $keywd; + + ($keywd,$keywdname) = split(/\s+/, $keywd); + $keywdname = $keywd unless ( $keywdname ); + + $l = length($keywd); + $h = 0; + for ( $i = 0 ; $i < $l ; $i++ ) { + $c = ord(substr($keywd,$i,1)) | 0x20; + $h = ((($h << 5)|($h >> 27)) ^ $c) & 0xFFFFFFFF; + } + if ( $seenhash{$h} ) { + printf STDERR "$0: hash collision (0x%08x) %s %s\n", + $h, $keywd, $seenhash{$h}; + } + $seenhash{$h} = $keywd; + printf("%-23s equ 0x%08x\n", "hash_${keywdname}", $h); +} diff --git a/syslinux/getc.inc b/syslinux/getc.inc new file mode 100644 index 0000000..c4d0b36 --- /dev/null +++ b/syslinux/getc.inc @@ -0,0 +1,290 @@ +;; $Id: getc.inc,v 1.6 2004/12/17 06:42:01 hpa Exp $ +;; ----------------------------------------------------------------------- +;; +;; Copyright 1994-2002 H. Peter Anvin - All Rights Reserved +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +;; Boston MA 02111-1307, USA; either version 2 of the License, or +;; (at your option) any later version; incorporated herein by reference. +;; +;; ----------------------------------------------------------------------- + +;; +;; getc.inc +;; +;; Simple file handling library (open, getc, ungetc) +;; + +; +; open,getc: Load a file a character at a time for parsing in a manner +; similar to the C library getc routine. Only one simultaneous +; use is supported. Note: "open" trashes the trackbuf. +; +; open: Input: mangled filename in DS:DI +; Output: ZF set on file not found or zero length +; +; openfd: Input: file handle in SI +; Output: none +; +; getc: Output: CF set on end of file +; Character loaded in AL +; +open: + call searchdir + jz openfd.ret +openfd: + pushf + mov [FBytes],ax + mov [FBytes+2],dx + mov eax,[FBytes] + add eax,SECTOR_SIZE-1 + shr eax,SECTOR_SHIFT + mov [FSectors],eax ; Number of sectors + mov [FNextClust],si ; Cluster pointer + mov ax,[EndOfGetCBuf] ; Pointer at end of buffer -> + mov [FPtr],ax ; nothing loaded yet + popf ; Restore no ZF +.ret: ret + +getc: + stc ; If we exit here -> EOF + mov ecx,[FBytes] + jecxz .ret + mov si,[FPtr] + cmp si,[EndOfGetCBuf] + jb .loaded + ; Buffer empty -- load another set + mov ecx,[FSectors] + cmp ecx,trackbufsize >> SECTOR_SHIFT + jna .oksize + mov ecx,trackbufsize >> SECTOR_SHIFT +.oksize: sub [FSectors],ecx ; Reduce remaining clusters + mov si,[FNextClust] + push es ; ES may be != DS, save old ES + push ds + pop es + mov bx,getcbuf + push bx + call getfssec ; Load a trackbuf full of data + mov [FNextClust],si ; Store new next pointer + pop si ; SI -> newly loaded data + pop es ; Restore ES +.loaded: lodsb ; Load a byte, increment SI + mov [FPtr],si ; Update next byte pointer + dec dword [FBytes] ; Update bytes left counter + clc ; Not EOF +.ret: ret + +; +; ungetc: Push a character (in AL) back into the getc buffer +; Note: if more than one byte is pushed back, this may cause +; bytes to be written below the getc buffer boundary. If there +; is a risk for this to occur, the getcbuf base address should +; be moved up. +; +ungetc: + mov si,[FPtr] + dec si + mov [si],al + mov [FPtr],si + inc dword [FBytes] + ret + +; +; skipspace: Skip leading whitespace using "getc". If we hit end-of-line +; or end-of-file, return with carry set; ZF = true of EOF +; ZF = false for EOLN; otherwise CF = ZF = 0. +; +; Otherwise AL = first character after whitespace +; +skipspace: +.loop: call getc + jc .eof + cmp al,1Ah ; DOS EOF + je .eof + cmp al,0Ah + je .eoln + cmp al,' ' + jbe .loop + ret ; CF = ZF = 0 +.eof: cmp al,al ; Set ZF + stc ; Set CF + ret +.eoln: add al,0FFh ; Set CF, clear ZF + ret + +; +; getint: Load an integer from the getc file. +; Return CF if error; otherwise return integer in EBX +; +getint: + mov di,NumBuf +.getnum: cmp di,NumBufEnd ; Last byte in NumBuf + jae .loaded + push di + call getc + pop di + jc .loaded + stosb + cmp al,'-' + jnb .getnum + call ungetc ; Unget non-numeric +.loaded: mov byte [di],0 + mov si,NumBuf + ; Fall through to parseint + +; +; parseint: Convert an integer to a number in EBX +; Get characters from string in DS:SI +; Return CF on error +; DS:SI points to first character after number +; +; Syntaxes accepted: [-]dec, [-]0+oct, [-]0x+hex, val+K, val+M +; +parseint: + push eax + push ecx + push bp + xor eax,eax ; Current digit (keep eax == al) + mov ebx,eax ; Accumulator + mov ecx,ebx ; Base + xor bp,bp ; Used for negative flag +.begin: lodsb + cmp al,'-' + jne .not_minus + xor bp,1 ; Set unary minus flag + jmp short .begin +.not_minus: + cmp al,'0' + jb .err + je .octhex + cmp al,'9' + ja .err + mov cl,10 ; Base = decimal + jmp short .foundbase +.octhex: + lodsb + cmp al,'0' + jb .km ; Value is zero + or al,20h ; Downcase + cmp al,'x' + je .ishex + cmp al,'7' + ja .err + mov cl,8 ; Base = octal + jmp short .foundbase +.ishex: + mov al,'0' ; No numeric value accrued yet + mov cl,16 ; Base = hex +.foundbase: + call unhexchar + jc .km ; Not a (hex) digit + cmp al,cl + jae .km ; Invalid for base + imul ebx,ecx ; Multiply accumulated by base + add ebx,eax ; Add current digit + lodsb + jmp short .foundbase +.km: + dec si ; Back up to last non-numeric + lodsb + or al,20h + cmp al,'k' + je .isk + cmp al,'m' + je .ism + dec si ; Back up +.fini: and bp,bp + jz .ret ; CF=0! + neg ebx ; Value was negative +.done: clc +.ret: pop bp + pop ecx + pop eax + ret +.err: stc + jmp short .ret +.isk: shl ebx,10 ; x 2^10 + jmp short .done +.ism: shl ebx,20 ; x 2^20 + jmp short .done + + + section .bss + alignb 4 +NumBuf resb 15 ; Buffer to load number +NumBufEnd resb 1 ; Last byte in NumBuf +FBytes resd 1 ; Number of bytes left in getc file +FSectors resd 1 ; Number of sectors in getc file +FNextClust resw 1 ; Pointer to next cluster in d:o +FPtr resw 1 ; Pointer to next char in buffer + +; +; unhexchar: Convert a hexadecimal digit in AL to the equivalent number; +; return CF=1 if not a hex digit +; + section .text +unhexchar: + cmp al,'0' + jb .ret ; If failure, CF == 1 already + cmp al,'9' + ja .notdigit + sub al,'0' ; CF <- 0 + ret +.notdigit: or al,20h ; upper case -> lower case + cmp al,'a' + jb .ret ; If failure, CF == 1 already + cmp al,'f' + ja .err + sub al,'a'-10 ; CF <- 0 + ret +.err: stc +.ret: ret + +; +; +; getline: Get a command line, converting control characters to spaces +; and collapsing streches to one; a space is appended to the +; end of the string, unless the line is empty. +; The line is terminated by ^J, ^Z or EOF and is written +; to ES:DI. On return, DI points to first char after string. +; CF is set if we hit EOF. +; +getline: + call skipspace + mov dl,1 ; Empty line -> empty string. + jz .eof ; eof + jc .eoln ; eoln + call ungetc +.fillloop: push dx + push di + call getc + pop di + pop dx + jc .ret ; CF set! + cmp al,' ' + jna .ctrl + xor dx,dx +.store: stosb + jmp short .fillloop +.ctrl: cmp al,10 + je .ret ; CF clear! + cmp al,26 + je .eof + and dl,dl + jnz .fillloop ; Ignore multiple spaces + mov al,' ' ; Ctrl -> space + inc dx + jmp short .store +.eoln: clc ; End of line is not end of file + jmp short .ret +.eof: stc +.ret: pushf ; We want the last char to be space! + and dl,dl + jnz .xret + mov al,' ' + stosb +.xret: popf + ret diff --git a/syslinux/gethostip.c b/syslinux/gethostip.c new file mode 100644 index 0000000..e2c6276 --- /dev/null +++ b/syslinux/gethostip.c @@ -0,0 +1,132 @@ +#ident "$Id: gethostip.c,v 1.4 2004/12/14 23:03:28 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2001-2004 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * gethostip.c + * + * Small program to use gethostbyname() to print out a hostname in + * hex and/or dotted-quad notation + */ + +#include <stdio.h> +#include <stdlib.h> +#include <netdb.h> +#include <sys/socket.h> +#include <unistd.h> +#include <sysexits.h> +#define _GNU_SOURCE /* For getopt_long */ +#include <getopt.h> + +const struct option options[] = +{ + { "hexadecimal", 0, NULL, 'x' }, + { "decimal", 0, NULL, 'd' }, + { "dotted-quad", 0, NULL, 'd' }, + { "full-output", 0, NULL, 'f' }, + { "name", 0, NULL, 'n' }, + { "help", 0, NULL, 'h' }, + { NULL, 0, NULL, 0 } +}; + +const char *program; + +void usage(int exit_code) +{ + fprintf(stderr, "Usage: %s [-dxnf] hostname/ip...\n", program); + exit(exit_code); +} + +int main(int argc, char *argv[]) +{ + int opt; + int output = 0; + int i; + char *sep; + int err = 0; + + struct hostent *host; + + program = argv[0]; + + while ( (opt = getopt_long(argc, argv, "dxfnh", options, NULL)) != -1 ) { + switch ( opt ) { + case 'd': + output |= 2; /* Decimal output */ + break; + case 'x': + output |= 4; /* Hexadecimal output */ + break; + case 'n': + output |= 1; /* Canonical name output */ + break; + case 'f': + output = 7; /* Full output */ + break; + case 'h': + usage(0); + break; + default: + usage(EX_USAGE); + break; + } + } + + if ( optind == argc ) + usage(EX_USAGE); + + if ( output == 0 ) + output = 7; /* Default output */ + + for ( i = optind ; i < argc ; i++ ) { + sep = ""; + host = gethostbyname(argv[i]); + if ( !host ) { + herror(argv[i]); + err = 1; + continue; + } + + if ( host->h_addrtype != AF_INET || host->h_length != 4 ) { + fprintf(stderr, "%s: No IPv4 address associated with name\n", argv[i]); + err = 1; + continue; + } + + if ( output & 1 ) { + printf("%s%s", sep, host->h_name); + sep = " "; + } + + if ( output & 2 ) { + printf("%s%u.%u.%u.%u", sep, + ((unsigned char *)host->h_addr)[0], + ((unsigned char *)host->h_addr)[1], + ((unsigned char *)host->h_addr)[2], + ((unsigned char *)host->h_addr)[3]); + sep = " "; + } + + if ( output & 4 ) { + printf("%s%02X%02X%02X%02X", sep, + ((unsigned char *)host->h_addr)[0], + ((unsigned char *)host->h_addr)[1], + ((unsigned char *)host->h_addr)[2], + ((unsigned char *)host->h_addr)[3]); + sep = " "; + } + + putchar('\n'); + } + + return err; +} diff --git a/syslinux/graphics.inc b/syslinux/graphics.inc new file mode 100644 index 0000000..0aa1943 --- /dev/null +++ b/syslinux/graphics.inc @@ -0,0 +1,336 @@ +;; $Id: graphics.inc,v 1.4 2004/12/17 06:42:01 hpa Exp $ +;; ----------------------------------------------------------------------- +;; +;; Copyright 1994-2002 H. Peter Anvin - All Rights Reserved +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +;; Boston MA 02111-1307, USA; either version 2 of the License, or +;; (at your option) any later version; incorporated herein by reference. +;; +;; ----------------------------------------------------------------------- + +; ---------------------------------------------------------------------------- +; VGA splash screen code +; ---------------------------------------------------------------------------- + +; +; vgadisplayfile: +; Display a graphical splash screen. +; +; Input: +; +; SI = cluster/socket pointer +; + section .text + +vgadisplayfile: + mov [VGACluster],si + push es + + ; This is a cheap and easy way to make sure the screen is + ; cleared in case we were in graphics mode already + call vgaclearmode + call vgasetmode + jnz .error_nz + +.graphalready: + mov ax,xfer_buf_seg ; Use as temporary storage + mov es,ax + mov fs,ax + + call vgagetchunk ; Get the first chunk + + ; The header WILL be in the first chunk. + cmp dword [es:xbs_vgabuf],0x1413f33d ; Magic number +.error_nz: jne .error + mov ax,[es:xbs_vgabuf+4] + mov [GraphXSize],ax + + mov dx,xbs_vgabuf+8 ; Color map offset + mov ax,1012h ; Set RGB registers + xor bx,bx ; First register number + mov cx,16 ; 16 registers + int 10h + +.movecursor: + mov ax,[es:xbs_vgabuf+6] ; Number of pixel rows + mov dx,[VGAFontSize] + add ax,dx + dec ax + div dl + xor dx,dx ; Set column to 0 + cmp al,[VidRows] + jb .rowsok + mov al,[VidRows] + dec al +.rowsok: + mov dh,al + mov ah,2 + xor bx,bx + int 10h ; Set cursor below image + + mov cx,[es:xbs_vgabuf+6] ; Number of graphics rows + + mov si,xbs_vgabuf+8+3*16 ; Beginning of pixel data + mov word [VGAPos],0 + +.drawpixelrow: + push cx + mov cx,[GraphXSize] + mov di,xbs_vgatmpbuf ; Row buffer + call rledecode ; Decode one row + push si + mov si,xbs_vgatmpbuf + mov di,si + add di,[GraphXSize] + mov cx,640/4 + xor eax,eax + rep stosd ; Clear rest of row + mov di,0A000h ; VGA segment + mov es,di + mov di,[VGAPos] + mov bp,640 + call packedpixel2vga + add word [VGAPos],byte 80 ; Advance to next pixel row + push fs + pop es + pop si + pop cx + loop .drawpixelrow + +.error: + pop es + ret + +; +; rledecode: +; Decode a pixel row in RLE16 format. +; +; FS:SI -> input +; CX -> pixel count +; ES:DI -> output (packed pixel) +; +rledecode: + shl esi,1 ; Nybble pointer + xor dl,dl ; Last pixel +.loop: + call .getnybble + cmp al,dl + je .run ; Start of run sequence + stosb + mov dl,al + dec cx + jnz .loop +.done: + shr esi,1 + adc si,byte 0 + ret +.run: + xor bx,bx + call .getnybble + and al,al + jz .longrun + mov bl,al +.dorun: + push cx + mov cx,bx + mov al,dl + rep stosb + pop cx + sub cx,bx + ja .loop + jmp short .done +.longrun: + call .getnybble + mov ah,al + call .getnybble + shl al,4 + or al,ah + mov bl,al + add bx,16 + jmp short .dorun +.getnybble: + shr esi,1 + fs lodsb + jc .high + dec si + and al,0Fh + stc + rcl esi,1 + ret +.high: + shr al,4 + cmp si,xbs_vgabuf+trackbufsize ; Chunk overrun + jb .nonewchunk + call vgagetchunk + mov si,xbs_vgabuf ; Start at beginning of buffer +.nonewchunk: + shl esi,1 + ret + +; +; vgagetchunk: +; Get a new trackbufsize chunk of VGA image data +; +; On input, ES is assumed to point to the buffer segment. +; +vgagetchunk: + pushad + mov si,[VGACluster] + and si,si + jz .eof ; EOF overrun, not much to do... + + mov cx,[BufSafe] ; One trackbuf worth of data + mov bx,xbs_vgabuf + call getfssec + + jnc .noteof + xor si,si +.noteof: mov [VGACluster],si + +.eof: popad + ret + +; +; packedpixel2vga: +; Convert packed-pixel to VGA bitplanes +; +; FS:SI -> packed pixel string +; BP -> pixel count (multiple of 8) +; ES:DI -> output +; +packedpixel2vga: + mov dx,3C4h ; VGA Sequencer Register select port + mov al,2 ; Sequencer mask + out dx,al ; Select the sequencer mask + inc dx ; VGA Sequencer Register data port + mov al,1 + mov bl,al +.planeloop: + pusha + out dx,al +.loop1: + mov cx,8 +.loop2: + xchg cx,bx + fs lodsb + shr al,cl + rcl ch,1 ; VGA is bigendian. Sigh. + xchg cx,bx + loop .loop2 + mov al,bh + stosb + sub bp,byte 8 + ja .loop1 + popa + inc bl + shl al,1 + cmp bl,4 + jbe .planeloop + ret + +; +; vgasetmode: +; Enable VGA graphics, if possible; return ZF=1 on success +; DS must be set to the base segment; ES is set to DS. +; +vgasetmode: + push ds + pop es + mov ax,1A00h ; Get video card and monitor + xor bx,bx + int 10h + sub bl, 7 ; BL=07h and BL=08h OK + cmp bl, 1 + ja .error ; ZF=0 +; mov bx,TextColorReg +; mov dx,1009h ; Read color registers +; int 10h + mov ax,0012h ; Set mode = 640x480 VGA 16 colors + int 10h + mov dx,linear_color + mov ax,1002h ; Write color registers + int 10h + mov [UsingVGA], byte 1 + + call use_font ; Set graphics font/data + mov byte [ScrollAttribute], 00h + + xor ax,ax ; Set ZF +.error: + ret + +; +; vgaclearmode: +; Disable VGA graphics. It is not safe to assume any value +; for DS or ES. +; +vgaclearmode: + push ds + push es + pushad + mov ax,cs + mov ds,ax + mov es,ax + cmp [UsingVGA], byte 1 + jne .done + mov ax,0003h ; Return to normal video mode + int 10h +; mov dx,TextColorReg ; Restore color registers +; mov ax,1002h +; int 10h + mov [UsingVGA], byte 0 + + call use_font ; Restore text font/data + mov byte [ScrollAttribute], 07h +.done: + popad + pop es + pop ds + ret + +; +; vgashowcursor/vgahidecursor: +; If VGA graphics is enabled, draw a cursor/clear a cursor +; +vgashowcursor: + pushad + mov al,'_' + jmp short vgacursorcommon +vgahidecursor: + pushad + mov al,' ' +vgacursorcommon: + cmp [UsingVGA], byte 1 + jne .done + mov ah,09h + mov bx,0007h + mov cx,1 + int 10h +.done: + popad + ret + + + section .data + ; Map colors to consecutive DAC registers +linear_color db 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0 +UsingVGA db 0 + + section .bss + alignb 2 +GraphXSize resw 1 ; Width of splash screen file +VGAPos resw 1 ; Pointer into VGA memory +VGACluster resw 1 ; Cluster pointer for VGA image file +VGAFilePtr resw 1 ; Pointer into VGAFileBuf +TextColorReg resb 17 ; VGA color registers for text mode +%if IS_SYSLINUX +VGAFileBuf resb FILENAME_MAX+2 ; Unmangled VGA image name +%else +VGAFileBuf resb FILENAME_MAX ; Unmangled VGA image name +%endif +VGAFileBufEnd equ $ +VGAFileMBuf resb FILENAME_MAX ; Mangled VGA image name + diff --git a/syslinux/highmem.inc b/syslinux/highmem.inc new file mode 100644 index 0000000..c355f0c --- /dev/null +++ b/syslinux/highmem.inc @@ -0,0 +1,145 @@ +;; $Id: highmem.inc,v 1.4 2004/12/17 06:42:01 hpa Exp $ +;; ----------------------------------------------------------------------- +;; +;; Copyright 1994-2004 H. Peter Anvin - All Rights Reserved +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +;; Boston MA 02111-1307, USA; either version 2 of the License, or +;; (at your option) any later version; incorporated herein by reference. +;; +;; ----------------------------------------------------------------------- + +;; +;; highmem.inc +;; +;; Probe for the size of high memory. This can be overridden by a +;; mem= command on the command line while booting a new kernel. +;; + + section .text + +; +; This is set up as a subroutine; it will set up the global variable +; HighMemSize. All registers are preserved. Assumes DS == CS. +; +highmemsize: + push es + pushad + +; +; First, try INT 15:E820 (get BIOS memory map) +; +get_e820: + xor ebx,ebx ; Start with first record + mov dword [E820Max],-(1 << 20) ; Max amount of high memory + mov dword [E820Mem],ebx ; Detected amount of high memory + mov es,bx ; Need ES = DS = 0 for now + jmp short .do_e820 ; Skip "at end" check first time! +.int_loop: and ebx,ebx ; If we're back at beginning... + jz .e820_done ; ... we're done +.do_e820: mov eax,0000E820h + mov edx,534D4150h ; "SMAP" backwards + xor ecx,ecx + mov cl,20 ; ECX <- 20 + mov di,E820Buf + int 15h + jnc .no_carry + ; If carry, ebx == 0 means error, ebx != 0 means we're done + and ebx,ebx + jnz .e820_done + jmp no_e820 +.no_carry: + cmp eax,534D4150h + jne no_e820 +; +; Look for a memory block starting at <= 1 MB and continuing upward +; + cmp dword [E820Buf+4], byte 0 + ja .int_loop ; Start >= 4 GB? + mov edx, (1 << 20) + sub edx, [E820Buf] + jnb .ram_range ; Start >= 1 MB? + ; If we get here, it starts > 1 MB but < 4 GB; if this is a + ; *non*-memory range, remember this as unusable; some BIOSes + ; get the length of primary RAM wrong! + cmp dword [E820Buf+16], byte 1 + je .int_loop ; If it's memory, don't worry about it + neg edx ; This means what for memory limit? + cmp edx,[E820Max] ; Better or worse + jnb .int_loop + mov [E820Max],edx + jmp .int_loop + +.ram_range: + stc + sbb eax,eax ; eax <- 0xFFFFFFFF + cmp dword [E820Buf+12], byte 0 + ja .huge ; Size >= 4 GB + mov eax, [E820Buf+8] +.huge: sub eax, edx ; Adjust size to start at 1 MB + jbe .int_loop ; Completely below 1 MB? + + ; Now EAX contains the size of memory 1 MB...up + cmp dword [E820Buf+16], byte 1 + jne .int_loop ; High memory isn't usable memory!!!! + + ; We're good! + mov [E820Mem],eax + jmp .int_loop ; Still need to add low 1 MB + +.e820_done: + mov eax,[E820Mem] + and eax,eax + jz no_e820 ; Nothing found by E820? + cmp eax,[E820Max] ; Make sure we're not limited + jna got_highmem_add1mb + mov eax,[E820Max] + jmp got_highmem_add1mb + +; +; INT 15:E820 failed. Try INT 15:E801. +; +no_e820: + mov ax,0e801h ; Query high memory (semi-recent) + int 15h + jc no_e801 + cmp ax,3c00h + ja no_e801 ; > 3C00h something's wrong with this call + jb e801_hole ; If memory hole we can only use low part + + mov ax,bx + shl eax,16 ; 64K chunks + add eax,(16 << 20) ; Add first 16M + jmp short got_highmem + +; +; INT 15:E801 failed. Try INT 15:88. +; +no_e801: + mov ah,88h ; Query high memory (oldest) + int 15h + cmp ax,14*1024 ; Don't trust memory >15M + jna e801_hole + mov ax,14*1024 +e801_hole: + and eax,0ffffh + shl eax,10 ; Convert from kilobytes +got_highmem_add1mb: + add eax,(1 << 20) ; First megabyte +got_highmem: +%if HIGHMEM_SLOP != 0 + sub eax,HIGHMEM_SLOP +%endif + mov [HighMemSize],eax + popad + pop es + ret ; Done! + + section .bss + alignb 4 +E820Buf resd 5 ; INT 15:E820 data buffer +E820Mem resd 1 ; Memory detected by E820 +E820Max resd 1 ; Is E820 memory capped? +HighMemSize resd 1 ; End of memory pointer (bytes) diff --git a/syslinux/init.inc b/syslinux/init.inc new file mode 100644 index 0000000..2976546 --- /dev/null +++ b/syslinux/init.inc @@ -0,0 +1,67 @@ +; -*- fundamental -*- +; ----------------------------------------------------------------------- +; +; Copyright 2004 H. Peter Anvin - All Rights Reserved +; +; This program is free software; you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +; Boston MA 02111-1307, USA; either version 2 of the License, or +; (at your option) any later version; incorporated herein by reference. +; +; ----------------------------------------------------------------------- +; $Id: init.inc,v 1.1 2004/12/19 07:08:48 hpa Exp $ + +; +; init.inc +; +; Common initialization code (inline) +; + + section .text +common_init: + ; Now set up screen parameters + call adjust_screen + + ; Wipe the F-key area + mov al,NULLFILE + mov di,FKeyName + mov cx,10*(1 << FILENAME_MAX_LG2) + rep stosb + + mov si,linuxauto_cmd ; Default command: "linux auto" + mov di,default_cmd + mov cx,linuxauto_len + rep movsb + + mov di,KbdMap ; Default keymap 1:1 + xor al,al + inc ch ; CX <- 256 +mkkeymap: stosb + inc al + loop mkkeymap + +; +; Clear Files structures +; + mov di,Files + mov cx,(MAX_OPEN*open_file_t_size)/4 + xor eax,eax + rep stosd + +%if IS_PXELINUX + mov di,Files+tftp_pktbuf + mov cx,MAX_OPEN +.setbufptr: + mov [di],ax + add di,open_file_t_size + add ax,PKTBUF_SIZE + loop .setbufptr +%endif + + section .data +linuxauto_cmd db 'linux auto',0 +linuxauto_len equ $-linuxauto_cmd + + section .text ; This is an inline file... + diff --git a/syslinux/isolinux-debug.bin b/syslinux/isolinux-debug.bin new file mode 100644 index 0000000000000000000000000000000000000000..0b0ed6584d742d70c1f443c6fb63a163b326927c GIT binary patch literal 11084 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 JHA?~j_`l#q4*dWC literal 0 HcmV?d00001 diff --git a/syslinux/isolinux.asm b/syslinux/isolinux.asm new file mode 100644 index 0000000..c98cef5 --- /dev/null +++ b/syslinux/isolinux.asm @@ -0,0 +1,1656 @@ +; -*- fundamental -*- (asm-mode sucks) +; $Id: isolinux.asm,v 1.113 2004/12/30 21:16:04 hpa Exp $ +; **************************************************************************** +; +; isolinux.asm +; +; A program to boot Linux kernels off a CD-ROM using the El Torito +; boot standard in "no emulation" mode, making the entire filesystem +; available. It is based on the SYSLINUX boot loader for MS-DOS +; floppies. +; +; Copyright (C) 1994-2004 H. Peter Anvin +; +; This program is free software; you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +; Boston MA 02111-1307, USA; either version 2 of the License, or +; (at your option) any later version; incorporated herein by reference. +; +; **************************************************************************** + +%define IS_ISOLINUX 1 +%include "macros.inc" +%include "config.inc" +%include "kernel.inc" +%include "bios.inc" +%include "tracers.inc" +%include "layout.inc" + +; +; Some semi-configurable constants... change on your own risk. +; +my_id equ isolinux_id +FILENAME_MAX_LG2 equ 8 ; log2(Max filename size Including final null) +FILENAME_MAX equ (1 << FILENAME_MAX_LG2) +NULLFILE equ 0 ; Zero byte == null file name +NULLOFFSET equ 0 ; Position in which to look +retry_count equ 6 ; How patient are we with the BIOS? +%assign HIGHMEM_SLOP 128*1024 ; Avoid this much memory near the top +MAX_OPEN_LG2 equ 6 ; log2(Max number of open files) +MAX_OPEN equ (1 << MAX_OPEN_LG2) +SECTOR_SHIFT equ 11 ; 2048 bytes/sector (El Torito requirement) +SECTOR_SIZE equ (1 << SECTOR_SHIFT) + +; +; This is what we need to do when idle +; +%macro RESET_IDLE 0 + ; Nothing +%endmacro +%macro DO_IDLE 0 + ; Nothing +%endmacro + +; +; The following structure is used for "virtual kernels"; i.e. LILO-style +; option labels. The options we permit here are `kernel' and `append +; Since there is no room in the bottom 64K for all of these, we +; stick them at vk_seg:0000 and copy them down before we need them. +; + struc vkernel +vk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!** +vk_rname: resb FILENAME_MAX ; Real name +vk_appendlen: resw 1 + alignb 4 +vk_append: resb max_cmd_len+1 ; Command line + alignb 4 +vk_end: equ $ ; Should be <= vk_size + endstruc + +; +; Segment assignments in the bottom 640K +; 0000h - main code/data segment (and BIOS segment) +; +real_mode_seg equ 3000h +vk_seg equ 2000h ; Virtual kernels +xfer_buf_seg equ 1000h ; Bounce buffer for I/O to high mem +comboot_seg equ real_mode_seg ; COMBOOT image loading zone + +; +; File structure. This holds the information for each currently open file. +; + struc open_file_t +file_sector resd 1 ; Sector pointer (0 = structure free) +file_left resd 1 ; Number of sectors left + endstruc + +%ifndef DEPEND +%if (open_file_t_size & (open_file_t_size-1)) +%error "open_file_t is not a power of 2" +%endif +%endif + + struc dir_t +dir_lba resd 1 ; Directory start (LBA) +dir_len resd 1 ; Length in bytes +dir_clust resd 1 ; Length in clusters + endstruc + +; --------------------------------------------------------------------------- +; BEGIN CODE +; --------------------------------------------------------------------------- + +; +; Memory below this point is reserved for the BIOS and the MBR +; + section .earlybss +trackbufsize equ 8192 +trackbuf resb trackbufsize ; Track buffer goes here +getcbuf resb trackbufsize +; ends at 4800h + + section .bss + alignb 4 +ISOFileName resb 64 ; ISO filename canonicalization buffer +ISOFileNameEnd equ $ +CurDir resb dir_t_size ; Current directory +RootDir resb dir_t_size ; Root directory +FirstSecSum resd 1 ; Checksum of bytes 64-2048 +ImageDwords resd 1 ; isolinux.bin size, dwords +InitStack resd 1 ; Initial stack pointer (SS:SP) +DiskSys resw 1 ; Last INT 13h call +ImageSectors resw 1 ; isolinux.bin size, sectors +DiskError resb 1 ; Error code for disk I/O +DriveNo resb 1 ; CD-ROM BIOS drive number +ISOFlags resb 1 ; Flags for ISO directory search +RetryCount resb 1 ; Used for disk access retries + +_spec_start equ $ + +; +; El Torito spec packet +; + + alignb 8 +spec_packet: resb 1 ; Size of packet +sp_media: resb 1 ; Media type +sp_drive: resb 1 ; Drive number +sp_controller: resb 1 ; Controller index +sp_lba: resd 1 ; LBA for emulated disk image +sp_devspec: resw 1 ; IDE/SCSI information +sp_buffer: resw 1 ; User-provided buffer +sp_loadseg: resw 1 ; Load segment +sp_sectors: resw 1 ; Sector count +sp_chs: resb 3 ; Simulated CHS geometry +sp_dummy: resb 1 ; Scratch, safe to overwrite + +; +; EBIOS drive parameter packet +; + alignb 8 +drive_params: resw 1 ; Buffer size +dp_flags: resw 1 ; Information flags +dp_cyl: resd 1 ; Physical cylinders +dp_head: resd 1 ; Physical heads +dp_sec: resd 1 ; Physical sectors/track +dp_totalsec: resd 2 ; Total sectors +dp_secsize: resw 1 ; Bytes per sector +dp_dpte: resd 1 ; Device Parameter Table +dp_dpi_key: resw 1 ; 0BEDDh if rest valid +dp_dpi_len: resb 1 ; DPI len + resb 1 + resw 1 +dp_bus: resb 4 ; Host bus type +dp_interface: resb 8 ; Interface type +db_i_path: resd 2 ; Interface path +db_d_path: resd 2 ; Device path + resb 1 +db_dpi_csum: resb 1 ; Checksum for DPI info + +; +; EBIOS disk address packet +; + alignb 8 +dapa: resw 1 ; Packet size +.count: resw 1 ; Block count +.off: resw 1 ; Offset of buffer +.seg: resw 1 ; Segment of buffer +.lba: resd 2 ; LBA (LSW, MSW) + +; +; Spec packet for disk image emulation +; + alignb 8 +dspec_packet: resb 1 ; Size of packet +dsp_media: resb 1 ; Media type +dsp_drive: resb 1 ; Drive number +dsp_controller: resb 1 ; Controller index +dsp_lba: resd 1 ; LBA for emulated disk image +dsp_devspec: resw 1 ; IDE/SCSI information +dsp_buffer: resw 1 ; User-provided buffer +dsp_loadseg: resw 1 ; Load segment +dsp_sectors: resw 1 ; Sector count +dsp_chs: resb 3 ; Simulated CHS geometry +dsp_dummy: resb 1 ; Scratch, safe to overwrite + + alignb 4 +_spec_end equ $ +_spec_len equ _spec_end - _spec_start + + alignb open_file_t_size +Files resb MAX_OPEN*open_file_t_size + +; +; Constants for the xfer_buf_seg +; +; The xfer_buf_seg is also used to store message file buffers. We +; need two trackbuffers (text and graphics), plus a work buffer +; for the graphics decompressor. +; +xbs_textbuf equ 0 ; Also hard-coded, do not change +xbs_vgabuf equ trackbufsize +xbs_vgatmpbuf equ 2*trackbufsize + + section .text +;; +;; Primary entry point. Because BIOSes are buggy, we only load the first +;; CD-ROM sector (2K) of the file, so the number one priority is actually +;; loading the rest. +;; +bootsec equ $ + +StackBuf equ $-44 + +_start: ; Far jump makes sure we canonicalize the address + cli + jmp 0:_start1 + times 8-($-$$) nop ; Pad to file offset 8 + + ; This table hopefully gets filled in by mkisofs using the + ; -boot-info-table option. If not, the values in this + ; table are default values that we can use to get us what + ; we need, at least under a certain set of assumptions. +bi_pvd: dd 16 ; LBA of primary volume descriptor +bi_file: dd 0 ; LBA of boot file +bi_length: dd 0xdeadbeef ; Length of boot file +bi_csum: dd 0xdeadbeef ; Checksum of boot file +bi_reserved: times 10 dd 0xdeadbeef ; Reserved + +_start1: mov [cs:InitStack],sp ; Save initial stack pointer + mov [cs:InitStack+2],ss + xor ax,ax + mov ss,ax + mov sp,StackBuf ; Set up stack + mov ds,ax + mov es,ax + mov fs,ax + mov gs,ax + sti + + cld + ; Show signs of life + mov si,syslinux_banner + call writestr +%ifdef DEBUG_MESSAGES + mov si,copyright_str + call writestr +%endif + + ; + ; Before modifying any memory, get the checksum of bytes + ; 64-2048 + ; +initial_csum: xor edi,edi + mov si,_start1 + mov cx,(SECTOR_SIZE-64) >> 2 +.loop: lodsd + add edi,eax + loop .loop + mov [FirstSecSum],edi + + mov [DriveNo],dl +%ifdef DEBUG_MESSAGES + mov si,startup_msg + call writemsg + mov al,dl + call writehex2 + call crlf +%endif + ; + ; Initialize spec packet buffers + ; + mov di,_spec_start + mov cx,_spec_len >> 2 + xor eax,eax + rep stosd + + ; Initialize length field of the various packets + mov byte [spec_packet],13h + mov byte [drive_params],30 + mov byte [dapa],16 + mov byte [dspec_packet],13h + + ; Other nonzero fields + inc word [dsp_sectors] + + ; Now figure out what we're actually doing + ; Note: use passed-in DL value rather than 7Fh because + ; at least some BIOSes will get the wrong value otherwise + mov ax,4B01h ; Get disk emulation status + mov dl,[DriveNo] + mov si,spec_packet + int 13h + jc award_hack ; changed for BrokenAwardHack + mov dl,[DriveNo] + cmp [sp_drive],dl ; Should contain the drive number + jne spec_query_failed + +%ifdef DEBUG_MESSAGES + mov si,spec_ok_msg + call writemsg + mov al,byte [sp_drive] + call writehex2 + call crlf +%endif + +found_drive: + ; Alright, we have found the drive. Now, try to find the + ; boot file itself. If we have a boot info table, life is + ; good; if not, we have to make some assumptions, and try + ; to figure things out ourselves. In particular, the + ; assumptions we have to make are: + ; - single session only + ; - only one boot entry (no menu or other alternatives) + + cmp dword [bi_file],0 ; Address of code to load + jne found_file ; Boot info table present :) + +%ifdef DEBUG_MESSAGES + mov si,noinfotable_msg + call writemsg +%endif + + ; No such luck. See if the the spec packet contained one. + mov eax,[sp_lba] + and eax,eax + jz set_file ; Good enough + +%ifdef DEBUG_MESSAGES + mov si,noinfoinspec_msg + call writemsg +%endif + + ; No such luck. Get the Boot Record Volume, assuming single + ; session disk, and that we're the first entry in the chain + mov eax,17 ; Assumed address of BRV + mov bx,trackbuf + call getonesec + + mov eax,[trackbuf+47h] ; Get boot catalog address + mov bx,trackbuf + call getonesec ; Get boot catalog + + mov eax,[trackbuf+28h] ; First boot entry + ; And hope and pray this is us... + + ; Some BIOSes apparently have limitations on the size + ; that may be loaded (despite the El Torito spec being very + ; clear on the fact that it must all be loaded.) Therefore, + ; we load it ourselves, and *bleep* the BIOS. + +set_file: + mov [bi_file],eax + +found_file: + ; Set up boot file sizes + mov eax,[bi_length] + sub eax,SECTOR_SIZE-3 + shr eax,2 ; bytes->dwords + mov [ImageDwords],eax ; boot file dwords + add eax,(2047 >> 2) + shr eax,9 ; dwords->sectors + mov [ImageSectors],ax ; boot file sectors + + mov eax,[bi_file] ; Address of code to load + inc eax ; Don't reload bootstrap code +%ifdef DEBUG_MESSAGES + mov si,offset_msg + call writemsg + call writehex8 + call crlf +%endif + + ; Just in case some BIOSes have problems with + ; segment wraparound, use the normalized address + mov bx,((7C00h+2048) >> 4) + mov es,bx + xor bx,bx + mov bp,[ImageSectors] +%ifdef DEBUG_MESSAGES + push ax + mov si,size_msg + call writemsg + mov ax,bp + call writehex4 + call crlf + pop ax +%endif + call getlinsec + + push ds + pop es + +%ifdef DEBUG_MESSAGES + mov si,loaded_msg + call writemsg +%endif + + ; Verify the checksum on the loaded image. +verify_image: + mov si,7C00h+2048 + mov bx,es + mov ecx,[ImageDwords] + mov edi,[FirstSecSum] ; First sector checksum +.loop es lodsd + add edi,eax + dec ecx + jz .done + and si,si + jnz .loop + ; SI wrapped around, advance ES + add bx,1000h + mov es,bx + jmp short .loop +.done: mov ax,ds + mov es,ax + cmp [bi_csum],edi + je integrity_ok + + mov si,checkerr_msg + call writemsg + jmp kaboom + +integrity_ok: +%ifdef DEBUG_MESSAGES + mov si,allread_msg + call writemsg +%endif + jmp all_read ; Jump to main code + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Start of BrokenAwardHack --- 10-nov-2002 Knut_Petersen@t-online.de +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; There is a problem with certain versions of the AWARD BIOS ... +;; the boot sector will be loaded and executed correctly, but, because the +;; int 13 vector points to the wrong code in the BIOS, every attempt to +;; load the spec packet will fail. We scan for the equivalent of +;; +;; mov ax,0201h +;; mov bx,7c00h +;; mov cx,0006h +;; mov dx,0180h +;; pushf +;; call <direct far> +;; +;; and use <direct far> as the new vector for int 13. The code above is +;; used to load the boot code into ram, and there should be no reason +;; for anybody to change it now or in the future. There are no opcodes +;; that use encodings relativ to IP, so scanning is easy. If we find the +;; code above in the BIOS code we can be pretty sure to run on a machine +;; with an broken AWARD BIOS ... +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;; +%ifdef DEBUG_MESSAGES ;; + ;; +award_notice db "Trying BrokenAwardHack first ...",CR,LF,0 ;; +award_not_orig db "BAH: Original Int 13 vector : ",0 ;; +award_not_new db "BAH: Int 13 vector changed to : ",0 ;; +award_not_succ db "BAH: SUCCESS",CR,LF,0 ;; +award_not_fail db "BAH: FAILURE" ;; +award_not_crlf db CR,LF,0 ;; + ;; +%endif ;; + ;; +award_oldint13 dd 0 ;; +award_string db 0b8h,1,2,0bbh,0,7ch,0b9h,6,0,0bah,80h,1,09ch,09ah ;; + ;; + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +award_hack: mov si,spec_err_msg ; Moved to this place from + call writemsg ; spec_query_faild + ; +%ifdef DEBUG_MESSAGES ; + ; + mov si,award_notice ; display our plan + call writemsg ; + mov si,award_not_orig ; display original int 13 + call writemsg ; vector +%endif ; + mov eax,[13h*4] ; + mov [award_oldint13],eax ; + ; +%ifdef DEBUG_MESSAGES ; + ; + call writehex8 ; + mov si,award_not_crlf ; + call writestr ; +%endif ; + push es ; save ES + mov ax,0f000h ; ES = BIOS Seg + mov es,ax ; + cld ; + xor di,di ; start at ES:DI = f000:0 +award_loop: push di ; save DI + mov si,award_string ; scan for award_string + mov cx,7 ; length of award_string = 7dw + repz cmpsw ; compare + pop di ; restore DI + jcxz award_found ; jmp if found + inc di ; not found, inc di + jno award_loop ; + ; +award_failed: pop es ; No, not this way :-(( +award_fail2: ; + ; +%ifdef DEBUG_MESSAGES ; + ; + mov si,award_not_fail ; display failure ... + call writemsg ; +%endif ; + mov eax,[award_oldint13] ; restore the original int + or eax,eax ; 13 vector if there is one + jz spec_query_failed ; and try other workarounds + mov [13h*4],eax ; + jmp spec_query_failed ; + ; +award_found: mov eax,[es:di+0eh] ; load possible int 13 addr + pop es ; restore ES + ; + cmp eax,[award_oldint13] ; give up if this is the + jz award_failed ; active int 13 vector, + mov [13h*4],eax ; otherwise change 0:13h*4 + ; + ; +%ifdef DEBUG_MESSAGES ; + ; + push eax ; display message and + mov si,award_not_new ; new vector address + call writemsg ; + pop eax ; + call writehex8 ; + mov si,award_not_crlf ; + call writestr ; +%endif ; + mov ax,4B01h ; try to read the spec packet + mov dl,[DriveNo] ; now ... it should not fail + mov si,spec_packet ; any longer + int 13h ; + jc award_fail2 ; + ; +%ifdef DEBUG_MESSAGES ; + ; + mov si,award_not_succ ; display our SUCCESS + call writemsg ; +%endif ; + jmp found_drive ; and leave error recovery code + ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; End of BrokenAwardHack ---- 10-nov-2002 Knut_Petersen@t-online.de +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + + ; INT 13h, AX=4B01h, DL=<passed in value> failed. + ; Try to scan the entire 80h-FFh from the end. + +spec_query_failed: + + ; some code moved to BrokenAwardHack + + mov dl,0FFh +.test_loop: pusha + mov ax,4B01h + mov si,spec_packet + mov byte [si],13 ; Size of buffer + int 13h + popa + jc .still_broken + + mov si,maybe_msg + call writemsg + mov al,dl + call writehex2 + call crlf + + cmp byte [sp_drive],dl + jne .maybe_broken + + ; Okay, good enough... + mov si,alright_msg + call writemsg + mov [DriveNo],dl +.found_drive: jmp found_drive + + ; Award BIOS 4.51 apparently passes garbage in sp_drive, + ; but if this was the drive number originally passed in + ; DL then consider it "good enough" +.maybe_broken: + cmp byte [DriveNo],dl + je .found_drive + +.still_broken: dec dx + cmp dl, 80h + jnb .test_loop + + ; No spec packet anywhere. Some particularly pathetic + ; BIOSes apparently don't even implement function + ; 4B01h, so we can't query a spec packet no matter + ; what. If we got a drive number in DL, then try to + ; use it, and if it works, then well... + mov dl,[DriveNo] + cmp dl,81h ; Should be 81-FF at least + jb fatal_error ; If not, it's hopeless + + ; Write a warning to indicate we're on *very* thin ice now + mov si,nospec_msg + call writemsg + mov al,dl + call writehex2 + call crlf + mov si,trysbm_msg + call writemsg + jmp .found_drive ; Pray that this works... + +fatal_error: + mov si,nothing_msg + call writemsg + +.norge: jmp short .norge + + ; Information message (DS:SI) output + ; Prefix with "isolinux: " + ; +writemsg: push ax + push si + mov si,isolinux_str + call writestr + pop si + call writestr + pop ax + ret + +; +; Write a character to the screen. There is a more "sophisticated" +; version of this in the subsequent code, so we patch the pointer +; when appropriate. +; + +writechr: + jmp near writechr_simple ; 3-byte jump + +writechr_simple: + pushfd + pushad + mov ah,0Eh + xor bx,bx + int 10h + popad + popfd + ret + +; +; Get one sector. Convenience entry point. +; +getonesec: + mov bp,1 + ; Fall through to getlinsec + +; +; Get linear sectors - EBIOS LBA addressing, 2048-byte sectors. +; +; Note that we can't always do this as a single request, because at least +; Phoenix BIOSes has a 127-sector limit. To be on the safe side, stick +; to 32 sectors (64K) per request. +; +; Input: +; EAX - Linear sector number +; ES:BX - Target buffer +; BP - Sector count +; +getlinsec: + mov si,dapa ; Load up the DAPA + mov [si+4],bx + mov bx,es + mov [si+6],bx + mov [si+8],eax +.loop: + push bp ; Sectors left + cmp bp,[MaxTransfer] + jbe .bp_ok + mov bp,[MaxTransfer] +.bp_ok: + mov [si+2],bp + push si + mov dl,[DriveNo] + mov ah,42h ; Extended Read + call xint13 + pop si + pop bp + movzx eax,word [si+2] ; Sectors we read + add [si+8],eax ; Advance sector pointer + sub bp,ax ; Sectors left + shl ax,SECTOR_SHIFT-4 ; 2048-byte sectors -> segment + add [si+6],ax ; Advance buffer pointer + and bp,bp + jnz .loop + mov eax,[si+8] ; Next sector + ret + + ; INT 13h with retry +xint13: mov byte [RetryCount],retry_count +.try: pushad + int 13h + jc .error + add sp,byte 8*4 ; Clean up stack + ret +.error: + mov [DiskError],ah ; Save error code + popad + mov [DiskSys],ax ; Save system call number + dec byte [RetryCount] + jz .real_error + push ax + mov al,[RetryCount] + mov ah,[dapa+2] ; Sector transfer count + cmp al,2 ; Only 2 attempts left + ja .nodanger + mov ah,1 ; Drop transfer size to 1 + jmp short .setsize +.nodanger: + cmp al,retry_count-2 + ja .again ; First time, just try again + shr ah,1 ; Otherwise, try to reduce + adc ah,0 ; the max transfer size, but not to 0 +.setsize: + mov [MaxTransfer],ah + mov [dapa+2],ah +.again: + pop ax + jmp .try + +.real_error: mov si,diskerr_msg + call writemsg + mov al,[DiskError] + call writehex2 + mov si,oncall_str + call writestr + mov ax,[DiskSys] + call writehex4 + mov si,ondrive_str + call writestr + mov al,dl + call writehex2 + call crlf + ; Fall through to kaboom + +; +; kaboom: write a message and bail out. Wait for a user keypress, +; then do a hard reboot. +; +kaboom: + lss sp,[cs:Stack] + mov ax,cs + mov ds,ax + mov es,ax + mov fs,ax + mov gs,ax + sti + mov si,err_bootfailed + call cwritestr + call getchar + cli + mov word [BIOS_magic],0 ; Cold reboot + jmp 0F000h:0FFF0h ; Reset vector address + +; ----------------------------------------------------------------------------- +; Common modules needed in the first sector +; ----------------------------------------------------------------------------- + +%include "writestr.inc" ; String output +writestr equ cwritestr +%include "writehex.inc" ; Hexadecimal output + +; ----------------------------------------------------------------------------- +; Data that needs to be in the first sector +; ----------------------------------------------------------------------------- + +syslinux_banner db CR, LF, 'ISOLINUX ', version_str, ' ', date, ' ', 0 +copyright_str db ' Copyright (C) 1994-', year, ' H. Peter Anvin' + db CR, LF, 0 +isolinux_str db 'isolinux: ', 0 +%ifdef DEBUG_MESSAGES +startup_msg: db 'Starting up, DL = ', 0 +spec_ok_msg: db 'Loaded spec packet OK, drive = ', 0 +secsize_msg: db 'Sector size appears to be ', 0 +offset_msg: db 'Loading main image from LBA = ', 0 +size_msg: db 'Sectors to load = ', 0 +loaded_msg: db 'Loaded boot image, verifying...', CR, LF, 0 +verify_msg: db 'Image checksum verified.', CR, LF, 0 +allread_msg db 'Main image read, jumping to main code...', CR, LF, 0 +%endif +noinfotable_msg db 'No boot info table, assuming single session disk...', CR, LF, 0 +noinfoinspec_msg db 'Spec packet missing LBA information, trying to wing it...', CR, LF, 0 +spec_err_msg: db 'Loading spec packet failed, trying to wing it...', CR, LF, 0 +maybe_msg: db 'Found something at drive = ', 0 +alright_msg: db 'Looks like it might be right, continuing...', CR, LF, 0 +nospec_msg db 'Extremely broken BIOS detected, last ditch attempt with drive = ', 0 +nothing_msg: db 'Failed to locate CD-ROM device; boot failed.', CR, LF +trysbm_msg db 'See http://syslinux.zytor.com/sbm for more information.', CR, LF, 0 +diskerr_msg: db 'Disk error ', 0 +oncall_str: db ', AX = ',0 +ondrive_str: db ', drive ', 0 +checkerr_msg: db 'Image checksum error, sorry...', CR, LF, 0 + +err_bootfailed db CR, LF, 'Boot failed: press a key to retry...' +bailmsg equ err_bootfailed +crlf_msg db CR, LF +null_msg db 0 + + alignb 4, db 0 +Stack dw _start, 0 ; SS:SP for stack reset +MaxTransfer dw 32 ; Max sectors per transfer + +rl_checkpt equ $ ; Must be <= 800h + +rl_checkpt_off equ ($-$$) +;%ifndef DEPEND +;%if rl_checkpt_off > 0x800 +;%error "Sector 0 overflow" +;%endif +;%endif + +; ---------------------------------------------------------------------------- +; End of code and data that have to be in the first sector +; ---------------------------------------------------------------------------- + +all_read: +; +; Initialize screen (if we're using one) +; + ; Now set up screen parameters + call adjust_screen + + ; Wipe the F-key area + mov al,NULLFILE + mov di,FKeyName + mov cx,10*(1 << FILENAME_MAX_LG2) + rep stosb + + ; Patch the writechr routine to point to the full code + mov word [writechr+1], writechr_full-(writechr+3) + +; Tell the user we got this far... +%ifndef DEBUG_MESSAGES ; Gets messy with debugging on + mov si,copyright_str + call writestr +%endif + +; Test tracers + TRACER 'T' + TRACER '>' + +; +; Common initialization code +; +%include "init.inc" +%include "cpuinit.inc" + +; +; Now we're all set to start with our *real* business. First load the +; configuration file (if any) and parse it. +; +; In previous versions I avoided using 32-bit registers because of a +; rumour some BIOSes clobbered the upper half of 32-bit registers at +; random. I figure, though, that if there are any of those still left +; they probably won't be trying to install Linux on them... +; +; The code is still ripe with 16-bitisms, though. Not worth the hassle +; to take'm out. In fact, we may want to put them back if we're going +; to boot ELKS at some point. +; + +; +; Now, we need to sniff out the actual filesystem data structures. +; mkisofs gave us a pointer to the primary volume descriptor +; (which will be at 16 only for a single-session disk!); from the PVD +; we should be able to find the rest of what we need to know. +; +get_fs_structures: + mov eax,[bi_pvd] + mov bx,trackbuf + call getonesec + + mov eax,[trackbuf+156+2] + mov [RootDir+dir_lba],eax + mov [CurDir+dir_lba],eax +%ifdef DEBUG_MESSAGES + mov si,dbg_rootdir_msg + call writemsg + call writehex8 + call crlf +%endif + mov eax,[trackbuf+156+10] + mov [RootDir+dir_len],eax + mov [CurDir+dir_len],eax + add eax,SECTOR_SIZE-1 + shr eax,SECTOR_SHIFT + mov [RootDir+dir_clust],eax + mov [CurDir+dir_clust],eax + + ; Look for an isolinux directory, and if found, + ; make it the current directory instead of the root + ; directory. + mov di,boot_dir ; Search for /boot/isolinux + mov al,02h + call searchdir_iso + jnz .found_dir + mov di,isolinux_dir + mov al,02h ; Search for /isolinux + call searchdir_iso + jz .no_isolinux_dir +.found_dir: + mov [CurDir+dir_len],eax + mov eax,[si+file_left] + mov [CurDir+dir_clust],eax + xor eax,eax ; Free this file pointer entry + xchg eax,[si+file_sector] + mov [CurDir+dir_lba],eax +%ifdef DEBUG_MESSAGES + push si + mov si,dbg_isodir_msg + call writemsg + pop si + call writehex8 + call crlf +%endif +.no_isolinux_dir: + +; +; Locate the configuration file +; +load_config: +%ifdef DEBUG_MESSAGES + mov si,dbg_config_msg + call writemsg +%endif + + mov di,isolinux_cfg + call open + jz no_config_file ; Not found or empty + +%ifdef DEBUG_MESSAGES + mov si,dbg_configok_msg + call writemsg +%endif + +; +; Now we have the config file open. Parse the config file and +; run the user interface. +; +%include "ui.inc" + +; +; Linux kernel loading code is common. +; +%include "runkernel.inc" + +; +; COMBOOT-loading code +; +%include "comboot.inc" +%include "com32.inc" +%include "cmdline.inc" + +; +; Boot sector loading code +; +%include "bootsect.inc" + +; +; Enable disk emulation. The kind of disk we emulate is dependent on the size of +; the file: 1200K, 1440K or 2880K floppy, otherwise harddisk. +; +is_disk_image: + TRACER CR + TRACER LF + TRACER 'D' + TRACER ':' + + shl edx,16 + mov dx,ax ; Set EDX <- file size + mov di,img_table + mov cx,img_table_count + mov eax,[si+file_sector] ; Starting LBA of file + mov [dsp_lba],eax ; Location of file + mov byte [dsp_drive], 0 ; 00h floppy, 80h hard disk +.search_table: + TRACER 't' + mov eax,[di+4] + cmp edx,[di] + je .type_found + add di,8 + loop .search_table + + ; Hard disk image. Need to examine the partition table + ; in order to deduce the C/H/S geometry. Sigh. +.hard_disk_image: + TRACER 'h' + cmp edx,512 + jb .bad_image + + mov bx,trackbuf + mov cx,1 ; Load 1 sector + call getfssec + + cmp word [trackbuf+510],0aa55h ; Boot signature + jne .bad_image ; Image not bootable + + mov cx,4 ; 4 partition entries + mov di,trackbuf+446 ; Start of partition table + + xor ax,ax ; Highest sector(al) head(ah) + +.part_scan: + cmp byte [di+4], 0 + jz .part_loop + lea si,[di+1] + call .hs_check + add si,byte 4 + call .hs_check +.part_loop: + add di,byte 16 + loop .part_scan + + push eax ; H/S + push edx ; File size + mov bl,ah + xor bh,bh + inc bx ; # of heads in BX + xor ah,ah ; # of sectors in AX + cwde ; EAX[31:16] <- 0 + mul bx + shl eax,9 ; Convert to bytes + ; Now eax contains the number of bytes per cylinder + pop ebx ; File size + xor edx,edx + div ebx + and edx,edx + jz .no_remainder + inc eax ; Fractional cylinder... + ; Now (e)ax contains the number of cylinders +.no_remainder: cmp eax,1024 + jna .ok_cyl + mov ax,1024 ; Max possible # +.ok_cyl: dec ax ; Convert to max cylinder no + pop ebx ; S(bl) H(bh) + shl ah,6 + or bl,ah + xchg ax,bx + shl eax,16 + mov ah,bl + mov al,4 ; Hard disk boot + mov byte [dsp_drive], 80h ; Drive 80h = hard disk + +.type_found: + TRACER 'T' + mov bl,[sp_media] + and bl,0F0h ; Copy controller info bits + or al,bl + mov [dsp_media],al ; Emulation type + shr eax,8 + mov [dsp_chs],eax ; C/H/S geometry + mov ax,[sp_devspec] ; Copy device spec + mov [dsp_devspec],ax + mov al,[sp_controller] ; Copy controller index + mov [dsp_controller],al + + TRACER 'V' + call vgaclearmode ; Reset video + + mov ax,4C00h ; Enable emulation and boot + mov si,dspec_packet + mov dl,[DriveNo] + lss sp,[InitStack] + TRACER 'X' + + int 13h + + ; If this returns, we have problems +.bad_image: + mov si,err_disk_image + call cwritestr + jmp enter_command + +; +; Look for the highest seen H/S geometry +; We compute cylinders separately +; +.hs_check: + mov bl,[si] ; Head # + cmp bl,ah + jna .done_track + mov ah,bl ; New highest head # +.done_track: mov bl,[si+1] + and bl,3Fh ; Sector # + cmp bl,al + jna .done_sector + mov al,bl +.done_sector: ret + +; +; Boot a specified local disk. AX specifies the BIOS disk number; or +; 0xFFFF in case we should execute INT 18h ("next device.") +; +local_boot: + call vgaclearmode + lss sp,[cs:Stack] ; Restore stack pointer + xor dx,dx + mov ds,dx + mov es,dx + mov fs,dx + mov gs,dx + mov si,localboot_msg + call writestr + cmp ax,-1 + je .int18 + + ; Load boot sector from the specified BIOS device and jump to it. + mov dl,al + xor dh,dh + push dx + xor ax,ax ; Reset drive + call xint13 + mov ax,0201h ; Read one sector + mov cx,0001h ; C/H/S = 0/0/1 (first sector) + mov bx,trackbuf + call xint13 + pop dx + cli ; Abandon hope, ye who enter here + mov si,trackbuf + mov di,07C00h + mov cx,512 ; Probably overkill, but should be safe + rep movsd + lss sp,[cs:InitStack] + jmp 0:07C00h ; Jump to new boot sector + +.int18: + int 18h ; Hope this does the right thing... + jmp kaboom ; If we returned, oh boy... + +; +; abort_check: let the user abort with <ESC> or <Ctrl-C> +; +abort_check: + call pollchar + jz ac_ret1 + pusha + call getchar + cmp al,27 ; <ESC> + je ac_kill + cmp al,3 ; <Ctrl-C> + jne ac_ret2 +ac_kill: mov si,aborted_msg + +; +; abort_load: Called by various routines which wants to print a fatal +; error message and return to the command prompt. Since this +; may happen at just about any stage of the boot process, assume +; our state is messed up, and just reset the segment registers +; and the stack forcibly. +; +; SI = offset (in _text) of error message to print +; +abort_load: + mov ax,cs ; Restore CS = DS = ES + mov ds,ax + mov es,ax + cli + lss sp,[cs:Stack] ; Reset the stack + sti + call cwritestr ; Expects SI -> error msg +al_ok: jmp enter_command ; Return to command prompt +; +; End of abort_check +; +ac_ret2: popa +ac_ret1: ret + + +; +; searchdir: +; +; Open a file +; +; On entry: +; DS:DI = filename +; If successful: +; ZF clear +; SI = file pointer +; DX:AX or EAX = file length in bytes +; If unsuccessful +; ZF set +; + +; +; searchdir_iso is a special entry point for ISOLINUX only. In addition +; to the above, searchdir_iso passes a file flag mask in AL. This is useful +; for searching for directories. +; +alloc_failure: + xor ax,ax ; ZF <- 1 + ret + +searchdir: + xor al,al +searchdir_iso: + mov [ISOFlags],al + TRACER 'S' + call allocate_file ; Temporary file structure for directory + jnz alloc_failure + push es + push ds + pop es ; ES = DS + mov si,CurDir + cmp byte [di],'/' ; If filename begins with slash + jne .not_rooted + inc di ; Skip leading slash + mov si,RootDir ; Reference root directory instead +.not_rooted: + mov eax,[si+dir_clust] + mov [bx+file_left],eax + mov eax,[si+dir_lba] + mov [bx+file_sector],eax + mov edx,[si+dir_len] + +.look_for_slash: + mov ax,di +.scan: + mov cl,[di] + inc di + and cl,cl + jz .isfile + cmp cl,'/' + jne .scan + mov [di-1],byte 0 ; Terminate at directory name + mov cl,02h ; Search for directory + xchg cl,[ISOFlags] + + push di ; Save these... + push cx + + ; Create recursion stack frame... + push word .resume ; Where to "return" to + push es +.isfile: xchg ax,di + +.getsome: + ; Get a chunk of the directory + ; This relies on the fact that ISOLINUX doesn't change SI + mov si,trackbuf + TRACER 'g' + pushad + xchg bx,si + mov cx,[BufSafe] + call getfssec + popad + +.compare: + movzx eax,byte [si] ; Length of directory entry + cmp al,33 + jb .next_sector + TRACER 'c' + mov cl,[si+25] + xor cl,[ISOFlags] + test cl, byte 8Eh ; Unwanted file attributes! + jnz .not_file + pusha + movzx cx,byte [si+32] ; File identifier length + add si,byte 33 ; File identifier offset + TRACER 'i' + call iso_compare_names + popa + je .success +.not_file: + sub edx,eax ; Decrease bytes left + jbe .failure + add si,ax ; Advance pointer + +.check_overrun: + ; Did we finish the buffer? + cmp si,trackbuf+trackbufsize + jb .compare ; No, keep going + + jmp short .getsome ; Get some more directory + +.next_sector: + ; Advance to the beginning of next sector + lea ax,[si+SECTOR_SIZE-1] + and ax,~(SECTOR_SIZE-1) + sub ax,si + jmp short .not_file ; We still need to do length checks + +.failure: xor eax,eax ; ZF = 1 + mov [bx+file_sector],eax + pop es + ret + +.success: + mov eax,[si+2] ; Location of extent + mov [bx+file_sector],eax + mov eax,[si+10] ; Data length + push eax + add eax,SECTOR_SIZE-1 + shr eax,SECTOR_SHIFT + mov [bx+file_left],eax + pop eax + mov edx,eax + shr edx,16 + and bx,bx ; ZF = 0 + mov si,bx + pop es + ret + +.resume: ; We get here if we were only doing part of a lookup + ; This relies on the fact that .success returns bx == si + xchg edx,eax ; Directory length in edx + pop cx ; Old ISOFlags + pop di ; Next filename pointer + mov byte [di-1], '/' ; Restore slash + mov [ISOFlags],cl ; Restore the flags + jz .failure ; Did we fail? If so fail for real! + jmp .look_for_slash ; Otherwise, next level + +; +; allocate_file: Allocate a file structure +; +; If successful: +; ZF set +; BX = file pointer +; In unsuccessful: +; ZF clear +; +allocate_file: + TRACER 'a' + push cx + mov bx,Files + mov cx,MAX_OPEN +.check: cmp dword [bx], byte 0 + je .found + add bx,open_file_t_size ; ZF = 0 + loop .check + ; ZF = 0 if we fell out of the loop +.found: pop cx + ret + +; +; iso_compare_names: +; Compare the names DS:SI and DS:DI and report if they are +; equal from an ISO 9660 perspective. SI is the name from +; the filesystem; CX indicates its length, and ';' terminates. +; DI is expected to end with a null. +; +; Note: clobbers AX, CX, SI, DI; assumes DS == ES == base segment +; + +iso_compare_names: + ; First, terminate and canonicalize input filename + push di + mov di,ISOFileName +.canon_loop: jcxz .canon_end + lodsb + dec cx + cmp al,';' + je .canon_end + and al,al + je .canon_end + stosb + cmp di,ISOFileNameEnd-1 ; Guard against buffer overrun + jb .canon_loop +.canon_end: + cmp di,ISOFileName + jbe .canon_done + cmp byte [di-1],'.' ; Remove terminal dots + jne .canon_done + dec di + jmp short .canon_end +.canon_done: + mov [di],byte 0 ; Null-terminate string + pop di + mov si,ISOFileName +.compare: + lodsb + mov ah,[di] + inc di + and ax,ax + jz .success ; End of string for both + and al,al ; Is either one end of string? + jz .failure ; If so, failure + and ah,ah + jz .failure + or ax,2020h ; Convert to lower case + cmp al,ah + je .compare +.failure: and ax,ax ; ZF = 0 (at least one will be nonzero) +.success: ret + +; +; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed +; to by ES:DI; ends on encountering any whitespace. +; +; This verifies that a filename is < FILENAME_MAX characters, +; doesn't contain whitespace, zero-pads the output buffer, +; and removes trailing dots and redundant slashes, +; so "repe cmpsb" can do a compare, and the +; path-searching routine gets a bit of an easier job. +; +mangle_name: + push bx + xor ax,ax + mov cx,FILENAME_MAX-1 + mov bx,di + +.mn_loop: + lodsb + cmp al,' ' ; If control or space, end + jna .mn_end + cmp al,ah ; Repeated slash? + je .mn_skip + xor ah,ah + cmp al,'/' + jne .mn_ok + mov ah,al +.mn_ok stosb +.mn_skip: loop .mn_loop +.mn_end: + cmp bx,di ; At the beginning of the buffer? + jbe .mn_zero + cmp byte [di-1],'.' ; Terminal dot? + je .mn_kill + cmp byte [di-1],'/' ; Terminal slash? + jne .mn_zero +.mn_kill: dec di ; If so, remove it + inc cx + jmp short .mn_end +.mn_zero: + inc cx ; At least one null byte + xor ax,ax ; Zero-fill name + rep stosb + pop bx + ret ; Done + +; +; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled +; filename to the conventional representation. This is needed +; for the BOOT_IMAGE= parameter for the kernel. +; NOTE: A 13-byte buffer is mandatory, even if the string is +; known to be shorter. +; +; DS:SI -> input mangled file name +; ES:DI -> output buffer +; +; On return, DI points to the first byte after the output name, +; which is set to a null byte. +; +unmangle_name: call strcpy + dec di ; Point to final null byte + ret + +; +; getfssec: Get multiple clusters from a file, given the file pointer. +; +; On entry: +; ES:BX -> Buffer +; SI -> File pointer +; CX -> Cluster count +; On exit: +; SI -> File pointer (or 0 on EOF) +; CF = 1 -> Hit EOF +; +getfssec: + TRACER 'F' + + push ds + push cs + pop ds ; DS <- CS + + movzx ecx,cx + cmp ecx,[si+file_left] + jna .ok_size + mov ecx,[si+file_left] +.ok_size: + + mov bp,cx + push cx + push si + mov eax,[si+file_sector] + TRACER 'l' + call getlinsec + xor ecx,ecx + pop si + pop cx + + add [si+file_sector],ecx + sub [si+file_left],ecx + ja .not_eof ; CF = 0 + + xor ecx,ecx + mov [si+file_sector],ecx ; Mark as unused + xor si,si + stc + +.not_eof: + pop ds + TRACER 'f' + ret + +; ----------------------------------------------------------------------------- +; Common modules +; ----------------------------------------------------------------------------- + +%include "getc.inc" ; getc et al +%include "conio.inc" ; Console I/O +%include "parseconfig.inc" ; High-level config file handling +%include "parsecmd.inc" ; Low-level config file handling +%include "bcopy32.inc" ; 32-bit bcopy +%include "loadhigh.inc" ; Load a file into high memory +%include "font.inc" ; VGA font stuff +%include "graphics.inc" ; VGA graphics +%include "highmem.inc" ; High memory sizing +%include "strcpy.inc" ; strcpy() +%include "rawcon.inc" ; Console I/O w/o using the console functions + +; ----------------------------------------------------------------------------- +; Begin data section +; ----------------------------------------------------------------------------- + + section .data + +boot_prompt db 'boot: ', 0 +wipe_char db BS, ' ', BS, 0 +err_notfound db 'Could not find kernel image: ',0 +err_notkernel db CR, LF, 'Invalid or corrupt kernel image.', CR, LF, 0 +err_noram db 'It appears your computer has less than ' + asciidec dosram_k + db 'K of low ("DOS")' + db CR, LF + db 'RAM. Linux needs at least this amount to boot. If you get' + db CR, LF + db 'this message in error, hold down the Ctrl key while' + db CR, LF + db 'booting, and I will take your word for it.', CR, LF, 0 +err_badcfg db 'Unknown keyword in config file.', CR, LF, 0 +err_noparm db 'Missing parameter in config file.', CR, LF, 0 +err_noinitrd db CR, LF, 'Could not find ramdisk image: ', 0 +err_nohighmem db 'Not enough memory to load specified kernel.', CR, LF, 0 +err_highload db CR, LF, 'Kernel transfer failure.', CR, LF, 0 +err_oldkernel db 'Cannot load a ramdisk with an old kernel image.' + db CR, LF, 0 +err_notdos db ': attempted DOS system call', CR, LF, 0 +err_comlarge db 'COMBOOT image too large.', CR, LF, 0 +err_bssimage db 'BSS images not supported.', CR, LF, 0 +err_a20 db CR, LF, 'A20 gate not responding!', CR, LF, 0 +notfound_msg db 'not found', CR, LF, 0 +localboot_msg db 'Booting from local disk...', CR, LF, 0 +cmdline_msg db 'Command line: ', CR, LF, 0 +ready_msg db 'Ready.', CR, LF, 0 +trying_msg db 'Trying to load: ', 0 +crlfloading_msg db CR, LF ; Fall through +loading_msg db 'Loading ', 0 +dotdot_msg db '.' +dot_msg db '.', 0 +fourbs_msg db BS, BS, BS, BS, 0 +aborted_msg db ' aborted.', CR, LF, 0 +crff_msg db CR, FF, 0 +default_str db 'default', 0 +default_len equ ($-default_str) +boot_dir db '/boot' ; /boot/isolinux +isolinux_dir db '/isolinux', 0 +ConfigName equ $ +isolinux_cfg db 'isolinux.cfg', 0 +err_disk_image db 'Cannot load disk image (invalid file)?', CR, LF, 0 + +%ifdef DEBUG_MESSAGES +dbg_rootdir_msg db 'Root directory at LBA = ', 0 +dbg_isodir_msg db 'isolinux directory at LBA = ', 0 +dbg_config_msg db 'About to load config file...', CR, LF, 0 +dbg_configok_msg db 'Configuration file opened...', CR, LF, 0 +%endif +; +; Command line options we'd like to take a look at +; +; mem= and vga= are handled as normal 32-bit integer values +initrd_cmd db 'initrd=' +initrd_cmd_len equ 7 + +; +; Config file keyword table +; +%include "keywords.inc" + +; +; Extensions to search for (in *forward* order). +; + align 4, db 0 +exten_table: db '.cbt' ; COMBOOT (specific) + db '.img' ; Disk image + db '.bin' ; CD boot sector + db '.com' ; COMBOOT (same as DOS) + db '.c32' ; COM32 +exten_table_end: + dd 0, 0 ; Need 8 null bytes here + +; +; Floppy image table +; + align 4, db 0 +img_table_count equ 3 +img_table: + dd 1200*1024 ; 1200K floppy + db 1 ; Emulation type + db 80-1 ; Max cylinder + db 15 ; Max sector + db 2-1 ; Max head + + dd 1440*1024 ; 1440K floppy + db 2 ; Emulation type + db 80-1 ; Max cylinder + db 18 ; Max sector + db 2-1 ; Max head + + dd 2880*1024 ; 2880K floppy + db 3 ; Emulation type + db 80-1 ; Max cylinder + db 36 ; Max sector + db 2-1 ; Max head + +; +; Misc initialized (data) variables +; + +; +; Variables that are uninitialized in SYSLINUX but initialized here +; +; **** ISOLINUX:: We may have to make this flexible, based on what the +; **** BIOS expects our "sector size" to be. +; + alignb 4, db 0 +BufSafe dw trackbufsize/SECTOR_SIZE ; Clusters we can load into trackbuf +BufSafeSec dw trackbufsize/SECTOR_SIZE ; = how many sectors? +BufSafeBytes dw trackbufsize ; = how many bytes? +EndOfGetCBuf dw getcbuf+trackbufsize ; = getcbuf+BufSafeBytes +%ifndef DEPEND +%if ( trackbufsize % SECTOR_SIZE ) != 0 +%error trackbufsize must be a multiple of SECTOR_SIZE +%endif +%endif diff --git a/syslinux/isolinux.bin b/syslinux/isolinux.bin new file mode 100644 index 0000000000000000000000000000000000000000..bb6b4b8b6d03aecfd8f8a274da8407bfdaca2c3c GIT binary patch literal 10424 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 N`CpkYXNmyee*tR=52*kE literal 0 HcmV?d00001 diff --git a/syslinux/isolinux.doc b/syslinux/isolinux.doc new file mode 100644 index 0000000..6556567 --- /dev/null +++ b/syslinux/isolinux.doc @@ -0,0 +1,111 @@ + ISOLINUX + + A bootloader for Linux using ISO 9660/El Torito CD-ROMs + + Copyright (C) 1994-2003 H. Peter Anvin + +This program is provided under the terms of the GNU General Public +License, version 2 or, at your option, any later version. There is no +warranty, neither expressed nor implied, to the function of this +program. Please see the included file COPYING for details. + +---------------------------------------------------------------------- + +ISOLINUX is a boot loader for Linux/i386 that operates off ISO 9660/El +Torito CD-ROMs in "no emulation" mode. This avoids the need to create +an "emulation disk image" with limited space (for "floppy emulation") +or compatibility problems (for "hard disk emulation".) + +This documentation isn't here yet, but here is enough that you should +be able to test it out: + +Make sure you have a recent enough version of mkisofs. I recommend +mkisofs 1.13 (distributed with cdrecord 1.9), but 1.12 might work as +well (not tested.) + +To create an image, create a directory called "isolinux" (or, if you +prefer, "boot/isolinux") underneath the root directory of your ISO +image master file tree. Copy isolinux.bin, a config file called +"isolinux.cfg" (see syslinux.doc for details on the configuration +file), and all necessary files (kernels, initrd, display files, etc.) +into this directory, then use the following command to create your ISO +image (add additional options as appropriate, such as -J or -R): + + mkisofs -o <isoimage> \ + -b isolinux/isolinux.bin -c isolinux/boot.cat \ + -no-emul-boot -boot-load-size 4 -boot-info-table \ + <root-of-iso-tree> + +(If you named the directory boot/isolinux that should of course be +-b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat.) + +ISOLINUX resolves pathnames the following way: + +- A pathname consists of names separated by slashes, Unix-style. +- A leading / means it searches from the root directory; otherwise the + search is from the isolinux directory (think of this as the "current + directory".) +- . and .. in pathname searches are not supported. +- The maximum length of any pathname is 255 characters. + +Note that ISOLINUX only uses the "plain" ISO 9660 filenames, i.e. it +does not support Rock Ridge or Joliet filenames. It can still be used +on a disk which uses Rock Ridge and/or Joliet extensions, of course. +Under Linux, you can verify the plain filenames by mounting with the +"-o norock,nojoliet" option to the mount command. Note, however, that +ISOLINUX does support "long" (level 2) ISO 9660 plain filenames, so if +compatibility with short-names-only operating systems like MS-DOS is +not an issue, you can use the "-l" or "-iso-level 2" option to mkisofs +to generate long (up to 31 characters) plain filenames. + +ISOLINUX does not support discontiguous files, interleaved mode, or +logical block and sector sizes other than 2048. This should normally +not be a problem. + +ISOLINUX is by default built in two versions, one version with extra +debugging messages enabled. If you are having problems with ISOLINUX, +I would greatly appreciate if you could try out the debugging version +(isolinux-debug.bin) and let me know what it reports. + +YOU MAY WANT TO CONSIDER USING THE DEBUGGING VERSION BY DEFAULT. + + + ++++ NOTE ON THE CONFIG FILE DIRECTORY ++++ + +ISOLINUX will search for the config file directory in the order +/boot/isolinux, /isolinux, /. The first directory that exists is +used, even if it contains no files. Therefore, please make sure that +these directories don't exist if you don't want ISOLINUX to use them. + + + ++++ BOOTING DOS (OR OTHER SIMILAR OPERATING SYSTEMS) ++++ + +WARNING: This feature depends on BIOS functionality which is +apparently broken in a very large number of BIOSes. Therefore, this +may not work on any particular system. No workaround is possible; if +you find that it doesn't work please complain to your vendor and +indicate that "BIOS INT 13h AX=4C00h fails." + +To boot DOS, or other real-mode operating systems (protected-mode +operating systems may or may not work correctly), using ISOLINUX, you +need to prepare a disk image (usually a floppy image, but a hard disk +image can be used on *most* systems) with the relevant operating +system. This file should be included on the CD-ROM in the /isolinux +directory, and have a .img extension. The ".img" extension does not +have to be specified on the command line, but has to be explicitly +specified if used in a "kernel" statement in isolinux.cfg. + +For a floppy image, the size of the image should be exactly one of the +following: + + 1,228,800 bytes - For a 1200K floppy image + 1,474,560 bytes - For a 1440K floppy image + 2,949,120 bytes - For a 2880K floppy image + +Any other size is assumed to be a hard disk image. In order to work +on as many systems as possible, a hard disk image should have exactly +one partition, marked active, that covers the entire size of the disk +image file. Even so, hard disk images are not supported on all +BIOSes. + + diff --git a/syslinux/kernel.inc b/syslinux/kernel.inc new file mode 100644 index 0000000..0a5acdc --- /dev/null +++ b/syslinux/kernel.inc @@ -0,0 +1,91 @@ +;; $Id: kernel.inc,v 1.5 2005/01/10 02:41:31 hpa Exp $ +;; ----------------------------------------------------------------------- +;; +;; Copyright 1994-2002 H. Peter Anvin - All Rights Reserved +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +;; Boston MA 02111-1307, USA; either version 2 of the License, or +;; (at your option) any later version; incorporated herein by reference. +;; +;; ----------------------------------------------------------------------- + +;; +;; kernel.inc +;; +;; Header file for the kernel interface definitions +;; + +%ifndef _KERNEL_INC +%define _KERNEL_INC + +;; +;; Structure of the real_mode_seg +;; + + struc real_mode_seg_t + resb 20h-($-$$) ; org 20h +kern_cmd_magic resw 1 ; 0020 Magic # for command line +kern_cmd_offset resw 1 ; 0022 Offset for kernel command line + resb 497-($-$$) ; org 497d +bs_setupsecs resb 1 ; 01F1 Sectors for setup code (0 -> 4) +bs_rootflags resw 1 ; 01F2 Root readonly flag +bs_syssize resw 1 ; 01F4 +bs_swapdev resw 1 ; 01F6 Swap device (obsolete) +bs_ramsize resw 1 ; 01F8 Ramdisk flags, formerly ramdisk size +bs_vidmode resw 1 ; 01FA Video mode +bs_rootdev resw 1 ; 01FC Root device +bs_bootsign resw 1 ; 01FE Boot sector signature (0AA55h) +su_jump resb 1 ; 0200 0EBh +su_jump2 resb 1 ; 0201 Size of following header +su_header resd 1 ; 0202 New setup code: header +su_version resw 1 ; 0206 See linux/arch/i386/boot/setup.S +su_switch resw 1 ; 0208 +su_setupseg resw 1 ; 020A +su_startsys resw 1 ; 020C +su_kver resw 1 ; 020E Kernel version pointer +su_loader resb 1 ; 0210 Loader ID +su_loadflags resb 1 ; 0211 Load high flag +su_movesize resw 1 ; 0212 +su_code32start resd 1 ; 0214 Start of code loaded high +su_ramdiskat resd 1 ; 0218 Start of initial ramdisk +su_ramdisklen resd 1 ; 021C Length of initial ramdisk +su_bsklugeoffs resw 1 ; 0220 +su_bsklugeseg resw 1 ; 0222 +su_heapend resw 1 ; 0224 +su_pad1 resw 1 ; 0226 +su_cmd_line_ptr resd 1 ; 0228 +su_ramdisk_max resd 1 ; 022C + resb (9000h-12)-($-$$) ; Were bootsect.S puts it... +linux_stack equ $ ; 8FF4 +linux_fdctab equ $ + resb 9000h-($-$$) +cmd_line_here equ $ ; 9000 Should be out of the way + endstruc + +; +; Kernel command line signature +; +CMD_MAGIC equ 0A33Fh ; Command line magic + +; +; Magic number of su_header field +; +HEADER_ID equ 'HdrS' ; HdrS (in littleendian hex) + +; +; Flags for the su_loadflags field +; +LOAD_HIGH equ 01h ; Large kernel, load high +CAN_USE_HEAP equ 80h ; Boot loader reports heap size + +; +; ID codes for various modules +; +syslinux_id equ 031h ; 3 = SYSLINUX family; 1 = SYSLINUX +pxelinux_id equ 032h ; 3 = SYSLINUX family; 2 = PXELINUX +isolinux_id equ 033h ; 3 = SYSLINUX family; 3 = ISOLINUX +extlinux_id equ 034h ; 3 = SYSLINUX family; 4 = EXTLINUX + +%endif ; _KERNEL_INC diff --git a/syslinux/keytab-lilo.doc b/syslinux/keytab-lilo.doc new file mode 100644 index 0000000..44ec5dc --- /dev/null +++ b/syslinux/keytab-lilo.doc @@ -0,0 +1,85 @@ +This is the documentation for the keytab-lilo.pl program. It was +taken verbatim from the LILO-20 README file; only this header was +added. + +LILO program code, documentation and auxiliary programs are +Copyright 1992-1997 Werner Almesberger. +All rights reserved. + +Redistribution and use in source and binary forms of parts of or the +whole original or derived work are permitted provided that the +original work is properly attributed to the author. The name of the +author may not be used to endorse or promote products derived from +this software without specific prior written permission. This work +is provided "as is" and without any express or implied warranties. + +To use a LILO keyboard table with SYSLINUX, specify the KBDMAP command +in syslinux.cfg, for example: + + kbdmap de.ktl + +============================================================================ + +Keyboard translation +-------------------- + +The PC keyboard emits so-called scan codes, which are basically key +numbers. The BIOS then translates those scan codes to the character codes +of the characters printed on the key-caps. By default, the BIOS normally +assumes that the keyboard has a US layout. Once an operating system is +loaded, this operating system can use a different mapping. + +At boot time, LILO only has access to the basic services provided by the +BIOS and therefore receives the character codes for an US keyboard. It +provides a simple mechanism to re-map the character codes to what is +appropriate for the actual layout.* + + * The current mechanism isn't perfect, because it sits on top of the + scan code to character code translation performed by the BIOS. This + means that key combinations that don't produce any useful character on + the US keyboard will be ignored by LILO. The advantage of this approach + is its simplicity. + + +Compiling keyboard translation tables +- - - - - - - - - - - - - - - - - - - + +LILO obtains layout information from the keyboard translation tables Linux +uses for the text console. They are usually stored in +/usr/lib/kbd/keytables. LILO comes with a program keytab-lilo.pl that reads +those tables and generates a table suitable for use by the map installer. +keytab-lilo.pl invokes the program loadkeys to print the tables in a format +that is easy to parse.* + + * On some systems, only root can execute loadkeys. It is then necessary + to run keytab-lilo.pl as root too. + +keytab-lilo.pl is used as follows: + + keytab-lilo.pl [ -p <old_code>=<new_code> ] ... + [<path>]<default_layout>[.<extension>] ] + [<path>]<kbd_layout>[.<extension>] ] + + -p <old_code>=<new_code> + Specifies corrections ("patches") to the mapping obtained from the + translation table files. E.g. if pressing the upper case "A" should + yield an at sign, -p 65=64 would be used. The -p option can be + repeated any number of times. The codes can also be given as + hexadecimal or as octal numbers if they are prefixed with 0x or 0, + respectively. + <path> The directory in which the file resides. The default path is + /usr/lib/kbd/keytables. + <extension> Usually the trailing .map, which is automatically added if + the file name doesn't contain dots. + <default_layout> Is the layout which specifies the translation by the + BIOS. If none is specified, us is assumed. + <kbd_layout> Is the actual layout of the keyboard. + +keytab-lilo.pl writes the resulting translation table as a binary string to +standard output. Such tables can be stored anywhere with any name, but the +suggested naming convention is /boot/<kbd>.ktl ("Keyboard Table for Lilo"), +where <kbd> is the name of the keyboard layout. + +Example: + +keytab-lilo.pl de >/boot/de.ktl diff --git a/syslinux/keytab-lilo.pl b/syslinux/keytab-lilo.pl new file mode 100755 index 0000000..867be7e --- /dev/null +++ b/syslinux/keytab-lilo.pl @@ -0,0 +1,111 @@ +#!/usr/bin/perl +# -------------------------------------------------------------------------- +# This program was taken from the LILO-20 distribution; only this header +# was added. +# +# LILO program code, documentation and auxiliary programs are +# Copyright 1992-1997 Werner Almesberger. +# All rights reserved. +# +# Redistribution and use in source and binary forms of parts of or the +# whole original or derived work are permitted provided that the +# original work is properly attributed to the author. The name of the +# author may not be used to endorse or promote products derived from +# this software without specific prior written permission. This work +# is provided "as is" and without any express or implied warranties. +# -------------------------------------------------------------------------- + +eval { use bytes; }; eval { binmode STDOUT; }; + +$DEFAULT_PATH = "/usr/lib/kbd/keytables"; +$DEFAULT_MAP = "us"; +$DEFAULT_EXT = ".map"; + +sub usage +{ + print STDERR + "usage: $0 [ -p old_code=new_code ] ...\n". + (" "x(8+length $0))."[path]default_layout[.map] ] ". + "[path]kbd_layout[.map]\n"; + exit 1; +} + + +while ($ARGV[0] eq "-p") { + shift(@ARGV); + &usage unless $ARGV[0] =~ /=/; + $table[eval($`)] = eval($'); + shift(@ARGV); +} +&usage unless defined $ARGV[0]; +load_map("def",defined $ARGV[1] ? $ARGV[0] : undef); +load_map("kbd",defined $ARGV[1] ? $ARGV[1] : $ARGV[0]); +&build_table("plain","shift","ctrl","altgr","shift_ctrl", + "altgr_ctrl","alt","shift_alt","ctrl_alt"); +for ($i = 0; $i < 256; $i++) { + printf("%c",$table[$i] ? $table[$i] : $i) || die "print: $!"; +} +close STDOUT || die "close: $!"; + + +sub load_map +{ + local ($pfx,$map) = @_; + local ($empty,$current); + + $map = $DEFAULT_MAP unless defined $map; + $map = $DEFAULT_PATH."/".$map unless $map =~ m|/|; + $map .= $DEFAULT_EXT unless $map =~ m|/[^/]+\.[^/]+$|; + if (!open(FILE,"loadkeys -m $map |")) { + print STDERR "loadkeys -m $map: $!\n"; + exit 1; + } + undef $current; + $empty = 1; + while (<FILE>) { + chop; + if (/^u_short\s+(\S+)_map\[\S+\]\s+=\s+{\s*$/) { + die "active at beginning of map" if defined $current; + $current = $pfx.":".$1; + next; + } + undef $current if /^};\s*$/; + next unless defined $current; + s/\s//g; + $map{$current} .= $_; + $empty = 0; + } + close FILE; + return unless $empty; + print STDERR "Keymap is empty\n"; + exit 1; +} + + +sub build_table +{ + local (@maps) = @_; + local (@tmp); + + $set = 0; + for $map (@maps) { + $code = $set; + for (split(",",$map{"def:".$map})) { + die "bad map entry $_ (def, map $map)" unless /^0x\S\S(\S\S)$/; + $tmp[$code] = hex $1 unless $tmp[$code]; + $code++; + } + $set += 256; + } + $set = 0; + for $map (@maps) { + $code = $set; + for (split(",",$map{"kbd:".$map})) { + die "bad map entry $_ (kbd, map $map)" unless /^0x\S\S(\S\S)$/; + $table[$tmp[$code]] = hex $1 unless $table[$tmp[$code]]; + $code++; + } + $set += 256; + } + $table[0] = 0; +} diff --git a/syslinux/keywords b/syslinux/keywords new file mode 100644 index 0000000..155a4e1 --- /dev/null +++ b/syslinux/keywords @@ -0,0 +1,34 @@ +# hash +menu +append +default +display +font +implicit +ipappend +kbdmap +kernel +label +localboot +prompt +say +serial +console +timeout +allowoptions +ontimeout +onerror +noescape +f0 +f1 +f2 +f3 +f4 +f5 +f6 +f7 +f8 +f9 +f10 +f11 +f12 diff --git a/syslinux/keywords.inc b/syslinux/keywords.inc new file mode 100644 index 0000000..453670e --- /dev/null +++ b/syslinux/keywords.inc @@ -0,0 +1,85 @@ +;; $Id: keywords.inc,v 1.12 2005/01/04 22:17:17 hpa Exp $ +;; ----------------------------------------------------------------------- +;; +;; Copyright 1994-2002 H. Peter Anvin - All Rights Reserved +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +;; Boston MA 02111-1307, USA; either version 2 of the License, or +;; (at your option) any later version; incorporated herein by reference. +;; +;; ----------------------------------------------------------------------- + +;; +;; keywords.inc +;; +;; Common header file for the handling of keyword hash and macros +;; + +%ifndef DEPEND ; Generated file +%include "kwdhash.gen" +%endif + +%macro keyword 2 + dd hash_%1 ; Hash value + dw 0 ; No argument + dw %2 ; Entrypoint +%endmacro + +%macro keyword 3 + dd hash_%1 ; Hash value + dw %3 ; 16-bit argument + dw %2 ; Entrypoint +%endmacro + +%macro keyword 4 + dd hash_%1 ; Hash value + db %3, %4 ; 2 8-bit arguments + dw %2 ; Entrypoint +%endmacro + +keywd_size equ 8 ; Bytes per keyword + + align 4, db 0 + +keywd_table: + keyword hash, pc_comment + keyword menu, pc_comment + keyword append, pc_append + keyword default, pc_default + keyword display, pc_filecmd, get_msg_file + keyword font, pc_filecmd, loadfont + keyword implicit, pc_setint16, AllowImplicit + keyword kbdmap, pc_filecmd, loadkeys + keyword kernel, pc_kernel + keyword label, pc_label + keyword prompt, pc_setint16, ForcePrompt + keyword say, pc_say + keyword serial, pc_serial + keyword console, pc_setint16, DisplayCon + keyword timeout, pc_timeout + keyword ontimeout, pc_ontimeout + keyword onerror, pc_onerror + keyword allowoptions, pc_setint16, AllowOptions + keyword noescape, pc_noescape + keyword f1, pc_fkey, FKeyName+(0<<FILENAME_MAX_LG2) + keyword f2, pc_fkey, FKeyName+(1<<FILENAME_MAX_LG2) + keyword f3, pc_fkey, FKeyName+(2<<FILENAME_MAX_LG2) + keyword f4, pc_fkey, FKeyName+(3<<FILENAME_MAX_LG2) + keyword f5, pc_fkey, FKeyName+(4<<FILENAME_MAX_LG2) + keyword f6, pc_fkey, FKeyName+(5<<FILENAME_MAX_LG2) + keyword f7, pc_fkey, FKeyName+(6<<FILENAME_MAX_LG2) + keyword f8, pc_fkey, FKeyName+(7<<FILENAME_MAX_LG2) + keyword f9, pc_fkey, FKeyName+(8<<FILENAME_MAX_LG2) + keyword f10, pc_fkey, FKeyName+(9<<FILENAME_MAX_LG2) + keyword f0, pc_fkey, FKeyName+(9<<FILENAME_MAX_LG2) +%if IS_PXELINUX + keyword ipappend, pc_ipappend +%endif +%if IS_PXELINUX || IS_ISOLINUX + keyword localboot, pc_localboot +%endif + +keywd_count equ ($-keywd_table)/keywd_size + diff --git a/syslinux/kwdhash.gen b/syslinux/kwdhash.gen new file mode 100644 index 0000000..d8c7300 --- /dev/null +++ b/syslinux/kwdhash.gen @@ -0,0 +1,34 @@ +hash_hash equ 0x00000023 +hash_menu equ 0x003719b5 +hash_append equ 0xc53999a4 +hash_default equ 0xcc5159ed +hash_display equ 0xd509bc40 +hash_font equ 0x0032b1b4 +hash_implicit equ 0xa6f50207 +hash_ipappend equ 0xc5399af0 +hash_kbdmap equ 0xd013b850 +hash_kernel equ 0xd068b4cc +hash_label equ 0x06f104cc +hash_localboot equ 0x04f0def4 +hash_prompt equ 0xe7163a74 +hash_say equ 0x0001c059 +hash_serial equ 0xe068a84c +hash_console equ 0x18d831fd +hash_timeout equ 0xd4e332c9 +hash_allowoptions equ 0x1648dd10 +hash_ontimeout equ 0xd4e35eb9 +hash_onerror equ 0x1a68c589 +hash_noescape equ 0x0d00090e +hash_f0 equ 0x00000cf0 +hash_f1 equ 0x00000cf1 +hash_f2 equ 0x00000cf2 +hash_f3 equ 0x00000cf3 +hash_f4 equ 0x00000cf4 +hash_f5 equ 0x00000cf5 +hash_f6 equ 0x00000cf6 +hash_f7 equ 0x00000cf7 +hash_f8 equ 0x00000cf8 +hash_f9 equ 0x00000cf9 +hash_f10 equ 0x00019e10 +hash_f11 equ 0x00019e11 +hash_f12 equ 0x00019e12 diff --git a/syslinux/layout.inc b/syslinux/layout.inc new file mode 100644 index 0000000..e890185 --- /dev/null +++ b/syslinux/layout.inc @@ -0,0 +1,55 @@ +; $Id: layout.inc,v 1.1 2004/12/28 06:05:14 hpa Exp $ +; ----------------------------------------------------------------------- +; +; Copyright 1994-2004 H. Peter Anvin - All Rights Reserved +; +; This program is free software; you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +; Bostom MA 02111-1307, USA; either version 2 of the License, or +; (at your option) any later version; incorporated herein by reference. +; +; ----------------------------------------------------------------------- + +; +; layout.inc +; +; Memory layout of segments +; + + +; Memory below 0800h is reserved for the BIOS and the MBR +BSS_START equ 0800h + +; PXELINUX needs lots of BSS, so it relocates itself on startup +%if IS_PXELINUX +TEXT_START equ 9000h +%else +TEXT_START equ 7C00h +%endif + +%ifdef MAP + [map all MAP] +%endif + +; +; The various sections and their relationship +; + org TEXT_START + + ; NASM BUG: refers to hacks to handle NASM 0.98.38 bugs; might need + ; conditional compilation + + section .earlybss nobits start=BSS_START + section .bcopy32 align=4 valign=16 follows=.data vfollows=.earlybss + ; NASM BUG: follows= here should be vfollows= + section .bss nobits align=256 follows=.bcopy32 + + section .text start=TEXT_START + ; NASM BUG: follows=.text not accepted here + section .data align=16 ; follows=.text + + ; NASM BUG: We would like to do follows=.bcopy32 + section .latebss nobits align=16 start=0E000h + + diff --git a/syslinux/ldlinux.asm b/syslinux/ldlinux.asm new file mode 100644 index 0000000..ef4952e --- /dev/null +++ b/syslinux/ldlinux.asm @@ -0,0 +1,1539 @@ +; -*- fundamental -*- (asm-mode sucks) +; $Id: ldlinux.asm,v 1.181 2005/01/18 13:13:50 hpa Exp $ +; **************************************************************************** +; +; ldlinux.asm +; +; A program to boot Linux kernels off an MS-DOS formatted floppy disk. This +; functionality is good to have for installation floppies, where it may +; be hard to find a functional Linux system to run LILO off. +; +; This program allows manipulation of the disk to take place entirely +; from MS-LOSS, and can be especially useful in conjunction with the +; umsdos filesystem. +; +; Copyright (C) 1994-2004 H. Peter Anvin +; +; This program is free software; you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +; Boston MA 02111-1307, USA; either version 2 of the License, or +; (at your option) any later version; incorporated herein by reference. +; +; **************************************************************************** + +%ifndef IS_MDSLINUX +%define IS_SYSLINUX 1 +%endif +%include "macros.inc" +%include "config.inc" +%include "kernel.inc" +%include "bios.inc" +%include "tracers.inc" +%include "layout.inc" +; +; Some semi-configurable constants... change on your own risk. +; +my_id equ syslinux_id +FILENAME_MAX_LG2 equ 4 ; log2(Max filename size Including final null) +FILENAME_MAX equ 11 ; Max mangled filename size +NULLFILE equ ' ' ; First char space == null filename +NULLOFFSET equ 0 ; Position in which to look +retry_count equ 6 ; How patient are we with the disk? +%assign HIGHMEM_SLOP 0 ; Avoid this much memory near the top +LDLINUX_MAGIC equ 0x3eb202fe ; A random number to identify ourselves with + +MAX_OPEN_LG2 equ 6 ; log2(Max number of open files) +MAX_OPEN equ (1 << MAX_OPEN_LG2) + +SECTOR_SHIFT equ 9 +SECTOR_SIZE equ (1 << SECTOR_SHIFT) + +; +; This is what we need to do when idle +; +%macro RESET_IDLE 0 + ; Nothing +%endmacro +%macro DO_IDLE 0 + ; Nothing +%endmacro + +; +; The following structure is used for "virtual kernels"; i.e. LILO-style +; option labels. The options we permit here are `kernel' and `append +; Since there is no room in the bottom 64K for all of these, we +; stick them at vk_seg:0000 and copy them down before we need them. +; + struc vkernel +vk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!** +vk_rname: resb FILENAME_MAX ; Real name +vk_appendlen: resw 1 + alignb 4 +vk_append: resb max_cmd_len+1 ; Command line + alignb 4 +vk_end: equ $ ; Should be <= vk_size + endstruc + +; +; Segment assignments in the bottom 640K +; Stick to the low 512K in case we're using something like M-systems flash +; which load a driver into low RAM (evil!!) +; +; 0000h - main code/data segment (and BIOS segment) +; +real_mode_seg equ 4000h +cache_seg equ 3000h ; 64K area for metadata cache +vk_seg equ 2000h ; Virtual kernels +xfer_buf_seg equ 1000h ; Bounce buffer for I/O to high mem +comboot_seg equ real_mode_seg ; COMBOOT image loading zone + +; +; File structure. This holds the information for each currently open file. +; + struc open_file_t +file_sector resd 1 ; Sector pointer (0 = structure free) +file_left resd 1 ; Number of sectors left + endstruc + +%ifndef DEPEND +%if (open_file_t_size & (open_file_t_size-1)) +%error "open_file_t is not a power of 2" +%endif +%endif + +; --------------------------------------------------------------------------- +; BEGIN CODE +; --------------------------------------------------------------------------- + +; +; Memory below this point is reserved for the BIOS and the MBR +; + section .earlybss +trackbufsize equ 8192 +trackbuf resb trackbufsize ; Track buffer goes here +getcbuf resb trackbufsize + ; ends at 4800h + + section .bss + alignb 8 + + ; Expanded superblock +SuperInfo equ $ + resq 16 ; The first 16 bytes expanded 8 times +FAT resd 1 ; Location of (first) FAT +RootDirArea resd 1 ; Location of root directory area +RootDir resd 1 ; Location of root directory proper +DataArea resd 1 ; Location of data area +RootDirSize resd 1 ; Root dir size in sectors +TotalSectors resd 1 ; Total number of sectors +EndSector resd 1 ; Location of filesystem end +ClustSize resd 1 ; Bytes/cluster +ClustMask resd 1 ; Sectors/cluster - 1 +CopySuper resb 1 ; Distinguish .bs versus .bss +DriveNumber resb 1 ; BIOS drive number +ClustShift resb 1 ; Shift count for sectors/cluster +ClustByteShift resb 1 ; Shift count for bytes/cluster + + alignb open_file_t_size +Files resb MAX_OPEN*open_file_t_size + +; +; Constants for the xfer_buf_seg +; +; The xfer_buf_seg is also used to store message file buffers. We +; need two trackbuffers (text and graphics), plus a work buffer +; for the graphics decompressor. +; +xbs_textbuf equ 0 ; Also hard-coded, do not change +xbs_vgabuf equ trackbufsize +xbs_vgatmpbuf equ 2*trackbufsize + + + section .text +; +; Some of the things that have to be saved very early are saved +; "close" to the initial stack pointer offset, in order to +; reduce the code size... +; +StackBuf equ $-44-32 ; Start the stack here (grow down - 4K) +PartInfo equ StackBuf ; Saved partition table entry +FloppyTable equ PartInfo+16 ; Floppy info table (must follow PartInfo) +OrigFDCTabPtr equ StackBuf-4 ; The high dword on the stack + +; +; Primary entry point. Tempting as though it may be, we can't put the +; initial "cli" here; the jmp opcode in the first byte is part of the +; "magic number" (using the term very loosely) for the DOS superblock. +; +bootsec equ $ + jmp short start ; 2 bytes + nop ; 1 byte +; +; "Superblock" follows -- it's in the boot sector, so it's already +; loaded and ready for us +; +bsOemName db 'SYSLINUX' ; The SYS command sets this, so... +; +; These are the fields we actually care about. We end up expanding them +; all to dword size early in the code, so generate labels for both +; the expanded and unexpanded versions. +; +%macro superb 1 +bx %+ %1 equ SuperInfo+($-superblock)*8+4 +bs %+ %1 equ $ + zb 1 +%endmacro +%macro superw 1 +bx %+ %1 equ SuperInfo+($-superblock)*8 +bs %+ %1 equ $ + zw 1 +%endmacro +%macro superd 1 +bx %+ %1 equ $ ; no expansion for dwords +bs %+ %1 equ $ + zd 1 +%endmacro +superblock equ $ + superw BytesPerSec + superb SecPerClust + superw ResSectors + superb FATs + superw RootDirEnts + superw Sectors + superb Media + superw FATsecs + superw SecPerTrack + superw Heads +superinfo_size equ ($-superblock)-1 ; How much to expand + superd Hidden + superd HugeSectors + ; + ; This is as far as FAT12/16 and FAT32 are consistent + ; + zb 54 ; FAT12/16 need 26 more bytes, + ; FAT32 need 54 more bytes +superblock_len equ $-superblock + +SecPerClust equ bxSecPerClust +; +; Note we don't check the constraints above now; we did that at install +; time (we hope!) +; +start: + cli ; No interrupts yet, please + cld ; Copy upwards +; +; Set up the stack +; + xor ax,ax + mov ss,ax + mov sp,StackBuf ; Just below BSS + mov es,ax +; +; DS:SI may contain a partition table entry. Preserve it for us. +; + mov cx,8 ; Save partition info + mov di,sp + rep movsw + + mov ds,ax ; Now we can initialize DS... + +; +; Now sautee the BIOS floppy info block to that it will support decent- +; size transfers; the floppy block is 11 bytes and is stored in the +; INT 1Eh vector (brilliant waste of resources, eh?) +; +; Of course, if BIOSes had been properly programmed, we wouldn't have +; had to waste precious space with this code. +; + mov bx,fdctab + lfs si,[bx] ; FS:SI -> original fdctab + push fs ; Save on stack in case we need to bail + push si + + ; Save the old fdctab even if hard disk so the stack layout + ; is the same. The instructions above do not change the flags + mov [DriveNumber],dl ; Save drive number in DL + and dl,dl ; If floppy disk (00-7F), assume no + ; partition table + js harddisk + +floppy: + mov cl,6 ; 12 bytes (CX == 0) + ; es:di -> FloppyTable already + ; This should be safe to do now, interrupts are off... + mov [bx],di ; FloppyTable + mov [bx+2],ax ; Segment 0 + fs rep movsw ; Faster to move words + mov cl,[bsSecPerTrack] ; Patch the sector count + mov [di-8],cl + ; AX == 0 here + int 13h ; Some BIOSes need this + + jmp short not_harddisk +; +; The drive number and possibly partition information was passed to us +; by the BIOS or previous boot loader (MBR). Current "best practice" is to +; trust that rather than what the superblock contains. +; +; Would it be better to zero out bsHidden if we don't have a partition table? +; +; Note: di points to beyond the end of PartInfo +; +harddisk: + test byte [di-16],7Fh ; Sanity check: "active flag" should + jnz no_partition ; be 00 or 80 + mov eax,[di-8] ; Partition offset (dword) + mov [bsHidden],eax +no_partition: +; +; Get disk drive parameters (don't trust the superblock.) Don't do this for +; floppy drives -- INT 13:08 on floppy drives will (may?) return info about +; what the *drive* supports, not about the *media*. Fortunately floppy disks +; tend to have a fixed, well-defined geometry which is stored in the superblock. +; + ; DL == drive # still + mov ah,08h + int 13h + jc no_driveparm + and ah,ah + jnz no_driveparm + shr dx,8 + inc dx ; Contains # of heads - 1 + mov [bsHeads],dx + and cx,3fh + mov [bsSecPerTrack],cx +no_driveparm: +not_harddisk: +; +; Ready to enable interrupts, captain +; + sti + + +; +; Do we have EBIOS (EDD)? +; +eddcheck: + mov bx,55AAh + mov ah,41h ; EDD existence query + mov dl,[DriveNumber] + int 13h + jc .noedd + cmp bx,0AA55h + jne .noedd + test cl,1 ; Extended disk access functionality set + jz .noedd + ; + ; We have EDD support... + ; + mov byte [getlinsec.jmp+1],getlinsec_ebios-(getlinsec.jmp+2) +.noedd: + +; +; Load the first sector of LDLINUX.SYS; this used to be all proper +; with parsing the superblock and root directory; it doesn't fit +; together with EBIOS support, unfortunately. +; + mov eax,[FirstSector] ; Sector start + mov bx,ldlinux_sys ; Where to load it + call getonesec + + ; Some modicum of integrity checking + cmp dword [ldlinux_magic],LDLINUX_MAGIC + jne kaboom + cmp dword [ldlinux_magic+4],HEXDATE + jne kaboom + + ; Go for it... + jmp ldlinux_ent + +; +; kaboom: write a message and bail out. +; +kaboom: + xor si,si + mov ss,si + mov sp,StackBuf-4 ; Reset stack + mov ds,si ; Reset data segment + pop dword [fdctab] ; Restore FDC table +.patch: mov si,bailmsg + call writestr ; Returns with AL = 0 + cbw ; AH <- 0 + int 16h ; Wait for keypress + int 19h ; And try once more to boot... +.norge: jmp short .norge ; If int 19h returned; this is the end + +; +; +; writestr: write a null-terminated string to the console +; This assumes we're on page 0. This is only used for early +; messages, so it should be OK. +; +writestr: +.loop: lodsb + and al,al + jz .return + mov ah,0Eh ; Write to screen as TTY + mov bx,0007h ; Attribute + int 10h + jmp short .loop +.return: ret + +; +; xint13: wrapper for int 13h which will retry 6 times and then die, +; AND save all registers except BP +; +xint13: +.again: + mov bp,retry_count +.loop: pushad + int 13h + popad + jnc writestr.return + dec bp + jnz .loop +.disk_error: + jmp strict near kaboom ; Patched + + +; +; getonesec: get one disk sector +; +getonesec: + mov bp,1 ; One sector + ; Fall through + +; +; getlinsec: load a sequence of BP floppy sector given by the linear sector +; number in EAX into the buffer at ES:BX. We try to optimize +; by loading up to a whole track at a time, but the user +; is responsible for not crossing a 64K boundary. +; (Yes, BP is weird for a count, but it was available...) +; +; On return, BX points to the first byte after the transferred +; block. +; +; This routine assumes CS == DS, and trashes most registers. +; +; Stylistic note: use "xchg" instead of "mov" when the source is a register +; that is dead from that point; this saves space. However, please keep +; the order to dst,src to keep things sane. +; +getlinsec: + add eax,[bsHidden] ; Add partition offset +.jmp: jmp strict short getlinsec_cbios ; This is patched + +; +; getlinsec_ebios: +; +; getlinsec implementation for EBIOS (EDD) +; +getlinsec_ebios: + mov si,dapa ; Load up the DAPA + mov [si+4],bx + mov [si+6],es + mov [si+8],eax +.loop: + push bp ; Sectors left + call maxtrans ; Enforce maximum transfer size +.bp_ok: + mov [si+2],bp + mov dl,[DriveNumber] + mov ah,42h ; Extended Read + call xint13 + pop bp + movzx eax,word [si+2] ; Sectors we read + add [si+8],eax ; Advance sector pointer + sub bp,ax ; Sectors left + shl ax,9 ; 512-byte sectors + add [si+4],ax ; Advance buffer pointer + and bp,bp + jnz .loop + mov eax,[si+8] ; Next sector + mov bx,[si+4] ; Buffer pointer + ret + +; +; getlinsec_cbios: +; +; getlinsec implementation for legacy CBIOS +; +getlinsec_cbios: +.loop: + push eax + push bp + push bx + + movzx esi,word [bsSecPerTrack] + movzx edi,word [bsHeads] + ; + ; Dividing by sectors to get (track,sector): we may have + ; up to 2^18 tracks, so we need to use 32-bit arithmetric. + ; + xor edx,edx ; Zero-extend LBA to 64 bits + div esi + xor cx,cx + xchg cx,dx ; CX <- sector index (0-based) + ; EDX <- 0 + ; eax = track # + div edi ; Convert track to head/cyl + ; + ; Now we have AX = cyl, DX = head, CX = sector (0-based), + ; BP = sectors to transfer, SI = bsSecPerTrack, + ; ES:BX = data target + ; + + call maxtrans ; Enforce maximum transfer size + + ; Must not cross track boundaries, so BP <= SI-CX + sub si,cx + cmp bp,si + jna .bp_ok + mov bp,si +.bp_ok: + + shl ah,6 ; Because IBM was STOOPID + ; and thought 8 bits were enough + ; then thought 10 bits were enough... + inc cx ; Sector numbers are 1-based, sigh + or cl,ah + mov ch,al + mov dh,dl + mov dl,[DriveNumber] + xchg ax,bp ; Sector to transfer count + mov ah,02h ; Read sectors + call xint13 + movzx ecx,al + shl ax,9 ; Convert sectors in AL to bytes in AX + pop bx + add bx,ax + pop bp + pop eax + add eax,ecx + sub bp,cx + jnz .loop + ret + +; +; Truncate BP to MaxTransfer +; +maxtrans: + cmp bp,[MaxTransfer] + jna .ok + mov bp,[MaxTransfer] +.ok: ret + +; +; Error message on failure +; +bailmsg: db 'Boot failed', 0Dh, 0Ah, 0 + +; +; EBIOS disk address packet +; + align 4, db 0 +dapa: + dw 16 ; Packet size +.count: dw 0 ; Block count +.off: dw 0 ; Offset of buffer +.seg: dw 0 ; Segment of buffer +.lba: dd 0 ; LBA (LSW) + dd 0 ; LBA (MSW) + + +%if 1 +bs_checkpt_off equ ($-$$) +%ifndef DEPEND +%if bs_checkpt_off > 1F8h +%error "Boot sector overflow" +%endif +%endif + + zb 1F8h-($-$$) +%endif +FirstSector dd 0xDEADBEEF ; Location of sector 1 +MaxTransfer dw 0x007F ; Max transfer size +bootsignature dw 0AA55h + +; +; =========================================================================== +; End of boot sector +; =========================================================================== +; Start of LDLINUX.SYS +; =========================================================================== + +ldlinux_sys: + +syslinux_banner db 0Dh, 0Ah +%if IS_MDSLINUX + db 'MDSLINUX ' +%else + db 'SYSLINUX ' +%endif + db version_str, ' ', date, ' ', 0 + db 0Dh, 0Ah, 1Ah ; EOF if we "type" this in DOS + + align 8, db 0 +ldlinux_magic dd LDLINUX_MAGIC + dd HEXDATE + +; +; This area is patched by the installer. It is found by looking for +; LDLINUX_MAGIC, plus 8 bytes. +; +patch_area: +LDLDwords dw 0 ; Total dwords starting at ldlinux_sys +LDLSectors dw 0 ; Number of sectors - (bootsec+this sec) +CheckSum dd 0 ; Checksum starting at ldlinux_sys + ; value = LDLINUX_MAGIC - [sum of dwords] + +; Space for up to 64 sectors, the theoretical maximum +SectorPtrs times 64 dd 0 + +ldlinux_ent: +; +; Note that some BIOSes are buggy and run the boot sector at 07C0:0000 +; instead of 0000:7C00 and the like. We don't want to add anything +; more to the boot sector, so it is written to not assume a fixed +; value in CS, but we don't want to deal with that anymore from now +; on. +; + jmp 0:.next +.next: + +; +; Tell the user we got this far +; + mov si,syslinux_banner + call writestr + +; +; Patch disk error handling +; + mov word [xint13.disk_error+1],do_disk_error-(xint13.disk_error+3) + +; +; Now we read the rest of LDLINUX.SYS. Don't bother loading the first +; sector again, though. +; +load_rest: + mov si,SectorPtrs + mov bx,7C00h+2*SECTOR_SIZE ; Where we start loading + mov cx,[LDLSectors] + +.get_chunk: + jcxz .done + xor bp,bp + lodsd ; First sector of this chunk + + mov edx,eax + +.make_chunk: + inc bp + dec cx + jz .chunk_ready + inc edx ; Next linear sector + cmp [esi],edx ; Does it match + jnz .chunk_ready ; If not, this is it + add esi,4 ; If so, add sector to chunk + jmp short .make_chunk + +.chunk_ready: + call getlinsecsr + shl bp,SECTOR_SHIFT + add bx,bp + jmp .get_chunk + +.done: + +; +; All loaded up, verify that we got what we needed. +; Note: the checksum field is embedded in the checksum region, so +; by the time we get to the end it should all cancel out. +; +verify_checksum: + mov si,ldlinux_sys + mov cx,[LDLDwords] + mov edx,-LDLINUX_MAGIC +.checksum: + lodsd + add edx,eax + loop .checksum + + and edx,edx ; Should be zero + jz all_read ; We're cool, go for it! + +; +; Uh-oh, something went bad... +; + mov si,checksumerr_msg + call writestr + jmp kaboom + +; +; ----------------------------------------------------------------------------- +; Subroutines that have to be in the first sector +; ----------------------------------------------------------------------------- + +; +; getlinsecsr: save registers, call getlinsec, restore registers +; +getlinsecsr: pushad + call getlinsec + popad + ret + +; +; This routine captures disk errors, and tries to decide if it is +; time to reduce the transfer size. +; +do_disk_error: + cmp ah,42h + je .ebios + shr al,1 ; Try reducing the transfer size + mov [MaxTransfer],al + jz kaboom ; If we can't, we're dead... + jmp xint13 ; Try again +.ebios: + push ax + mov ax,[si+2] + shr ax,1 + mov [MaxTransfer],ax + mov [si+2],ax + pop ax + jmp xint13 + +; +; Checksum error message +; +checksumerr_msg db 'Load error - ', 0 ; Boot failed appended + +; +; Debug routine +; +%ifdef debug +safedumpregs: + cmp word [Debug_Magic],0D00Dh + jnz nc_return + jmp dumpregs +%endif + +rl_checkpt equ $ ; Must be <= 8000h + +rl_checkpt_off equ ($-$$) +%if 0 ; ndef DEPEND +%if rl_checkpt_off > 400h +%error "Sector 1 overflow" +%endif +%endif + +; ---------------------------------------------------------------------------- +; End of code and data that have to be in the first sector +; ---------------------------------------------------------------------------- + +all_read: +; +; Let the user (and programmer!) know we got this far. This used to be +; in Sector 1, but makes a lot more sense here. +; + mov si,copyright_str + call writestr + + +; +; Insane hack to expand the superblock to dwords +; +expand_super: + xor eax,eax + mov si,superblock + mov di,SuperInfo + mov cx,superinfo_size +.loop: + lodsw + dec si + stosd ; Store expanded word + xor ah,ah + stosd ; Store expanded byte + loop .loop + +; +; Compute some information about this filesystem. +; + +; First, generate the map of regions +genfatinfo: + mov edx,[bxSectors] + and dx,dx + jnz .have_secs + mov edx,[bsHugeSectors] +.have_secs: + mov [TotalSectors],edx + + add edx,eax + mov [EndSector],edx + + mov eax,[bxResSectors] + mov [FAT],eax ; Beginning of FAT + mov edx,[bxFATsecs] + and dx,dx + jnz .have_fatsecs + mov edx,[bootsec+36] ; FAT32 BPB_FATsz32 +.have_fatsecs: + imul edx,[bxFATs] + add eax,edx + mov [RootDirArea],eax ; Beginning of root directory + mov [RootDir],eax ; For FAT12/16 == root dir location + + mov edx,[bxRootDirEnts] + add dx,SECTOR_SIZE/32-1 + shr dx,SECTOR_SHIFT-5 + mov [RootDirSize],edx + add eax,edx + mov [DataArea],eax ; Beginning of data area + +; Next, generate a cluster size shift count and mask + mov eax,[bxSecPerClust] + bsr cx,ax + mov [ClustShift],cl + push cx + add cl,9 + mov [ClustByteShift],cl + pop cx + dec ax + mov [ClustMask],eax + inc ax + shl eax,9 + mov [ClustSize],eax + +; +; FAT12, FAT16 or FAT28^H^H32? This computation is fscking ridiculous. +; +getfattype: + mov eax,[EndSector] + sub eax,[DataArea] + shr eax,cl ; cl == ClustShift + mov cl,nextcluster_fat12-(nextcluster+2) + cmp eax,4085 ; FAT12 limit + jb .setsize + mov cl,nextcluster_fat16-(nextcluster+2) + cmp eax,65525 ; FAT16 limit + jb .setsize + ; + ; FAT32, root directory is a cluster chain + ; + mov cl,[ClustShift] + mov eax,[bootsec+44] ; Root directory cluster + sub eax,2 + shl eax,cl + add eax,[DataArea] + mov [RootDir],eax + mov cl,nextcluster_fat28-(nextcluster+2) +.setsize: + mov byte [nextcluster+1],cl + +; +; Common initialization code +; +%include "cpuinit.inc" +%include "init.inc" + +; +; Clear Files structures +; + mov di,Files + mov cx,(MAX_OPEN*open_file_t_size)/4 + xor eax,eax + rep stosd + +; +; Initialize the metadata cache +; + call initcache + +; +; Now, everything is "up and running"... patch kaboom for more +; verbosity and using the full screen system +; + ; E9 = JMP NEAR + mov dword [kaboom.patch],0e9h+((kaboom2-(kaboom.patch+3)) << 8) + +; +; Now we're all set to start with our *real* business. First load the +; configuration file (if any) and parse it. +; +; In previous versions I avoided using 32-bit registers because of a +; rumour some BIOSes clobbered the upper half of 32-bit registers at +; random. I figure, though, that if there are any of those still left +; they probably won't be trying to install Linux on them... +; +; The code is still ripe with 16-bitisms, though. Not worth the hassle +; to take'm out. In fact, we may want to put them back if we're going +; to boot ELKS at some point. +; + +; +; Load configuration file +; + mov di,syslinux_cfg + call open + jz no_config_file + +; +; Now we have the config file open. Parse the config file and +; run the user interface. +; +%include "ui.inc" + +; +; Linux kernel loading code is common. +; +%include "runkernel.inc" + +; +; COMBOOT-loading code +; +%include "comboot.inc" +%include "com32.inc" +%include "cmdline.inc" + +; +; Boot sector loading code +; +%include "bootsect.inc" + +; +; abort_check: let the user abort with <ESC> or <Ctrl-C> +; +abort_check: + call pollchar + jz ac_ret1 + pusha + call getchar + cmp al,27 ; <ESC> + je ac_kill + cmp al,3 ; <Ctrl-C> + jne ac_ret2 +ac_kill: mov si,aborted_msg + +; +; abort_load: Called by various routines which wants to print a fatal +; error message and return to the command prompt. Since this +; may happen at just about any stage of the boot process, assume +; our state is messed up, and just reset the segment registers +; and the stack forcibly. +; +; SI = offset (in _text) of error message to print +; +abort_load: + mov ax,cs ; Restore CS = DS = ES + mov ds,ax + mov es,ax + cli + mov sp,StackBuf-2*3 ; Reset stack + mov ss,ax ; Just in case... + sti + call cwritestr ; Expects SI -> error msg +al_ok: jmp enter_command ; Return to command prompt +; +; End of abort_check +; +ac_ret2: popa +ac_ret1: ret + +; +; allocate_file: Allocate a file structure +; +; If successful: +; ZF set +; BX = file pointer +; In unsuccessful: +; ZF clear +; +allocate_file: + TRACER 'a' + push cx + mov bx,Files + mov cx,MAX_OPEN +.check: cmp dword [bx], byte 0 + je .found + add bx,open_file_t_size ; ZF = 0 + loop .check + ; ZF = 0 if we fell out of the loop +.found: pop cx + ret + +; +; searchdir: +; Search the root directory for a pre-mangled filename in DS:DI. +; +; NOTE: This file considers finding a zero-length file an +; error. This is so we don't have to deal with that special +; case elsewhere in the program (most loops have the test +; at the end). +; +; If successful: +; ZF clear +; SI = file pointer +; DX:AX = file length in bytes +; If unsuccessful +; ZF set +; + +searchdir: + call allocate_file + jnz .alloc_failure + + push gs + push es + push ds + pop es ; ES = DS + + mov eax,[RootDir] ; First root directory sector + +.scansector: + call getcachesector + ; GS:SI now points to this sector + + mov cx,SECTOR_SIZE/32 ; 32 == directory entry size +.scanentry: + cmp byte [gs:si],0 + jz .failure ; Hit directory high water mark + push cx + push si + push di + mov cx,11 + gs repe cmpsb + pop di + pop si + pop cx + jz .found + add si,32 + loop .scanentry + + call nextsector + jnc .scansector ; CF is set if we're at end + + ; If we get here, we failed +.failure: + pop es + pop gs +.alloc_failure: + xor ax,ax ; ZF <- 1 + ret +.found: + mov eax,[gs:si+28] ; File size + add eax,SECTOR_SIZE-1 + shr eax,SECTOR_SHIFT + jz .failure ; Zero-length file + mov [bx+4],eax + + mov cl,[ClustShift] + mov dx,[gs:si+20] ; High cluster word + shl edx,16 + mov dx,[gs:si+26] ; Low cluster word + sub edx,2 + shl edx,cl + add edx,[DataArea] + mov [bx],edx ; Starting sector + + mov eax,[gs:si+28] ; File length again + mov dx,[gs:si+30] ; 16-bitism, sigh + mov si,bx + and eax,eax ; ZF <- 0 + + pop es + pop gs + ret + +; +; writechr: Write a single character in AL to the console without +; mangling any registers; handle video pages correctly. +; +writechr: + call write_serial ; write to serial port if needed + pushfd + test byte [cs:DisplayCon], 01h + jz .nothing + pushad + mov ah,0Eh + mov bl,07h ; attribute + mov bh,[cs:BIOS_page] ; current page + int 10h + popad +.nothing: + popfd + ret + +; +; +; kaboom2: once everything is loaded, replace the part of kaboom +; starting with "kaboom.patch" with this part + +kaboom2: + mov si,err_bootfailed + call cwritestr + call getchar + call vgaclearmode + int 19h ; And try once more to boot... +.norge: jmp short .norge ; If int 19h returned; this is the end + +; +; mangle_name: Mangle a DOS filename pointed to by DS:SI into a buffer pointed +; to by ES:DI; ends on encountering any whitespace +; + +mangle_name: + mov cx,11 ; # of bytes to write +mn_loop: + lodsb + cmp al,' ' ; If control or space, end + jna mn_end + cmp al,'.' ; Period -> space-fill + je mn_is_period + cmp al,'a' + jb mn_not_lower + cmp al,'z' + ja mn_not_uslower + sub al,020h + jmp short mn_not_lower +mn_is_period: mov al,' ' ; We need to space-fill +mn_period_loop: cmp cx,3 ; If <= 3 characters left + jbe mn_loop ; Just ignore it + stosb ; Otherwise, write a period + loop mn_period_loop ; Dec CX and (always) jump +mn_not_uslower: cmp al,ucase_low + jb mn_not_lower + cmp al,ucase_high + ja mn_not_lower + mov bx,ucase_tab-ucase_low + cs xlatb +mn_not_lower: stosb + loop mn_loop ; Don't continue if too long +mn_end: + mov al,' ' ; Space-fill name + rep stosb ; Doesn't do anything if CX=0 + ret ; Done + +; +; Upper-case table for extended characters; this is technically code page 865, +; but code page 437 users will probably not miss not being able to use the +; cent sign in kernel images too much :-) +; +; The table only covers the range 129 to 164; the rest we can deal with. +; +ucase_low equ 129 +ucase_high equ 164 +ucase_tab db 154, 144, 'A', 142, 'A', 143, 128, 'EEEIII' + db 142, 143, 144, 146, 146, 'O', 153, 'OUUY', 153, 154 + db 157, 156, 157, 158, 159, 'AIOU', 165 + +; +; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled +; filename to the conventional representation. This is needed +; for the BOOT_IMAGE= parameter for the kernel. +; NOTE: A 13-byte buffer is mandatory, even if the string is +; known to be shorter. +; +; DS:SI -> input mangled file name +; ES:DI -> output buffer +; +; On return, DI points to the first byte after the output name, +; which is set to a null byte. +; +unmangle_name: + push si ; Save pointer to original name + mov cx,8 + mov bp,di +un_copy_body: lodsb + call lower_case + stosb + cmp al,' ' + jbe un_cb_space + mov bp,di ; Position of last nonblank+1 +un_cb_space: loop un_copy_body + mov di,bp + mov al,'.' ; Don't save + stosb + mov cx,3 +un_copy_ext: lodsb + call lower_case + stosb + cmp al,' ' + jbe un_ce_space + mov bp,di +un_ce_space: loop un_copy_ext + mov di,bp + mov byte [es:di], 0 + pop si + ret + +; +; lower_case: Lower case a character in AL +; +lower_case: + cmp al,'A' + jb lc_ret + cmp al,'Z' + ja lc_1 + or al,20h + ret +lc_1: cmp al,lcase_low + jb lc_ret + cmp al,lcase_high + ja lc_ret + push bx + mov bx,lcase_tab-lcase_low + cs xlatb + pop bx +lc_ret: ret + +; +; getfssec_edx: Get multiple sectors from a file +; +; This routine makes sure the subtransfers do not cross a 64K boundary, +; and will correct the situation if it does, UNLESS *sectors* cross +; 64K boundaries. +; +; ES:BX -> Buffer +; EDX -> Current sector number +; CX -> Sector count (0FFFFh = until end of file) +; Must not exceed the ES segment +; Returns EDX=0, CF=1 on EOF (not necessarily error) +; All arguments are advanced to reflect data read. +; +getfssec_edx: + push ebp + push eax +.getfragment: + xor ebp,ebp ; Fragment sector count + push edx ; Starting sector pointer +.getseccnt: + inc bp + dec cx + jz .do_read + xor eax,eax + mov ax,es + shl ax,4 + add ax,bx ; Now AX = how far into 64K block we are + not ax ; Bytes left in 64K block + inc eax + shr eax,SECTOR_SHIFT ; Sectors left in 64K block + cmp bp,ax + jnb .do_read ; Unless there is at least 1 more sector room... + mov eax,edx ; Current sector + inc edx ; Predict it's the linearly next sector + call nextsector + jc .do_read + cmp edx,eax ; Did it match? + jz .getseccnt +.do_read: + pop eax ; Starting sector pointer + call getlinsecsr + lea eax,[eax+ebp-1] ; This is the last sector actually read + shl bp,9 + add bx,bp ; Adjust buffer pointer + call nextsector + jc .eof + mov edx,eax + and cx,cx + jnz .getfragment +.done: + pop eax + pop ebp + ret +.eof: + xor edx,edx + stc + jmp .done + +; +; getfssec: Get multiple sectors from a file +; +; Same as above, except SI is a pointer to a open_file_t +; +; ES:BX -> Buffer +; DS:SI -> Pointer to open_file_t +; CX -> Sector count (0FFFFh = until end of file) +; Must not exceed the ES segment +; Returns CF=1 on EOF (not necessarily error) +; All arguments are advanced to reflect data read. +; +getfssec: + push edx + movzx edx,cx + cmp edx,[si+4] + jbe .sizeok + mov edx,[si+4] + mov cx,dx +.sizeok: + sub [si+4],edx + mov edx,[si] + call getfssec_edx + mov [si],edx + pop edx + ret + +; +; nextcluster: Advance a cluster pointer in EDI to the next cluster +; pointed at in the FAT tables. CF=0 on return if end of file. +; +nextcluster: + jmp strict short nextcluster_fat28 ; This gets patched + +nextcluster_fat12: + push eax + push edx + push bx + push cx + push si + mov edx,edi + shr edi,1 + pushf ; Save the shifted-out LSB (=CF) + add edx,edi + mov eax,edx + shr eax,9 + call getfatsector + mov bx,dx + and bx,1FFh + mov cl,[gs:si+bx] + inc edx + mov eax,edx + shr eax,9 + call getfatsector + mov bx,dx + and bx,1FFh + mov ch,[gs:si+bx] + popf + jnc .even + shr cx,4 +.even: and cx,0FFFh + movzx edi,cx + cmp di,0FF0h + pop si + pop cx + pop bx + pop edx + pop eax + ret + +; +; FAT16 decoding routine. +; +nextcluster_fat16: + push eax + push si + push bx + mov eax,edi + shr eax,SECTOR_SHIFT-1 + call getfatsector + mov bx,di + add bx,bx + and bx,1FEh + movzx edi,word [gs:si+bx] + cmp di,0FFF0h + pop bx + pop si + pop eax + ret +; +; FAT28 ("FAT32") decoding routine. +; +nextcluster_fat28: + push eax + push si + push bx + mov eax,edi + shr eax,SECTOR_SHIFT-2 + call getfatsector + mov bx,di + add bx,bx + add bx,bx + and bx,1FCh + mov edi,dword [gs:si+bx] + and edi,0FFFFFFFh ; 28 bits only + cmp edi,0FFFFFF0h + pop bx + pop si + pop eax + ret + +; +; nextsector: Given a sector in EAX on input, return the next sector +; of the same filesystem object, which may be the root +; directory or a cluster chain. Returns EOF. +; +; Assumes CS == DS. +; +nextsector: + push edi + push edx + mov edx,[DataArea] + mov edi,eax + sub edi,edx + jae .isdata + + ; Root directory + inc eax + cmp eax,edx + cmc + jmp .done + +.isdata: + not edi + test edi,[ClustMask] + jz .endcluster + + ; It's not the final sector in a cluster + inc eax + jmp .done + +.endcluster: + push gs ; nextcluster trashes gs + push cx + not edi + mov cl,[ClustShift] + shr edi,cl + add edi,2 + + ; Now EDI contains the cluster number + call nextcluster + cmc + jc .exit ; There isn't anything else... + + ; New cluster number now in EDI + sub edi,2 + shl edi,cl ; CF <- 0, unless something is very wrong + lea eax,[edi+edx] +.exit: + pop cx + pop gs +.done: + pop edx + pop edi + ret + +; +; getfatsector: Check for a particular sector (in EAX) in the FAT cache, +; and return a pointer in GS:SI, loading it if needed. +; +; Assumes CS == DS. +; +getfatsector: + add eax,[FAT] ; FAT starting address + jmp getcachesector + +; ----------------------------------------------------------------------------- +; Common modules +; ----------------------------------------------------------------------------- + +%include "getc.inc" ; getc et al +%include "conio.inc" ; Console I/O +%include "writestr.inc" ; String output +%include "parseconfig.inc" ; High-level config file handling +%include "parsecmd.inc" ; Low-level config file handling +%include "bcopy32.inc" ; 32-bit bcopy +%include "loadhigh.inc" ; Load a file into high memory +%include "font.inc" ; VGA font stuff +%include "graphics.inc" ; VGA graphics +%include "highmem.inc" ; High memory sizing +%include "strcpy.inc" ; strcpy() +%include "cache.inc" ; Metadata disk cache + +; ----------------------------------------------------------------------------- +; Begin data section +; ----------------------------------------------------------------------------- + + section .data +; +; Lower-case table for codepage 865 +; +lcase_low equ 128 +lcase_high equ 165 +lcase_tab db 135, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138 + db 139, 140, 141, 132, 134, 130, 145, 145, 147, 148, 149 + db 150, 151, 152, 148, 129, 155, 156, 155, 158, 159, 160 + db 161, 162, 163, 164, 164 + +copyright_str db ' Copyright (C) 1994-', year, ' H. Peter Anvin' + db CR, LF, 0 +boot_prompt db 'boot: ', 0 +wipe_char db BS, ' ', BS, 0 +err_notfound db 'Could not find kernel image: ',0 +err_notkernel db CR, LF, 'Invalid or corrupt kernel image.', CR, LF, 0 +err_noram db 'It appears your computer has less than ' + asciidec dosram_k + db 'K of low ("DOS")' + db CR, LF + db 'RAM. Linux needs at least this amount to boot. If you get' + db CR, LF + db 'this message in error, hold down the Ctrl key while' + db CR, LF + db 'booting, and I will take your word for it.', CR, LF, 0 +err_badcfg db 'Unknown keyword in syslinux.cfg.', CR, LF, 0 +err_noparm db 'Missing parameter in syslinux.cfg.', CR, LF, 0 +err_noinitrd db CR, LF, 'Could not find ramdisk image: ', 0 +err_nohighmem db 'Not enough memory to load specified kernel.', CR, LF, 0 +err_highload db CR, LF, 'Kernel transfer failure.', CR, LF, 0 +err_oldkernel db 'Cannot load a ramdisk with an old kernel image.' + db CR, LF, 0 +err_notdos db ': attempted DOS system call', CR, LF, 0 +err_comlarge db 'COMBOOT image too large.', CR, LF, 0 +err_a20 db CR, LF, 'A20 gate not responding!', CR, LF, 0 +err_bootfailed db CR, LF, 'Boot failed: please change disks and press ' + db 'a key to continue.', CR, LF, 0 +ready_msg db 'Ready.', CR, LF, 0 +crlfloading_msg db CR, LF +loading_msg db 'Loading ', 0 +dotdot_msg db '.' +dot_msg db '.', 0 +aborted_msg db ' aborted.' ; Fall through to crlf_msg! +crlf_msg db CR, LF +null_msg db 0 +crff_msg db CR, FF, 0 +syslinux_cfg db 'SYSLINUXCFG' ; Mangled form +ConfigName db 'syslinux.cfg',0 ; Unmangled form +%if IS_MDSLINUX +manifest db 'MANIFEST ' +%endif +; +; Command line options we'd like to take a look at +; +; mem= and vga= are handled as normal 32-bit integer values +initrd_cmd db 'initrd=' +initrd_cmd_len equ 7 + +; +; Config file keyword table +; +%include "keywords.inc" + +; +; Extensions to search for (in *forward* order). +; +exten_table: db 'CBT',0 ; COMBOOT (specific) + db 'BSS',0 ; Boot Sector (add superblock) + db 'BS ',0 ; Boot Sector + db 'COM',0 ; COMBOOT (same as DOS) + db 'C32',0 ; COM32 +exten_table_end: + dd 0, 0 ; Need 8 null bytes here + +; +; Misc initialized (data) variables +; +%ifdef debug ; This code for debugging only +debug_magic dw 0D00Dh ; Debug code sentinel +%endif + + alignb 4, db 0 +BufSafe dw trackbufsize/SECTOR_SIZE ; Clusters we can load into trackbuf +BufSafeSec dw trackbufsize/SECTOR_SIZE ; = how many sectors? +BufSafeBytes dw trackbufsize ; = how many bytes? +EndOfGetCBuf dw getcbuf+trackbufsize ; = getcbuf+BufSafeBytes +%ifndef DEPEND +%if ( trackbufsize % SECTOR_SIZE ) != 0 +%error trackbufsize must be a multiple of SECTOR_SIZE +%endif +%endif diff --git a/syslinux/ldlinux.bin b/syslinux/ldlinux.bin new file mode 100644 index 0000000000000000000000000000000000000000..d089e0d12ec0692717f4a90b73a75167eb198127 GIT binary patch literal 9932 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 BG_(K! literal 0 HcmV?d00001 diff --git a/syslinux/ldlinux.bss b/syslinux/ldlinux.bss new file mode 100644 index 0000000000000000000000000000000000000000..24cf9753406d0725136347e55d57dd343a39ecc9 GIT binary patch literal 512 zcmaDIF(EiI*vHc^G=hP;;MX6+1AQ0vY^m-$u#<zK^ZDnceK&SjFz|0N=U))kA-2?8 z;ZlX@Mz&7-PIso1&r7@bBx*W*f1DM5t^UpRLwzYnTDR+uw8b(tTR6@N7YQpoDdj)- zio>Z>Osb~&p?xQxM9uHrt3tOpc8M+ZJ}X=#(D*xaRVmlEgN!At$JiWd8PXR1sNKy_ z_acNLt<g@Q?jO@8yHdWiMmv?dQ@`IkmNLIIVKV&IcWuvx>b`qv{cIHs`)<^}U}u<d zR_v_g>wjw$4wP_i;oHs5a8}^;r^9>M7}65X3a2F&fAKB-`ts=iy^IWL%xp3>udVmJ zsO^kl>2YC8>vZ7=eNoNOnZpEf(-x-}C;rE#@o#rwN@H~4&^&tZ0Vksii{jhTTWQ@c z9NjT2htmQ=gVXr8n@QB9@o%@2s!21vl=l6b;mP(>Y2UxUFl5j?XZf{^sq^cBCv1)! z4?B)_Tmu<Abqmvry#HzZ+fE#Oz!}YWI5sUJjq!x$+0qS%t@ZxYma%l}{i!|dl%HRs ckd~O4lbXWI#lXNIfEKy$_pQBG&k(u_07?S9-T(jq literal 0 HcmV?d00001 diff --git a/syslinux/ldlinux.sys b/syslinux/ldlinux.sys new file mode 100644 index 0000000000000000000000000000000000000000..9bbe3b463248bb4dc94c5da51803c94e391e8dc4 GIT binary patch literal 9420 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 literal 0 HcmV?d00001 diff --git a/syslinux/libfat/cache.c b/syslinux/libfat/cache.c new file mode 100644 index 0000000..378705f --- /dev/null +++ b/syslinux/libfat/cache.c @@ -0,0 +1,70 @@ +#ident "$Id: cache.c,v 1.1 2004/12/15 10:14:39 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * cache.c + * + * Simple sector cache + */ + +#include <stdlib.h> +#include "libfatint.h" + +void * libfat_get_sector(struct libfat_filesystem *fs, libfat_sector_t n) +{ + struct libfat_sector *ls; + + for ( ls = fs->sectors ; ls ; ls = ls->next ) { + if ( ls->n == n ) + return ls->data; /* Found in cache */ + } + + /* Not found in cache */ + ls = malloc(sizeof(struct libfat_sector)); + if ( !ls ) { + libfat_flush(fs); + ls = malloc(sizeof(struct libfat_sector)); + + if ( !ls ) + return NULL; /* Can't allocate memory */ + } + + if ( fs->read(fs->readptr, ls->data, LIBFAT_SECTOR_SIZE, n) + != LIBFAT_SECTOR_SIZE ) { + free(ls); + return NULL; /* I/O error */ + } + + ls->n = n; + ls->next = fs->sectors; + fs->sectors = ls; + + return ls->data; +} + +void libfat_flush(struct libfat_filesystem *fs) +{ + struct libfat_sector *ls, *lsnext; + + lsnext = fs->sectors; + fs->sectors = NULL; + + for ( ls = lsnext ; ls ; ls = lsnext ) { + lsnext = ls->next; + free(ls); + } +} + + + + diff --git a/syslinux/libfat/fat.h b/syslinux/libfat/fat.h new file mode 100644 index 0000000..07ea0d8 --- /dev/null +++ b/syslinux/libfat/fat.h @@ -0,0 +1,112 @@ +#ident "$Id: fat.h,v 1.1 2004/12/15 10:14:39 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2001-2004 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * fat.h + * + * Basic data structures for a FAT filesystem + */ + +#ifndef FAT_H +#define FAT_H + +#include "ulint.h" + +/* The poor excuse FAT has for a superblock -- in the boot sector */ +struct fat_bootsect { + le8_t bsJump[3]; /* Jump to code */ + char bsOemName[8]; /* Formatting program */ + le16_t bsBytesPerSec; /* Bytes/sector */ + le8_t bsSecPerClust; /* Sectors/cluster */ + le16_t bsResSectors; /* Reserved sectors */ + le8_t bsFATs; /* Number of FATs */ + le16_t bsRootDirEnts; /* Number of entries/root directory */ + le16_t bsSectors; /* Number of sectors [1] */ + le8_t bsMedia; /* Magic media type byte */ + le16_t bsFATsecs; /* Sectors/FAT */ + le16_t bsSecPerTrack; /* Sectors/track */ + le16_t bsHeads; /* Number of heads */ + le32_t bsHiddenSecs; /* Number of hidden sectors */ + le32_t bsHugeSectors; /* Number of sectors [2] */ + union { + /* FAT12/16 */ + struct { + le8_t bsDriveNumber; /* Drive number */ + le8_t bsReserved1; /* Reserved */ + le8_t bsBootSignature; /* 0x29 */ + le32_t bsVolumeID; /* Volume serial number */ + char bsVolumeLabel[11]; /* Volume name */ + char bsFileSysType[8]; /* File system type */ + + le8_t bsCode[448]; /* Boot sector code */ + } fat16; + + /* FAT32 */ + struct { + le32_t bpb_fatsz32; /* Sectors/FAT */ + le16_t bpb_extflags; /* Extended flags */ + le16_t bpb_fsver; /* Filesystem version */ + le32_t bpb_rootclus; /* Root directory cluster */ + le16_t bpb_fsinfo; /* FSINFO sector number */ + le16_t bpb_bkbootsec; /* Backup boot sector (superblock) */ + char bpb_reserved[12]; + + /* Same shit, different offset! */ + le8_t bsDriveNumber; /* Drive number */ + le8_t bsReserved1; /* Reserved */ + le8_t bsBootSignature; /* 0x29 */ + le32_t bsVolumeID; /* Volume serial number */ + char bsVolumeLabel[11]; /* Volume name */ + char bsFileSysType[8]; /* File system type */ + + le8_t bsCode[420]; /* Boot sector code */ + } fat32; + } u; + + le16_t bsSignature; /* 0xAA55 */ +}; + +#define BS_BOOTSIGNATURE 0x29 +#define BS_SIGNATURE 0xAA55 + +/* A FAT filesystem directory entry */ + +struct fat_dirent +{ + le8_t name[11]; /* Mangled filename */ + le8_t attribute; /* File type/attribute */ + le8_t caseflags; /* VFAT: case for basis and extension */ + le8_t ctime_ms; /* ms of creation time */ + le32_t ctime; /* Creation time */ + le16_t atime; /* Date portion (high 16 bits) of atime */ + le16_t clusthi; /* FAT32: high 16 bits of cluster */ + le32_t mtime; /* Modification time */ + le16_t clustlo; /* First cluster pointer */ + le32_t size; /* File size (bytes) */ +}; + +/* A VFAT filesystem continuation entry */ +struct fat_vfat_slot +{ + le8_t id; /* Sequence number for slot */ + le16_t name0[5]; /* 5 characters */ + le8_t attribute; /* Attribute byte */ + le8_t reserved; /* Reserved, MBZ */ + le8_t alias_csum; /* Short name checksum */ + le16_t name5[6]; /* 6 characters */ + le16_t firstclust; /* MBZ */ + le16_t name11[2]; /* 2 characters */ +}; + +#endif /* FAT_H */ + diff --git a/syslinux/libfat/fatchain.c b/syslinux/libfat/fatchain.c new file mode 100644 index 0000000..b9f115d --- /dev/null +++ b/syslinux/libfat/fatchain.c @@ -0,0 +1,136 @@ +#ident "$Id: fatchain.c,v 1.1 2004/12/15 10:14:39 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * fatchain.c + * + * Follow a FAT chain + */ + +#include "libfatint.h" +#include "ulint.h" + +/* + * Convert a cluster number (or 0 for the root directory) to a + * sector number. Return -1 on failure. + */ +libfat_sector_t libfat_clustertosector(const struct libfat_filesystem *fs, + int32_t cluster) +{ + if ( cluster == 0 ) + cluster = fs->rootcluster; + + if ( cluster == 0 ) + return fs->rootdir; + else if ( cluster < 2 || cluster >= fs->endcluster ) + return -1; + else + return fs->data + ((libfat_sector_t)(cluster-2) << fs->clustshift); +} + +/* + * Get the next sector of either the root directory or a FAT chain. + * Returns 0 on end of file and -1 on error. + */ + +libfat_sector_t libfat_nextsector(struct libfat_filesystem *fs, + libfat_sector_t s) +{ + int32_t cluster, nextcluster; + uint32_t fatoffset; + libfat_sector_t fatsect; + uint8_t *fsdata; + uint32_t clustmask = fs->clustsize - 1; + libfat_sector_t rs; + + if ( s < fs->data ) { + if ( s < fs->rootdir ) + return -1; + + /* Root directory */ + s++; + return ( s < fs->data ) ? s : 0; + } + + rs = s - fs->data; + + if ( ~rs & clustmask ) + return s+1; /* Next sector in cluster */ + + cluster = 2 + (rs >> fs->clustshift); + + if ( cluster >= fs->endcluster ) + return -1; + + switch ( fs->fat_type ) { + case FAT12: + /* Get first byte */ + fatoffset = cluster + (cluster >> 1); + fatsect = fs->fat + (fatoffset >> LIBFAT_SECTOR_SHIFT); + fsdata = libfat_get_sector(fs, fatsect); + if ( !fsdata ) + return -1; + nextcluster = fsdata[fatoffset & LIBFAT_SECTOR_MASK]; + + /* Get second byte */ + fatoffset++; + fatsect = fs->fat + (fatoffset >> LIBFAT_SECTOR_SHIFT); + fsdata = libfat_get_sector(fs, fatsect); + if ( !fsdata ) + return -1; + nextcluster |= fsdata[fatoffset & LIBFAT_SECTOR_MASK] << 8; + + /* Extract the FAT entry */ + if ( cluster & 1 ) + nextcluster >>= 4; + else + nextcluster &= 0x0FFF; + + if ( nextcluster >= 0x0FF8 ) + return 0; + break; + + case FAT16: + fatoffset = cluster << 1; + fatsect = fs->fat + (fatoffset >> LIBFAT_SECTOR_SHIFT); + fsdata = libfat_get_sector(fs, fatsect); + if ( !fsdata ) + return -1; + nextcluster = read16((le16_t *)&fsdata[fatoffset & LIBFAT_SECTOR_MASK]); + + if ( nextcluster >= 0x0FFF8 ) + return 0; + break; + + case FAT28: + fatoffset = cluster << 2; + fatsect = fs->fat + (fatoffset >> LIBFAT_SECTOR_SHIFT); + fsdata = libfat_get_sector(fs, fatsect); + if ( !fsdata ) + return -1; + nextcluster = read32((le32_t *)&fsdata[fatoffset & LIBFAT_SECTOR_MASK]); + nextcluster &= 0x0FFFFFFF; + + if ( nextcluster >= 0x0FFFFFF8 ) + return 0; + break; + + default: + return -1; /* WTF? */ + } + + return libfat_clustertosector(fs, nextcluster); +} + + + diff --git a/syslinux/libfat/libfat.h b/syslinux/libfat/libfat.h new file mode 100644 index 0000000..2172e35 --- /dev/null +++ b/syslinux/libfat/libfat.h @@ -0,0 +1,87 @@ +#ident "$Id: libfat.h,v 1.3 2005/01/04 03:04:53 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * libfat.h + * + * Headers for the libfat library + */ + +#ifndef LIBFAT_H +#define LIBFAT_H + +#include <stddef.h> +#include <inttypes.h> + +#define LIBFAT_SECTOR_SHIFT 9 +#define LIBFAT_SECTOR_SIZE 512 +#define LIBFAT_SECTOR_MASK 511 + +typedef uint32_t libfat_sector_t; +struct libfat_filesystem; + +struct libfat_direntry { + libfat_sector_t sector; + int offset; + unsigned char entry[32]; +}; + +/* + * Open the filesystem. The readfunc is the function to read + * sectors, in the format: + * int readfunc(intptr_t readptr, void *buf, size_t secsize, + * libfat_sector_t secno) + * + * ... where readptr is a private argument. + * + * A return value of != secsize is treated as error. + */ +struct libfat_filesystem * +libfat_open(int (*readfunc)(intptr_t, void *, size_t, libfat_sector_t), + intptr_t readptr); + +void libfat_close(struct libfat_filesystem *); + +/* + * Convert a cluster number (or 0 for the root directory) to a + * sector number. Return -1 on failure. + */ +libfat_sector_t libfat_clustertosector(const struct libfat_filesystem *fs, + int32_t cluster); + +/* + * Get the next sector of either the root directory or a FAT chain. + * Returns 0 on end of file and -1 on error. + */ +libfat_sector_t libfat_nextsector(struct libfat_filesystem *fs, + libfat_sector_t s); + +/* + * Flush all cached sectors for this filesystem. + */ +void libfat_flush(struct libfat_filesystem *fs); + +/* + * Get a pointer to a specific sector. + */ +void * libfat_get_sector(struct libfat_filesystem *fs, libfat_sector_t n); + +/* + * Search a FAT directory for a particular pre-mangled filename. + * Copies the directory entry into direntry and returns 0 if found. + */ +int32_t libfat_searchdir(struct libfat_filesystem *fs, int32_t dirclust, + const void *name, struct libfat_direntry *direntry); + +#endif /* LIBFAT_H */ + diff --git a/syslinux/libfat/libfatint.h b/syslinux/libfat/libfatint.h new file mode 100644 index 0000000..b357d70 --- /dev/null +++ b/syslinux/libfat/libfatint.h @@ -0,0 +1,56 @@ +#ident "$Id: libfatint.h,v 1.2 2004/12/15 20:29:17 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * libfatint.h + * + * Internals for the libfat filesystem + */ + +#ifndef LIBFATINT_H +#define LIBFATINT_H + +#include "libfat.h" +#include "fat.h" + +struct libfat_sector { + libfat_sector_t n; /* Sector number */ + struct libfat_sector *next; /* Next in list */ + char data[LIBFAT_SECTOR_SIZE]; +}; + +enum fat_type { + FAT12, + FAT16, + FAT28 +}; + +struct libfat_filesystem { + int (*read)(intptr_t, void *, size_t, libfat_sector_t); + intptr_t readptr; + + enum fat_type fat_type; + unsigned int clustsize; + int clustshift; + int32_t endcluster; /* Highest legal cluster number + 1 */ + int32_t rootcluster; /* Root directory cluster */ + + libfat_sector_t fat; /* Start of FAT */ + libfat_sector_t rootdir; /* Start of root directory */ + libfat_sector_t data; /* Start of data area */ + libfat_sector_t end; /* End of filesystem */ + + struct libfat_sector *sectors; +}; + +#endif /* LIBFATINT_H */ diff --git a/syslinux/libfat/open.c b/syslinux/libfat/open.c new file mode 100644 index 0000000..504a994 --- /dev/null +++ b/syslinux/libfat/open.c @@ -0,0 +1,118 @@ +#ident "$Id: open.c,v 1.2 2004/12/15 20:29:17 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * open.c + * + * Open a FAT filesystem and compute some initial values; return NULL + * on failure. + */ + +#include <stdlib.h> +#include "libfatint.h" +#include "ulint.h" + +struct libfat_filesystem * +libfat_open(int (*readfunc)(intptr_t, void *, size_t, libfat_sector_t), + intptr_t readptr) +{ + struct libfat_filesystem *fs = NULL; + struct fat_bootsect *bs; + int i; + uint32_t sectors, fatsize, minfatsize, rootdirsize; + uint32_t nclusters; + + fs = malloc(sizeof(struct libfat_filesystem)); + if ( !fs ) + goto barf; + + fs->sectors = NULL; + fs->read = readfunc; + fs->readptr = readptr; + + bs = libfat_get_sector(fs, 0); + if ( !bs ) + goto barf; + + if ( read16(&bs->bsBytesPerSec) != LIBFAT_SECTOR_SIZE ) + goto barf; + + for ( i = 0 ; i <= 8 ; i++ ) { + if ( (uint8_t)(1 << i) == read8(&bs->bsSecPerClust) ) + break; + } + if ( i > 8 ) + goto barf; + fs->clustsize = 1 << i; /* Treat 0 as 2^8 = 64K */ + fs->clustshift = i; + + sectors = read16(&bs->bsSectors); + if ( !sectors ) + sectors = read32(&bs->bsHugeSectors); + + fs->end = sectors; + + fs->fat = read16(&bs->bsResSectors); + fatsize = read16(&bs->bsFATsecs); + if ( !fatsize ) + fatsize = read32(&bs->u.fat32.bpb_fatsz32); + + fs->rootdir = fs->fat + fatsize * read8(&bs->bsFATs); + + rootdirsize = ((read16(&bs->bsRootDirEnts) << 5) + LIBFAT_SECTOR_MASK) + >> LIBFAT_SECTOR_SHIFT; + fs->data = fs->rootdir + rootdirsize; + + /* Sanity checking */ + if ( fs->data >= fs->end ) + goto barf; + + /* Figure out how many clusters */ + nclusters = (fs->end - fs->data) >> fs->clustshift; + fs->endcluster = nclusters + 2; + + if ( nclusters <= 0xff4 ) { + fs->fat_type = FAT12; + minfatsize = fs->endcluster + (fs->endcluster >> 1); + } else if ( nclusters <= 0xfff4 ) { + fs->fat_type = FAT16; + minfatsize = fs->endcluster << 1; + } else if ( nclusters <= 0xffffff4 ) { + fs->fat_type = FAT28; + minfatsize = fs->endcluster << 2; + } else + goto barf; /* Impossibly many clusters */ + + minfatsize = (minfatsize + LIBFAT_SECTOR_SIZE-1) >> LIBFAT_SECTOR_SHIFT; + + if ( minfatsize > fatsize ) + goto barf; /* The FATs don't fit */ + + if ( fs->fat_type == FAT28 ) + fs->rootcluster = read32(&bs->u.fat32.bpb_rootclus); + else + fs->rootcluster = 0; + + return fs; /* All good */ + + barf: + if ( fs ) + free(fs); + return NULL; +} + +void libfat_close(struct libfat_filesystem *fs) +{ + libfat_flush(fs); + free(fs); +} diff --git a/syslinux/libfat/searchdir.c b/syslinux/libfat/searchdir.c new file mode 100644 index 0000000..b014552 --- /dev/null +++ b/syslinux/libfat/searchdir.c @@ -0,0 +1,64 @@ +#ident "$Id: searchdir.c,v 1.2 2005/01/04 03:04:54 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * searchdir.c + * + * Search a FAT directory for a particular pre-mangled filename. + * Copies the directory entry into direntry and returns the starting cluster + * if found; returns -2 on not found, -1 on error, 0 on empty file. + */ + +#include <string.h> +#include "libfatint.h" + +int32_t libfat_searchdir(struct libfat_filesystem *fs, int32_t dirclust, + const void *name, struct libfat_direntry *direntry) +{ + struct fat_dirent *dep; + int nent; + libfat_sector_t s = libfat_clustertosector(fs, dirclust); + + while ( 1 ) { + if ( s == 0 ) + return -2; /* Not found */ + else if ( s == (libfat_sector_t)-1 ) + return -1; /* Error */ + + dep = libfat_get_sector(fs, s); + if ( !dep ) + return -1; /* Read error */ + + for ( nent = 0 ; nent < LIBFAT_SECTOR_SIZE ; + nent += sizeof(struct fat_dirent) ) { + if ( !memcmp(dep->name, name, 11) ) { + if ( direntry ) { + memcpy(direntry->entry, dep, sizeof (*dep)); + direntry->sector = s; + direntry->offset = nent; + } + if ( read32(&dep->size) == 0 ) + return 0; /* An empty file has no clusters */ + else + return read16(&dep->clustlo) + (read16(&dep->clusthi) << 16); + } + + if ( dep->name[0] == 0 ) + return -2; /* Hit high water mark */ + + dep++; + } + + s = libfat_nextsector(fs, s); + } +} diff --git a/syslinux/libfat/ulint.h b/syslinux/libfat/ulint.h new file mode 100644 index 0000000..963f903 --- /dev/null +++ b/syslinux/libfat/ulint.h @@ -0,0 +1,115 @@ +#ident "$Id: ulint.h,v 1.3 2004/12/20 04:57:44 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2001-2004 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139, + * USA; either version 2 of the License, or (at your option) any later + * version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * ulint.h + * + * Basic operations on unaligned, littleendian integers + */ + +#ifndef ULINT_H +#define ULINT_H + +#include <inttypes.h> + +/* These are unaligned, littleendian integer types */ + +typedef uint8_t le8_t; /* 8-bit byte */ +typedef uint8_t le16_t[2]; /* 16-bit word */ +typedef uint8_t le32_t[4]; /* 32-bit dword */ + +/* Read/write these quantities */ + +static inline unsigned char +read8(le8_t *_p) +{ + return *_p; +} + +static inline void +write8(le8_t *_p, uint8_t _v) +{ + *_p = _v; +} + +#if defined(__i386__) || defined(__x86_64__) + +/* Littleendian architectures which support unaligned memory accesses */ + +static inline unsigned short +read16(le16_t *_p) +{ + return *((const uint16_t *)_p); +} + +static inline void +write16(le16_t *_p, unsigned short _v) +{ + *((uint16_t *)_p) = _v; +} + +static inline unsigned int +read32(le32_t *_p) +{ + return *((const uint32_t *)_p); +} + +static inline void +write32(le32_t *_p, uint32_t _v) +{ + *((uint32_t *)_p) = _v; +} + +#else + +/* Generic, mostly portable versions */ + +static inline unsigned short +read16(le16_t *_p) +{ + uint16_t _v; + + _v = p[0]; + _v |= p[1] << 8; + return _v; +} + +static inline void +write16(le16_t *_p, uint16_t _v) +{ + _p[0] = _v & 0xFF; + _p[1] = (_v >> 8) & 0xFF; +} + +static inline unsigned int +read32(le32_t *_p) +{ + _v = _p[0]; + _v |= _p[1] << 8; + _v |= _p[2] << 16; + _v |= _p[3] << 24; + return _v; +} + +static inline void +write32(le32_t *_p, uint32_t _v) +{ + _p[0] = _v & 0xFF; + _p[1] = (_v >> 8) & 0xFF; + _p[2] = (_v >> 16) & 0xFF; + _p[3] = (_v >> 24) & 0xFF; +} + +#endif + +#endif /* ULINT_H */ diff --git a/syslinux/loadhigh.inc b/syslinux/loadhigh.inc new file mode 100644 index 0000000..2b20181 --- /dev/null +++ b/syslinux/loadhigh.inc @@ -0,0 +1,96 @@ +;; $Id: loadhigh.inc,v 1.7 2005/01/06 22:34:06 hpa Exp $ +;; ----------------------------------------------------------------------- +;; +;; Copyright 1994-2002 H. Peter Anvin - All Rights Reserved +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +;; Boston MA 02111-1307, USA; either version 2 of the License, or +;; (at your option) any later version; incorporated herein by reference. +;; +;; ----------------------------------------------------------------------- + +;; +;; loadhigh.inc +;; +;; Load a file into high memory +;; + + section .text + +; +; load_high: loads (the remainder of) a file into high memory. +; This routine prints dots for each 64K transferred, and +; calls abort_check periodically. +; +; The xfer_buf_seg is used as a bounce buffer. +; +; The input address (EDI) should be dword aligned, and the final +; stretch is padded with zeroes if necessary. +; +; Inputs: SI = file handle/cluster pointer +; EDI = target address in high memory +; EAX = size of remaining file in bytes +; DX = zero-padding mask (e.g. 0003h for pad to dword) +; +; Outputs: SI = file handle/cluster pointer +; EDI = first untouched address (not including padding) +; +load_high: + push es + + mov bx,xfer_buf_seg + mov es,bx + +.read_loop: + and si,si ; If SI == 0 then we have end of file + jz .eof + push si + mov si,dot_msg + call cwritestr + pop si + call abort_check + + push eax ; <A> Total bytes to transfer + cmp eax,(1 << 16) ; Max 64K in one transfer + jna .size_ok + mov eax,(1 << 16) +.size_ok: + push eax ; <B> Bytes transferred this chunk + add eax,SECTOR_SIZE-1 + shr eax,SECTOR_SHIFT ; Convert to sectors + + ; Now (e)ax contains the number of sectors to get + push edi ; <C> Target buffer + mov cx,ax + xor bx,bx ; ES:0 + call getfssec ; Load the data into xfer_buf_seg + pop edi ; <C> Target buffer + pop ecx ; <B> Byte count this round + push ecx ; <B> Byte count this round + push edi ; <C> Target buffer +.fix_slop: + test cx,dx + jz .noslop + ; The last dword fractional - pad with zeroes + ; Zero-padding is critical for multi-file initramfs. + mov byte [es:ecx],0 + inc ecx + jmp short .fix_slop +.noslop: + push esi ; <D> File handle/cluster pointer + mov esi,(xfer_buf_seg << 4) ; Source address + call bcopy ; Copy to high memory + pop esi ; <D> File handle/cluster pointer + pop edi ; <C> Target buffer + pop ecx ; <B> Byte count this round + pop eax ; <A> Total bytes to transfer + add edi,ecx + sub eax,ecx + jnz .read_loop ; More to read... + +.eof: + pop es + ret + diff --git a/syslinux/lss16toppm b/syslinux/lss16toppm new file mode 100755 index 0000000..807f651 --- /dev/null +++ b/syslinux/lss16toppm @@ -0,0 +1,112 @@ +#!/usr/bin/perl +## $Id: lss16toppm,v 1.6 2004/12/14 23:03:28 hpa Exp $ +## ----------------------------------------------------------------------- +## +## Copyright 2001-2004 H. Peter Anvin - All Rights Reserved +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, Inc., 53 Temple Place Ste 330, +## Boston MA 02111-1307, USA; either version 2 of the License, or +## (at your option) any later version; incorporated herein by reference. +## +## ----------------------------------------------------------------------- + +## +## lss16toppm: +## Convert an LSS-16 image to PPM +## +## Usage: +## +## lss16toppm [-map] < file.lss > file.ppm +## +## The -map causes the color map to be output on stderr. +## + +eval { use bytes; }; +eval { binmode STDIN; }; +eval { binmode STDOUT; }; + +$map = 0; +foreach $arg ( @ARGV ) { + if ( $arg eq '-map' ) { + $map = 1; + } else { + print STDERR "$0: Unknown option: $arg\n"; + exit 127; + } +} + +if ( read(STDIN, $header, 56) != 56 ) { + print STDERR "$0: Short file\n"; + exit 1; +} + +($magic, $xsize, $ysize, @colorset) = unpack("Vvvc48", $header); + +if ( $magic != 0x1413f33d ) { + print STDERR "$0: Invalid file format\n"; + exit 1; +} + +%color = (); +for ( $i = 0 ; $i < 16 ; $i++ ) { + $r = int((shift @colorset) * 255 / 63 + 0.5); + $g = int((shift @colorset) * 255 / 63 + 0.5); + $b = int((shift @colorset) * 255 / 63 + 0.5); + + $color{$i} = pack("ccc", $r, $g, $b); + + if ( $map ) { + printf STDERR "#%02x%02x%02x=%d\n", $r, $g, $b, $i; + } +} + +sub get_nybble() { + my($ch,$n); + if ( defined($nybble_buf) ) { + $n = $nybble_buf; + undef $nybble_buf; + } else { + if ( read(STDIN, $ch, 1) != 1 ) { + print STDERR "$0: Short read on input (file corrupt)\n"; + exit 1; + } + $ch = ord($ch); + $nybble_buf = $ch >> 4; + $n = $ch & 0xF; + } + return $n; +} + +print "P6\n"; +print "$xsize $ysize\n"; +print "255\n"; + +for ( $y = 0 ; $y < $ysize ; $y++ ) { + $x = 0; + $last = 0; + undef $nybble_buf; # Nybble buffer starts clear on each line + while ( $x < $xsize ) { + $n = get_nybble(); + + if ( $n != $last ) { + print $color{$n}; + $last = $n; + $x++; + } else { + $c = get_nybble(); + if ( $c == 0 ) { + # Double-nybble run + $c = get_nybble(); + $c += get_nybble() << 4; + $c += 16; + } + # Truncate overlong runs + $c = $xsize-$x if ( $c > $xsize-$x ); + # Output run + print $color{$n} x $c; + $x += $c; + } + } +} diff --git a/syslinux/macros.inc b/syslinux/macros.inc new file mode 100644 index 0000000..575e118 --- /dev/null +++ b/syslinux/macros.inc @@ -0,0 +1,111 @@ +;; $Id: macros.inc,v 1.9 2004/12/14 22:46:25 hpa Exp $ +;; ----------------------------------------------------------------------- +;; +;; Copyright 1994-2004 H. Peter Anvin - All Rights Reserved +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +;; Boston MA 02111-1307, USA; either version 2 of the License, or +;; (at your option) any later version; incorporated herein by reference. +;; +;; ----------------------------------------------------------------------- + +;; +;; macros.inc +;; +;; Convenient macros +;; + +%ifndef _MACROS_INC +%define _MACROS_INC + +; +; Identify the module we're compiling; the "correct" should be defined +; in the module itself to 1 +; +%ifndef IS_SYSLINUX +%define IS_SYSLINUX 0 +%endif +%ifndef IS_MDSLINUX +%define IS_MDSLINUX 0 +%endif +%ifndef IS_PXELINUX +%define IS_PXELINUX 0 +%endif +%ifndef IS_ISOLINUX +%define IS_ISOLINUX 0 +%endif +%ifndef IS_EXTLINUX +%define IS_EXTLINUX 0 +%endif + +; +; Macros similar to res[bwd], but which works in the code segment (after +; section .text) or the data segment (section .data) +; +%macro zb 1.nolist + times %1 db 0 +%endmacro + +%macro zw 1.nolist + times %1 dw 0 +%endmacro + +%macro zd 1.nolist + times %1 dd 0 +%endmacro + +; +; Macro to emit an unsigned decimal number as a string +; +%macro asciidec 1.nolist +%ifndef DEPEND ; Not safe for "depend" +%if %1 >= 1000000000 + db ((%1/1000000000) % 10) + '0' +%endif +%if %1 >= 100000000 + db ((%1/100000000) % 10) + '0' +%endif +%if %1 >= 10000000 + db ((%1/10000000) % 10) + '0' +%endif +%if %1 >= 1000000 + db ((%1/1000000) % 10) + '0' +%endif +%if %1 >= 100000 + db ((%1/100000) % 10) + '0' +%endif +%if %1 >= 10000 + db ((%1/10000) % 10) + '0' +%endif +%if %1 >= 1000 + db ((%1/1000) % 10) + '0' +%endif +%if %1 >= 100 + db ((%1/100) % 10) + '0' +%endif +%if %1 >= 10 + db ((%1/10) % 10) + '0' +%endif + db (%1 % 10) + '0' +%endif +%endmacro + +; +; Macros for network byte order of constants +; +%define htons(x) ( ( ((x) & 0FFh) << 8 ) + ( ((x) & 0FF00h) >> 8 ) ) +%define ntohs(x) htons(x) +%define htonl(x) ( ( ((x) & 0FFh) << 24) + ( ((x) & 0FF00h) << 8 ) + ( ((x) & 0FF0000h) >> 8 ) + ( ((x) & 0FF000000h) >> 24) ) +%define ntohl(x) htonl(x) + +; +; ASCII +; +CR equ 13 ; Carriage Return +LF equ 10 ; Line Feed +FF equ 12 ; Form Feed +BS equ 8 ; Backspace + +%endif ; _MACROS_INC diff --git a/syslinux/mbr.asm b/syslinux/mbr.asm new file mode 100644 index 0000000..7db0b6c --- /dev/null +++ b/syslinux/mbr.asm @@ -0,0 +1,229 @@ +; ----------------------------------------------------------------------- +; +; Copyright 2003-2004 H. Peter Anvin - All Rights Reserved +; +; Permission is hereby granted, free of charge, to any person +; obtaining a copy of this software and associated documentation +; files (the "Software"), to deal in the Software without +; restriction, including without limitation the rights to use, +; copy, modify, merge, publish, distribute, sublicense, and/or +; sell copies of the Software, and to permit persons to whom +; the Software is furnished to do so, subject to the following +; conditions: +; +; The above copyright notice and this permission notice shall +; be included in all copies or substantial portions of the Software. +; +; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +; OTHER DEALINGS IN THE SOFTWARE. +; +; ----------------------------------------------------------------------- + +; +; mbr.asm +; +; Simple Master Boot Record, including support for EBIOS extensions. +; +; The MBR lives in front of the boot sector, and is responsible for +; loading the boot sector of the active partition. The EBIOS support +; is needed if the active partition starts beyond cylinder 1024. +; +; This MBR determines all geometry info at runtime. It uses only the +; linear block field in the partition table. It does, however, pass +; the partition table information unchanged to the target OS. +; +; This MBR should be "8086-clean", i.e. not require a 386. +; + +%include "bios.inc" + +; +; Note: The MBR is actually loaded at 0:7C00h, but we quickly move it down to +; 0600h. +; + section .text + cpu 8086 + org 0600h + +_start: cli + xor ax,ax + mov ds,ax + mov es,ax + mov ss,ax + mov sp,7C00h + sti + cld + mov si,sp ; Start address + mov di,0600h ; Destination address + mov cx,512/2 + rep movsw + +; +; Now, jump to the copy at 0600h so we can load the boot sector at 7C00h. +; Since some BIOSes seem to think 0000:7C00h and 07C0:0000h are the same +; thing, use a far jump to canonicalize the address. This also makes +; sure that it is a code speculation barrier. +; + + jmp 0:next ; Jump to copy at 0600h + +next: + mov [DriveNo], dl ; Drive number stored in DL +; +; Check for CHS parameters. This doesn't work on floppy disks, +; but for an MBR we don't care. +; + mov ah,08h ; Get drive parameters + int 13h + xor ax,ax + mov al,dh + inc ax ; From 0-based to count + mov [Heads],ax + and cl,3Fh ; Max sector number + mov [Sectors],cl + ; Note: we actually don't care about the number of + ; cylinders, since that's the highest-order division + +; +; Now look for one (and only one) active partition. +; + mov si,PartitionTable + xor ax,ax + mov cx,4 +checkpartloop: + test byte [si],80h + jz .notactive + inc ax + mov di,si +.notactive: add si,byte 16 + loop checkpartloop + + cmp ax,byte 1 ; Better be only one + jnz not_one_partition + +; +; Now we have the active partition partition information in DS:DI. +; Check to see if we support EBIOS. +; + mov dl,[DriveNo] + mov ax,4100h + mov bx,055AAh + xor cx,cx + xor dh,dh + stc + int 13h + jc no_ebios + cmp bx,0AA55h + jne no_ebios + test cl,1 ; LBA device access + jz no_ebios +; +; We have EBIOS. Load the boot sector using LBA. +; + push di + mov si,dapa + mov bx,[di+8] ; Copy the block address + mov [si+8],bx + mov bx,[di+10] + mov [si+10],bx + mov dl,[DriveNo] + mov ah,42h ; Extended Read + jmp short common_tail +; +; No EBIOS. Load the boot sector using CHS. +; +no_ebios: + push di + mov ax,[di+8] + mov dx,[di+10] + div word [Sectors] + inc dx + mov cx,dx ; Sector # + xor dx,dx + div word [Heads] + ; DX = head #, AX = cylinder # + mov ch,al + shr ax,1 + shr ax,1 + and al,0C0h + or cl,al + mov dh,dl ; Head # + mov dl,[DriveNo] + mov bx,7C00h + mov ax,0201h ; Read one sector +common_tail: + int 13h + jc disk_error + pop si ; DS:SI -> partition table entry +; +; Verify that we have a boot sector, jump +; + cmp word [7C00h+510],0AA55h + jne missing_os + cli + jmp 0:7C00h ; Jump to boot sector; far + ; jump is speculation barrier + ; (Probably not neecessary, but + ; there is plenty of space.) + +not_one_partition: + ja too_many_os +missing_os: + mov si,missing_os_msg + jmp short die +too_many_os: +disk_error: + mov si,bad_disk_msg +die: +.msgloop: + lodsb + and al,al + jz .now + mov ah,0Eh ; TTY output + mov bh,[BIOS_page] ; Current page + mov bl,07h + int 10h + jmp short .msgloop +.now: + jmp short .now + + align 4, db 0 ; Begin data area + +; +; EBIOS disk address packet +; +dapa: + dw 16 ; Packet size +.count: dw 1 ; Block count +.off: dw 7C00h ; Offset of buffer +.seg: dw 0 ; Segment of buffer +.lba: dd 0 ; LBA (LSW) + dd 0 ; LBA (MSW) + +; CHS information +Heads: dw 0 +Sectors: dw 0 + +; Error messages +missing_os_msg db 'Missing operating system', 13, 10, 0 +bad_disk_msg db 'Operating system loading error', 13, 10, 0 + +; +; Maximum MBR size: 446 bytes; end-of-boot-sector signature also needed. +; Note that some operating systems (NT, DR-DOS) put additional stuff at +; the end of the MBR, so shorter is better. Location 440 is known to +; have a 4-byte attempt-at-unique-ID for some OSes. +; + +PartitionTable equ $$+446 ; Start of partition table + +; +; BSS data; put at 800h +; +DriveNo equ 0800h diff --git a/syslinux/mbr.bin b/syslinux/mbr.bin new file mode 100644 index 0000000000000000000000000000000000000000..8b0e8587a21fe8d07fdc1228a3723dbfc1a48307 GIT binary patch literal 304 zcmexmc%bh_-+{ghdl+hd|LJ_TpMh;B1LNnVuVmR67&^olIJR({6*fH3@xfv72eyWX z_8okm*!JyXH$1SDh2a}ZLkY7(=lAAg0*^j7|6nXF?h<3**umhqdsV36NrP`c&k7eQ zH~tP?RVw@KAY+L{_`U~h-LV{<F&y2oT%9poAk|x(UTcMSyK;1ga(y@Z#OBm_(eToD zvkz<?M=!p(_(J6X$H9(kAa%PLYIZO(ofR$;i)*y|R~x#jl;hVch8hNja@Kuc*j_X5 z<7Z!^aG-=|3tyLA63b@xvjVT*zy8O-Ai%)L08)kwd^3xSGxO3F@(WUn5=%g=;>zNZ b)LdRJ27fdmg`E7v6p)J4qN4mFUM>azc{q6y literal 0 HcmV?d00001 diff --git a/syslinux/memdisk/.depend b/syslinux/memdisk/.depend new file mode 100644 index 0000000..764f5c9 --- /dev/null +++ b/syslinux/memdisk/.depend @@ -0,0 +1,27 @@ +conio.s: conio.c ../com32/include/stdint.h memdisk.h \ + ../com32/include/com32.h ../com32/include/klibc/compiler.h conio.h \ + ../com32/include/stddef.h ../com32/include/bitsize/stddef.h \ + ../com32/include/stdarg.h +e820func.s: e820func.c ../com32/include/stdint.h memdisk.h \ + ../com32/include/com32.h ../com32/include/klibc/compiler.h e820.h +e820test.s: e820test.c ../com32/include/string.h \ + ../com32/include/klibc/extern.h ../com32/include/stddef.h \ + ../com32/include/bitsize/stddef.h ../com32/include/stdio.h \ + ../com32/include/stdarg.h ../com32/include/stdlib.h \ + ../com32/include/klibc/compiler.h ../com32/include/inttypes.h \ + ../com32/include/stdint.h e820.h +inflate.s: inflate.c +msetup.s: msetup.c ../com32/include/stdint.h memdisk.h \ + ../com32/include/com32.h ../com32/include/klibc/compiler.h conio.h \ + ../com32/include/stddef.h ../com32/include/bitsize/stddef.h \ + ../com32/include/stdarg.h e820.h +setup.s: setup.c ../com32/include/stdint.h e820.h conio.h \ + ../com32/include/stddef.h ../com32/include/bitsize/stddef.h \ + ../com32/include/stdarg.h version.h memdisk.h ../com32/include/com32.h \ + ../com32/include/klibc/compiler.h +unzip.s: unzip.c ../com32/include/stdint.h memdisk.h \ + ../com32/include/com32.h ../com32/include/klibc/compiler.h conio.h \ + ../com32/include/stddef.h ../com32/include/bitsize/stddef.h \ + ../com32/include/stdarg.h inflate.c +memdisk.bin: memdisk.asm +memdisk16.bin: memdisk16.asm diff --git a/syslinux/memdisk/Makefile b/syslinux/memdisk/Makefile new file mode 100644 index 0000000..aa030a9 --- /dev/null +++ b/syslinux/memdisk/Makefile @@ -0,0 +1,121 @@ +#ident "$Id: Makefile,v 1.29 2004/12/29 01:58:02 hpa Exp $" +## ----------------------------------------------------------------------- +## +## Copyright 2001-2004 H. Peter Anvin - All Rights Reserved +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, Inc., 53 Temple Place Ste 330, +## Boston MA 02111-1307, USA; either version 2 of the License, or +## (at your option) any later version; incorporated herein by reference. +## +## ----------------------------------------------------------------------- + +VERSION := $(shell cat ../version) + +gcc_ok = $(shell if gcc $(1) -c -x c /dev/null -o /dev/null 2>/dev/null; \ + then echo $(1); else echo $(2); fi) + +M32 := $(call gcc_ok,-m32,) +ALIGN := $(call gcc_ok,-falign-functions=0 -falign-jumps=0 -falign-loops=0,-malign-functions=0 -malign-jumps=0 -malign-loops=0) + +CC = gcc $(M32) +CFLAGS = -g -W -Wall -Wno-sign-compare \ + -Os -fomit-frame-pointer -march=i386 $(ALIGN) \ + -DVERSION='"$(VERSION)"' -DDATE='"$(DATE)"' +LDFLAGS = -g +INCLUDE = -I../com32/include +LD = ld -m elf_i386 +NASM = nasm -O99 +NFLAGS = -dVERSION='"$(VERSION)"' -dDATE='"$(DATE)"' +NINCLUDE = +OBJCOPY = objcopy +PERL = perl + +# Important: init.o16 must be first!! +OBJS16 = init.o16 init32.o +OBJS32 = start32.o setup.o msetup.o e820func.o conio.o memcpy.o memset.o \ + unzip.o memdisk.o + +CSRC = setup.c msetup.c e820func.c conio.c unzip.c +SSRC = +NASMSRC = memdisk.asm memdisk16.asm + +all: memdisk e820test + +# tidy, clean removes everything except the final binary +tidy: + rm -f *.o *.s *.o16 *.s16 *.bin *.lst *.elf e820test + +clean: tidy + +# spotless also removes the product binary +spotless: clean + rm -f memdisk .depend + +%.o: %.asm + $(NASM) $(NFLAGS) -f elf -l $*.lst -o $@ $< + +%.o: %.s + $(CC) -x assembler -c -o $@ $< + +%.o16: %.s16 + $(CC) -x assembler -c -o $@ $< + +%.o: %.c + $(CC) $(INCLUDE) $(CFLAGS) -c -o $@ $< + +%.s16: %.s + echo '.code16gcc' | cat - $< > $@ + +%.s: %.S + $(CC) -x c $(INCLUDE) $(CFLAGS) -traditional -E -o $@ $< + +%.s16: %.S16 + $(CC) -x c $(INCLUDE) $(CFLAGS) -traditional -E -o $@ $< + +%.s: %.c + $(CC) $(INCLUDE) $(CFLAGS) -S -o $@ $< + +%.i: %.c + $(CC) $(INCLUDE) $(CFLAGS) -E -o $@ $< + +# Cancel default rule +%.o: %.c + +%.bin: %.asm + $(NASM) -f bin $(NFLAGS) $(NINCLUDE) -o $@ -l $*.lst $< + +memdisk16.elf: $(OBJS16) + $(LD) -Ttext 0 -o $@ $^ + +memdisk32.elf: $(OBJS32) + $(LD) -Ttext 0x100000 -o $@ $^ + +%.bin: %.elf + $(OBJCOPY) -O binary $< $@ + +memdisk: memdisk16.bin memdisk32.bin postprocess.pl + $(PERL) postprocess.pl $@ memdisk16.bin memdisk32.bin + +e820test: e820func.o msetup.o e820test.o memdisk.o + $(CC) $(LDFLAGS) -o $@ $^ + +memdisk.o: memdisk.bin + $(LD) -r -b binary -o $@ $< + +.depend: + rm -f .depend + for csrc in *.c ; do $(CC) $(INCLUDE) -MM $$csrc | sed -e 's/\.o/\.s/' >> .depend ; done + for ssrc in $(SSRC) ; do $(CC) $(INCLUDE) -x c -traditional -MM $$ssrc | sed -e 's/\.S16\.o/\.o16/' >> .depend ; done + for nsrc in $(NASMSRC) ; do $(NASM) -DDEPEND $(NINCLUDE) -o `echo $$nsrc | sed -e 's/\.asm/\.bin/'` -M $$nsrc >> .depend ; done + +depend: + rm -f .depend + $(MAKE) .depend + +# This file contains the version number, so add a dependency for it +setup.s: ../version + +# Include dependencies file +include .depend diff --git a/syslinux/memdisk/conio.c b/syslinux/memdisk/conio.c new file mode 100644 index 0000000..85f26d9 --- /dev/null +++ b/syslinux/memdisk/conio.c @@ -0,0 +1,365 @@ +#ident "$Id: conio.c,v 1.8 2004/12/14 22:46:25 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2001 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * conio.c + * + * Output to the screen + */ + +#include <stdint.h> +#include "memdisk.h" +#include "conio.h" + +int putchar(int ch) +{ + com32sys_t regs; + + if ( ch == '\n' ) { + /* \n -> \r\n */ + putchar('\r'); + } + + regs.eax.w[0] = 0x0e00|(ch&0xff); + syscall(0x10, ®s, NULL); + + return ch; +} + +int puts(const char *s) +{ + int count = 0; + + while ( *s ) { + putchar(*s); + count++; + s++; + } + + return count; +} + +/* + * Oh, it's a waste of space, but oh-so-yummy for debugging. It's just + * initialization code anyway, so it doesn't take up space when we're + * actually running. This version of printf() does not include 64-bit + * support. "Live with it." + * + * Most of this code was shamelessly snarfed from the Linux kernel, then + * modified. + */ + +static inline int +isdigit(int ch) +{ + return (ch >= '0') && (ch <= '9'); +} + +static int skip_atoi(const char **s) +{ + int i=0; + + while (isdigit(**s)) + i = i*10 + *((*s)++) - '0'; + return i; +} + +unsigned int atou(const char *s) +{ + unsigned int i = 0; + while (isdigit(*s)) + i = i*10 + (*s++ - '0'); + return i; +} + +static int strnlen(const char *s, int maxlen) +{ + const char *es = s; + while ( *es && maxlen ) { + es++; maxlen--; + } + + return (es-s); +} + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SPECIAL 32 /* 0x */ +#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ + +#define do_div(n,base) ({ \ +int __res; \ +__res = ((unsigned long) n) % (unsigned) base; \ +n = ((unsigned long) n) / (unsigned) base; \ +__res; }) + +static char * number(char * str, long num, int base, int size, int precision + ,int type) +{ + char c,sign,tmp[66]; + const char *digits="0123456789abcdefghijklmnopqrstuvwxyz"; + int i; + + if (type & LARGE) + digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + if (type & LEFT) + type &= ~ZEROPAD; + if (base < 2 || base > 36) + return 0; + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) { + if (num < 0) { + sign = '-'; + num = -num; + size--; + } else if (type & PLUS) { + sign = '+'; + size--; + } else if (type & SPACE) { + sign = ' '; + size--; + } + } + if (type & SPECIAL) { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + i = 0; + if (num == 0) + tmp[i++]='0'; + else while (num != 0) + tmp[i++] = digits[do_div(num,base)]; + if (i > precision) + precision = i; + size -= precision; + if (!(type&(ZEROPAD+LEFT))) + while(size-->0) + *str++ = ' '; + if (sign) + *str++ = sign; + if (type & SPECIAL) { + if (base==8) + *str++ = '0'; + else if (base==16) { + *str++ = '0'; + *str++ = digits[33]; + } + } + if (!(type & LEFT)) + while (size-- > 0) + *str++ = c; + while (i < precision--) + *str++ = '0'; + while (i-- > 0) + *str++ = tmp[i]; + while (size-- > 0) + *str++ = ' '; + return str; +} + +/* Forward decl. needed for IP address printing stuff... */ +int sprintf(char * buf, const char *fmt, ...); + +int vsprintf(char *buf, const char *fmt, va_list args) +{ + int len; + unsigned long num; + int i, base; + char * str; + const char *s; + + int flags; /* flags to number() */ + + int field_width; /* width of output field */ + int precision; /* min. # of digits for integers; max + number of chars for from string */ + int qualifier; /* 'h', 'l', or 'L' for integer fields */ + + for (str=buf ; *fmt ; ++fmt) { + if (*fmt != '%') { + *str++ = *fmt; + continue; + } + + /* process flags */ + flags = 0; + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': flags |= LEFT; goto repeat; + case '+': flags |= PLUS; goto repeat; + case ' ': flags |= SPACE; goto repeat; + case '#': flags |= SPECIAL; goto repeat; + case '0': flags |= ZEROPAD; goto repeat; + } + + /* get field width */ + field_width = -1; + if (isdigit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt == '.') { + ++fmt; + if (isdigit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { + qualifier = *fmt; + ++fmt; + } + + /* default base */ + base = 10; + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + *str++ = ' '; + *str++ = (unsigned char) va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + continue; + + case 's': + s = va_arg(args, char *); + len = strnlen(s, precision); + + if (!(flags & LEFT)) + while (len < field_width--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = *s++; + while (len < field_width--) + *str++ = ' '; + continue; + + case 'p': + if (field_width == -1) { + field_width = 2*sizeof(void *); + flags |= ZEROPAD; + } + str = number(str, + (unsigned long) va_arg(args, void *), 16, + field_width, precision, flags); + continue; + + + case 'n': + if (qualifier == 'l') { + long * ip = va_arg(args, long *); + *ip = (str - buf); + } else { + int * ip = va_arg(args, int *); + *ip = (str - buf); + } + continue; + + case '%': + *str++ = '%'; + continue; + + /* integer number formats - set up the flags and "break" */ + case 'o': + base = 8; + break; + + case 'X': + flags |= LARGE; + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + break; + + default: + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + continue; + } + if (qualifier == 'l') + num = va_arg(args, unsigned long); + else if (qualifier == 'h') { + num = (unsigned short) va_arg(args, int); + if (flags & SIGN) + num = (short) num; + } else if (flags & SIGN) + num = va_arg(args, int); + else + num = va_arg(args, unsigned int); + str = number(str, num, base, field_width, precision, flags); + } + *str = '\0'; + return str-buf; +} + +int sprintf(char * buf, const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i=vsprintf(buf,fmt,args); + va_end(args); + return i; +} + +int printf(const char *fmt, ...) +{ + char printf_buf[1024]; + va_list args; + int printed; + + va_start(args, fmt); + printed = vsprintf(printf_buf, fmt, args); + va_end(args); + + puts(printf_buf); + + return printed; +} + diff --git a/syslinux/memdisk/conio.h b/syslinux/memdisk/conio.h new file mode 100644 index 0000000..f17b8ec --- /dev/null +++ b/syslinux/memdisk/conio.h @@ -0,0 +1,32 @@ +#ident "$Id: conio.h,v 1.5 2004/12/14 22:46:25 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2001 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * conio.h + * + * Limited console I/O + */ + +#ifndef CONIO_H +#define CONIO_H + +#include <stdint.h> +#include <stddef.h> +#include <stdarg.h> + +int putchar(int); +int puts(const char *); +int printf(const char *, ...); +unsigned int atou(const char *); + +#endif diff --git a/syslinux/memdisk/e820.h b/syslinux/memdisk/e820.h new file mode 100644 index 0000000..1a4d87e --- /dev/null +++ b/syslinux/memdisk/e820.h @@ -0,0 +1,34 @@ +#ident "$Id: e820.h,v 1.4 2004/12/14 22:46:25 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2001 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * e820.h + * + * Common routines for e820 memory map management + */ + +#include <stdint.h> + +struct e820range { + uint64_t start; + uint32_t type; +} __attribute__((packed)); + +extern struct e820range ranges[]; +extern int nranges; +extern uint32_t dos_mem, low_mem, high_mem; + +extern void e820map_init(void); +extern void insertrange(uint64_t, uint64_t, uint32_t); +extern void get_mem(void); +extern void parse_mem(void); diff --git a/syslinux/memdisk/e820data b/syslinux/memdisk/e820data new file mode 100644 index 0000000..34ab566 --- /dev/null +++ b/syslinux/memdisk/e820data @@ -0,0 +1,13 @@ +0000000000000000 000000000009bc00 1 +000000000009bc00 0000000000004400 2 +00000000000e9800 0000000000016800 2 +0000000000100000 0000000006ee0000 1 +0000000006fe0000 000000000000fc00 3 +0000000006fefc00 0000000000000400 4 +0000000006ff0000 0000000000002000 2 +0000000006ff2000 000000000000e000 1 +0000000007000000 0000000000100000 2 +00000000fff00000 0000000000100000 2 + +0000000000586000 0000000000168000 2 +000000000009ba00 0000000000000200 2 diff --git a/syslinux/memdisk/e820func.c b/syslinux/memdisk/e820func.c new file mode 100644 index 0000000..b486b8a --- /dev/null +++ b/syslinux/memdisk/e820func.c @@ -0,0 +1,105 @@ +#ident "$Id: e820func.c,v 1.7 2004/12/14 22:46:25 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2001 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * e820func.c + * + * E820 range database manager + */ + +#include <stdint.h> +#include "memdisk.h" /* For memset() */ +#include "e820.h" + +#define MAXRANGES 64 +/* All of memory starts out as one range of "indeterminate" type */ +struct e820range ranges[MAXRANGES]; +int nranges; + + +void e820map_init(void) +{ + memset(ranges, 0, sizeof(ranges)); + nranges = 1; + ranges[1].type = -1; +} + +static void insertrange_at(int where, uint64_t start, uint32_t type) +{ + int i; + + for ( i = nranges ; i > where ; i-- ) + ranges[i] = ranges[i-1]; + + ranges[where].start = start; + ranges[where].type = type; + + nranges++; + ranges[nranges].start = 0ULL; + ranges[nranges].type = (uint32_t)-1; +} + +void insertrange(uint64_t start, uint64_t len, uint32_t type) +{ + uint64_t last; + uint32_t oldtype; + int i, j; + + /* Remove this to make len == 0 mean all of memory */ + if ( len == 0 ) + return; /* Nothing to insert */ + + last = start+len-1; /* May roll over */ + + i = 0; + oldtype = -2; + while ( start > ranges[i].start && ranges[i].type != -1 ) { + oldtype = ranges[i].type; + i++; + } + + /* Consider the replacement policy. This current one is "overwrite." */ + + if ( start < ranges[i].start || ranges[i].type == -1 ) + insertrange_at(i++, start, type); + + while ( i == 0 || last > ranges[i].start-1 ) { + oldtype = ranges[i].type; + ranges[i].type = type; + i++; + } + + if ( last < ranges[i].start-1 ) + insertrange_at(i, last+1, oldtype); + + /* Now the map is correct, but quite possibly not optimal. Scan the + map for ranges which are redundant and remove them. */ + i = j = 1; + oldtype = ranges[0].type; + while ( i < nranges ) { + if ( ranges[i].type == oldtype ) { + i++; + } else { + oldtype = ranges[i].type; + if ( i != j ) + ranges[j] = ranges[i]; + i++; j++; + } + } + + if ( i != j ) { + ranges[j] = ranges[i]; /* Termination sentinel copy */ + nranges -= (i-j); + } +} + diff --git a/syslinux/memdisk/e820test.c b/syslinux/memdisk/e820test.c new file mode 100644 index 0000000..15d26e8 --- /dev/null +++ b/syslinux/memdisk/e820test.c @@ -0,0 +1,89 @@ +#ident "$Id: e820test.c,v 1.8 2004/12/14 22:46:25 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2001-2003 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * e820hack.c + * + * Test of INT 15:E820 canonicalization/manipulation routine + */ + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <inttypes.h> +#include "e820.h" + +void *sys_bounce; /* Dummy */ + +extern void parse_mem(void); +extern uint32_t dos_mem, low_mem, high_mem; + +void __attribute__((noreturn)) die(void) +{ + abort(); +} + +void printranges(void) { + int i; + + for ( i = 0 ; i < nranges ; i++ ) { + printf("%016llx %016llx %d\n", + ranges[i].start, + ranges[i+1].start - ranges[i].start, + ranges[i].type); + } +} + +int main(void) +{ + uint64_t start, len; + uint32_t type; + char line[BUFSIZ], *p; + + e820map_init(); + printranges(); + + while ( fgets(line, BUFSIZ, stdin) ) { + p = strchr(line, ':'); + p = p ? p+1 : line; + if ( sscanf(p, " %llx %llx %d", &start, &len, &type) == 3 ) { + putchar('\n'); + printf("%016llx %016llx %d <-\n", start, len, type); + putchar('\n'); + insertrange(start, len, type); + printranges(); + } + } + + parse_mem(); + + putchar('\n'); + printf("DOS mem = %#10x (%u K)\n", dos_mem, dos_mem >> 10); + printf("Low mem = %#10x (%u K)\n", low_mem, low_mem >> 10); + printf("High mem = %#10x (%u K)\n", high_mem, high_mem >> 10); + putchar('\n'); + + /* Now, steal a chunk (2K) of DOS memory and make sure it registered OK */ + insertrange(dos_mem-2048, 2048, 2); /* Type 2 = reserved */ + + printranges(); + parse_mem(); + + putchar('\n'); + printf("DOS mem = %#10x (%u K)\n", dos_mem, dos_mem >> 10); + printf("Low mem = %#10x (%u K)\n", low_mem, low_mem >> 10); + printf("High mem = %#10x (%u K)\n", high_mem, high_mem >> 10); + putchar('\n'); + + return 0; +} diff --git a/syslinux/memdisk/inflate.c b/syslinux/memdisk/inflate.c new file mode 100644 index 0000000..2974970 --- /dev/null +++ b/syslinux/memdisk/inflate.c @@ -0,0 +1,1083 @@ +#define DEBG(x) +#define DEBG1(x) +/* inflate.c -- Not copyrighted 1992 by Mark Adler + version c10p1, 10 January 1993 */ + +/* + * Adapted for booting Linux by Hannu Savolainen 1993 + * based on gzip-1.0.3 + * + * Nicolas Pitre <nico@cam.org>, 1999/04/14 : + * Little mods for all variable to reside either into rodata or bss segments + * by marking constant variables with 'const' and initializing all the others + * at run-time only. This allows for the kernel uncompressor to run + * directly from Flash or ROM memory on embedded systems. + * + * Adapted for MEMDISK by H. Peter Anvin, April 2003 + */ + +/* + Inflate deflated (PKZIP's method 8 compressed) data. The compression + method searches for as much of the current string of bytes (up to a + length of 258) in the previous 32 K bytes. If it doesn't find any + matches (of at least length 3), it codes the next byte. Otherwise, it + codes the length of the matched string and its distance backwards from + the current position. There is a single Huffman code that codes both + single bytes (called "literals") and match lengths. A second Huffman + code codes the distance information, which follows a length code. Each + length or distance code actually represents a base value and a number + of "extra" (sometimes zero) bits to get to add to the base value. At + the end of each deflated block is a special end-of-block (EOB) literal/ + length code. The decoding process is basically: get a literal/length + code; if EOB then done; if a literal, emit the decoded byte; if a + length then get the distance and emit the referred-to bytes from the + sliding window of previously emitted data. + + There are (currently) three kinds of inflate blocks: stored, fixed, and + dynamic. The compressor deals with some chunk of data at a time, and + decides which method to use on a chunk-by-chunk basis. A chunk might + typically be 32 K or 64 K. If the chunk is incompressible, then the + "stored" method is used. In this case, the bytes are simply stored as + is, eight bits per byte, with none of the above coding. The bytes are + preceded by a count, since there is no longer an EOB code. + + If the data is compressible, then either the fixed or dynamic methods + are used. In the dynamic method, the compressed data is preceded by + an encoding of the literal/length and distance Huffman codes that are + to be used to decode this block. The representation is itself Huffman + coded, and so is preceded by a description of that code. These code + descriptions take up a little space, and so for small blocks, there is + a predefined set of codes, called the fixed codes. The fixed method is + used if the block codes up smaller that way (usually for quite small + chunks), otherwise the dynamic method is used. In the latter case, the + codes are customized to the probabilities in the current block, and so + can code it much better than the pre-determined fixed codes. + + The Huffman codes themselves are decoded using a multi-level table + lookup, in order to maximize the speed of decoding plus the speed of + building the decoding tables. See the comments below that precede the + lbits and dbits tuning parameters. + */ + + +/* + Notes beyond the 1.93a appnote.txt: + + 1. Distance pointers never point before the beginning of the output + stream. + 2. Distance pointers can point back across blocks, up to 32k away. + 3. There is an implied maximum of 7 bits for the bit length table and + 15 bits for the actual data. + 4. If only one code exists, then it is encoded using one bit. (Zero + would be more efficient, but perhaps a little confusing.) If two + codes exist, they are coded using one bit each (0 and 1). + 5. There is no way of sending zero distance codes--a dummy must be + sent if there are none. (History: a pre 2.0 version of PKZIP would + store blocks with no distance codes, but this was discovered to be + too harsh a criterion.) Valid only for 1.93a. 2.04c does allow + zero distance codes, which is sent as one code of zero bits in + length. + 6. There are up to 286 literal/length codes. Code 256 represents the + end-of-block. Note however that the static length tree defines + 288 codes just to fill out the Huffman codes. Codes 286 and 287 + cannot be used though, since there is no length base or extra bits + defined for them. Similarly, there are up to 30 distance codes. + However, static trees define 32 codes (all 5 bits) to fill out the + Huffman codes, but the last two had better not show up in the data. + 7. Unzip can check dynamic Huffman blocks for complete code sets. + The exception is that a single code would not be complete (see #4). + 8. The five bits following the block type is really the number of + literal codes sent minus 257. + 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits + (1+6+6). Therefore, to output three times the length, you output + three codes (1+1+1), whereas to output four times the same length, + you only need two codes (1+3). Hmm. + 10. In the tree reconstruction algorithm, Code = Code + Increment + only if BitLength(i) is not zero. (Pretty obvious.) + 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) + 12. Note: length code 284 can represent 227-258, but length code 285 + really is 258. The last length deserves its own, short code + since it gets used a lot in very redundant files. The length + 258 is special since 258 - 3 (the min match length) is 255. + 13. The literal/length and distance code bit lengths are read as a + single stream of lengths. It is possible (and advantageous) for + a repeat code (16, 17, or 18) to go across the boundary between + the two sets of lengths. + */ + +#ifdef RCSID +static char rcsid[] = "#Id: inflate.c,v 0.14 1993/06/10 13:27:04 jloup Exp #"; +#endif + +#define slide window + +/* Huffman code lookup table entry--this entry is four bytes for machines + that have 16-bit pointers (e.g. PC's in the small or medium model). + Valid extra bits are 0..13. e == 15 is EOB (end of block), e == 16 + means that v is a literal, 16 < e < 32 means that v is a pointer to + the next table, which codes e - 16 bits, and lastly e == 99 indicates + an unused code. If a code with e == 99 is looked up, this implies an + error in the data. */ +struct huft { + uch e; /* number of extra bits or operation */ + uch b; /* number of bits in this code or subcode */ + union { + ush n; /* literal, length base, or distance base */ + struct huft *t; /* pointer to next level of table */ + } v; +}; + + +/* Function prototypes */ +STATIC int huft_build OF((unsigned *, unsigned, unsigned, + const ush *, const ush *, struct huft **, int *)); +STATIC int huft_free OF((struct huft *)); +STATIC int inflate_codes OF((struct huft *, struct huft *, int, int)); +STATIC int inflate_stored OF((void)); +STATIC int inflate_fixed OF((void)); +STATIC int inflate_dynamic OF((void)); +STATIC int inflate_block OF((int *)); +STATIC int inflate OF((void)); + + +/* The inflate algorithm uses a sliding 32 K byte window on the uncompressed + stream to find repeated byte strings. This is implemented here as a + circular buffer. The index is updated simply by incrementing and then + ANDing with 0x7fff (32K-1). */ +/* It is left to other modules to supply the 32 K area. It is assumed + to be usable as if it were declared "uch slide[32768];" or as just + "uch *slide;" and then malloc'ed in the latter case. The definition + must be in unzip.h, included above. */ +/* unsigned wp; current position in slide */ +#define wp outcnt +#define flush_output(w) (wp=(w),flush_window()) + +/* Tables for deflate from PKZIP's appnote.txt. */ +static const unsigned border[] = { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; +static const ush cplens[] = { /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + /* note: see note #13 above about the 258 in this list. */ +static const ush cplext[] = { /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */ +static const ush cpdist[] = { /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; +static const ush cpdext[] = { /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + + + +/* Macros for inflate() bit peeking and grabbing. + The usage is: + + NEEDBITS(j) + x = b & mask_bits[j]; + DUMPBITS(j) + + where NEEDBITS makes sure that b has at least j bits in it, and + DUMPBITS removes the bits from b. The macros use the variable k + for the number of bits in b. Normally, b and k are register + variables for speed, and are initialized at the beginning of a + routine that uses these macros from a global bit buffer and count. + + If we assume that EOB will be the longest code, then we will never + ask for bits with NEEDBITS that are beyond the end of the stream. + So, NEEDBITS should not read any more bytes than are needed to + meet the request. Then no bytes need to be "returned" to the buffer + at the end of the last block. + + However, this assumption is not true for fixed blocks--the EOB code + is 7 bits, but the other literal/length codes can be 8 or 9 bits. + (The EOB code is shorter than other codes because fixed blocks are + generally short. So, while a block always has an EOB, many other + literal/length codes have a significantly lower probability of + showing up at all.) However, by making the first table have a + lookup of seven bits, the EOB code will be found in that first + lookup, and so will not require that too many bits be pulled from + the stream. + */ + +STATIC ulg bb; /* bit buffer */ +STATIC unsigned bk; /* bits in bit buffer */ + +STATIC const ush mask_bits[] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + +#define NEXTBYTE() (uch)get_byte() +#define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<<k;k+=8;}} +#define DUMPBITS(n) {b>>=(n);k-=(n);} + + +/* + Huffman code decoding is performed using a multi-level table lookup. + The fastest way to decode is to simply build a lookup table whose + size is determined by the longest code. However, the time it takes + to build this table can also be a factor if the data being decoded + is not very long. The most common codes are necessarily the + shortest codes, so those codes dominate the decoding time, and hence + the speed. The idea is you can have a shorter table that decodes the + shorter, more probable codes, and then point to subsidiary tables for + the longer codes. The time it costs to decode the longer codes is + then traded against the time it takes to make longer tables. + + This results of this trade are in the variables lbits and dbits + below. lbits is the number of bits the first level table for literal/ + length codes can decode in one step, and dbits is the same thing for + the distance codes. Subsequent tables are also less than or equal to + those sizes. These values may be adjusted either when all of the + codes are shorter than that, in which case the longest code length in + bits is used, or when the shortest code is *longer* than the requested + table size, in which case the length of the shortest code in bits is + used. + + There are two different values for the two tables, since they code a + different number of possibilities each. The literal/length table + codes 286 possible values, or in a flat code, a little over eight + bits. The distance table codes 30 possible values, or a little less + than five bits, flat. The optimum values for speed end up being + about one bit more than those, so lbits is 8+1 and dbits is 5+1. + The optimum values may differ though from machine to machine, and + possibly even between compilers. Your mileage may vary. + */ + + +STATIC const int lbits = 9; /* bits in base literal/length lookup table */ +STATIC const int dbits = 6; /* bits in base distance lookup table */ + + +/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ +#define BMAX 16 /* maximum bit length of any code (16 for explode) */ +#define N_MAX 288 /* maximum number of codes in any set */ + + +STATIC unsigned hufts; /* track memory usage */ + + +STATIC int huft_build(b, n, s, d, e, t, m) +unsigned *b; /* code lengths in bits (all assumed <= BMAX) */ +unsigned n; /* number of codes (assumed <= N_MAX) */ +unsigned s; /* number of simple-valued codes (0..s-1) */ +const ush *d; /* list of base values for non-simple codes */ +const ush *e; /* list of extra bits for non-simple codes */ +struct huft **t; /* result: starting table */ +int *m; /* maximum lookup bits, returns actual */ +/* Given a list of code lengths and a maximum table size, make a set of + tables to decode that set of codes. Return zero on success, one if + the given code set is incomplete (the tables are still built in this + case), two if the input is invalid (all zero length codes or an + oversubscribed set of lengths), and three if not enough memory. */ +{ + unsigned a; /* counter for codes of length k */ + unsigned c[BMAX+1]; /* bit length count table */ + unsigned f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + register unsigned i; /* counter, current code */ + register unsigned j; /* counter */ + register int k; /* number of bits in current code */ + int l; /* bits per table (returned in m) */ + register unsigned *p; /* pointer into c[], b[], or v[] */ + register struct huft *q; /* points to current table */ + struct huft r; /* table entry for structure assignment */ + struct huft *u[BMAX]; /* table stack */ + unsigned v[N_MAX]; /* values in order of bit length */ + register int w; /* bits before this table == (l * h) */ + unsigned x[BMAX+1]; /* bit offsets, then code stack */ + unsigned *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + unsigned z; /* number of entries in current table */ + +DEBG("huft1 "); + + /* Generate counts for each bit length */ + memzero(c, sizeof(c)); + p = b; i = n; + do { + Tracecv(*p, (stderr, (n-i >= ' ' && n-i <= '~' ? "%c %d\n" : "0x%x %d\n"), + n-i, *p)); + c[*p]++; /* assume all entries <= BMAX */ + p++; /* Can't combine with above line (Solaris bug) */ + } while (--i); + if (c[0] == n) /* null input--all zero length codes */ + { + *t = (struct huft *)NULL; + *m = 0; + return 0; + } + +DEBG("huft2 "); + + /* Find minimum and maximum length, bound *m by those */ + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((unsigned)l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((unsigned)l > i) + l = i; + *m = l; + +DEBG("huft3 "); + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return 2; /* bad input: more codes than bits */ + if ((y -= c[i]) < 0) + return 2; + c[i] += y; + +DEBG("huft4 "); + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + +DEBG("huft5 "); + + /* Make a table of values in order of bit lengths */ + p = b; i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + +DEBG("h6 "); + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = -l; /* bits decoded == (l * h) */ + u[0] = (struct huft *)NULL; /* just to keep compilers happy */ + q = (struct huft *)NULL; /* ditto */ + z = 0; /* ditto */ +DEBG("h6a "); + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { +DEBG("h6b "); + a = c[k]; + while (a--) + { +DEBG("h6b1 "); + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l) + { +DEBG1("1 "); + h++; + w += l; /* previous table always l bits */ + + /* compute minimum size table less than or equal to l bits */ + z = (z = g - w) > (unsigned)l ? l : z; /* upper limit on table size */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ +DEBG1("2 "); + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } +DEBG1("3 "); + z = 1 << j; /* table entries for j-bit table */ + + /* allocate and link in new table */ + if ((q = (struct huft *)malloc((z + 1)*sizeof(struct huft))) == + (struct huft *)NULL) + { + if (h) + huft_free(u[0]); + return 3; /* not enough memory */ + } +DEBG1("4 "); + hufts += z + 1; /* track memory usage */ + *t = q + 1; /* link to list for huft_free() */ + *(t = &(q->v.t)) = (struct huft *)NULL; + u[h] = ++q; /* table starts after link */ + +DEBG1("5 "); + /* connect to last table, if there is one */ + if (h) + { + x[h] = i; /* save pattern for backing up */ + r.b = (uch)l; /* bits to dump before this table */ + r.e = (uch)(16 + j); /* bits in this table */ + r.v.t = q; /* pointer to this table */ + j = i >> (w - l); /* (get around Turbo C bug) */ + u[h-1][j] = r; /* connect to last table */ + } +DEBG1("6 "); + } +DEBG("h6c "); + + /* set up table entry in r */ + r.b = (uch)(k - w); + if (p >= v + n) + r.e = 99; /* out of values--invalid code */ + else if (*p < s) + { + r.e = (uch)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */ + r.v.n = (ush)(*p); /* simple code is just the value */ + p++; /* one compiler does not like *p++ */ + } + else + { + r.e = (uch)e[*p - s]; /* non-simple--look up in lists */ + r.v.n = d[*p++ - s]; + } +DEBG("h6d "); + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + while ((i & ((1 << w) - 1)) != x[h]) + { + h--; /* don't need to update q */ + w -= l; + } +DEBG("h6e "); + } +DEBG("h6f "); + } + +DEBG("huft7 "); + + /* Return true (1) if we were given an incomplete table */ + return y != 0 && g != 1; +} + + + +STATIC int huft_free(t) +struct huft *t; /* table to free */ +/* Free the malloc'ed tables built by huft_build(), which makes a linked + list of the tables it made, with the links in a dummy first entry of + each table. */ +{ + register struct huft *p, *q; + + + /* Go through linked list, freeing from the malloced (t[-1]) address. */ + p = t; + while (p != (struct huft *)NULL) + { + q = (--p)->v.t; + free((char*)p); + p = q; + } + return 0; +} + + +STATIC int inflate_codes(tl, td, bl, bd) +struct huft *tl, *td; /* literal/length and distance decoder tables */ +int bl, bd; /* number of bits decoded by tl[] and td[] */ +/* inflate (decompress) the codes in a deflated (compressed) block. + Return an error code or zero if it all goes ok. */ +{ + register unsigned e; /* table entry flag/number of extra bits */ + unsigned n, d; /* length and index for copy */ + unsigned w; /* current window position */ + struct huft *t; /* pointer to table entry */ + unsigned ml, md; /* masks for bl and bd bits */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + + /* make local copies of globals */ + b = bb; /* initialize bit buffer */ + k = bk; + w = wp; /* initialize window position */ + + /* inflate the coded data */ + ml = mask_bits[bl]; /* precompute masks for speed */ + md = mask_bits[bd]; + for (;;) /* do until end of block */ + { + NEEDBITS((unsigned)bl) + if ((e = (t = tl + ((unsigned)b & ml))->e) > 16) + do { + if (e == 99) + return 1; + DUMPBITS(t->b) + e -= 16; + NEEDBITS(e) + } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16); + DUMPBITS(t->b) + if (e == 16) /* then it's a literal */ + { + slide[w++] = (uch)t->v.n; + Tracevv((stderr, "%c", slide[w-1])); + if (w == WSIZE) + { + flush_output(w); + w = 0; + } + } + else /* it's an EOB or a length */ + { + /* exit if end of block */ + if (e == 15) + break; + + /* get length of block to copy */ + NEEDBITS(e) + n = t->v.n + ((unsigned)b & mask_bits[e]); + DUMPBITS(e); + + /* decode distance of block to copy */ + NEEDBITS((unsigned)bd) + if ((e = (t = td + ((unsigned)b & md))->e) > 16) + do { + if (e == 99) + return 1; + DUMPBITS(t->b) + e -= 16; + NEEDBITS(e) + } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16); + DUMPBITS(t->b) + NEEDBITS(e) + d = w - t->v.n - ((unsigned)b & mask_bits[e]); + DUMPBITS(e) + Tracevv((stderr,"\\[%d,%d]", w-d, n)); + + /* do the copy */ + do { + n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e); +#if !defined(NOMEMCPY) && !defined(DEBUG) + if (w - d >= e) /* (this test assumes unsigned comparison) */ + { + memcpy(slide + w, slide + d, e); + w += e; + d += e; + } + else /* do it slow to avoid memcpy() overlap */ +#endif /* !NOMEMCPY */ + do { + slide[w++] = slide[d++]; + Tracevv((stderr, "%c", slide[w-1])); + } while (--e); + if (w == WSIZE) + { + flush_output(w); + w = 0; + } + } while (n); + } + } + + + /* restore the globals from the locals */ + wp = w; /* restore global window pointer */ + bb = b; /* restore global bit buffer */ + bk = k; + + /* done */ + return 0; +} + + + +STATIC int inflate_stored() +/* "decompress" an inflated type 0 (stored) block. */ +{ + unsigned n; /* number of bytes in block */ + unsigned w; /* current window position */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + +DEBG("<stor"); + + /* make local copies of globals */ + b = bb; /* initialize bit buffer */ + k = bk; + w = wp; /* initialize window position */ + + + /* go to byte boundary */ + n = k & 7; + DUMPBITS(n); + + + /* get the length and its complement */ + NEEDBITS(16) + n = ((unsigned)b & 0xffff); + DUMPBITS(16) + NEEDBITS(16) + if (n != (unsigned)((~b) & 0xffff)) + return 1; /* error in compressed data */ + DUMPBITS(16) + + + /* read and output the compressed data */ + while (n--) + { + NEEDBITS(8) + slide[w++] = (uch)b; + if (w == WSIZE) + { + flush_output(w); + w = 0; + } + DUMPBITS(8) + } + + + /* restore the globals from the locals */ + wp = w; /* restore global window pointer */ + bb = b; /* restore global bit buffer */ + bk = k; + + DEBG(">"); + return 0; +} + + + +STATIC int inflate_fixed() +/* decompress an inflated type 1 (fixed Huffman codes) block. We should + either replace this with a custom decoder, or at least precompute the + Huffman tables. */ +{ + int i; /* temporary variable */ + struct huft *tl; /* literal/length code table */ + struct huft *td; /* distance code table */ + int bl; /* lookup bits for tl */ + int bd; /* lookup bits for td */ + unsigned l[288]; /* length list for huft_build */ + +DEBG("<fix"); + + /* set up literal table */ + for (i = 0; i < 144; i++) + l[i] = 8; + for (; i < 256; i++) + l[i] = 9; + for (; i < 280; i++) + l[i] = 7; + for (; i < 288; i++) /* make a complete, but wrong code set */ + l[i] = 8; + bl = 7; + if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0) + return i; + + + /* set up distance table */ + for (i = 0; i < 30; i++) /* make an incomplete code set */ + l[i] = 5; + bd = 5; + if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1) + { + huft_free(tl); + + DEBG(">"); + return i; + } + + + /* decompress until an end-of-block code */ + if (inflate_codes(tl, td, bl, bd)) + return 1; + + + /* free the decoding tables, return */ + huft_free(tl); + huft_free(td); + return 0; +} + + + +STATIC int inflate_dynamic() +/* decompress an inflated type 2 (dynamic Huffman codes) block. */ +{ + int i; /* temporary variables */ + unsigned j; + unsigned l; /* last length */ + unsigned m; /* mask for bit lengths table */ + unsigned n; /* number of lengths to get */ + struct huft *tl; /* literal/length code table */ + struct huft *td; /* distance code table */ + int bl; /* lookup bits for tl */ + int bd; /* lookup bits for td */ + unsigned nb; /* number of bit length codes */ + unsigned nl; /* number of literal/length codes */ + unsigned nd; /* number of distance codes */ +#ifdef PKZIP_BUG_WORKAROUND + unsigned ll[288+32]; /* literal/length and distance code lengths */ +#else + unsigned ll[286+30]; /* literal/length and distance code lengths */ +#endif + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + +DEBG("<dyn"); + + /* make local bit buffer */ + b = bb; + k = bk; + + + /* read in table lengths */ + NEEDBITS(5) + nl = 257 + ((unsigned)b & 0x1f); /* number of literal/length codes */ + DUMPBITS(5) + NEEDBITS(5) + nd = 1 + ((unsigned)b & 0x1f); /* number of distance codes */ + DUMPBITS(5) + NEEDBITS(4) + nb = 4 + ((unsigned)b & 0xf); /* number of bit length codes */ + DUMPBITS(4) +#ifdef PKZIP_BUG_WORKAROUND + if (nl > 288 || nd > 32) +#else + if (nl > 286 || nd > 30) +#endif + return 1; /* bad lengths */ + +DEBG("dyn1 "); + + /* read in bit-length-code lengths */ + for (j = 0; j < nb; j++) + { + NEEDBITS(3) + ll[border[j]] = (unsigned)b & 7; + DUMPBITS(3) + } + for (; j < 19; j++) + ll[border[j]] = 0; + +DEBG("dyn2 "); + + /* build decoding table for trees--single level, 7 bit lookup */ + bl = 7; + if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0) + { + if (i == 1) + huft_free(tl); + return i; /* incomplete code set */ + } + +DEBG("dyn3 "); + + /* read in literal and distance code lengths */ + n = nl + nd; + m = mask_bits[bl]; + i = l = 0; + while ((unsigned)i < n) + { + NEEDBITS((unsigned)bl) + j = (td = tl + ((unsigned)b & m))->b; + DUMPBITS(j) + j = td->v.n; + if (j < 16) /* length of code in bits (0..15) */ + ll[i++] = l = j; /* save last length in l */ + else if (j == 16) /* repeat last length 3 to 6 times */ + { + NEEDBITS(2) + j = 3 + ((unsigned)b & 3); + DUMPBITS(2) + if ((unsigned)i + j > n) + return 1; + while (j--) + ll[i++] = l; + } + else if (j == 17) /* 3 to 10 zero length codes */ + { + NEEDBITS(3) + j = 3 + ((unsigned)b & 7); + DUMPBITS(3) + if ((unsigned)i + j > n) + return 1; + while (j--) + ll[i++] = 0; + l = 0; + } + else /* j == 18: 11 to 138 zero length codes */ + { + NEEDBITS(7) + j = 11 + ((unsigned)b & 0x7f); + DUMPBITS(7) + if ((unsigned)i + j > n) + return 1; + while (j--) + ll[i++] = 0; + l = 0; + } + } + +DEBG("dyn4 "); + + /* free decoding table for trees */ + huft_free(tl); + +DEBG("dyn5 "); + + /* restore the global bit buffer */ + bb = b; + bk = k; + +DEBG("dyn5a "); + + /* build the decoding tables for literal/length and distance codes */ + bl = lbits; + if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) + { +DEBG("dyn5b "); + if (i == 1) { + error(" incomplete literal tree"); + huft_free(tl); + } + return i; /* incomplete code set */ + } +DEBG("dyn5c "); + bd = dbits; + if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) + { +DEBG("dyn5d "); + if (i == 1) { + error(" incomplete distance tree"); +#ifdef PKZIP_BUG_WORKAROUND + i = 0; + } +#else + huft_free(td); + } + huft_free(tl); + return i; /* incomplete code set */ +#endif + } + +DEBG("dyn6 "); + + /* decompress until an end-of-block code */ + if (inflate_codes(tl, td, bl, bd)) + return 1; + +DEBG("dyn7 "); + + /* free the decoding tables, return */ + huft_free(tl); + huft_free(td); + + DEBG(">"); + return 0; +} + + + +STATIC int inflate_block(e) +int *e; /* last block flag */ +/* decompress an inflated block */ +{ + unsigned t; /* block type */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + DEBG("<blk"); + + /* make local bit buffer */ + b = bb; + k = bk; + + + /* read in last block bit */ + NEEDBITS(1) + *e = (int)b & 1; + DUMPBITS(1) + + + /* read in block type */ + NEEDBITS(2) + t = (unsigned)b & 3; + DUMPBITS(2) + + + /* restore the global bit buffer */ + bb = b; + bk = k; + + /* inflate that block type */ + if (t == 2) + return inflate_dynamic(); + if (t == 0) + return inflate_stored(); + if (t == 1) + return inflate_fixed(); + + DEBG(">"); + + /* bad block type */ + return 2; +} + + + +STATIC int inflate() +/* decompress an inflated entry */ +{ + int e; /* last block flag */ + int r; /* result code */ + unsigned h; /* maximum struct huft's malloc'ed */ + void *ptr; + + /* initialize window, bit buffer */ + wp = 0; + bk = 0; + bb = 0; + + + /* decompress until the last block */ + h = 0; + do { + hufts = 0; + gzip_mark(&ptr); + if ((r = inflate_block(&e)) != 0) { + gzip_release(&ptr); + return r; + } + gzip_release(&ptr); + if (hufts > h) + h = hufts; + } while (!e); + + /* Undo too much lookahead. The next read will be byte aligned so we + * can discard unused bits in the last meaningful byte. + */ + while (bk >= 8) { + bk -= 8; + unget_byte(); + } + + /* flush out slide */ + flush_output(wp); + + + /* return success */ +#ifdef DEBUG + fprintf(stderr, "<%u> ", h); +#endif /* DEBUG */ + return 0; +} + +/********************************************************************** + * + * The following are support routines for inflate.c + * + **********************************************************************/ + +static ulg crc_32_tab[256]; +static ulg crc; /* initialized in makecrc() so it'll reside in bss */ +#define CRC_VALUE (crc ^ 0xffffffffL) + +/* + * Code to compute the CRC-32 table. Borrowed from + * gzip-1.0.3/makecrc.c. + */ + +static void +makecrc(void) +{ +/* Not copyrighted 1990 Mark Adler */ + + unsigned long c; /* crc shift register */ + unsigned long e; /* polynomial exclusive-or pattern */ + int i; /* counter for all possible eight bit values */ + int k; /* byte being shifted into crc apparatus */ + + /* terms of polynomial defining this crc (except x^32): */ + static const int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* Make exclusive-or pattern from polynomial */ + e = 0; + for (i = 0; i < sizeof(p)/sizeof(int); i++) + e |= 1L << (31 - p[i]); + + crc_32_tab[0] = 0; + + for (i = 1; i < 256; i++) + { + c = 0; + for (k = i | 256; k != 1; k >>= 1) + { + c = c & 1 ? (c >> 1) ^ e : c >> 1; + if (k & 1) + c ^= e; + } + crc_32_tab[i] = c; + } + + /* this is initialized here so this code could reside in ROM */ + crc = (ulg)0xffffffffL; /* shift register contents */ +} + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ +#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ +#define RESERVED 0xC0 /* bit 6,7: reserved */ + +/* + * Do the uncompression! + */ +int gunzip() +{ + int res; + + /* Decompress */ + if ((res = inflate())) { + switch (res) { + case 0: + break; + case 1: + error("invalid compressed format (err=1)"); + break; + case 2: + error("invalid compressed format (err=2)"); + break; + case 3: + error("out of memory"); + break; + default: + error("invalid compressed format (other)"); + } + return -1; + } + + return 0; +} diff --git a/syslinux/memdisk/memcpy.S b/syslinux/memdisk/memcpy.S new file mode 100644 index 0000000..a976c8b --- /dev/null +++ b/syslinux/memdisk/memcpy.S @@ -0,0 +1,29 @@ +# $Id: memcpy.S,v 1.1 2003/04/15 19:31:04 hpa Exp $ +# +# memcpy.S +# +# Simple memcpy() implementation +# + + .text + .globl memcpy + .type memcpy, @function +memcpy: + cld + pushl %edi + pushl %esi + movl 12(%esp),%edi + movl 16(%esp),%esi + movl 20(%esp),%eax + movl %eax,%ecx + shrl $2,%ecx + rep ; movsl + movl %eax,%ecx + andl $3,%ecx + rep ; movsb + movl 12(%esp),%eax + popl %esi + popl %edi + ret + + .size memcpy,.-memcpy diff --git a/syslinux/memdisk/memdisk b/syslinux/memdisk/memdisk new file mode 100644 index 0000000000000000000000000000000000000000..29aa74807f3fa430b95319ac69ae5d62ec3ea041 GIT binary patch literal 19124 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 Ck?QmS literal 0 HcmV?d00001 diff --git a/syslinux/memdisk/memdisk.asm b/syslinux/memdisk/memdisk.asm new file mode 100644 index 0000000..e2165be --- /dev/null +++ b/syslinux/memdisk/memdisk.asm @@ -0,0 +1,759 @@ +; -*- fundamental -*- (asm-mode sucks) +; $Id: memdisk.asm,v 1.29 2005/04/29 06:08:03 hpa Exp $ +; **************************************************************************** +; +; memdisk.asm +; +; A program to emulate an INT 13h disk BIOS from a "disk" in extended +; memory. +; +; Copyright (C) 2001-2004 H. Peter Anvin +; +; This program is free software; you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +; Boston MA 02111-1307, USA; either version 2 of the License, or +; (at your option) any later version; incorporated herein by reference. +; +; **************************************************************************** + +%ifndef DEPEND +%include "../version.gen" +%endif + +; %define DEBUG_TRACERS ; Uncomment to get debugging tracers + +%ifdef DEBUG_TRACERS + +%macro TRACER 1 + call debug_tracer + db %1 +%endmacro + +%else ; DEBUG_TRACERS + +%macro TRACER 1 +%endmacro + +%endif ; DEBUG_TRACERS + +%define CONFIG_READONLY 0x01 +%define CONFIG_RAW 0x02 +%define CONFIG_BIGRAW 0x08 ; MUST be 8! + + org 0h + +%define SECTORSIZE_LG2 9 ; log2(sector size) +%define SECTORSIZE (1 << SECTORSIZE_LG2) + + ; Parameter registers definition; this is the definition + ; of the stack frame. +%define P_DS word [bp+34] +%define P_ES word [bp+32] +%define P_EAX dword [bp+28] +%define P_HAX word [bp+30] +%define P_AX word [bp+28] +%define P_AL byte [bp+28] +%define P_AH byte [bp+29] +%define P_ECX dword [bp+24] +%define P_HCX word [bp+26] +%define P_CX word [bp+24] +%define P_CL byte [bp+24] +%define P_CH byte [bp+25] +%define P_EDX dword [bp+20] +%define P_HDX word [bp+22] +%define P_DX word [bp+20] +%define P_DL byte [bp+20] +%define P_DH byte [bp+21] +%define P_EBX dword [bp+16] +%define P_HBX word [bp+18] +%define P_HBXL byte [bp+18] +%define P_BX word [bp+16] +%define P_BL byte [bp+16] +%define P_BH byte [bp+17] +%define P_EBP dword [bp+8] +%define P_BP word [bp+8] +%define P_ESI dword [bp+4] +%define P_SI word [bp+4] +%define P_EDI dword [bp] +%define P_DI word [bp] + + section .text + ; These pointers are used by the installer and + ; must be first in the binary +Pointers: dw Int13Start + dw Int15Start + dw PatchArea + dw TotalSize + +Int13Start: + ; Swap stack + mov [cs:Stack],esp + mov [cs:SavedAX],ax + mov ax,ss + mov [cs:Stack+4],ax + mov ax,cs + mov ss,ax + mov sp,[cs:MyStack] + + ; See if DL points to our class of device (FD, HD) + push dx + push dx + xor dl,[cs:DriveNo] + pop dx + js .nomatch ; If SF=0, we have a class match here + jz .our_drive ; If ZF=1, we have an exact match + cmp dl,[cs:DriveNo] + jb .nomatch ; Drive < Our drive + dec dl ; Drive > Our drive, adjust drive # +.nomatch: + mov ax,[cs:SavedAX] + pushf + call far [cs:OldInt13] + pushf + push bp + mov bp,sp + cmp byte [cs:SavedAX+1],08h + je .norestoredl + cmp byte [cs:SavedAX+1],15h + jne .restoredl + test byte [bp+4],80h ; Hard disk? + jnz .norestoredl +.restoredl: + mov dl,[bp+4] +.norestoredl: + push ax + push ebx + push ds + mov ax,[bp+2] ; Flags + lds ebx,[cs:Stack] + mov [bx+4],al ; Arithmetric flags + pop ds + pop ebx + pop ax + pop bp + lss esp,[cs:Stack] + iret + +.our_drive: + ; Set up standard entry frame + push ds + push es + mov ds,ax + mov es,ax + mov ax,[SavedAX] + pushad + mov bp,sp ; Point BP to the entry stack frame + TRACER 'F' + ; Note: AH == P_AH here + cmp ah,Int13FuncsMax + jae Invalid_jump + xor al,al ; AL = 0 is standard entry condition + mov di,ax + shr di,7 ; Convert AH to an offset in DI + call [Int13Funcs+di] + +Done: ; Standard routine for return + mov P_AX,ax +DoneWeird: + TRACER 'D' + xor bx,bx + mov es,bx + mov bx,[StatusPtr] + mov [es:bx],ah ; Save status + and ah,ah + + lds ebx,[Stack] + ; This sets the low byte (the arithmetric flags) of the + ; FLAGS on stack to either 00h (no flags) or 01h (CF) + ; depending on if AH was zero or not. + setnz [bx+4] ; Set CF iff error + popad + pop es + pop ds + lss esp,[cs:Stack] + iret + +Reset: + ; Reset affects multiple drives, so we need to pass it on + TRACER 'R' + test dl,dl ; Always pass it on if we are resetting HD + js .pass_on ; Bit 7 set + ; Some BIOSes get very unhappy if we pass a reset floppy + ; command to them and don't actually have any floppies. + ; This is a bug, but we have to deal with it nontheless. + ; Therefore, if we are the *ONLY* floppy drive, and the + ; user didn't request HD reset, then just drop the command. + xor ax,ax ; Bottom of memory + mov es,ax + ; BIOS equipment byte, top two bits + 1 == total # of floppies + test byte [es:0x410],0C0h + jz success + ; ... otherwise pass it to the BIOS +.pass_on: + pop ax ; Drop return address + popad ; Restore all registers + pop es + pop ds + lss esp,[cs:Stack] ; Restore the stack + and dl,80h ; Clear all but the type bit + jmp far [cs:OldInt13] + + +Invalid: + pop dx ; Drop return address +Invalid_jump: + TRACER 'I' + mov ah,01h ; Unsupported function + jmp short Done + +GetDriveType: + test byte [DriveNo],80h + mov bl,02h ; Type 02h = floppy with changeline + jz .floppy + ; Hard disks only... + inc bx ; Type = 03h + mov dx,[DiskSize] ; Return the disk size in sectors + mov P_DX,dx + mov cx,[DiskSize+2] + mov P_CX,cx +.floppy: + mov P_AH,bl ; 02h floppy, 03h hard disk + pop ax ; Drop return address + xor ax,ax ; Success... + jmp short DoneWeird ; But don't stick it into P_AX + +GetStatus: + xor ax,ax + mov es,ax + mov bx,[StatusPtr] + mov ah,[bx] ; Copy last status + ret + +ReadMult: + TRACER 'm' +Read: + TRACER 'R' + call setup_regs +do_copy: + TRACER '<' + call bcopy + TRACER '>' + movzx ax,P_AL ; AH = 0, AL = transfer count + ret + +WriteMult: + TRACER 'M' +Write: + TRACER 'W' + test byte [ConfigFlags],CONFIG_READONLY + jnz .readonly + call setup_regs + xchg esi,edi ; Opposite direction of a Read! + jmp short do_copy +.readonly: mov ah,03h ; Write protected medium + ret + + ; Verify integrity; just bounds-check +Seek: +Verify: + call setup_regs ; Returns error if appropriate + ; And fall through to success + +CheckIfReady: ; These are always-successful noop functions +Recalibrate: +InitWithParms: +DetectChange: +SetMode: +success: + xor ax,ax ; Always successful + ret + +GetParms: + TRACER 'G' + mov dl,[DriveCnt] ; Cached data + mov P_DL,dl + test byte [DriveNo],80h + jnz .hd + mov P_DI,DPT + mov P_ES,cs + mov bl,[DriveType] + mov P_BL,bl +.hd: + mov ax,[Cylinders] + dec ax ; We report the highest #, not the count + xchg al,ah + shl al,6 + or al,[Sectors] + mov P_CX,ax + mov ax,[Heads] + dec ax + mov P_DH,al + + ; + ; Is this MEMDISK installation check? + ; + cmp P_HAX,'ME' + jne .notic + cmp P_HCX,'MD' + jne .notic + cmp P_HDX,'IS' + jne .notic + cmp P_HBX,'K?' + jne .notic + + ; MEMDISK installation check... + mov P_HAX,'!M' + mov P_HCX,'EM' + mov P_HDX,'DI' + mov P_HBX,'SK' + mov P_ES,cs + mov P_DI,MemDisk_Info + +.notic: + xor ax,ax + ret + + ; Set up registers as for a "Read", and compares against disk size +setup_regs: + + ; Convert a CHS address in P_CX/P_DH into an LBA in eax + ; CH = cyl[7:0] + ; CL[0:5] = sector (1-based) CL[7:6] = cyl[9:8] + ; DH = head + movzx ecx,P_CX + movzx ebx,cl ; Sector number + and bl,3Fh + dec ebx ; Sector number is 1-based + cmp bx,[Sectors] + jae .overrun + movzx edi,P_DH ; Head number + movzx eax,word [Heads] + cmp di,ax + jae .overrun + shr cl,6 + xchg cl,ch ; Now (E)CX <- cylinder number + mul ecx ; eax <- Heads*cyl# (edx <- 0) + add eax,edi + mul dword [Sectors] + add eax,ebx + ; Now eax = LBA, edx = 0 + + ; + ; setup_regs continues... + ; + ; Note: edi[31:16] and ecx[31:16] = 0 already + mov di,P_BX ; Get linear address of target buffer + mov cx,P_ES + shl ecx,4 + add edi,ecx ; EDI = address to fetch to + movzx ecx,P_AL ; Sector count + mov esi,eax + add eax,ecx ; LBA of final sector + 1 + shl esi,SECTORSIZE_LG2 ; LBA -> byte offset + add esi,[DiskBuf] ; Get address in high memory + cmp eax,[DiskSize] ; Check the high mark against limit + ja .overrun + shl ecx,SECTORSIZE_LG2-2 ; Convert count to 32-bit words + ret + +.overrun: pop ax ; Drop setup_regs return address + mov ax,0200h ; Missing address mark + ret ; Return to Done + +int15_e820: + cmp edx,534D4150h ; "SMAP" + jne near oldint15 + cmp ecx,20 ; Need 20 bytes + jb err86 + push ds + push cs + pop ds + and ebx,ebx + jne .renew + mov ebx,E820Table +.renew: + add bx,12 ; Advance to next + mov eax,[bx-4] ; Type + and eax,eax ; Null type? + jz .renew ; If so advance to next + mov [es:di+16],eax + mov eax,[bx-12] ; Start addr (low) + mov [es:di],eax + mov ecx,[bx-8] ; Start addr (high) + mov [es:di+4],ecx + mov eax,[bx] ; End addr (low) + mov ecx,[bx+4] ; End addr (high) + sub eax,[bx-12] ; Derive the length + sbb ecx,[bx-8] + mov [es:di+8],eax ; Length (low) + mov [es:di+12],ecx ; Length (high) + cmp dword [bx+8],-1 ; Type of next = end? + jne .notdone + xor ebx,ebx ; Done with table +.notdone: + mov eax,edx ; "SMAP" + pop ds + mov ecx,20 ; Bytes loaded +int15_success: + mov byte [bp+6], 02h ; Clear CF + pop bp + iret + +err86: + mov byte [bp+6], 03h ; Set CF + mov ah,86h + pop bp + iret + +Int15Start: + push bp + mov bp,sp + cmp ax,0E820h + je near int15_e820 + cmp ax,0E801h + je int15_e801 + cmp ax,0E881h + je int15_e881 + cmp ah,88h + je int15_88 +oldint15: pop bp + jmp far [cs:OldInt15] + +int15_e801: + mov ax,[cs:Mem1MB] + mov cx,ax + mov bx,[cs:Mem16MB] + mov dx,bx + jmp short int15_success + +int15_e881: + mov eax,[cs:Mem1MB] + mov ecx,eax + mov ebx,[cs:Mem16MB] + mov edx,ebx + jmp short int15_success + +int15_88: + mov ax,[cs:MemInt1588] + jmp short int15_success + +; +; Routine to copy in/out of high memory +; esi = linear source address +; edi = linear target address +; ecx = 32-bit word count +; +; Assumes cs = ds = es +; +bcopy: + push eax + push ebx + push edx + push ebp + + test byte [ConfigFlags],CONFIG_RAW + jz .anymode + + smsw ax ; Unprivileged! + test al,01h + jnz .protmode + +.realmode: + TRACER 'r' + ; We're in real mode, do it outselves + + pushfd + push ds + push es + + cli + cld + + xor ebx,ebx + mov bx,cs + shl ebx,4 + lea edx,[Shaker+ebx] + mov [Shaker+2],edx + + ; Test to see if A20 is enabled or not + xor ax,ax + mov ds,ax + dec ax + mov es,ax + + mov ax,[0] + mov bx,ax + xor bx,[es:10h] + not ax + mov [0],ax + mov dx,ax + xor dx,[es:10h] + not ax + mov [0],ax + + or dx,bx + push dx ; Save A20 status + jnz .skip_a20e + + mov ax,2401h ; Enable A20 + int 15h +.skip_a20e: + mov dl,[ConfigFlags] + and dx,CONFIG_BIGRAW + add dx,8 + ; DX = 16 for BIGRAW, 8 for RAW + ; 8 is selector for a 64K flat segment, + ; 16 is selector for a 4GB flat segment. + + lgdt [cs:Shaker] + mov eax,cr0 + or al,01h + mov cr0,eax + + mov bx,16 ; Large flat segment + mov ds,bx + mov es,bx + + a32 rep movsd + + ; DX has the appropriate value to put in + ; the registers on return + mov ds,dx + mov es,dx + + and al,~01h + mov cr0,eax + + pop es + pop ds + + pop dx ; A20 status + and dx,dx + jnz .skip_a20d + mov ax,2400h ; Disable A20 + int 15h +.skip_a20d: + popfd + jmp .done + +.protmode: + TRACER 'p' +.anymode: + +.copy_loop: + push esi + push edi + push ecx + cmp ecx,4000h + jna .safe_size + mov ecx,4000h +.safe_size: + push ecx ; Transfer size this cycle + mov eax, esi + mov [Mover_src1], si + shr eax, 16 + mov [Mover_src1+2], al + mov [Mover_src2], ah + mov eax, edi + mov [Mover_dst1], di + shr eax, 16 + mov [Mover_dst1+2], al + mov [Mover_dst2], ah + mov si,Mover + mov ah, 87h + shl cx,1 ; Convert to 16-bit words + int 15h + cli ; Some BIOSes enable interrupts on INT 15h + pop eax ; Transfer size this cycle + pop ecx + pop edi + pop esi + jc .error + lea esi,[esi+4*eax] + lea edi,[edi+4*eax] + sub ecx, eax + jnz .copy_loop + ; CF = 0 +.error: +.done: + pop ebp + pop edx + pop ebx + pop eax + ret + +%ifdef DEBUG_TRACERS +debug_tracer: pushad + pushfd + mov bp,sp + mov bx,[bp+9*4] + mov al,[cs:bx] + inc word [bp+9*4] + mov ah,0Eh + mov bx,7 + int 10h + popfd + popad + ret +%endif + + section .data + alignb 2 +Int13Funcs dw Reset ; 00h - RESET + dw GetStatus ; 01h - GET STATUS + dw Read ; 02h - READ + dw Write ; 03h - WRITE + dw Verify ; 04h - VERIFY + dw Invalid ; 05h - FORMAT TRACK + dw Invalid ; 06h - FORMAT TRACK AND SET BAD FLAGS + dw Invalid ; 07h - FORMAT DRIVE AT TRACK + dw GetParms ; 08h - GET PARAMETERS + dw InitWithParms ; 09h - INITIALIZE CONTROLLER WITH DRIVE PARAMETERS + dw Invalid ; 0Ah + dw Invalid ; 0Bh + dw Seek ; 0Ch - SEEK TO CYLINDER + dw Reset ; 0Dh - RESET HARD DISKS + dw Invalid ; 0Eh + dw Invalid ; 0Fh + dw CheckIfReady ; 10h - CHECK IF READY + dw Recalibrate ; 11h - RECALIBRATE + dw Invalid ; 12h + dw Invalid ; 13h + dw Invalid ; 14h + dw GetDriveType ; 15h - GET DRIVE TYPE + dw DetectChange ; 16h - DETECT DRIVE CHANGE +%if 0 + dw Invalid ; 17h + dw Invalid ; 18h + dw Invalid ; 19h + dw Invalid ; 1Ah + dw Invalid ; 1Bh + dw Invalid ; 1Ch + dw Invalid ; 1Dh + dw Invalid ; 1Eh + dw Invalid ; 1Fh + dw Invalid ; 20h + dw ReadMult ; 21h - READ MULTIPLE + dw WriteMult ; 22h - WRITE MULTIPLE + dw SetMode ; 23h - SET CONTROLLER FEATURES + dw SetMode ; 24h - SET MULTIPLE MODE + dw Invalid ; 25h - IDENTIFY DRIVE + dw Invalid ; 26h + dw Invalid ; 27h + dw Invalid ; 28h + dw Invalid ; 29h + dw Invalid ; 2Ah + dw Invalid ; 2Bh + dw Invalid ; 2Ch + dw Invalid ; 2Dh + dw Invalid ; 2Eh + dw Invalid ; 2Fh + dw Invalid ; 30h + dw Invalid ; 31h + dw Invalid ; 32h + dw Invalid ; 33h + dw Invalid ; 34h + dw Invalid ; 35h + dw Invalid ; 36h + dw Invalid ; 37h + dw Invalid ; 38h + dw Invalid ; 39h + dw Invalid ; 3Ah + dw Invalid ; 3Bh + dw Invalid ; 3Ch + dw Invalid ; 3Dh + dw Invalid ; 3Eh + dw Invalid ; 3Fh + dw Invalid ; 40h + dw EDDPresence ; 41h - EDD PRESENCE DETECT + dw EDDRead ; 42h - EDD READ + dw EDDWrite ; 43h - EDD WRITE + dw EDDVerify ; 44h - EDD VERIFY + dw Invalid ; 45h - EDD LOCK/UNLOCK MEDIA + dw Invalid ; 46h - EDD EJECT + dw EDDSeek ; 47h - EDD SEEK + dw EDDGetParms ; 48h - EDD GET PARAMETERS +%endif + +Int13FuncsEnd equ $ +Int13FuncsMax equ (Int13FuncsEnd-Int13Funcs) >> 1 + + alignb 8, db 0 +Shaker dw ShakerEnd-$ + dd 0 ; Pointer to self + dw 0 + +Shaker_RMDS: dd 0x0000ffff ; 64K data segment + dd 0x00009300 + +Shaker_DS: dd 0x0000ffff ; 4GB data segment + dd 0x008f9300 + +ShakerEnd equ $ + + alignb 8, db 0 + + +Mover dd 0, 0, 0, 0 ; Must be zero + dw 0ffffh ; 64 K segment size +Mover_src1: db 0, 0, 0 ; Low 24 bits of source addy + db 93h ; Access rights + db 00h ; Extended access rights +Mover_src2: db 0 ; High 8 bits of source addy + dw 0ffffh ; 64 K segment size +Mover_dst1: db 0, 0, 0 ; Low 24 bits of target addy + db 93h ; Access rights + db 00h ; Extended access rights +Mover_dst2: db 0 ; High 8 bits of source addy +Mover_dummy2: dd 0, 0, 0, 0 ; More space for the BIOS + + alignb 4, db 0 +MemDisk_Info equ $ ; Pointed to by installation check +MDI_Bytes dw 27 ; Total bytes in MDI structure +MDI_Version db VER_MINOR, VER_MAJOR ; MEMDISK version + +PatchArea equ $ ; This gets filled in by the installer + +DiskBuf dd 0 ; Linear address of high memory disk +DiskSize dd 0 ; Size of disk in blocks +CommandLine dw 0, 0 ; Far pointer to saved command line + +OldInt13 dd 0 ; INT 13h in chain +OldInt15 dd 0 ; INT 15h in chain + +OldDosMem dw 0 ; Old position of DOS mem end +BootLoaderID db 0 ; Boot loader ID from header +; ---- MDI structure ends here --- + db 0, 0, 0 ; pad + +MemInt1588 dw 0 ; 1MB-65MB memory amount (1K) + +Cylinders dw 0 ; Cylinder count +Heads dw 0 ; Head count +Sectors dd 0 ; Sector count (zero-extended) + +Mem1MB dd 0 ; 1MB-16MB memory amount (1K) +Mem16MB dd 0 ; 16MB-4G memory amount (64K) + +DriveNo db 0 ; Our drive number +DriveType db 0 ; Our drive type (floppies) +DriveCnt db 0 ; Drive count (from the BIOS) + +ConfigFlags db 0 ; Bit 0 - readonly + +MyStack dw 0 ; Offset of stack +StatusPtr dw 0 ; Where to save status (zeroseg ptr) + +DPT times 16 db 0 ; BIOS parameter table pointer (floppies) + + ; End patch area + +Stack dd 0 ; Saved SS:ESP on invocation + dw 0 +SavedAX dw 0 ; AX saved on invocation + + alignb 4, db 0 ; We *MUST* end on a dword boundary + +E820Table equ $ ; The installer loads the E820 table here +TotalSize equ $ ; End pointer diff --git a/syslinux/memdisk/memdisk.doc b/syslinux/memdisk/memdisk.doc new file mode 100644 index 0000000..e0e2310 --- /dev/null +++ b/syslinux/memdisk/memdisk.doc @@ -0,0 +1,186 @@ +$Id: memdisk.doc,v 1.17 2005/04/29 06:04:45 hpa Exp $ +[This documentation is rather crufty at the moment.] + +MEMDISK is meant to allow booting legacy operating systems via PXE, +and as a workaround for BIOSes where ISOLINUX image support doesn't +work. + +MEMDISK simulates a disk by claiming a chunk of high memory for the +disk and a (very small - 2K typical) chunk of low (DOS) memory for the +driver itself, then hooking the INT 13h (disk driver) and INT 15h +(memory query) BIOS interrupts. + +To use it, type on the SYSLINUX command line: + +memdisk initrd=diskimg.img + +... where diskimg.img is the disk image you want to boot from. + +[Obviously, the memdisk binary as well as your disk image file need to +be present in the boot image directory.] + +... or add to your syslinux.cfg/pxelinux.cfg/isolinux.cfg something like: + +label dos + kernel memdisk + append initrd=dosboot.img + +Note the following: + +a) The disk image can be uncompressed or compressed with gzip or zip. + +b) If the disk image is one of the following sizes, it's assumed to be a + floppy image: + + 368,640 bytes - 360K floppy + 737,280 bytes - 720K floppy + 1,222,800 bytes - 1200K floppy + 1,474,560 bytes - 1440K floppy + 1,720,320 bytes - 1680K floppy (common extended format) + 1,763,328 bytes - 1722K floppy (common extended format) + 2,949,120 bytes - 2880K floppy + 3,932,160 bytes - 3840K floppy (extended format) + + For any other size, the image is assumed to be a hard disk image, + and should typically have an MBR and a partition table. It may + optionally have a DOSEMU geometry header; in which case the header + is used to determine the C/H/S geometry of the disk. Otherwise, + the geometry is determined by examining the partition table, so the + entire image should be partitioned for proper operation (it may be + divided between multiple partitions, however.) + + You can also specify the geometry manually with the following command + line options: + + c=<number> Specify number of cylinders (max 1024[*]) + h=<number> Specify number of heads (max 256[*]) + s=<number> Specify number of sectors (max 63) + floppy The image is a floppy image + harddisk The image is a hard disk image + + [*] MS-DOS only allows max 255 heads, and only allows 255 cylinders + on floppy disks. + +c) The disk is normally writable (although, of course, there is + nothing backing it up, so it only lasts until reset.) If you want, + you can mimic a write-protected disk by specifying the command line + option: + + ro Disk is readonly + +d) MEMDISK normally uses the BIOS "INT 15h mover" API to access high + memory. This is well-behaved with extended memory managers which load + later. Unfortunately it appears that the "DOS boot disk" from + WinME/XP *deliberately* crash the system when this API is invoked. + The following command-line options tells MEMDISK to enter protected + mode directly, whenever possible: + + raw Use raw access to protected mode memory. + + bigraw Use raw access to protected mode memory, and leave the + CPU in "big real" mode afterwards. + + +Some interesting things to note: + +If you're using MEMDISK to boot DOS from a CD-ROM (using ISOLINUX), +you might find the generic El Torito CD-ROM driver by Gary Tong and +Bart Lagerweij useful: + + http://www.nu2.nu/eltorito/ + + +Similarly, if you're booting DOS over the network using PXELINUX, you +can use the "keeppxe" option and use the generic PXE (UNDI) NDIS +network driver, which is part of the PROBOOT.EXE distribution from +Intel: + + http://www.intel.com/support/network/adapter/1000/software.htm + + +Additional technical information: + +Starting with version 2.08, MEMDISK now supports an installation check +API. This works as follows: + + EAX = 454D08xxh ("ME") (08h = parameter query) + ECX = 444Dxxxxh ("MD") + EDX = 5349xxnnh ("IS") (nn = drive #) + EBX = 3F4Bxxxxh ("K?") + INT 13h + +If drive nn is a MEMDISK, the registers will contain: + + EAX = 4D21xxxxh ("!M") + ECX = 4D45xxxxh ("EM") + EDX = 4944xxxxh ("DI") + EBX = 4B53xxxxh ("SK") + + ES:DI -> MEMDISK info structures + +The low parts of EAX/ECX/EDX/EBX have the normal return values for INT +13h, AH=08h, i.e. information of the disk geometry etc. + +See Ralf Brown's interrupt list, +http://www.cs.cmu.edu/afs/cs.cmu.edu/user/ralf/pub/WWW/files.html or +http://www.ctyme.com/rbrown.htm, for a detailed description. + +The MEMDISK info structure currently contains: + + [ES:DI] word Total size of structure (currently 27 bytes) + [ES:DI+2] byte MEMDISK minor version + [ES:DI+3] byte MEMDISK major version + [ES:DI+4] dword Pointer to MEMDISK data in high memory + [ES:DI+8] dword Size of MEMDISK data in 512-byte sectors + [ES:DI+12] 16:16 Far pointer to command line + [ES:DI+16] 16:16 Old INT 13h pointer + [ES:DI+20] 16:16 Old INT 15h pointer + [ES:DI+24] word Amount of DOS memory before MEMDISK loaded + [ES:DI+26] byte Boot loader ID + +MEMDISK 3.00 and higher has the size of this structure as 27; earlier +versions had size 26 and did not include the boot loader ID. + +In addition, the following fields are available at [ES:0]: + + [ES:0] word Offset of INT 13h routine (segment == ES) + [ES:2] word Offset of INT 15h routine (segment == ES) + +The program mdiskchk.c in the sample directory is an example on how +this API can be used. + +The following code can be used to "disable" MEMDISK. Note that it +does not free the handler in DOS memory, and that running this from +DOS will probably crash your machine (DOS doesn't like drives +suddenly disappearing from underneath): + + mov eax, 454D0800h + mov ecx, 444D0000h + mov edx, 53490000h + drive # + mov ebx, 3F4B0000h + int 13h + + shr eax, 16 + cmp ax, 4D21h + jne not_memdisk + shr ecx, 16 + cmp cx, 4D45h + jne not_memdisk + shr edx, 16 + cmp dx, 4944h + jne not_memdisk + shr ebx, 16 + cmp bx, 4B53h + jne not_memdisk + + cli + mov bx,[es:0] ; INT 13h handler offset + mov eax,[es:di+16] ; Old INT 13h handler + mov byte [es:bx], 0EAh ; FAR JMP + mov [es:bx+1], eax + + mov bx,[es:2] ; INT 15h handler offset + mov eax,[es:di+20] ; Old INT 15h handler + mov byte [es:bx], 0EAh ; FAR JMP + mov [es:bx+1], eax + sti diff --git a/syslinux/memdisk/memdisk.h b/syslinux/memdisk/memdisk.h new file mode 100644 index 0000000..92e517f --- /dev/null +++ b/syslinux/memdisk/memdisk.h @@ -0,0 +1,74 @@ +#ident "$Id: memdisk.h,v 1.9 2005/03/08 18:39:32 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2001-2003 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * memdisk.h + * + * Miscellaneous header definitions + */ + +#ifndef MEMDISK_H +#define MEMDISK_H + +/* We use the com32 interface for calling 16-bit code */ +#include <com32.h> + +/* The real-mode segment */ +#define LOW_SEG 0x0800 + +typedef void (*syscall_t)(uint8_t, com32sys_t *, com32sys_t *); +extern syscall_t syscall; +extern void *sys_bounce; + +/* What to call when we're dead */ +extern void __attribute__((noreturn)) die(void); + +/* Standard routines */ +#define memcpy(a,b,c) __builtin_memcpy(a,b,c) +#define memset(a,b,c) __builtin_memset(a,b,c) +#define strcpy(a,b) __builtin_strcpy(a,b) +#define strlen(a) __builtin_strlen(a) + +/* memcpy() but returns a pointer to end of buffer */ +static inline void * +memcpy_endptr(void *__d, const void *__s, unsigned int __n) +{ + memcpy(__d, __s, __n); + return (void *)((char *)__d + __n); +} + +/* memcmp() */ +static inline int +memcmp(const void *__a, const void *__b, unsigned int __n) +{ + const unsigned char *__aa = __a; + const unsigned char *__bb = __b; + int __d; + + while ( __n ) { + __d = *__bb++ - *__aa++; + if ( __d ) + return __d; + } + + return 0; +} + +/* Decompression */ +extern int check_zip(void *indata, uint32_t size, uint32_t *zbytes_p, + uint32_t *dbytes_p, uint32_t *orig_crc, + uint32_t *offset_p); +extern void *unzip(void *indata, uint32_t zbytes, uint32_t dbytes, + uint32_t orig_crc, void *target); + +#endif diff --git a/syslinux/memdisk/memdisk16.asm b/syslinux/memdisk/memdisk16.asm new file mode 100644 index 0000000..f3f2d1a --- /dev/null +++ b/syslinux/memdisk/memdisk16.asm @@ -0,0 +1,768 @@ +;; -*- fundamental -*- +;; $Id: memdisk16.asm,v 1.3 2004/12/14 22:46:25 hpa Exp $ +;; ----------------------------------------------------------------------- +;; +;; Copyright 1994-2004 H. Peter Anvin - All Rights Reserved +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +;; Boston MA 02111-1307, USA; either version 2 of the License, or +;; (at your option) any later version; incorporated herein by reference. +;; +;; ----------------------------------------------------------------------- + +;; +;; init16.asm +;; +;; Routine to initialize and to trampoline into 32-bit +;; protected memory. This code is derived from bcopy32.inc and +;; com32.inc in the main SYSLINUX distribution. +;; + +MY_CS equ 0x0800 ; Segment address to use +CS_BASE equ (MY_CS << 4) ; Corresponding address + +; Low memory bounce buffer +BOUNCE_SEG equ (MY_CS+0x1000) + +%define DO_WBINVD 0 + +%define STACK_HEAP_SIZE (128*1024) + + section .rodata align=16 + section .data align=16 + section .bss align=16 + +;; ----------------------------------------------------------------------- +;; Kernel image header +;; ----------------------------------------------------------------------- + + section .text ; Must be first in image + bits 16 + +cmdline times 497 db 0 ; We put the command line here +setup_sects db 0 +root_flags dw 0 +syssize dw 0 +swap_dev dw 0 +ram_size dw 0 +vid_mode dw 0 +root_dev dw 0 +boot_flag dw 0xAA55 + +_start: jmp short start + + db "HdrS" ; Header signature + dw 0x0203 ; Header version number + +realmode_swtch dw 0, 0 ; default_switch, SETUPSEG +start_sys_seg dw 0x1000 ; obsolete +version_ptr dw memdisk_version-0x200 ; version string ptr +type_of_loader db 0 ; Filled in by boot loader +loadflags db 1 ; Please load high +setup_move_size dw 0 ; Unused +code32_start dd 0x100000 ; 32-bit start address +ramdisk_image dd 0 ; Loaded ramdisk image address +ramdisk_size dd 0 ; Size of loaded ramdisk +bootsect_kludge dw 0, 0 +heap_end_ptr dw 0 +pad1 dw 0 +cmd_line_ptr dd 0 ; Command line +ramdisk_max dd 0xffffffff ; Highest allowed ramdisk address + + section .rodata +memdisk_version: + db "MEMDISK ", VERSION, " ", DATE, 0 + +;; ----------------------------------------------------------------------- +;; End kernel image header +;; ----------------------------------------------------------------------- + +; +; Move ourselves down into memory to reduce the risk of conflicts; +; then canonicalize CS to match the other segments. +; + section .text + bits 16 +start: + mov ax,MY_CS + mov es,ax + movzx cx,byte [setup_sects] + inc cx ; Add one for the boot sector + shl cx,7 ; Convert to dwords + xor si,si + xor di,di + mov fs,si ; fs <- 0 + cld + rep movsd + mov ds,ax + mov ss,ax + xor esp,esp ; Stack at top of 64K segment + jmp MY_CS:.next +.next: + +; +; Copy the command line, if there is one +; +copy_cmdline: + xor di,di ; Bottom of our own segment (= "boot sector") + mov eax,[cmd_line_ptr] + and eax,eax + jz .endcmd ; No command line + mov si,ax + shr eax,4 ; Convert to segment + and si,0x000F ; Starting offset only + mov gs,ax + mov cx,496 ; Max number of bytes +.copycmd: + gs lodsb + and al,al + jz .endcmd + stosb + loop .copycmd +.endcmd: + xor al,al + stosb + +; +; Now jump to 32-bit code +; + sti + call init32 +; +; When init32 returns, we have been set up, the new boot sector loaded, +; and we should go and and run the newly loaded boot sector +; +; The setup function returns (in AL) the drive number which should be +; put into DL +; + mov dx,ax + + cli + xor esi,esi ; No partition table involved + mov ds,si ; Make all the segments consistent + mov es,si + mov fs,si + mov gs,si + mov ss,si + mov esp,0x7C00 ; Good place for SP to start out + jmp 0:0x7C00 + +; +; We enter protected mode, set up a flat 32-bit environment, run rep movsd +; and then exit. IMPORTANT: This code assumes cs == MY_CS. +; +; This code is probably excessively anal-retentive in its handling of +; segments, but this stuff is painful enough as it is without having to rely +; on everything happening "as it ought to." +; + section .rodata + + ; desc base, limit, flags +%macro desc 3 + dd (%2 & 0xffff) | ((%1 & 0xffff) << 16) + dd (%1 & 0xff000000) | (%2 & 0xf0000) | ((%3 & 0xf0ff) << 8) | ((%1 & 0x00ff0000) >> 16) +%endmacro + + align 8, db 0 +call32_gdt: dw call32_gdt_size-1 ; Null descriptor - contains GDT +.adj1: dd call32_gdt+CS_BASE ; pointer for LGDT instruction + dw 0 + + ; 0008: Code segment, use16, readable, dpl 0, base CS_BASE, 64K + desc CS_BASE, 0xffff, 0x009b + + ; 0010: Data segment, use16, read/write, dpl 0, base CS_BASE, 64K + desc CS_BASE, 0xffff, 0x0093 + + ; 0018: Data segment, use16, read/write, dpl 0, base 0, 4G + desc 0, 0xfffff, 0x809b + + ; 0020: Code segment, use32, read/write, dpl 0, base 0, 4G + desc 0, 0xfffff, 0xc09b + + ; 0028: Data segment, use32, read/write, dpl 0, base 0, 4G + desc 0, 0xfffff, 0xc093 + +call32_gdt_size: equ $-call32_gdt + +err_a20: db 'ERROR: A20 gate not responding!',13,10,0 + + section .bss + alignb 4 +SavedSSSP resd 1 ; Place to save SS:SP +Return resd 1 ; Return value +A20Test resw 1 ; Space to test A20 +A20Tries resb 1 + + section .data + alignb 4 +Target dd 0 ; Target address +Target_Seg dw 20h ; Target CS + +A20Type dw 0 ; Default = unknown + + section .text + bits 16 +; +; Routines to enable and disable (yuck) A20. These routines are gathered +; from tips from a couple of sources, including the Linux kernel and +; http://www.x86.org/. The need for the delay to be as large as given here +; is indicated by Donnie Barnes of RedHat, the problematic system being an +; IBM ThinkPad 760EL. +; +; We typically toggle A20 twice for every 64K transferred. +; +%define io_delay call _io_delay +%define IO_DELAY_PORT 80h ; Invalid port (we hope!) +%define disable_wait 32 ; How long to wait for a disable + +%define A20_DUNNO 0 ; A20 type unknown +%define A20_NONE 1 ; A20 always on? +%define A20_BIOS 2 ; A20 BIOS enable +%define A20_KBC 3 ; A20 through KBC +%define A20_FAST 4 ; A20 through port 92h + + align 2, db 0 +A20List dw a20_dunno, a20_none, a20_bios, a20_kbc, a20_fast +A20DList dw a20d_dunno, a20d_none, a20d_bios, a20d_kbc, a20d_fast +a20_adjust_cnt equ ($-A20List)/2 + +slow_out: out dx, al ; Fall through + +_io_delay: out IO_DELAY_PORT,al + out IO_DELAY_PORT,al + ret + +enable_a20: + pushad + mov byte [A20Tries],255 ; Times to try to make this work + +try_enable_a20: + +; +; Flush the caches +; +%if DO_WBINVD + call try_wbinvd +%endif + +; +; If the A20 type is known, jump straight to type +; + mov bp,[A20Type] + add bp,bp ; Convert to word offset +.adj4: jmp word [bp+A20List] + +; +; First, see if we are on a system with no A20 gate +; +a20_dunno: +a20_none: + mov byte [A20Type], A20_NONE + call a20_test + jnz a20_done + +; +; Next, try the BIOS (INT 15h AX=2401h) +; +a20_bios: + mov byte [A20Type], A20_BIOS + mov ax,2401h + pushf ; Some BIOSes muck with IF + int 15h + popf + + call a20_test + jnz a20_done + +; +; Enable the keyboard controller A20 gate +; +a20_kbc: + mov dl, 1 ; Allow early exit + call empty_8042 + jnz a20_done ; A20 live, no need to use KBC + + mov byte [A20Type], A20_KBC ; Starting KBC command sequence + + mov al,0D1h ; Command write + out 064h, al + call empty_8042_uncond + + mov al,0DFh ; A20 on + out 060h, al + call empty_8042_uncond + + ; Verify that A20 actually is enabled. Do that by + ; observing a word in low memory and the same word in + ; the HMA until they are no longer coherent. Note that + ; we don't do the same check in the disable case, because + ; we don't want to *require* A20 masking (SYSLINUX should + ; work fine without it, if the BIOS does.) +.kbc_wait: push cx + xor cx,cx +.kbc_wait_loop: + call a20_test + jnz a20_done_pop + loop .kbc_wait_loop + + pop cx +; +; Running out of options here. Final attempt: enable the "fast A20 gate" +; +a20_fast: + mov byte [A20Type], A20_FAST ; Haven't used the KBC yet + in al, 092h + or al,02h + and al,~01h ; Don't accidentally reset the machine! + out 092h, al + +.fast_wait: push cx + xor cx,cx +.fast_wait_loop: + call a20_test + jnz a20_done_pop + loop .fast_wait_loop + + pop cx + +; +; Oh bugger. A20 is not responding. Try frobbing it again; eventually give up +; and report failure to the user. +; + + dec byte [A20Tries] + jnz try_enable_a20 + + + ; Error message time + mov si,err_a20 +print_err: + lodsb + and al,al + jz die + mov bx,7 + mov ah,0xe + int 10h + jmp print_err + + +die: + sti +.hlt: hlt + jmp short .hlt + +; +; A20 unmasked, proceed... +; +a20_done_pop: pop cx +a20_done: popad + ret + +; +; This routine tests if A20 is enabled (ZF = 0). This routine +; must not destroy any register contents. +; +a20_test: + push es + push cx + push ax + mov cx,0FFFFh ; HMA = segment 0FFFFh + mov es,cx + mov cx,32 ; Loop count + mov ax,[A20Test] +.a20_wait: inc ax + mov [A20Test],ax + io_delay ; Serialize, and fix delay + cmp ax,[es:A20Test+CS_BASE+10h] + loopz .a20_wait +.a20_done: pop ax + pop cx + pop es + ret + +disable_a20: + pushad +; +; Flush the caches +; +%if DO_WBINVD + call try_wbinvd +%endif + + mov bp,[A20Type] + add bp,bp ; Convert to word offset +.adj5: jmp word [bp+A20DList] + +a20d_bios: + mov ax,2400h + pushf ; Some BIOSes muck with IF + int 15h + popf + jmp short a20d_snooze + +; +; Disable the "fast A20 gate" +; +a20d_fast: + in al, 092h + and al,~03h + out 092h, al + jmp short a20d_snooze + +; +; Disable the keyboard controller A20 gate +; +a20d_kbc: + call empty_8042_uncond + mov al,0D1h + out 064h, al ; Command write + call empty_8042_uncond + mov al,0DDh ; A20 off + out 060h, al + call empty_8042_uncond + ; Wait a bit for it to take effect +a20d_snooze: + push cx + mov cx, disable_wait +.delayloop: call a20_test + jz .disabled + loop .delayloop +.disabled: pop cx +a20d_dunno: +a20d_none: + popad + ret + +; +; Routine to empty the 8042 KBC controller. If dl != 0 +; then we will test A20 in the loop and exit if A20 is +; suddenly enabled. +; +empty_8042_uncond: + xor dl,dl +empty_8042: + call a20_test + jz .a20_on + and dl,dl + jnz .done +.a20_on: io_delay + in al, 064h ; Status port + test al,1 + jz .no_output + io_delay + in al, 060h ; Read input + jmp short empty_8042 +.no_output: + test al,2 + jnz empty_8042 + io_delay +.done: ret + +; +; Execute a WBINVD instruction if possible on this CPU +; +%if DO_WBINVD +try_wbinvd: + wbinvd + ret +%endif + + section .bss + alignb 4 +PMESP resd 1 ; Protected mode %esp + + section .idt nobits align=4096 + alignb 4096 +pm_idt resb 4096 ; Protected-mode IDT, followed by interrupt stubs + + + + +pm_entry: equ 0x100000 + + section .rodata + align 4, db 0 +call32_pmidt: + dw 8*256 ; Limit + dd pm_idt+CS_BASE ; Address + +call32_rmidt: + dw 0ffffh ; Limit + dd 0 ; Address + + section .text +; +; This is the main entrypoint in this function +; +init32: + mov ebx,call32_call_start+CS_BASE ; Where to go in PM + +call32_enter_pm: + mov ax,cs + mov ds,ax + cli + mov [SavedSSSP],sp + mov [SavedSSSP+2],ss + cld + call a20_test + jnz .a20ok + call enable_a20 + +.a20ok: + lgdt [call32_gdt] ; Set up GDT + lidt [call32_pmidt] ; Set up the IDT + mov eax,cr0 + or al,1 + mov cr0,eax ; Enter protected mode + jmp 20h:dword .in_pm+CS_BASE + + bits 32 +.in_pm: + xor eax,eax ; Available for future use... + mov fs,eax + mov gs,eax + + mov al,28h ; Set up data segments + mov es,eax + mov ds,eax + mov ss,eax + + mov esp,[PMESP+CS_BASE] ; Load protmode %esp if available + jmp ebx ; Go to where we need to go + +; +; This is invoked before first dispatch of the 32-bit code, in 32-bit mode +; +call32_call_start: + ; + ; Point the stack into low memory + ; We have: this segment, bounce buffer, then stack+heap + ; + mov esp, CS_BASE + 0x20000 + STACK_HEAP_SIZE + and esp, ~0xf + + ; + ; Set up the protmode IDT and the interrupt jump buffers + ; + mov edi,pm_idt+CS_BASE + + ; Form an interrupt gate descriptor + ; WARNING: This is broken if pm_idt crosses a 64K boundary; + ; however, it can't because of the alignment constraints. + mov ebx,pm_idt+CS_BASE+8*256 + mov eax,0x0020ee00 + xchg ax,bx + xor ecx,ecx + inc ch ; ecx <- 256 + + push ecx +.make_idt: + stosd + add eax,8 + xchg eax,ebx + stosd + xchg eax,ebx + loop .make_idt + + pop ecx + + ; Each entry in the interrupt jump buffer contains + ; the following instructions: + ; + ; 00000000 60 pushad + ; 00000001 B0xx mov al,<interrupt#> + ; 00000003 E9xxxxxxxx jmp call32_handle_interrupt + + mov eax,0xe900b060 + mov ebx,call32_handle_interrupt+CS_BASE + sub ebx,edi + +.make_ijb: + stosd + sub [edi-2],cl ; Interrupt # + xchg eax,ebx + sub eax,8 + stosd + xchg eax,ebx + loop .make_ijb + + ; Now everything is set up for interrupts... + + push dword (BOUNCE_SEG << 4) ; Bounce buffer address + push dword call32_syscall+CS_BASE ; Syscall entry point + sti ; Interrupts OK now + call pm_entry-CS_BASE ; Run the program... + + ; ... on return ... + mov [Return+CS_BASE],eax + + ; ... fall through to call32_exit ... + +call32_exit: + mov bx,call32_done ; Return to command loop + +call32_enter_rm: + cli + cld + mov [PMESP+CS_BASE],esp ; Save exit %esp + xor esp,esp ; Make sure the high bits are zero + jmp 08h:.in_pm16 ; Return to 16-bit mode first + + bits 16 +.in_pm16: + mov ax,10h ; Real-mode-like segment + mov es,ax + mov ds,ax + mov ss,ax + mov fs,ax + mov gs,ax + + lidt [call32_rmidt] ; Real-mode IDT (rm needs no GDT) + mov eax,cr0 + and al,~1 + mov cr0,eax + jmp MY_CS:.in_rm + +.in_rm: ; Back in real mode + mov ax,cs ; Set up sane segments + mov ds,ax + mov es,ax + mov fs,ax + mov gs,ax + lss sp,[SavedSSSP] ; Restore stack + jmp bx ; Go to whereever we need to go... + +call32_done: + call disable_a20 + sti + mov ax,[Return] + ret + +; +; 16-bit support code +; + bits 16 + +; +; 16-bit interrupt-handling code +; +call32_int_rm: + pushf ; Flags on stack + push cs ; Return segment + push word .cont ; Return address + push dword edx ; Segment:offset of IVT entry + retf ; Invoke IVT routine +.cont: ; ... on resume ... + mov ebx,call32_int_resume+CS_BASE + jmp call32_enter_pm ; Go back to PM + +; +; 16-bit system call handling code +; +call32_sys_rm: + pop gs + pop fs + pop es + pop ds + popad + popfd + retf ; Invoke routine +.return: + pushfd + pushad + push ds + push es + push fs + push gs + mov ebx,call32_sys_resume+CS_BASE + jmp call32_enter_pm + +; +; 32-bit support code +; + bits 32 + +; +; This is invoked on getting an interrupt in protected mode. At +; this point, we need to context-switch to real mode and invoke +; the interrupt routine. +; +; When this gets invoked, the registers are saved on the stack and +; AL contains the register number. +; +call32_handle_interrupt: + movzx eax,al + xor ebx,ebx ; Actually makes the code smaller + mov edx,[ebx+eax*4] ; Get the segment:offset of the routine + mov bx,call32_int_rm + jmp call32_enter_rm ; Go to real mode + +call32_int_resume: + popad + iret + +; +; Syscall invocation. We manifest a structure on the real-mode stack, +; containing the call32sys_t structure from <call32.h> as well as +; the following entries (from low to high address): +; - Target offset +; - Target segment +; - Return offset +; - Return segment (== real mode cs) +; - Return flags +; +call32_syscall: + pushfd ; Save IF among other things... + pushad ; We only need to save some, but... + cld + + movzx edi,word [SavedSSSP+CS_BASE] + movzx eax,word [SavedSSSP+CS_BASE+2] + sub edi,54 ; Allocate 54 bytes + mov [SavedSSSP+CS_BASE],di + shl eax,4 + add edi,eax ; Create linear address + + mov esi,[esp+11*4] ; Source regs + xor ecx,ecx + mov cl,11 ; 44 bytes to copy + rep movsd + + movzx eax,byte [esp+10*4] ; Interrupt number + ; ecx == 0 here; adding it to the EA makes the + ; encoding smaller + mov eax,[ecx+eax*4] ; Get IVT entry + stosd ; Save in stack frame + mov eax,call32_sys_rm.return + (MY_CS << 16) ; Return seg:offs + stosd ; Save in stack frame + mov eax,[edi-12] ; Return flags + and eax,0x200cd7 ; Mask (potentially) unsafe flags + mov [edi-12],eax ; Primary flags entry + stosw ; Return flags + + mov bx,call32_sys_rm + jmp call32_enter_rm ; Go to real mode + + ; On return, the 44-byte return structure is on the + ; real-mode stack. +call32_sys_resume: + movzx esi,word [SavedSSSP+CS_BASE] + movzx eax,word [SavedSSSP+CS_BASE+2] + mov edi,[esp+12*4] ; Dest regs + shl eax,4 + add esi,eax ; Create linear address + and edi,edi ; NULL pointer? + jnz .do_copy +.no_copy: mov edi,esi ; Do a dummy copy-to-self +.do_copy: xor ecx,ecx + mov cl,11 ; 44 bytes + rep movsd ; Copy register block + + add dword [SavedSSSP+CS_BASE],44 ; Remove from stack + + popad + popfd + ret ; Return to 32-bit program diff --git a/syslinux/memdisk/memset.S b/syslinux/memdisk/memset.S new file mode 100644 index 0000000..15b6499 --- /dev/null +++ b/syslinux/memdisk/memset.S @@ -0,0 +1,30 @@ +# $Id: memset.S,v 1.1 2003/04/14 22:28:30 hpa Exp $ +# +# memset.S +# +# Simple memset() implementation +# + + .text + .globl memset + .type memset, @function +memset: + cld + pushl %edi + pushl %esi + movl 12(%esp),%edi + movzbl 16(%esp),%eax + movl 20(%esp),%esi + imull $0x01010101,%eax + movl %esi,%ecx + shrl $2,%ecx + rep ; stosl + movl %esi,%ecx + andl $3,%ecx + rep ; stosb + movl 12(%esp),%eax + popl %esi + popl %edi + ret + + .size memcpy,.-memcpy diff --git a/syslinux/memdisk/msetup.c b/syslinux/memdisk/msetup.c new file mode 100644 index 0000000..1af2e4e --- /dev/null +++ b/syslinux/memdisk/msetup.c @@ -0,0 +1,169 @@ +#ident "$Id: msetup.c,v 1.12 2004/12/14 22:46:25 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2001-2003 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * msetup.c + * + * Initialization code for memory-based disk + */ + +#include <stdint.h> +#include "memdisk.h" +#include "conio.h" +#include "e820.h" + +static inline int get_e820(void) +{ + struct e820_info { + uint64_t base; + uint64_t len; + uint32_t type; + } *buf = sys_bounce; + uint32_t copied; + int range_count = 0; + com32sys_t regs; + + memset(®s, 0, sizeof regs); + + do { + regs.eax.l = 0x0000e820; + regs.ecx.l = sizeof(*buf); + regs.edx.l = 0x534d4150; + regs.edi.w[0] = OFFS(buf); + regs.es = SEG(buf); + + syscall(0x15, ®s, ®s); + copied = (regs.eflags.l & 1) ? 0 : regs.ecx.l; + + if ( regs.eax.l != 0x534d4150 || copied < 20 ) + break; + + printf("e820: %08x%08x %08x%08x %d\n", + (uint32_t)(buf->base >> 32), (uint32_t)buf->base, + (uint32_t)(buf->len >> 32), (uint32_t)buf->len, + buf->type); + + insertrange(buf->base, buf->len, buf->type); + range_count++; + + } while ( regs.ebx.l ); + + return !range_count; +} + +static inline void get_dos_mem(void) +{ + com32sys_t regs; + + memset(®s, 0, sizeof regs); + syscall(0x12, ®s, ®s); + insertrange(0, (uint64_t)((uint32_t)regs.eax.w[0] << 10), 1); + printf(" DOS: %d K\n", regs.eax.w[0]); +} + +static inline int get_e801(void) +{ + int err; + com32sys_t regs; + + memset(®s, 0, sizeof regs); + + regs.eax.w[0] = 0xe801; + syscall(0x15, ®s, ®s); + + if ( !(err = regs.eflags.l & 1) ) { + if ( regs.eax.w[0] ) { + insertrange(0x100000, (uint64_t)((uint32_t)regs.eax.w[0] << 10), 1); + } + if ( regs.ebx.w[0] ) { + insertrange(0x1000000, (uint64_t)((uint32_t)regs.ebx.w[0] << 16), 1); + } + + printf("e801: %04x %04x\n", regs.eax.w[0], regs.ebx.w[0]); + } + + return err; +} + +static inline int get_88(void) +{ + com32sys_t regs; + int err; + + memset(®s, 0, sizeof regs); + + regs.eax.b[1] = 0x88; + syscall(0x15, ®s, ®s); + + + if ( !(err = regs.eflags.l & 1) ) { + if ( regs.eax.w[0] ) { + insertrange(0x100000, (uint64_t)((uint32_t)regs.eax.w[0] << 10), 1); + } + + printf(" 88: %04x\n", regs.eax.w[0]); + } + + return err; +} + +uint32_t dos_mem = 0; /* 0-1MB */ +uint32_t low_mem = 0; /* 1-16MB */ +uint32_t high_mem = 0; /* 16+ MB */ + +void get_mem(void) +{ + if ( get_e820() ) { + get_dos_mem(); + if ( get_e801() ) { + if ( get_88() ) { + puts("MEMDISK: Unable to obtain memory map\n"); + die(); + } + } + } +} + +#define PW(x) (1ULL << (x)) + +void parse_mem(void) +{ + struct e820range *ep; + + dos_mem = low_mem = high_mem = 0; + + /* Derive "dos mem", "high mem", and "low mem" from the range array */ + for ( ep = ranges ; ep->type != -1 ; ep++ ) { + if ( ep->type == 1 ) { + /* Only look at memory ranges */ + if ( ep->start == 0 ) { + if ( ep[1].start > PW(20) ) + dos_mem = PW(20); + else + dos_mem = ep[1].start; + } + if ( ep->start <= PW(20) && ep[1].start > PW(20) ) { + if ( ep[1].start > PW(24) ) + low_mem = PW(24) - PW(20); + else + low_mem = ep[1].start - PW(20); + } + if ( ep->start <= PW(24) && ep[1].start > PW(24) ) { + if ( ep[1].start > PW(32) ) + high_mem = PW(32) - PW(24); + else + high_mem = ep[1].start - PW(24); + } + } + } +} diff --git a/syslinux/memdisk/postprocess.pl b/syslinux/memdisk/postprocess.pl new file mode 100755 index 0000000..32e7640 --- /dev/null +++ b/syslinux/memdisk/postprocess.pl @@ -0,0 +1,58 @@ +#!/usr/bin/perl +## ----------------------------------------------------------------------- +## +## Copyright 2001 H. Peter Anvin - All Rights Reserved +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, Inc., 53 Temple Place Ste 330, +## Boston MA 02111-1307, USA; either version 2 of the License, or +## (at your option) any later version; incorporated herein by reference. +## +## ----------------------------------------------------------------------- +## $Id: postprocess.pl,v 1.4 2004/12/14 22:46:25 hpa Exp $ + +# +# Postprocess the memdisk binary. +# + +eval { use bytes; }; + +($out,$file16,$file32) = @ARGV; + +open(OUT, "> $out\0") or die "$0: Cannot create file: $out\n"; +eval { binmode OUT; }; +open(FILE, "< $file16\0") or die "$0: Cannot open file: $file16\n"; +eval { binmode FILE }; + +@info = stat(FILE); +$size = $info[7]; + +$sectors = ($size + 511) >> 9; +$xsize = $sectors << 9; + +read(FILE, $f16, $size); + +print OUT $f16; + +if ( $size != $xsize ) { + # Pad to a sector boundary + print OUT "\0" x ($xsize-$size); +} + +seek(OUT, 0x1f1, SEEK_SET); # setup_sects +# All sectors are setup except the first +print OUT pack("C", $sectors-1); + +seek(OUT, $xsize, SEEK_SET); +close(FILE); + +open(FILE, "+< $file32\0") or die "$0: Cannot open file: $file32\n"; + +while ( ($n = read(FILE, $f32, 65536)) > 0 ) { + print OUT $f32; +} + +close(FILE); +close(OUT); + diff --git a/syslinux/memdisk/setup.c b/syslinux/memdisk/setup.c new file mode 100644 index 0000000..0fe649b --- /dev/null +++ b/syslinux/memdisk/setup.c @@ -0,0 +1,761 @@ +#ident "$Id: setup.c,v 1.50 2005/04/29 06:04:45 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2001-2004 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#include <stdint.h> +#include "e820.h" +#include "conio.h" +#include "version.h" +#include "memdisk.h" + +const char memdisk_version[] = +"MEMDISK " VERSION " " DATE; +const char copyright[] = +"Copyright " FIRSTYEAR "-" COPYYEAR " H. Peter Anvin"; + +extern const char _binary_memdisk_bin_start[], _binary_memdisk_bin_end[]; +extern const char _binary_memdisk_bin_size[]; /* Weird, I know */ + +struct memdisk_header { + uint16_t int13_offs; + uint16_t int15_offs; + uint16_t patch_offs; + uint16_t total_size; +}; + +/* The Disk Parameter Table may be required */ +typedef union { + struct hd_dpt { + uint16_t max_cyl; /* Max cylinder */ + uint8_t max_head; /* Max head */ + uint8_t junk1[5]; /* Obsolete junk, leave at zero */ + uint8_t ctrl; /* Control byte */ + uint8_t junk2[7]; /* More obsolete junk */ + } hd; + struct fd_dpt { + uint8_t specify1; /* "First specify byte" */ + uint8_t specify2; /* "Second specify byte" */ + uint8_t delay; /* Delay until motor turn off */ + uint8_t sectors; /* Sectors/track */ + + uint8_t bps; /* Bytes/sector (02h = 512) */ + uint8_t isgap; /* Length of intersector gap */ + uint8_t dlen; /* Data length (0FFh) */ + uint8_t fgap; /* Formatting gap */ + + uint8_t ffill; /* Format fill byte */ + uint8_t settle; /* Head settle time (ms) */ + uint8_t mstart; /* Motor start time */ + uint8_t _pad1; /* Padding */ + + uint32_t old_fd_dpt; /* Extension: pointer to old INT 1Eh */ + } fd; +} dpt_t; + +struct patch_area { + uint32_t diskbuf; + uint32_t disksize; + uint16_t cmdline_off, cmdline_seg; + + uint32_t oldint13; + uint32_t oldint15; + + uint16_t olddosmem; + uint8_t bootloaderid; + + uint8_t _pad[3]; + uint16_t memint1588; + + uint16_t cylinders; + uint16_t heads; + uint32_t sectors; + + uint32_t mem1mb; + uint32_t mem16mb; + + uint8_t driveno; + uint8_t drivetype; + uint8_t drivecnt; + uint8_t configflags; +#define CONFIG_READONLY 0x01 +#define CONFIG_RAW 0x02 +#define CONFIG_BIGRAW 0x08 /* MUST be 8! */ + + uint16_t mystack; + uint16_t statusptr; + + dpt_t dpt; +}; + +/* This is the header in the boot sector/setup area */ +struct setup_header { + char cmdline[0x1f1]; + uint8_t setup_secs; + uint16_t syssize; + uint16_t swap_dev; + uint16_t ram_size; + uint16_t vid_mode; + uint16_t root_dev; + uint16_t boot_flag; + uint16_t jump; + char header[4]; + uint16_t version; + uint32_t realmode_swtch; + uint32_t start_sys; + uint8_t type_of_loader; + uint8_t loadflags; + uint16_t setup_move_size; + uint32_t code32_start; + uint32_t ramdisk_image; + uint32_t ramdisk_size; + uint32_t bootsect_kludge; + uint16_t head_end_ptr; + uint16_t pad1; + uint32_t cmd_line_ptr; + uint32_t initrd_addr_max; +}; + +const struct setup_header * const shdr = (struct setup_header *)(LOW_SEG << 4); + +/* Access to high memory */ + +/* Access to objects in the zero page */ +static inline void +wrz_8(uint32_t addr, uint8_t data) +{ + *((uint8_t *)addr) = data; +} +static inline void +wrz_16(uint32_t addr, uint16_t data) +{ + *((uint16_t *)addr) = data; +} +static inline void +wrz_32(uint32_t addr, uint32_t data) +{ + *((uint32_t *)addr) = data; +} +static inline uint8_t +rdz_8(uint32_t addr) +{ + return *((uint8_t *)addr); +} +static inline uint16_t +rdz_16(uint32_t addr) +{ + return *((uint16_t *)addr); +} +static inline uint32_t +rdz_32(uint32_t addr) +{ + return *((uint32_t *)addr); +} + +/* Addresses in the zero page */ +#define BIOS_INT13 (0x13*4) /* INT 13h vector */ +#define BIOS_INT15 (0x15*4) /* INT 15h vector */ +#define BIOS_INT1E (0x1E*4) /* INT 1Eh vector */ +#define BIOS_INT40 (0x40*4) /* INT 13h vector */ +#define BIOS_INT41 (0x41*4) /* INT 41h vector */ +#define BIOS_INT46 (0x46*4) /* INT 46h vector */ +#define BIOS_BASEMEM 0x413 /* Amount of DOS memory */ +#define BIOS_EQUIP 0x410 /* BIOS equipment list */ +#define BIOS_HD_COUNT 0x475 /* Number of hard drives present */ + +/* + * Routine to seek for a command-line item and return a pointer + * to the data portion, if present + */ + +/* Magic return values */ +#define CMD_NOTFOUND ((char *)-1) /* Not found */ +#define CMD_BOOL ((char *)-2) /* Found boolean option */ +#define CMD_HASDATA(X) ((int)(X) >= 0) + +const char *getcmditem(const char *what) +{ + const char *p; + const char *wp = what; + int match = 0; + + for ( p = shdr->cmdline ; *p ; p++ ) { + switch ( match ) { + case 0: /* Ground state */ + if ( *p == ' ' ) + break; + + wp = what; + match = 1; + /* Fall through */ + + case 1: /* Matching */ + if ( *wp == '\0' ) { + if ( *p == '=' ) + return p+1; + else if ( *p == ' ' ) + return CMD_BOOL; + else { + match = 2; + break; + } + } + if ( *p != *wp++ ) + match = 2; + break; + + case 2: /* Mismatch, skip rest of option */ + if ( *p == ' ' ) + match = 0; /* Next option */ + break; + } + } + + /* Check for matching string at end of line */ + if ( match == 1 && *wp == '\0' ) + return CMD_BOOL; + + return CMD_NOTFOUND; +} + +/* + * Check to see if this is a gzip image + */ +#define UNZIP_ALIGN 512 + +extern void _end; /* Symbol signalling end of data */ + +void unzip_if_needed(uint32_t *where_p, uint32_t *size_p) +{ + uint32_t where = *where_p; + uint32_t size = *size_p; + uint32_t zbytes; + uint32_t startrange, endrange; + uint32_t gzdatasize, gzwhere; + uint32_t orig_crc, offset; + uint32_t target = 0; + int i, okmem; + + /* Is it a gzip image? */ + if (check_zip ((void *)where, size, &zbytes, &gzdatasize, + &orig_crc, &offset) == 0) { + + if (offset + zbytes > size) { + /* Assertion failure; check_zip is supposed to guarantee this + never happens. */ + puts("internal error: check_zip returned nonsense\n"); + die(); + } + + /* Find a good place to put it: search memory ranges in descending order + until we find one that is legal and fits */ + okmem = 0; + for ( i = nranges-1 ; i >= 0 ; i-- ) { + /* We can't use > 4G memory (32 bits only.) Truncate to 2^32-1 + so we don't have to deal with funny wraparound issues. */ + + /* Must be memory */ + if ( ranges[i].type != 1 ) + continue; + + /* Range start */ + if ( ranges[i].start >= 0xFFFFFFFF ) + continue; + startrange = (uint32_t)ranges[i].start; + + /* Range end (0 for end means 2^64) */ + endrange = ((ranges[i+1].start >= 0xFFFFFFFF || + ranges[i+1].start == 0) + ? 0xFFFFFFFF : (uint32_t)ranges[i+1].start); + + /* Make sure we don't overwrite ourselves */ + if ( startrange < (uint32_t)&_end ) + startrange = (uint32_t)&_end; + + /* Allow for alignment */ + startrange = (ranges[i].start + (UNZIP_ALIGN-1)) & ~(UNZIP_ALIGN-1); + + /* In case we just killed the whole range... */ + if ( startrange >= endrange ) + continue; + + /* Must be large enough... don't rely on gzwhere for this (wraparound) */ + if ( endrange-startrange < gzdatasize ) + continue; + + /* This is where the gz image should be put if we put it in this range */ + gzwhere = (endrange - gzdatasize) & ~(UNZIP_ALIGN-1); + + /* Cast to uint64_t just in case we're flush with the top byte */ + if ( (uint64_t)where+size >= gzwhere && where < endrange ) { + /* Need to move source data to avoid compressed/uncompressed overlap */ + uint32_t newwhere; + + if ( gzwhere-startrange < size ) + continue; /* Can't fit both old and new */ + + newwhere = (gzwhere - size) & ~(UNZIP_ALIGN-1); + printf("Moving compressed data from 0x%08x to 0x%08x\n", + where, newwhere); + + /* Our memcpy() is OK, because we always move from a higher + address to a lower one */ + memcpy((void *)newwhere, (void *)where, size); + where = newwhere; + } + + target = gzwhere; + okmem = 1; + break; + } + + if ( !okmem ) { + printf("Not enough memory to decompress image (need 0x%08x bytes)\n", + gzdatasize); + die(); + } + + printf("gzip image: decompressed addr 0x%08x, len 0x%08x: ", + target, gzdatasize); + + *size_p = gzdatasize; + *where_p = (uint32_t)unzip((void *)(where + offset), zbytes, + gzdatasize, orig_crc, (void *)target); + } +} + +/* + * Figure out the "geometry" of the disk in question + */ +struct geometry { + uint32_t sectors; /* 512-byte sector count */ + uint32_t c, h, s; /* C/H/S geometry */ + uint32_t offset; /* Byte offset for disk */ + uint8_t type; /* Type byte for INT 13h AH=08h */ + uint8_t driveno; /* Drive no */ +}; + +static const struct geometry geometries[] = +{ + { 360*2, 40, 2, 9, 0, 0x01, 0 }, /* 360 K */ + { 720*2, 80, 2, 9, 0, 0x03, 0 }, /* 720 K*/ + { 1200*2, 80, 2, 15, 0, 0x02, 0 }, /* 1200 K */ + { 1440*2, 80, 2, 18, 0, 0x04, 0 }, /* 1440 K */ + { 1680*2, 80, 2, 21, 0, 0x04, 0 }, /* 1680 K */ + { 1722*2, 82, 2, 21, 0, 0x04, 0 }, /* 1722 K */ + { 2880*2, 80, 2, 36, 0, 0x06, 0 }, /* 2880 K */ + { 3840*2, 80, 2, 48, 0, 0x06, 0 }, /* 3840 K */ +}; +#define known_geometries (sizeof(geometries)/sizeof(struct geometry)) + +/* Format of a DOS partition table entry */ +struct ptab_entry { + uint8_t active; + uint8_t start_h, start_s, start_c; + uint8_t type; + uint8_t end_h, end_s, end_c; + uint32_t start; + uint32_t size; +}; + +/* Format of a DOSEMU header */ +struct dosemu_header { + uint8_t magic[7]; /* DOSEMU\0 */ + uint32_t h; + uint32_t s; + uint32_t c; + uint32_t offset; + uint8_t pad[105]; +} __attribute__((packed)); + +#define FOUR(a,b,c,d) (((a) << 24)|((b) << 16)|((c) << 8)|(d)) + +const struct geometry *get_disk_image_geometry(uint32_t where, uint32_t size) +{ + static struct geometry hd_geometry = { 0, 0, 0, 0, 0, 0, 0x80 }; + struct ptab_entry ptab[4]; /* Partition table buffer */ + struct dosemu_header dosemu; + unsigned int sectors, v; + unsigned int max_c, max_h, max_s; + unsigned int c, h, s, offset; + int i; + int drive_specified; + const char *p; + + printf("command line: %s\n", shdr->cmdline); + + offset = 0; + if ( CMD_HASDATA(p = getcmditem("offset")) && (v = atou(p)) ) + offset = v; + + sectors = (size-offset) >> 9; + for ( i = 0 ; i < known_geometries ; i++ ) { + if ( sectors == geometries[i].sectors ) { + hd_geometry = geometries[i]; + break; + } + } + + hd_geometry.sectors = sectors; + hd_geometry.offset = offset; + + /* Do we have a DOSEMU header? */ + memcpy(&dosemu, (char *)where+hd_geometry.offset, sizeof dosemu); + if ( !memcmp("DOSEMU", dosemu.magic, 7) ) { + /* Always a hard disk unless overruled by command-line options */ + hd_geometry.driveno = 0x80; + hd_geometry.type = 0; + hd_geometry.c = dosemu.c; + hd_geometry.h = dosemu.h; + hd_geometry.s = dosemu.s; + hd_geometry.offset += dosemu.offset; + sectors = (size-hd_geometry.offset) >> 9; + } + + if ( CMD_HASDATA(p = getcmditem("c")) && (v = atou(p)) ) + hd_geometry.c = v; + if ( CMD_HASDATA(p = getcmditem("h")) && (v = atou(p)) ) + hd_geometry.h = v; + if ( CMD_HASDATA(p = getcmditem("s")) && (v = atou(p)) ) + hd_geometry.s = v; + + if ( getcmditem("floppy") != CMD_NOTFOUND ) { + hd_geometry.driveno = 0; + if ( hd_geometry.type == 0 ) + hd_geometry.type = 0x10; /* ATAPI floppy, e.g. LS-120 */ + drive_specified = 1; + } else if ( getcmditem("harddisk") != CMD_NOTFOUND ) { + hd_geometry.driveno = 0x80; + hd_geometry.type = 0; + drive_specified = 1; + } + + if ( (hd_geometry.c == 0) || (hd_geometry.h == 0) || + (hd_geometry.s == 0) ) { + /* Hard disk image, need to examine the partition table for geometry */ + memcpy(&ptab, (char *)where+hd_geometry.offset+(512-2-4*16), sizeof ptab); + + max_c = max_h = 0; max_s = 1; + for ( i = 0 ; i < 4 ; i++ ) { + if ( ptab[i].type ) { + c = ptab[i].start_c + (ptab[i].start_s >> 6); + s = (ptab[i].start_s & 0x3f); + h = ptab[i].start_h; + + if ( max_c < c ) max_c = c; + if ( max_h < h ) max_h = h; + if ( max_s < s ) max_s = s; + + c = ptab[i].end_c + (ptab[i].end_s >> 6); + s = (ptab[i].end_s & 0x3f); + h = ptab[i].end_h; + + if ( max_c < c ) max_c = c; + if ( max_h < h ) max_h = h; + if ( max_s < s ) max_s = s; + } + } + + max_c++; max_h++; /* Convert to count (1-based) */ + + if ( !hd_geometry.h ) + hd_geometry.h = max_h; + if ( !hd_geometry.s ) + hd_geometry.s = max_s; + if ( !hd_geometry.c ) + hd_geometry.c = sectors/(hd_geometry.h*hd_geometry.s); + } + + if ( (size-hd_geometry.offset) & 0x1ff ) { + puts("MEMDISK: Image has fractional end sector\n"); + } + if ( sectors % (hd_geometry.h*hd_geometry.s) ) { + puts("MEMDISK: Image seems to have fractional end cylinder\n"); + } + if ( (hd_geometry.c*hd_geometry.h*hd_geometry.s) > sectors ) { + puts("MEMDISK: Image appears to be truncated\n"); + } + + return &hd_geometry; +} + +/* + * Jump here if all hope is gone... + */ +void __attribute__((noreturn)) die(void) +{ + asm volatile("sti"); + for(;;) + asm volatile("hlt"); +} + +#define STACK_NEEDED 512 /* Number of bytes of stack */ + +/* + * Actual setup routine + * Returns the drive number (which is then passed in %dl to the + * called routine.) + */ +syscall_t syscall; +void *sys_bounce; + +uint32_t setup(syscall_t cs_syscall, void *cs_bounce) +{ + unsigned int bin_size = (int) &_binary_memdisk_bin_size; + struct memdisk_header *hptr; + struct patch_area *pptr; + uint16_t driverseg; + uint32_t driverptr, driveraddr; + uint16_t dosmem_k; + uint32_t stddosmem; + const struct geometry *geometry; + int total_size, cmdlinelen; + com32sys_t regs; + uint32_t ramdisk_image, ramdisk_size; + + /* Set up global variables */ + syscall = cs_syscall; + sys_bounce = cs_bounce; + + /* Show signs of life */ + printf("%s %s\n", memdisk_version, copyright); + + if ( !shdr->ramdisk_image || !shdr->ramdisk_size ) { + puts("MEMDISK: No ramdisk image specified!\n"); + die(); + } + + ramdisk_image = shdr->ramdisk_image; + ramdisk_size = shdr->ramdisk_size; + + e820map_init(); /* Initialize memory data structure */ + get_mem(); /* Query BIOS for memory map */ + parse_mem(); /* Parse memory map */ + + printf("Ramdisk at 0x%08x, length 0x%08x\n", + ramdisk_image, ramdisk_size); + + unzip_if_needed(&ramdisk_image, &ramdisk_size); + + geometry = get_disk_image_geometry(ramdisk_image, ramdisk_size); + + printf("Disk is %s, %u K, C/H/S = %u/%u/%u\n", + geometry->driveno ? "hard disk" : "floppy", + geometry->sectors >> 1, + geometry->c, geometry->h, geometry->s); + + /* Reserve the ramdisk memory */ + insertrange(ramdisk_image, ramdisk_size, 2); + parse_mem(); /* Recompute variables */ + + /* Figure out where it needs to go */ + hptr = (struct memdisk_header *) &_binary_memdisk_bin_start; + pptr = (struct patch_area *)(_binary_memdisk_bin_start + hptr->patch_offs); + + dosmem_k = rdz_16(BIOS_BASEMEM); + pptr->olddosmem = dosmem_k; + stddosmem = dosmem_k << 10; + /* If INT 15 E820 and INT 12 disagree, go with the most conservative */ + if ( stddosmem > dos_mem ) + stddosmem = dos_mem; + + pptr->driveno = geometry->driveno; + pptr->drivetype = geometry->type; + pptr->cylinders = geometry->c; + pptr->heads = geometry->h; + pptr->sectors = geometry->s; + pptr->disksize = geometry->sectors; + pptr->diskbuf = ramdisk_image + geometry->offset; + pptr->statusptr = (geometry->driveno & 0x80) ? 0x474 : 0x441; + + pptr->bootloaderid = shdr->type_of_loader; + + pptr->configflags = 0; + /* Set config flags */ + if ( getcmditem("ro") != CMD_NOTFOUND ) { + puts("Marking disk readonly\n"); + pptr->configflags |= CONFIG_READONLY; + } + if ( getcmditem("raw") != CMD_NOTFOUND ) { + puts("Using raw access to high memory\n"); + pptr->configflags |= CONFIG_RAW; + } + if ( getcmditem("bigraw") != CMD_NOTFOUND ) { + puts("Using raw access to high memory - assuming big real mode\n"); + pptr->configflags |= CONFIG_BIGRAW|CONFIG_RAW; + } + + /* Set up a drive parameter table */ + if ( geometry->driveno & 0x80 ) { + /* Hard disk */ + pptr->dpt.hd.max_cyl = geometry->c-1; + pptr->dpt.hd.max_head = geometry->h-1; + pptr->dpt.hd.ctrl = (geometry->h > 8) ? 0x08: 0; + } else { + /* Floppy - most of these fields are bogus and mimic + a 1.44 MB floppy drive */ + pptr->dpt.fd.specify1 = 0xdf; + pptr->dpt.fd.specify2 = 0x02; + pptr->dpt.fd.delay = 0x25; + pptr->dpt.fd.sectors = geometry->s; + pptr->dpt.fd.bps = 0x02; + pptr->dpt.fd.isgap = 0x12; + pptr->dpt.fd.dlen = 0xff; + pptr->dpt.fd.fgap = 0x6c; + pptr->dpt.fd.ffill = 0xf6; + pptr->dpt.fd.settle = 0x0f; + pptr->dpt.fd.mstart = 0x05; + + pptr->dpt.fd.old_fd_dpt = rdz_32(BIOS_INT1E); + } + + /* The size is given by hptr->total_size plus the size of the E820 + map -- 12 bytes per range; we may need as many as 2 additional + ranges (each insertrange() can worst-case turn 1 area into 3) + plus the terminating range, over what nranges currently show. */ + cmdlinelen = strlen(shdr->cmdline)+1; + total_size = hptr->total_size; /* Actual memdisk code */ + total_size += (nranges+3)*sizeof(ranges[0]); /* E820 memory ranges */ + total_size += cmdlinelen; /* Command line */ + total_size += STACK_NEEDED; /* Stack */ + printf("Total size needed = %u bytes, allocating %uK\n", + total_size, (total_size+0x3ff) >> 10); + + if ( total_size > dos_mem ) { + puts("MEMDISK: Insufficient low memory\n"); + die(); + } + + driveraddr = stddosmem - total_size; + driveraddr &= ~0x3FF; + + printf("Old dos memory at 0x%05x (map says 0x%05x), loading at 0x%05x\n", + stddosmem, dos_mem, driveraddr); + + /* Reserve this range of memory */ + wrz_16(BIOS_BASEMEM, driveraddr >> 10); + insertrange(driveraddr, dos_mem-driveraddr, 2); + parse_mem(); + + pptr->mem1mb = low_mem >> 10; + pptr->mem16mb = high_mem >> 16; + if ( low_mem == (15 << 20) ) { + /* lowmem maxed out */ + uint32_t int1588mem = (high_mem >> 10)+(low_mem >> 10); + pptr->memint1588 = (int1588mem > 0xffff) ? 0xffff : int1588mem; + } else { + pptr->memint1588 = low_mem >> 10; + } + + printf("1588: 0x%04x 15E801: 0x%04x 0x%04x\n", + pptr->memint1588, pptr->mem1mb, pptr->mem16mb); + + driverseg = driveraddr >> 4; + driverptr = driverseg << 16; + + /* Anything beyond the end is for the stack */ + pptr->mystack = (uint16_t)(stddosmem-driveraddr); + + pptr->oldint13 = rdz_32(BIOS_INT13); + pptr->oldint15 = rdz_32(BIOS_INT15); + + /* Adjust the E820 table: if there are null ranges (type 0) + at the end, change them to type end of list (-1). + This is necessary for the driver to be able to report end + of list correctly. */ + while ( nranges && ranges[nranges-1].type == 0 ) { + ranges[--nranges].type = -1; + } + + /* Query drive parameters of this type */ + memset(®s, 0, sizeof regs); + regs.es = 0; + regs.eax.b[1] = 0x08; + regs.edx.b[0] = geometry->driveno; + syscall(0x13, ®s, ®s); + + if ( regs.eflags.l & 1 ) { + printf("INT 13 08: Failure, assuming this is the only drive\n"); + pptr->drivecnt = 1; + } else { + printf("INT 13 08: Success, count = %u, BPT = %04x:%04x\n", + regs.edx.b[0], regs.es, regs.edi.w[0]); + pptr->drivecnt = regs.edx.b[0]+1; + } + + /* Pointer to the command line */ + pptr->cmdline_off = bin_size + (nranges+1)*sizeof(ranges[0]); + pptr->cmdline_seg = driverseg; + + /* Copy driver followed by E820 table followed by command line */ + { + unsigned char *dpp = (unsigned char *)(driverseg << 4); + dpp = memcpy_endptr(dpp, &_binary_memdisk_bin_start, bin_size); + dpp = memcpy_endptr(dpp, ranges, (nranges+1)*sizeof(ranges[0])); + dpp = memcpy_endptr(dpp, shdr->cmdline, cmdlinelen+1); + } + + /* Install the interrupt handlers */ + printf("old: int13 = %08x int15 = %08x\n", + rdz_32(BIOS_INT13), rdz_32(BIOS_INT15)); + + wrz_32(BIOS_INT13, driverptr+hptr->int13_offs); + wrz_32(BIOS_INT15, driverptr+hptr->int15_offs); + + printf("new: int13 = %08x int15 = %08x\n", + rdz_32(BIOS_INT13), rdz_32(BIOS_INT15)); + + /* Update various BIOS magic data areas (gotta love this shit) */ + + if ( geometry->driveno & 0x80 ) { + /* Update BIOS hard disk count */ + wrz_8(BIOS_HD_COUNT, rdz_8(BIOS_HD_COUNT)+1); + } else { + /* Update BIOS floppy disk count */ + uint8_t equip = rdz_8(BIOS_EQUIP); + if ( equip & 1 ) { + if ( (equip & (3 << 6)) != (3 << 6) ) { + equip += (1 << 6); + } + } else { + equip |= 1; + equip &= ~(3 << 6); + } + wrz_8(BIOS_EQUIP, equip); + } + + /* Reboot into the new "disk"; this is also a test for the interrupt hooks */ + puts("Loading boot sector... "); + + memset(®s, 0, sizeof regs); + // regs.es = 0; + regs.eax.w[0] = 0x0201; /* Read sector */ + regs.ebx.w[0] = 0x7c00; /* 0000:7C00 */ + regs.ecx.w[0] = 1; /* One sector */ + regs.edx.w[0] = geometry->driveno; + syscall(0x13, ®s, ®s); + + if ( regs.eflags.l & 1 ) { + puts("MEMDISK: Failed to load new boot sector\n"); + die(); + } + + if ( getcmditem("pause") != CMD_NOTFOUND ) { + puts("press any key to boot... "); + regs.eax.w[0] = 0; + syscall(0x16, ®s, NULL); + } + + puts("booting...\n"); + + /* On return the assembly code will jump to the boot vector */ + return geometry->driveno; +} diff --git a/syslinux/memdisk/start32.S b/syslinux/memdisk/start32.S new file mode 100644 index 0000000..cbf7b62 --- /dev/null +++ b/syslinux/memdisk/start32.S @@ -0,0 +1,9 @@ +# $Id: start32.S,v 1.1 2003/04/15 19:29:59 hpa Exp $ +# +# Simple stub to get us to the right point in the 32-bit code; +# this module must be linked first +# + .text + .globl _start +_start: + jmp setup diff --git a/syslinux/memdisk/testdata1 b/syslinux/memdisk/testdata1 new file mode 100644 index 0000000..34ab566 --- /dev/null +++ b/syslinux/memdisk/testdata1 @@ -0,0 +1,13 @@ +0000000000000000 000000000009bc00 1 +000000000009bc00 0000000000004400 2 +00000000000e9800 0000000000016800 2 +0000000000100000 0000000006ee0000 1 +0000000006fe0000 000000000000fc00 3 +0000000006fefc00 0000000000000400 4 +0000000006ff0000 0000000000002000 2 +0000000006ff2000 000000000000e000 1 +0000000007000000 0000000000100000 2 +00000000fff00000 0000000000100000 2 + +0000000000586000 0000000000168000 2 +000000000009ba00 0000000000000200 2 diff --git a/syslinux/memdisk/testdata2 b/syslinux/memdisk/testdata2 new file mode 100644 index 0000000..8bec5bf --- /dev/null +++ b/syslinux/memdisk/testdata2 @@ -0,0 +1,10 @@ +0000000000000000 000000000009bc00 1 +000000000009bc00 0000000000004400 2 +00000000000e9800 0000000000016800 2 +0000000000100000 0000000006ee0000 1 +0000000006fe0000 000000000000fc00 3 +0000000006fefc00 0000000000000400 4 +0000000006ff0000 0000000000002000 2 +0000000006ff2000 000000000000e000 1 +0000000007000000 0000000000100000 2 +00000000fff00000 0000000000100000 2 diff --git a/syslinux/memdisk/testdata3 b/syslinux/memdisk/testdata3 new file mode 100644 index 0000000..38a4502 --- /dev/null +++ b/syslinux/memdisk/testdata3 @@ -0,0 +1,14 @@ +0000000000000000 000000000009bc00 1 +000000000009bc00 0000000000004400 2 +00000000000e9800 0000000000016800 2 +0000000000100000 0000000006ee0000 1 +0000000006fe0000 000000000000fc00 3 +0000000006fefc00 0000000000000400 4 +0000002000000000 0000001000000000 1 +0000000006ff0000 0000000000002000 2 +0000000006ff2000 000000000000e000 1 +0000000007000000 0000000000100000 2 +00000000fff00000 0000000000100000 2 + +0000000000586000 0000000000168000 2 +000000000009ba00 0000000000000200 2 diff --git a/syslinux/memdisk/unzip.c b/syslinux/memdisk/unzip.c new file mode 100644 index 0000000..1960c93 --- /dev/null +++ b/syslinux/memdisk/unzip.c @@ -0,0 +1,388 @@ +/* + * unzip.c + * + * This is a collection of several routines from gzip-1.0.3 + * adapted for Linux. + * + * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994 + * puts by Nick Holloway 1993, better puts by Martin Mares 1995 + * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 + * + * Adapted for MEMDISK by H. Peter Anvin, April 2003 + */ + +#include <stdint.h> +#include "memdisk.h" +#include "conio.h" + +/* + * gzip declarations + */ + +#define OF(args) args +#define STATIC static + +#define memzero(s, n) memset ((s), 0, (n)) + +typedef uint8_t uch; +typedef uint16_t ush; +typedef uint32_t ulg; + +#define WSIZE 0x8000 /* Window size must be at least 32k, */ + /* and a power of two */ + +static uch *inbuf; /* input pointer */ +static uch window[WSIZE]; /* sliding output window buffer */ + +static unsigned insize; /* total input bytes read */ +static unsigned inbytes; /* valid bytes in inbuf */ +static unsigned outcnt; /* bytes in output buffer */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ +#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ +#define RESERVED 0xC0 /* bit 6,7: reserved */ + +/* Diagnostic functions */ +#ifdef DEBUG +# define Assert(cond,msg) {if(!(cond)) error(msg);} +# define Trace(x) fprintf x +# define Tracev(x) {if (verbose) fprintf x ;} +# define Tracevv(x) {if (verbose>1) fprintf x ;} +# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} +# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + +static int fill_inbuf(void); +static void flush_window(void); +static void error(char *m); +static void gzip_mark(void **); +static void gzip_release(void **); + +/* Get byte from input buffer */ +static inline uch get_byte(void) +{ + if ( inbytes ) { + uch b = *inbuf++; + inbytes--; + return b; + } else { + return fill_inbuf(); /* Input buffer underrun */ + } +} + +/* Unget byte from input buffer */ +static inline void unget_byte(void) +{ + inbytes++; + inbuf--; +} + +static ulg bytes_out = 0; /* Number of bytes output */ +static uch *output_data; /* Output data pointer */ +static ulg output_size; /* Number of output bytes expected */ + +static void *malloc(int size); +static void free(void *where); + +static ulg free_mem_ptr, free_mem_end_ptr; + +#include "inflate.c" + +static void *malloc(int size) +{ + void *p; + + if (size < 0) error("malloc error"); + + free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */ + + p = (void *)free_mem_ptr; + free_mem_ptr += size; + + if (free_mem_ptr >= free_mem_end_ptr) + error("out of memory"); + + return p; +} + +static void free(void *where) +{ + /* Don't care */ + (void)where; +} + +static void gzip_mark(void **ptr) +{ + *ptr = (void *) free_mem_ptr; +} + +static void gzip_release(void **ptr) +{ + free_mem_ptr = (long) *ptr; +} + +/* =========================================================================== + * Fill the input buffer. This is called only when the buffer is empty + * and at least one byte is really needed. + */ +static int fill_inbuf(void) +{ + /* This should never happen. We have already pointed the algorithm + to all the data we have. */ + printf("failed\nDecompression error: ran out of input data\n"); + die(); +} + +/* =========================================================================== + * Write the output window window[0..outcnt-1] and update crc and bytes_out. + * (Used for the decompressed data only.) + */ +static void flush_window(void) +{ + ulg c = crc; /* temporary variable */ + unsigned n; + uch *in, *out, ch; + + if ( bytes_out+outcnt > output_size ) + error("output buffer overrun"); + + in = window; + out = output_data; + for (n = 0; n < outcnt; n++) { + ch = *out++ = *in++; + c = crc_32_tab[(c ^ ch) & 0xff] ^ (c >> 8); + } + crc = c; + output_data = out; + bytes_out += (ulg)outcnt; + outcnt = 0; +} + +static void error(char *x) +{ + printf("failed\nDecompression error: %s\n", x); + die(); +} + +/* GZIP header */ +struct gzip_header { + uint16_t magic; + uint8_t method; + uint8_t flags; + uint32_t timestamp; + uint8_t extra_flags; + uint8_t os_type; +} __attribute__ ((packed)); +/* (followed by optional and variable length "extra", "original name", + and "comment" fields) */ + +struct gzip_trailer { + uint32_t crc; + uint32_t dbytes; +} __attribute__ ((packed)); + +/* PKZIP header. See + * <http://www.pkware.com/products/enterprise/white_papers/appnote.html>. + */ +struct pkzip_header { + uint32_t magic; + uint16_t version; + uint16_t flags; + uint16_t method; + uint16_t modified_time; + uint16_t modified_date; + uint32_t crc; + uint32_t zbytes; + uint32_t dbytes; + uint16_t filename_len; + uint16_t extra_len; +} __attribute__ ((packed)); +/* (followed by optional and variable length "filename" and "extra" + fields) */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ +#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ +#define RESERVED 0xC0 /* bit 6,7: reserved */ + +/* pkzip flag byte */ +#define PK_ENCRYPTED 0x01 /* bit 0 set: file is encrypted */ +#define PK_DATADESC 0x08 /* bit 3 set: file has trailing "data + descriptor" */ +#define PK_UNSUPPORTED 0xFFF0 /* All other bits must be zero */ + + +/* Return 0 if (indata, size) points to a ZIP file, and fill in + compressed data size, uncompressed data size, CRC, and offset of + data. + + If indata is not a ZIP file, return -1. */ +int check_zip(void *indata, uint32_t size, uint32_t *zbytes_p, + uint32_t *dbytes_p, uint32_t *orig_crc, uint32_t *offset_p) { + struct gzip_header *gzh = (struct gzip_header *)indata; + struct pkzip_header *pkzh = (struct pkzip_header *)indata; + uint32_t offset; + + if (gzh->magic == 0x8b1f) { + struct gzip_trailer *gzt = indata + size - sizeof (struct gzip_trailer); + /* We only support method #8, DEFLATED */ + if (gzh->method != 8) { + error("gzip file uses invalid method"); + return -1; + } + if (gzh->flags & ENCRYPTED) { + error("gzip file is encrypted; not supported"); + return -1; + } + if (gzh->flags & CONTINUATION) { + error("gzip file is a continuation file; not supported"); + return -1; + } + if (gzh->flags & RESERVED) { + error("gzip file has unsupported flags"); + return -1; + } + offset = sizeof (*gzh); + if (gzh->flags & EXTRA_FIELD) { + /* Skip extra field */ + unsigned len = *(unsigned *)(indata + offset); + offset += 2 + len; + } + if (gzh->flags & ORIG_NAME) { + /* Discard the old name */ + uint8_t *p = indata; + while (p[offset] != 0 && offset < size) { + offset++; + } + offset++; + } + + if (gzh->flags & COMMENT) { + /* Discard the comment */ + uint8_t *p = indata; + while (p[offset] != 0 && offset < size) { + offset++; + } + offset++; + } + + if (offset > size) { + error ("gzip file corrupt"); + return -1; + } + *zbytes_p = size - offset - sizeof (struct gzip_trailer); + *dbytes_p = gzt->dbytes; + *orig_crc = gzt->crc; + *offset_p = offset; + return 0; + } + else if (pkzh->magic == 0x04034b50UL) { + /* Magic number matches pkzip file. */ + + offset = sizeof (*pkzh); + if (pkzh->flags & PK_ENCRYPTED) { + error("pkzip file is encrypted; not supported"); + return -1; + } + if (pkzh->flags & PK_DATADESC) { + error("pkzip file uses data_descriptor field; not supported"); + return -1; + } + if (pkzh->flags & PK_UNSUPPORTED) { + error("pkzip file has unsupported flags"); + return -1; + } + + /* We only support method #8, DEFLATED */ + if (pkzh->method != 8) { + error("pkzip file uses invalid method"); + return -1; + } + /* skip header */ + offset = sizeof (*pkzh); + /* skip filename */ + offset += pkzh->filename_len; + /* skip extra field */ + offset += pkzh->extra_len; + + if (offset + pkzh->zbytes > size) { + error ("pkzip file corrupt"); + return -1; + } + + *zbytes_p = pkzh->zbytes; + *dbytes_p = pkzh->dbytes; + *orig_crc = pkzh->crc; + *offset_p = offset; + return 0; + } + else { + /* Magic number does not match. */ + return -1; + } + + error ("Internal error in check_zip"); + return -1; +} + +/* + * Decompress the image, trying to flush the end of it as close + * to end_mem as possible. Return a pointer to the data block, + * and change datalen. + */ +extern void _end; + +void *unzip(void *indata, uint32_t zbytes, uint32_t dbytes, + uint32_t orig_crc, void *target) +{ + /* Set up the heap; it's the 64K after the bounce buffer */ + free_mem_ptr = (ulg)sys_bounce + 0x10000; + free_mem_end_ptr = free_mem_ptr + 0x10000; + + /* Set up input buffer */ + inbuf = indata; + /* Sometimes inflate() looks beyond the end of the compressed data, + but it always backs up before it is done. So we give it 4 bytes + of slack. */ + insize = inbytes = zbytes + 4; + + /* Set up output buffer */ + outcnt = 0; + output_data = target; + output_size = dbytes; + bytes_out = 0; + + makecrc(); + gunzip(); + + /* Verify that gunzip() consumed the entire input. */ + if (inbytes != 4) + error("compressed data length error"); + + /* Check the uncompressed data length and CRC. */ + if ( bytes_out != dbytes ) + error("uncompressed data length error"); + + if (orig_crc != CRC_VALUE) + error("crc error"); + + puts("ok\n"); + + return target; +} diff --git a/syslinux/memdisk/version.h b/syslinux/memdisk/version.h new file mode 100644 index 0000000..5112a4d --- /dev/null +++ b/syslinux/memdisk/version.h @@ -0,0 +1,26 @@ +#ident "$Id: version.h,v 1.5 2005/01/03 08:31:59 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2002 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * version.h + * + * MEMDISK version data + */ + +#ifndef MEMDISK_VERSION_H +#define MEMDISK_VERSION_H + +#define FIRSTYEAR "2001" +#define COPYYEAR "2005" + +#endif diff --git a/syslinux/menu/CHANGES b/syslinux/menu/CHANGES new file mode 100644 index 0000000..3998f1b --- /dev/null +++ b/syslinux/menu/CHANGES @@ -0,0 +1,12 @@ +Changes in v1.1 +--------------- +* Additional handler type: Keys handler +* Menuitem handlers now have a return value of type t_handler_return. + For all simple cases, you just return ACTION_VALID or ACTION_INVALID + (For some types of menu items, handlers are ignored, and for + others the return value is ignored) +* add_menu takes an extra argument (to better control memory footprint) + You can just set it to -1 to choose the default value +* Now the menu system support long menu's using scroll bars. +* Support for passwords and context sensitive help is added. + diff --git a/syslinux/menu/HISTORY b/syslinux/menu/HISTORY new file mode 100644 index 0000000..06d3360 --- /dev/null +++ b/syslinux/menu/HISTORY @@ -0,0 +1,20 @@ + +GCC & 32-bit code +----------------- +Due to the limitations of the COM file format, +(64KB limit on memory footprint) the code has been changed +so that the code compiles to a 32-bit COMBOOT program. +Since the code makes use of BIOS calls, this code cannot be +compiled into a format which can execute under Linux. As a +side effect, there is no nice way to debug this code. In order +to debug this code, you will have to run the code under syslinux. + +GCC & 16-bit code +----------------- +The code was ported to GCC by Peter Anvin. + +OpenWatcom & 16-bit code +------------------------ +Originally this code was written for the Openwatcom compiler +and generated .COM files, which could execute under DOS as well as +SYSLINUX. diff --git a/syslinux/menu/MANUAL b/syslinux/menu/MANUAL new file mode 100644 index 0000000..50652fb --- /dev/null +++ b/syslinux/menu/MANUAL @@ -0,0 +1,330 @@ + Overview of writing code using the menu system + ---------------------------------------------- + +This file contains implementation and developer documentation. +For simple cases, you should start by using simple.c as a template. +complex.c illustrates most of the features available in the menu system. + +Menu Features currently supported are: +* menu items, +* submenus, +* disabled items, +* checkboxes, +* invisible items (useful for dynamic menus), and +* Radio menus, +* Context sensitive help +* Authenticated users + +The keys used are: + +* Arrow Keys, PgUp, PgDn, Home, End Keys +* Space to switch state of a checkbox +* Enter to choose the item +* Escape to exit from it +* Shortcut keys + +1. Overview +----------- + +The code usually consists of many stages. + + * Configuring the menusytem + * Installing global handlers [optional] + * Populating the menusystem + * Executing the menusystem + * Processing the result + +1.1 Configuring the menusystem +------------------------------ +This includes setting the window the menu system should use, +the choice of colors, the title of the menu etc. In most functions +calls, a value of -1 indicates that the default value be used. +For details about what the arguments are look at function +declarations in menu.h + +<code> + // Choose the default title and setup default values for all attributes.... + init_menusystem(NULL); + set_window_size(1,1,23,78); // Leave one row/col border all around + + // Choose the default values for all attributes and char's + // -1 means choose defaults (Actually the next 4 lines are not needed) + set_normal_attr (-1,-1,-1,-1); + set_status_info (-1,-1); + set_title_info (-1,-1); + set_misc_info(-1,-1,-1,-1); +</code> + +1.2 Populating the menusystem +----------------------------- +This involves adding a menu to the system, and the options which +should appear in the menu. An example is given below. + +<code> + MAINMENU = add_menu(" Menu Title ",-1); + CHECKED = 1; + add_item("option1","Status 1",OPT_RUN,"kernel1 arg1=val1",0); + add_item("selfloop","Status 2",OPT_SUBMENU,NULL,MAINMENU); + add_sep(); + add_item("checkbox,"Checkbox Info",OPT_CHECKBOX,NULL,CHECKED); + add_item("Exit ","Status String",OPT_EXITMENU,NULL,0); + // "any string" not used by the menu system, useful for storing kernel names + // NUM = index of submenu if OPT_SUBMENU, + // 0/1 default checked state if OPT_CHECKBOX + // unused otherwise. +</code> + +The call to add_menu has two arguments, the first being the title of +the menu and the second an upper bound on the number of items in the menu. +Putting a -1, will use the default (see MENUSIZE in menu.h). If you try +to add more items than specified, the extra items will not appear in +the menu. The accuracy of this number affects the memory required +to run the system. Currently the code compiles to a .COM file which +has a 64K limit on memory used. + +The call to add_item has five arguments. +The first argument is the text which appears in the menu itself. +The second argument is the text displayed in the status line. +The third argument indicates the type of this menuitem. It is one of +the following + + * OPT_RUN : executable content + * OPT_EXITMENU : exits menu to parent + * OPT_SUBMENU : if selected, displays a submenu + * OPT_CHECKBOX : associates a boolean with this item which can be toggled + * OPT_RADIOMENU: associates this with a radio menu. + After execution, the data field of this item will point + to the option selected. + * OPT_SEP : A menu seperator (visually divide menu into parts) + * OPT_RADIOITEM: this item is one of the options in a RADIOMENU + * OPT_INACTIVE : A disabled item (user cannot select this) + * OPT_INVISIBLE: This item will not be displayed. + +The fourth argument is the value of the data field. This pointer is just +stored. In case of a radiomenu this points to the menuitem chosen (Dont +forget to typecase this pointer to (t_menuitem *) when reading this info). + +The fifth argument is a number whose meaning depends on the type of the +item. For a CHECKBOX it should be 0/1 setting the initial state of the +checkbox. For a SUBMENU it should be the index of the menu which should +be displayed if this option is chosen. For a RADIOMENU it should be the +index of the menu which contains all the options (All items in that menu +should not of type RADIOITEM are ignored). For all other types, this +argument has no meaning at all. + +A call to add_sep is a convenient shorthand for calling add_item +with the type set to OPT_SEP. + +1.3 Executing the menusystem +---------------------------- +This is the simplest of all. Just call showmenus, with the index +of the main menu as its argument. It returns a pointer to the menu +item which was selected by the user. + +<code> + choice = showmenus(MAIN); // Initial menu is the one with index MAIN +</code> + +1.4 Processing the result +------------------------- +This pointer will either be NULL (user hit Escape) or always point +to a menuitem which can be "executed", i.e. it will be of type OPT_RUN. +Usually at this point, all we need to do is to ask syslinux to run +the command associated with this menuitem. The following code executes +the command stored in choice->data (there is no other use for the data +field, except for radiomenu's) + +<code> + if (choice) + { + if (choice->action == OPT_RUN) + { + if (syslinux) runcommand(choice->data); + else csprint(choice->data,0x07); + return 1; + } + csprint("Error in programming!",0x07); + } +</code> + +2. Advanced features +-------------------- +Everycall to add_item actually returns a pointer to the menuitem +created. This can be useful when using any of the advanced features. + +2.1 extra_data +-------------- +For example, every menuitem has an "extra_data" field (a pointer) +which the user can use to point any data he/she pleases. The menusystem +itself does not use this field in anyway. + +2.2 helpid +---------- +Every item also has a field called "helpid". It is meant to hold some +kind of identifier which can be referenced and used to generate +a context sensitive help system. This can be set after a call to +add_item as follows +<code> + add_item("selfloop","Status 2",OPT_SUBMENU,NULL,MAINMENU); + set_item_options('A',4516); +</code> + +The first is the shortcut key for this entry. You can put -1 to ensure +that the shortcut key is not reset. The second is some unsigned integer. +If this value is 0xFFFF, then the helpid is not changed. + +2.3 Installing global handlers +------------------------------ +It is possible to register handlers for the menu system. These are +user functions which are called by the menusystem in certain +situations. Usually the handlers get a pointer to the menusystem +datastructure as well as a pointer to the current item selected. +Some handlers may get additional information. Some handlers are +required to return values while others are not required to do so. + +Currently the menusystem support three types of global handlers +* timeout handler +* screen handler +* keys handler + +2.3.1 timeout handler +--------------------- +This is installed using a call to "reg_ontimeout(fn,numsteps,stepsize)" +function. fn is a pointer to a function which takes no arguments and +returns one of CODE_WAIT, CODE_ENTER, CODE_ESCAPE. This function is +called when numsteps*stepsize Centiseconds have gone by without any +user input. If the function returns CODE_WAIT then the menusystem +waits for user input (for another numsteps*stepsize Centiseconds). If +CODE_ENTER or CODE_ESCAPE is returned, then the system pretends that +the user hit ENTER or ESCAPE on the keyboard and acts accordingly. + +2.3.2 Screen handler +-------------------- +This is installed using a call to "reg_handler(HDLR_SCREEN,fn)". fn is +a pointer to a function which takes a pointer to the menusystem +datastructure and the current item selected and returns nothing. +This is called everytime a menu is drawn (i.e. everytime user changes +the current selection). This is meant for displaying any additional +information which reflects the current state of the system. + +2.3.3 Keys handler +------------------ +This is installed using a call to "reg_handler(HDLR_KEYS,fn)". fn is +a pointer to a function which takes a pointer to the menusystem +datastructure, the current item and the scan code of a key and returns +nothing. This function is called when the user presses a key which +the menusystem does not know to dealwith. In any case, when this call +returns the screen should not have changed in any way. Usually, +one can change the active page and display any output needed and +reset the active page when you return from this call. + +complex.c implements a key_handler, which implements a simple +context sensitive help system, by displaying the contents of a +file whose name is based on the helpid of the active item. + +Also, complex.c's handler allows certain users to make changes +to edit the commands associated with a menu item. + +2.4 Installing item level handlers +---------------------------------- +In addition to global handlers, one can also install handlers for each +individual item. A handler for an individual item is a function which +takes a pointer to the menusystem datastructure and a pointer to the +current item and return a structure of type t_handler_return. Currently +it has two bit fields "valid" and "refresh". + +This handler is called when the user hits "enter" on a RUN item, or +changes the status of a CHECKBOX, or called *after* a radio menu choice +has been set. In all other cases, installing a handler has no effect. + +The handler can change any of the internal datastructures it pleases. +For e.g. in a radiomenu handler, one can change the text displayed +on the menuitem depending on which choice was selected (see complex.c +for an example). The return values are ignored for RADIOMENU's. + +In case of RUN items: the return values are used as follows. If the +return value of "valid" was false, then this user choice is ignored. +This is useful if the handler has useful side effects. For e.g. +complex.c has a Login item, whose handler always return INVALID. It +sets a global variable to the name of the user logged in, and enables +some menu items, and makes some invisible items visible. + +* If the handler does not change the visibility status of any items, + the handler should set "refresh" to 0. +* If the handler changes the visibility status of items in the current + menu set "refresh" to 1. +* If you are changing the visibility status of items in menu's currently + not displayed, then you can set "refresh" to 0. +* Changing the visibility status of items in another menu + which is currently displayed, is not supported. If you do it, + the screen contents may not reflect the change until you get to the + menu which was changed. When you do get to that menu, you may notice + pieces of the old menu still on the screen. + +In case of CHECKBOXES: the return value of "valid" is ignored. Because, +the handler can change the value of checkbox if the user selected value +is not appropriate. only the value of "refresh" is honored. In this case +all the caveats in the previous paragraph apply. + +menu.h defines two instances of t_handler_return +ACTION_VALID and ACTION_INVALID for common use. These set the valid flag +to 1 and 0 respectively and the refresh flag to 0. + +3. Things to look out for +------------------------- +When you define the menu system, always declare it in the opposite +order, i.e. all lower level menu's should be defined before the higher +level menus. This is because in order to define the MAINMENU, you need +to know the index assigned to all its submenus. + +4. Additional Modules +--------------------- +You can make use of the following additional modules, in writing your +handlers. + +* Passwords +* Help + +4.1 Passwords +------------- +This module was written by Th. Gebhardt. This is basically a modification +of the DES crypt function obtained by removing the dependence of the +original crypt function on C libraries. The following functions are +defined + + init_passwords(PWDFILE) + // Read in the password database from the file + authenticate_user(user,pwd) + // Checks if user,pwd is valid + isallowed(user,perm) + // Checks if the user has a specified permission + close_passwords() + // Unloads password database from memory + + See the sample password file for more details about the file format + and the implementation of permissions. + +See complex.c for a example of how to use this. + +4.2 Help +-------- +This can be used to set up a context sensitive help system. The following +functions are defined + + init_help(HELPBASEDIR) + // Initialises the help system. All help files will be loaded + // from the directory specified. + runhelpsystem(context) + // Displays the contents of HELPBASEDIR/hlp<context>.txt + +In order to have a functioning help system, you just need to create +the hlp<NNNNN>.txt files and initialize the help system by specifying +the base directory. + +The first line of this file assumed to be the title of the help screen. +You can use ^N and ^O to change attributes absolutely and relatively, +i.e. [^O]46 (i.e. Ctrl-O followed by chars 4 and 6) will set the +attribute to 46, while [^N]08 will XOR the current attribute with +specified number, thus in this case the first [^N]08 will turn on +highlighting and the second one will turn it off. + diff --git a/syslinux/menu/Makefile b/syslinux/menu/Makefile new file mode 100644 index 0000000..b30ce03 --- /dev/null +++ b/syslinux/menu/Makefile @@ -0,0 +1,79 @@ +#ident "$Id: Makefile,v 1.9 2005/04/28 23:12:09 hpa Exp $" +## ----------------------------------------------------------------------- +## +## Copyright 2001-2005 H. Peter Anvin - All Rights Reserved +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, Inc., 53 Temple Place Ste 330, +## Boston MA 02111-1307, USA; either version 2 of the License, or +## (at your option) any later version; incorporated herein by reference. +## +## ----------------------------------------------------------------------- + +## +## samples for syslinux users +## + +gcc_ok = $(shell if gcc $(1) -c -x c /dev/null -o /dev/null 2>/dev/null; \ + then echo $(1); else echo $(2); fi) + +M32 := $(call gcc_ok,-m32,) + +CC = gcc +LD = ld -m elf_i386 +AR = ar +NASM = nasm +RANLIB = ranlib +COM32DIR = ../com32 +LUDIR = $(COM32DIR)/libutil +LDIR = $(COM32DIR)/lib +CFLAGS = $(M32) -mregparm=3 -DREGPARM=3 -W -Wall -march=i386 -Os -fomit-frame-pointer -I$(LUDIR)/include -I$(COM32DIR)/include -Ilibmenu -D__COM32__ +SFLAGS = -D__COM32__ -march=i386 +LDFLAGS = -T $(LDIR)/com32.ld +OBJCOPY = objcopy +LIBGCC := $(shell $(CC) --print-libgcc) + +LIBS = libmenu/libmenu.a $(LUDIR)/libutil_com.a $(LDIR)/libcom32.a $(LIBGCC) + +LIBMENU = libmenu/syslnx.o libmenu/com32io.o libmenu/tui.o \ + libmenu/menu.o libmenu/passwords.o libmenu/des.o libmenu/help.o + +MENUS = $(patsubst %.c,%.c32,$(wildcard *.c)) + +.SUFFIXES: .S .c .o .elf .c32 + +.PRECIOUS: %.o +%.o: %.S + $(CC) $(SFLAGS) -c -o $@ $< + +.PRECIOUS: %.o +%.o: %.c %.h + $(CC) $(CFLAGS) -c -o $@ $< + +.PRECIOUS: %.elf +%.elf: %.o $(LIBS) + $(LD) $(LDFLAGS) -o $@ $^ + +%.c32: %.elf + $(OBJCOPY) -O binary $< $@ + +all: menus + +libmenu/libmenu.a: $(LIBMENU) + -rm -f $@ + $(AR) cq $@ $^ + $(RANLIB) $@ + +tidy: + rm -f *.o *.lo *.a *.lst *.elf libmenu/*.o libmenu/*.a + +clean: tidy + rm -f *.lss *.c32 *.com + +spotless: clean + rm -f *~ \#* + +menus: $(MENUS) + +install: # Don't install samples diff --git a/syslinux/menu/README b/syslinux/menu/README new file mode 100644 index 0000000..66116e9 --- /dev/null +++ b/syslinux/menu/README @@ -0,0 +1,93 @@ + Text User Interface using comboot + --------------------------------- + +This is a menu system written by Murali Krishnan Ganapathy and ported +from OpenWatcom to gcc by HPA. It is currently being maintained by the +original author. + +To configure the menus, you need to set up a menu configuration file +to have the menu items you desire, then build the menu system using +make. You can use either simple.c or complex.c as a starting point +for your own menu configuration file; then add the name with a .c32 +extension to the MENUS list in the Makefile. + +The resulting code is a 32-bit COMBOOT code, and hence can be executed +only under syslinux. You can use tools like bochs to help debug your +code. + +Menu Features currently supported are: +* menu items, +* submenus, +* disabled items, +* checkboxes, +* invisible items (useful for dynamic menus), and +* Radio menus, +* Context sensitive help +* Authenticated users +* Editing commands associated with items + +The keys used are: + +* Arrow Keys, PgUp, PgDn, Home, End Keys +* Space to switch state of a checkbox +* Enter to choose the item +* Escape to exit from it +* Shortcut keys + +Features +-------- +This is a general purpose menu system implemented using only BIOS calls, +so it can be executed in a COMBOOT environment as well. It is highly +customizable. Some features include: + +* Status line + Display any help information associated with each menu item. +* Window + Specify a window within which the menu system draws all its menu's. + It is upto the user to ensure that the menu's fit within the window. +* Positioning submenus + By default, each submenu is positioned just below the corresponding + entry of the parent menu. However, the user may position each menu + at a specific location of his choice. This is useful, when the menu's + have lots of options. +* Registering handlers for each menu item + This is mainly used for checkboxes and radiomenu's, where a selection may + result in disabling other menu items/checkboxes +* Global Screen Handler + This is called every time the menu is redrawn. The user can display + additional information (usually outside the window where the menu is + being displayed). See the complex.c for an example, where the global + handler is used to display the choices made so far. +* Global Keys Handler + This is called every time the user presses a key which the menu + system does not understand. This can be used to display context + sensitive help. See complex.c for how to use this hook to implement + a context sensitive help system as well as "On the fly" editing + of commands associated with menus. +* Shortcut Keys + With each item one can register a shortcut key from [A-Za-z0-9]. + Pressing a key within that range, will take you to the next item + with that shortcut key (so you can have multiple items with the + same shortcut key). The default shortcut key for each item, is + the lower case version of the first char of the item in the range + [A-Za-z0-9]. +* Escape Keys + Each item entry can have a substring enclosed in < and >. This part + is highlighted. Can be used to highlight the shortcut keys. By default + if an item has a <, then the first char inside < and > in the range + [A-Za-z0-9] is converted to lower case and set as the shortcut key. +* Ontimeout handler + The user can register an ontimeout handler, which gets called if + no key has been pressed for a user specific amount of time (default 5 min). + For an example see the complex.c file. + +Credits +------- +* The Watcom developers and Peter Anvin for figuring out an OS + independent startup code. +* Thomas for porting the crypt function and removing all C library + dependencies +* Peter Anvin for porting the code to GCC + +- Murali (gmurali+guicd@cs.uchicago.edu) + diff --git a/syslinux/menu/TODO b/syslinux/menu/TODO new file mode 100644 index 0000000..59e653c --- /dev/null +++ b/syslinux/menu/TODO @@ -0,0 +1,9 @@ +* Read menu structure from config files + - This will eliminate the need for recompiling the code, especially + for the simple menus +* Features to add + - Parse commandline arguments +* Help support + - Beef up help.c so that the text file can be larger than one page, and + user can scroll down page to view extra text. + diff --git a/syslinux/menu/complex.c b/syslinux/menu/complex.c new file mode 100644 index 0000000..dc4cbce --- /dev/null +++ b/syslinux/menu/complex.c @@ -0,0 +1,424 @@ +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +#include "menu.h" +#include "com32io.h" +#include "help.h" +#include "passwords.h" +#include "des.h" +#include <stdlib.h> +#include <stdio.h> + +/* Global variables */ +char infoline[160]; +char buffer[80]; + +// Different network options +static char nonet[] = "<n>etwork [none]"; +static char dhcpnet[]="<n>etwork [dhcp]"; +static char statnet[]="<n>etwork [static]"; + +static char loginstr[] = "<L>ogin "; +static char logoutstr[]= "<L>ogout "; + +struct { + unsigned int baseurl : 1; // Do we need to specify by url + unsigned int mountcd : 1; // Should we mount the cd + unsigned int winrep : 1; // Want to repair windows? + unsigned int linrep : 1; // Want to repair linux? +} flags; + +// Some menu options +t_menuitem *baseurl,*mountcd,*network,*runprep,*winrep,*linrep; +t_menuitem * stat,*dhcp,*none,*prepopt,*secret; + +// all the menus we are going to declare +unsigned char TESTING,RESCUE,MAIN,PREPMENU,NETMENU,LONGMENU,SECRETMENU; + +char username[12]; // Name of user currently using the system + +/* End globals */ + +TIMEOUTCODE ontimeout() +{ + beep(); + return CODE_WAIT; +} + + +#define INFLINE 22 +#define PWDLINE 3 +#define PWDPROMPT 21 +#define PWDCOLUMN 60 +#define PWDATTR 0x74 +#define EDITPROMPT 21 + +void keys_handler(t_menusystem *ms, t_menuitem *mi,unsigned int scancode) +{ + char nc; + + if ((scancode >> 8) == F1) { // If scancode of F1 + runhelpsystem(mi->helpid); + } + // If user hit TAB, and item is an "executable" item + // and user has privileges to edit it, edit it in place. + if (((scancode & 0xFF) == 0x09) && (mi->action == OPT_RUN) && + (isallowed(username,"editcmd") || isallowed(username,"root"))) { + nc = getnumcols(); + // User typed TAB and has permissions to edit command line + gotoxy(EDITPROMPT,1,ms->menupage); + csprint("Command line:",0x07); + editstring(mi->data,ACTIONLEN); + gotoxy(EDITPROMPT,1,ms->menupage); + cprint(' ',0x07,nc-1,ms->menupage); + } +} + +t_handler_return login_handler(t_menusystem *ms, t_menuitem *mi) +{ + (void)mi; // Unused + char pwd[40]; + char login[40]; + char nc; + t_handler_return rv; + + if (mi->item == loginstr) { /* User wants to login */ + nc = getnumcols(); + gotoxy(PWDPROMPT,1,ms->menupage); + csprint("Enter Username: ",0x07); + getstring(login, sizeof username); + gotoxy(PWDPROMPT,1,ms->menupage); + cprint(' ',0x07,nc,ms->menupage); + csprint("Enter Password: ",0x07); + getpwd(pwd, sizeof pwd); + gotoxy(PWDPROMPT,1,ms->menupage); + cprint(' ',0x07,nc,ms->menupage); + + if (authenticate_user(login,pwd)) + { + strcpy(username,login); + mi->item = logoutstr; // Change item to read "Logout" + } + else strcpy(username,GUEST_USER); + } + else // User needs to logout + { + strcpy(username,GUEST_USER); + mi->item = loginstr; + } + + if (strcmp(username,GUEST_USER)==0) + { + prepopt->action = OPT_INACTIVE; + secret->action = OPT_INVISIBLE; + } + else + { + prepopt->action = OPT_SUBMENU; + prepopt->itemdata.radiomenunum = PREPMENU; + secret->action = OPT_SUBMENU; + secret->itemdata.submenunum = SECRETMENU; + } + rv.valid = 0; + rv.refresh = 1; + return rv; +} + +void msys_handler(t_menusystem *ms, t_menuitem *mi) +{ + char nc; + void *v; + nc = getnumcols(); // Get number of columns + + gotoxy(PWDLINE,PWDCOLUMN,ms->menupage); + csprint("User: ",PWDATTR); + cprint(ms->fillchar,ms->fillattr,sizeof username,ms->menupage); + gotoxy(PWDLINE,PWDCOLUMN +6,ms->menupage); + csprint(username,PWDATTR); + + if (mi->parindex != PREPMENU) // If we are not in the PREP MENU + { + gotoxy(INFLINE,0,ms->menupage); + cprint(' ',0x07,nc,ms->menupage); + gotoxy(INFLINE+1,0,ms->menupage); + cprint(' ',0x07,nc,ms->menupage); + return; + } + strcpy (infoline," "); + if (flags.baseurl) strcat(infoline,"baseurl=http://192.168.11.12/gui "); + if (flags.mountcd) strcat(infoline,"mountcd=yes "); + v = (void *)network->data; + if (v!=NULL) // Some network option specified + { + strcat(infoline,"network="); + strcat(infoline,(char *)(((t_menuitem *)v)->data)); + } + if (flags.winrep) strcat(infoline,"repair=win "); + if (flags.linrep) strcat(infoline,"repair=lin "); + + gotoxy(INFLINE,0,ms->menupage); + cprint(' ',0x07,nc,ms->menupage); + gotoxy(INFLINE+1,0,ms->menupage); + cprint(' ',0x07,nc,ms->menupage); + gotoxy(INFLINE,0,ms->menupage); + csprint("Kernel Arguments:",0x07); + gotoxy(INFLINE,17,ms->menupage); + csprint(infoline,0x07); +} + +t_handler_return network_handler(t_menusystem *ms, t_menuitem *mi) +{ + // mi=network since this is handler only for that. + (void)ms; // Unused + + if (mi->data == (void *)none) mi->item = nonet; + if (mi->data == (void *)stat) mi->item = statnet; + if (mi->data == (void *)dhcp) mi->item = dhcpnet; + return ACTION_INVALID; // VALID or INVALID does not matter +} + +t_handler_return checkbox_handler(t_menusystem *ms, t_menuitem *mi) +{ + (void)ms; /* Unused */ + + if (mi->action != OPT_CHECKBOX) return ACTION_INVALID; + + if (strcmp(mi->data,"baseurl") == 0) flags.baseurl = (mi->itemdata.checked ? 1 : 0); + if (strcmp(mi->data,"winrepair") == 0) { + if (mi->itemdata.checked) + { + flags.winrep = 1; + linrep->action = OPT_INACTIVE; + } + else + { + flags.winrep = 0; + linrep->action = OPT_CHECKBOX; + } + } + if (strcmp(mi->data,"linrepair") == 0) { + if (mi->itemdata.checked) + { + flags.linrep = 1; + winrep->action = OPT_INACTIVE; + } + else + { + flags.winrep = 0; + winrep->action = OPT_CHECKBOX; + } + } + if (strcmp(mi->data,"mountcd") == 0) flags.mountcd = (mi->itemdata.checked ? 1 : 0); + return ACTION_VALID; +} + +/* + Clears keyboard buffer and then + wait for stepsize*numsteps milliseconds for user to press any key + checks for keypress every stepsize milliseconds. + Returns: 1 if user pressed a key (not read from the buffer), + 0 if time elapsed +*/ +int checkkeypress(int stepsize, int numsteps) +{ + int i; + clearkbdbuf(); + for (i=0; i < numsteps; i++) + { + if (checkkbdbuf()) return 1; + sleep(stepsize); + } + return 0; +} + +int main() +{ + t_menuitem * curr; + char cmd[160]; + char ip[30]; + + // Set default username as guest + strcpy(username,GUEST_USER); + + // Switch video mode here + // setvideomode(0x18); // or whatever mode you want + + // Choose the default title and setup default values for all attributes.... + init_passwords("/isolinux/password"); + init_help("/isolinux/help"); + init_menusystem(NULL); + set_window_size(1,1,20,78); // Leave some space around + + // Choose the default values for all attributes and char's + // -1 means choose defaults (Actually the next 4 lines are not needed) + //set_normal_attr (-1,-1,-1,-1); + //set_status_info (-1,-1); // Display status on the last line + //set_title_info (-1,-1); + //set_misc_info(-1,-1,-1,-1); + + // Register the menusystem handler + reg_handler(HDLR_SCREEN,&msys_handler); + reg_handler(HDLR_KEYS,&keys_handler); + // Register the ontimeout handler, with a time out of 10 seconds + reg_ontimeout(ontimeout,1000,0); + + NETMENU = add_menu(" Init Network ",-1); + none = add_item("<N>one","Dont start network",OPT_RADIOITEM,"no ",0); + dhcp = add_item("<d>hcp","Use DHCP",OPT_RADIOITEM,"dhcp ",0); + stat = add_item("<s>tatic","Use static IP I will specify later",OPT_RADIOITEM,"static ",0); + + TESTING = add_menu(" Testing ",-1); + set_menu_pos(5,55); + add_item("<M>emory Test","Perform extensive memory testing",OPT_RUN, "memtest",0); + add_item("<I>nvisible","You dont see this",OPT_INVISIBLE,"junk",0); + add_item("<E>xit this menu","Go one level up",OPT_EXITMENU,"exit",0); + + RESCUE = add_menu(" Rescue Options ",-1); + add_item("<L>inux Rescue","linresc",OPT_RUN,"linresc",0); + add_item("<D>os Rescue","dosresc",OPT_RUN,"dosresc",0); + add_item("<W>indows Rescue","winresc",OPT_RUN,"winresc",0); + add_item("<E>xit this menu","Go one level up",OPT_EXITMENU,"exit",0); + + PREPMENU = add_menu(" Prep options ",-1); + baseurl = add_item("<b>aseurl by IP?","Specify gui baseurl by IP address",OPT_CHECKBOX,"baseurl",0); + mountcd = add_item("<m>ountcd?","Mount the cdrom drive?",OPT_CHECKBOX,"mountcd",0); + network = add_item(dhcpnet,"How to initialise network device?",OPT_RADIOMENU,NULL,NETMENU); + add_sep(); + winrep = add_item("Reinstall <w>indows","Re-install the windows side of a dual boot setup",OPT_CHECKBOX,"winrepair",0); + linrep = add_item("Reinstall <l>inux","Re-install the linux side of a dual boot setup",OPT_CHECKBOX,"linrepair",0); + add_sep(); + runprep = add_item("<R>un prep now","Execute prep with the above options",OPT_RUN,"prep",0); + add_item("<E>xit this menu","Go up one level",OPT_EXITMENU,"exitmenu",0); + baseurl->handler = &checkbox_handler; + mountcd->handler = &checkbox_handler; + winrep->handler = &checkbox_handler; + linrep->handler = &checkbox_handler; + network->handler = &network_handler; + flags.baseurl = 0; + flags.mountcd = 0; + flags.winrep = 0; + flags.linrep = 0; + + SECRETMENU = add_menu(" Secret Menu ",-1); + add_item("secret 1","Secret",OPT_RUN,"A",0); + add_item("secret 2","Secret",OPT_RUN,"A",0); + + LONGMENU = add_menu(" Long Menu ",40); // Override default here + add_item("<A>a","Aa",OPT_RUN,"A",0); + add_item("<B>b","Ab",OPT_RUN,"A",0); + add_item("<C>","A",OPT_RUN,"A",0); + add_item("<D>","A",OPT_RUN,"A",0); + add_item("<E>","A",OPT_RUN,"A",0); + add_item("<F>","A",OPT_RUN,"A",0); + add_item("<G>","A",OPT_RUN,"A",0); + add_item("<H>","A",OPT_RUN,"A",0); + add_item("<I>","A",OPT_RUN,"A",0); + add_item("<J>","A",OPT_RUN,"A",0); + add_item("<K>","A",OPT_RUN,"A",0); + add_item("<L>","A",OPT_RUN,"A",0); + add_item("<J>","A",OPT_RUN,"A",0); + add_item("<K>","A",OPT_RUN,"A",0); + add_item("<L>","A",OPT_RUN,"A",0); + add_item("<M>","A",OPT_RUN,"A",0); + add_item("<N>","A",OPT_RUN,"A",0); + add_item("<O>","A",OPT_RUN,"A",0); + add_item("<P>","A",OPT_RUN,"A",0); + add_item("<Q>","A",OPT_RUN,"A",0); + add_item("<R>","A",OPT_RUN,"A",0); + add_item("<S>","A",OPT_RUN,"A",0); + add_item("<T>","A",OPT_RUN,"A",0); + add_item("<U>","A",OPT_RUN,"A",0); + add_item("<V>","A",OPT_RUN,"A",0); + add_item("<W>","A",OPT_RUN,"A",0); + add_item("<X>","A",OPT_RUN,"A",0); + add_item("<Y>","A",OPT_RUN,"A",0); + add_item("<Z>","A",OPT_RUN,"A",0); + add_item("<1>","A",OPT_RUN,"A",0); + add_item("<2>","A",OPT_RUN,"A",0); + add_item("<3>","A",OPT_RUN,"A",0); + add_item("<4>","A",OPT_RUN,"A",0); + add_item("<5>","A",OPT_RUN,"A",0); + add_item("<6>","A",OPT_RUN,"A",0); + add_item("<7>","A",OPT_RUN,"A",0); + add_item("<8>","A",OPT_RUN,"A",0); + add_item("<9>","A",OPT_RUN,"A",0); + + MAIN = add_menu(" Main Menu ",8); + curr = add_item(loginstr,"Login as a privileged user",OPT_RUN,NULL,0); + set_item_options(-1,23); + curr->handler = &login_handler; + + add_item("<P>repare","prep",OPT_RUN,"prep",0); + set_item_options(-1,24); + prepopt = add_item("<P>rep options...","Options for prep image: Requires authenticated user",OPT_INACTIVE,NULL,PREPMENU); + set_item_options(-1,25); + + add_item("<R>escue options...","Troubleshoot a system",OPT_SUBMENU,NULL,RESCUE); + set_item_options(-1,26); + add_item("<T>esting...","Options to test hardware",OPT_SUBMENU,NULL,TESTING); + set_item_options(-1,27); + add_item("<L>ong Menu...","test menu system",OPT_SUBMENU,NULL,LONGMENU); + set_item_options(-1,28); + secret = add_item("<S>ecret Menu...","Secret menu",OPT_INVISIBLE,NULL,SECRETMENU); + set_item_options(-1,29); + add_item("<E>xit to prompt", "Exit the menu system", OPT_EXITMENU, "exit", 0); + set_item_options(-1,30); + csprint("Press any key within 5 seconds to show menu...",0x07); + if (!checkkeypress(100,50)) // Granularity of 100 milliseconds + { + csprint("Sorry! Time's up.\r\n",0x07); + return 1; + } + else clearkbdbuf(); // Just in case user pressed something important + curr = showmenus(MAIN); + if (curr) + { + if (curr->action == OPT_RUN) + { + strcpy(cmd,curr->data); + if (curr == runprep) + { + strcat(cmd,infoline); + if (network->data == (void *)stat) // We want static + { + csprint("Enter IP address (last two octets only): ",0x07); + strcpy(ip, "Junk"); + editstring(ip, sizeof ip); + strcat(cmd,"ipaddr=192.168."); + strcat(cmd,ip); + } + } + if (issyslinux()) + runsyslinuxcmd(cmd); + else csprint(cmd,0x07); + return 1; // Should not happen when run from SYSLINUX + } + } + // If user quits the menu system, control comes here + // If you want to execute some specific command uncomment the next two lines + + // if (syslinux) runcommand(YOUR_COMMAND_HERE); + // else csprint(YOUR_COMMAND_HERE,0x07); + + // Deallocate space used for these data structures + close_passwords(); + close_help(); + close_menusystem(); + + // Return to prompt + return 0; +} + diff --git a/syslinux/menu/libmenu/com32io.c b/syslinux/menu/libmenu/com32io.c new file mode 100644 index 0000000..a493142 --- /dev/null +++ b/syslinux/menu/libmenu/com32io.c @@ -0,0 +1,147 @@ +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#include <string.h> +#include <com32.h> +#include "com32io.h" +#include "syslnx.h" + +com32sys_t inreg,outreg; // Global register sets for use + +/* Print character and attribute at cursor */ +void cprint(char chr,char attr,unsigned int times,char disppage) +{ + REG_AH(inreg) = 0x09; + REG_AL(inreg) = chr; + REG_BH(inreg) = disppage; + REG_BL(inreg) = attr; + REG_CX(inreg) = times; + __intcall(0x10,&inreg,&outreg); +} + +void setdisppage(char num) // Set the display page to specified number +{ + REG_AH(inreg) = 0x05; + REG_AL(inreg) = num; + __intcall(0x10,&inreg,&outreg); +} + +char getdisppage() // Get current display page +{ + REG_AH(inreg) = 0x0f; + __intcall(0x10,&inreg,&outreg); + return REG_BH(outreg); +} + +void getpos(char * row, char * col, char page) +{ + REG_AH(inreg) = 0x03; + REG_BH(inreg) = page; + __intcall(0x10,&inreg,&outreg); + *row = REG_DH(outreg); + *col = REG_DL(outreg); +} + +void gotoxy(char row,char col, char page) +{ + REG_AH(inreg) = 0x02; + REG_BH(inreg) = page; + REG_DX(inreg) = (row << 8)+col; + __intcall(0x10,&inreg,&outreg); +} + +unsigned char sleep(unsigned int msec) +{ + unsigned long micro = 1000*msec; + + REG_AH(inreg) = 0x86; + REG_CX(inreg) = (micro >> 16); + REG_DX(inreg) = (micro % 0x10000); + __intcall(0x15,&inreg,&outreg); + return REG_AH(outreg); +} + +void beep() +{ + REG_AH(inreg) = 0x0E; + REG_AL(inreg) = 0x07; + REG_BH(inreg) = 0; + __intcall(0x10,&inreg,&outreg); +} + +void scrollup() +{ + unsigned int dx = (getnumrows()<< 8) + getnumcols(); + REG_AH(inreg) = 0x06; + REG_AL(inreg) = 0x01; + REG_BH(inreg) = 0x07; // Attribute to write blanks lines + REG_DX(inreg) = dx; // BOT RIGHT corner to window + REG_CX(inreg) = 0; // TOP LEFT of window +} + +char inputc(char * scancode) +{ + REG_AH(inreg) = 0x10; + __intcall(0x16,&inreg,&outreg); + if (scancode) + *scancode = REG_AH(outreg); + return REG_AL(outreg); +} + +void getcursorshape(char *start, char *end) +{ + char page = getdisppage(); + REG_AH(inreg) = 0x03; + REG_BH(inreg) = page; + __intcall(0x10,&inreg,&outreg); + *start = REG_CH(outreg); + *end = REG_CL(outreg); +} + +void setcursorshape(char start, char end) +{ + REG_AH(inreg) = 0x01; + REG_CH(inreg) = start; + REG_CL(inreg) = end; + __intcall(0x10,&inreg,&outreg); +} + +char getchar(void) +{ + REG_AH(inreg) = 0x08; + __intcall(0x21,&inreg,&outreg); + return REG_AL(outreg); +} + +void setvideomode(char mode) +{ + REG_AH(inreg) = 0x00; + REG_AL(inreg) = mode; + __intcall(0x10,&inreg,&outreg); +} + +unsigned char checkkbdbuf() +{ + REG_AH(inreg) = 0x11; + __intcall(0x16,&inreg,&outreg); + return (outreg.eflags.l & EFLAGS_ZF); +} + +// Get char displayed at current position +unsigned char getcharat(char page) +{ + REG_AH(inreg) = 0x08; + REG_BH(inreg) = page; + __intcall(0x16,&inreg,&outreg); + return REG_AL(outreg); +} + diff --git a/syslinux/menu/libmenu/com32io.h b/syslinux/menu/libmenu/com32io.h new file mode 100644 index 0000000..899260d --- /dev/null +++ b/syslinux/menu/libmenu/com32io.h @@ -0,0 +1,97 @@ +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#ifndef __COM32IO_H__ +#define __COM32IO_H__ + +#include <com32.h> + +#ifndef NULL +#define NULL ((void *)0) +#endif + +/* BIOS Assisted output routines */ + +void cswprint(const char *str, char attr, char left); +// Print a C str (NUL-terminated) respecting the left edge of window +// i.e. \n in str will move cursor to column left +// Print a C str (NUL-terminated) + +static inline void csprint(const char *str, char attr) +{ + cswprint(str,attr,0); +} + +void cprint(char chr,char attr,unsigned int times, char disppage); // Print a char + +void setdisppage(char num); // Set the display page to specified number + +char getdisppage(); // Get current display page + +void gotoxy(char row,char col, char page); + +void getpos(char * row, char * col, char page); + +char inputc(char * scancode); // Return ASCII char by val, and scancode by reference + +static inline void putch(char x, char attr, char page) +{ + cprint(x,attr,1,page); +} + +void setcursorshape(char start,char end); // Set cursor shape +void getcursorshape(char *start,char *end); // Get shape for current page + +// Get char displayed at current position in specified page +unsigned char getcharat(char page); + +static inline void cursoroff(void) /* Turns off cursor */ +{ + setcursorshape(32,33); +} + +static inline void cursoron(void) /* Turns on cursor */ +{ + setcursorshape(6,7); +} + +static inline unsigned char readbiosb(unsigned int ofs) +{ + return *((unsigned char *)MK_PTR(0,ofs)); +} + +static inline char getnumrows() +{ + return readbiosb(0x484); // Actually numrows - 1 +} + +static inline char getnumcols(void) +{ + return readbiosb(0x44a); // Actually numcols +} + +void scrollup(); //Scroll up display screen by one line + +void setvideomode(char mode); // Set the video mode. + +unsigned char sleep(unsigned int msec); // Sleep for specified time + +void beep(); // A Bell + +unsigned char checkkbdbuf(); // Check to see if there is kbd buffer is non-empty? + +static inline void clearkbdbuf() // Clear the kbd buffer (how many chars removed?) +{ + while (checkkbdbuf()) inputc(NULL); +} + +#endif diff --git a/syslinux/menu/libmenu/des.c b/syslinux/menu/libmenu/des.c new file mode 100644 index 0000000..6309453 --- /dev/null +++ b/syslinux/menu/libmenu/des.c @@ -0,0 +1,1102 @@ +/* + * FreeSec: libcrypt for NetBSD + * + * Copyright (c) 1994 David Burren + * All rights reserved. + * + * Adapted for FreeBSD-2.0 by Geoffrey M. Rehmet + * this file should now *only* export crypt(), in order to make + * binaries of libcrypt exportable from the USA + * + * Adapted for FreeBSD-4.0 by Mark R V Murray + * this file should now *only* export crypt_des(), in order to make + * a module that can be optionally included in libcrypt. + * + * Adapted for pxelinux menu environment by Th.Gebhardt + * removed dependencies of standard C libs + * added LOWSPACE option (using common space for different arrays) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of other contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This is an original implementation of the DES and the crypt(3) interfaces + * by David Burren <davidb@werj.com.au>. + * + * An excellent reference on the underlying algorithm (and related + * algorithms) is: + * + * B. Schneier, Applied Cryptography: protocols, algorithms, + * and source code in C, John Wiley & Sons, 1994. + * + * Note that in that book's description of DES the lookups for the initial, + * pbox, and final permutations are inverted (this has been brought to the + * attention of the author). A list of errata for this book has been + * posted to the sci.crypt newsgroup by the author and is available for FTP. + * + * ARCHITECTURE ASSUMPTIONS: + * It is assumed that the 8-byte arrays passed by reference can be + * addressed as arrays of u_int32_t's (ie. the CPU is not picky about + * alignment). + */ + + +#define LOWSPACE + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +typedef unsigned long my_u_int32_t; +typedef unsigned char my_u_char_t; + +/* Re-entrantify me -- all this junk needs to be in + * struct crypt_data to make this really reentrant... */ +static my_u_char_t inv_key_perm[64]; +static my_u_char_t inv_comp_perm[56]; +static my_u_char_t u_sbox[8][64]; +static my_u_char_t un_pbox[32]; +static my_u_int32_t en_keysl[16], en_keysr[16]; +static my_u_int32_t de_keysl[16], de_keysr[16]; + +#ifndef LOWSPACE +static my_u_int32_t ip_maskl[8][256], ip_maskr[8][256]; +static my_u_int32_t fp_maskl[8][256], fp_maskr[8][256]; +static my_u_int32_t key_perm_maskl[8][128], key_perm_maskr[8][128]; +static my_u_int32_t comp_maskl[8][128], comp_maskr[8][128]; +#endif + +static my_u_int32_t saltbits; +static my_u_int32_t old_salt; +static my_u_int32_t old_rawkey0, old_rawkey1; + +#ifdef LOWSPACE +static my_u_int32_t common[8][256]; +#endif + +/* Static stuff that stays resident and doesn't change after + * being initialized, and therefore doesn't need to be made + * reentrant. */ +static my_u_char_t init_perm[64], final_perm[64]; +static my_u_char_t m_sbox[4][4096]; + +#ifndef LOWSPACE +static my_u_int32_t psbox[4][256]; +#endif + +/* A pile of data */ +static const my_u_char_t ascii64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +static const my_u_char_t IP[64] = { + 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8, + 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7 +}; + +static const my_u_char_t key_perm[56] = { + 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, + 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36, + 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, + 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4 +}; + +static const my_u_char_t key_shifts[16] = { + 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 +}; + +static const my_u_char_t comp_perm[48] = { + 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, + 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, + 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, + 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32 +}; + +/* + * No E box is used, as it's replaced by some ANDs, shifts, and ORs. + */ + +static const my_u_char_t sbox[8][64] = { + { + 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, + 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, + 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, + 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 + }, + { + 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, + 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, + 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, + 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 + }, + { + 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, + 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, + 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, + 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 + }, + { + 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, + 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, + 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, + 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 + }, + { + 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, + 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, + 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, + 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 + }, + { + 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, + 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, + 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, + 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 + }, + { + 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, + 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, + 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, + 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 + }, + { + 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, + 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, + 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, + 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 + } +}; + +static const my_u_char_t pbox[32] = { + 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, + 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25 +}; + +static const my_u_int32_t bits32[32] = +{ + 0x80000000, 0x40000000, 0x20000000, 0x10000000, + 0x08000000, 0x04000000, 0x02000000, 0x01000000, + 0x00800000, 0x00400000, 0x00200000, 0x00100000, + 0x00080000, 0x00040000, 0x00020000, 0x00010000, + 0x00008000, 0x00004000, 0x00002000, 0x00001000, + 0x00000800, 0x00000400, 0x00000200, 0x00000100, + 0x00000080, 0x00000040, 0x00000020, 0x00000010, + 0x00000008, 0x00000004, 0x00000002, 0x00000001 +}; + +static const my_u_int32_t bits28[28] = +{ + 0x08000000, 0x04000000, 0x02000000, 0x01000000, + 0x00800000, 0x00400000, 0x00200000, 0x00100000, + 0x00080000, 0x00040000, 0x00020000, 0x00010000, + 0x00008000, 0x00004000, 0x00002000, 0x00001000, + 0x00000800, 0x00000400, 0x00000200, 0x00000100, + 0x00000080, 0x00000040, 0x00000020, 0x00000010, + 0x00000008, 0x00000004, 0x00000002, 0x00000001 +}; + +static const my_u_int32_t bits24[24] = +{ + 0x00800000, 0x00400000, 0x00200000, 0x00100000, + 0x00080000, 0x00040000, 0x00020000, 0x00010000, + 0x00008000, 0x00004000, 0x00002000, 0x00001000, + 0x00000800, 0x00000400, 0x00000200, 0x00000100, + 0x00000080, 0x00000040, 0x00000020, 0x00000010, + 0x00000008, 0x00000004, 0x00000002, 0x00000001 +}; + +static const my_u_char_t bits8[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; +// static const my_u_int32_t *bits28, *bits24; + + +static int +ascii_to_bin(char ch) +{ + if (ch > 'z') + return(0); + if (ch >= 'a') + return(ch - 'a' + 38); + if (ch > 'Z') + return(0); + if (ch >= 'A') + return(ch - 'A' + 12); + if (ch > '9') + return(0); + if (ch >= '.') + return(ch - '.'); + return(0); +} + +static void +des_init(void) +{ + +#ifdef LOWSPACE + int i, j, b; +#else + int i, j, b, k, inbit, obit; + my_u_int32_t *p, *il, *ir, *fl, *fr; +#endif + static int des_initialised = 0; + + if (des_initialised==1) + return; + + old_rawkey0 = old_rawkey1 = 0L; + saltbits = 0L; + old_salt = 0L; + // bits24 = (bits28 = bits32 + 4) + 4; + + /* + * Invert the S-boxes, reordering the input bits. + */ + for (i = 0; i < 8; i++) + for (j = 0; j < 64; j++) { + b = (j & 0x20) | ((j & 1) << 4) | ((j >> 1) & 0xf); + u_sbox[i][j] = sbox[i][b]; + } + + /* + * Convert the inverted S-boxes into 4 arrays of 8 bits. + * Each will handle 12 bits of the S-box input. + */ + for (b = 0; b < 4; b++) + for (i = 0; i < 64; i++) + for (j = 0; j < 64; j++) + m_sbox[b][(i << 6) | j] = + (my_u_char_t)((u_sbox[(b << 1)][i] << 4) | + u_sbox[(b << 1) + 1][j]); + + /* + * Set up the initial & final permutations into a useful form, and + * initialise the inverted key permutation. + */ + for (i = 0; i < 64; i++) { + init_perm[final_perm[i] = IP[i] - 1] = (my_u_char_t)i; + inv_key_perm[i] = 255; + } + + /* + * Invert the key permutation and initialise the inverted key + * compression permutation. + */ + for (i = 0; i < 56; i++) { + inv_key_perm[key_perm[i] - 1] = (my_u_char_t)i; + inv_comp_perm[i] = 255; + } + + /* + * Invert the key compression permutation. + */ + for (i = 0; i < 48; i++) { + inv_comp_perm[comp_perm[i] - 1] = (my_u_char_t)i; + } + + /* + * Set up the OR-mask arrays for the initial and final permutations, + * and for the key initial and compression permutations. + */ + +#ifndef LOWSPACE + for (k = 0; k < 8; k++) { + for (i = 0; i < 256; i++) { + *(il = &ip_maskl[k][i]) = 0L; + *(ir = &ip_maskr[k][i]) = 0L; + *(fl = &fp_maskl[k][i]) = 0L; + *(fr = &fp_maskr[k][i]) = 0L; + for (j = 0; j < 8; j++) { + inbit = 8 * k + j; + if (i & bits8[j]) { + if ((obit = init_perm[inbit]) < 32) + *il |= bits32[obit]; + else + *ir |= bits32[obit-32]; + if ((obit = final_perm[inbit]) < 32) + *fl |= bits32[obit]; + else + *fr |= bits32[obit - 32]; + } + } + } + for (i = 0; i < 128; i++) { + *(il = &key_perm_maskl[k][i]) = 0L; + *(ir = &key_perm_maskr[k][i]) = 0L; + for (j = 0; j < 7; j++) { + inbit = 8 * k + j; + if (i & bits8[j + 1]) { + if ((obit = inv_key_perm[inbit]) == 255) + continue; + if (obit < 28) + *il |= bits28[obit]; + else + *ir |= bits28[obit - 28]; + } + } + *(il = &comp_maskl[k][i]) = 0L; + *(ir = &comp_maskr[k][i]) = 0L; + for (j = 0; j < 7; j++) { + inbit = 7 * k + j; + if (i & bits8[j + 1]) { + if ((obit=inv_comp_perm[inbit]) == 255) + continue; + if (obit < 24) + *il |= bits24[obit]; + else + *ir |= bits24[obit - 24]; + } + } + } + } +#endif + + /* + * Invert the P-box permutation, and convert into OR-masks for + * handling the output of the S-box arrays setup above. + */ + for (i = 0; i < 32; i++) + un_pbox[pbox[i] - 1] = (my_u_char_t)i; + +#ifndef LOWSPACE + for (b = 0; b < 4; b++) + for (i = 0; i < 256; i++) { + *(p = &psbox[b][i]) = 0L; + for (j = 0; j < 8; j++) { + if (i & bits8[j]) + *p |= bits32[un_pbox[8 * b + j]]; + } + } +#endif + des_initialised = 1; +} + + +#ifdef LOWSPACE + +static void +setup_ip_maskl(void) +{ + int i, j, k, inbit, obit; + my_u_int32_t *il; + + for (k = 0; k < 8; k++) { + for (i = 0; i < 256; i++) { + *(il = &common[k][i]) = 0L; + for (j = 0; j < 8; j++) { + inbit = 8 * k + j; + if (i & bits8[j]) { + if ((obit = init_perm[inbit]) < 32) + *il |= bits32[obit]; + } + } + } + } +} + +static void +setup_ip_maskr(void) +{ + int i, j, k, inbit, obit; + my_u_int32_t *ir; + + for (k = 0; k < 8; k++) { + for (i = 0; i < 256; i++) { + *(ir = &common[k][i]) = 0L; + for (j = 0; j < 8; j++) { + inbit = 8 * k + j; + if (i & bits8[j]) { + if ((obit = init_perm[inbit]) >= 32) + *ir |= bits32[obit-32]; + } + } + } + } +} + +static void +setup_fp_maskl(void) +{ + int i, j, k, inbit, obit; + my_u_int32_t *fl; + + for (k = 0; k < 8; k++) { + for (i = 0; i < 256; i++) { + *(fl = &common[k][i]) = 0L; + for (j = 0; j < 8; j++) { + inbit = 8 * k + j; + if (i & bits8[j]) { + if ((obit = final_perm[inbit]) < 32) + *fl |= bits32[obit]; + } + } + } + } +} + +static void +setup_fp_maskr(void) +{ + int i, j, k, inbit, obit; + my_u_int32_t *fr; + + for (k = 0; k < 8; k++) { + for (i = 0; i < 256; i++) { + *(fr = &common[k][i]) = 0L; + for (j = 0; j < 8; j++) { + inbit = 8 * k + j; + if (i & bits8[j]) { + if ((obit = final_perm[inbit]) >= 32) + *fr |= bits32[obit - 32]; + } + } + } + } +} + +static void +setup_key_perm_maskl(void) +{ + int i, j, k, inbit, obit; + my_u_int32_t *il; + + for (k = 0; k < 8; k++) { + for (i = 0; i < 128; i++) { + *(il = &common[k][i]) = 0L; + for (j = 0; j < 7; j++) { + inbit = 8 * k + j; + if (i & bits8[j + 1]) { + if ((obit = inv_key_perm[inbit]) == 255) + continue; + if (obit < 28) + *il |= bits28[obit]; + } + } + } + } +} + +static void +setup_key_perm_maskr(void) +{ + int i, j, k, inbit, obit; + my_u_int32_t *ir; + + for (k = 0; k < 8; k++) { + for (i = 0; i < 128; i++) { + *(ir = &common[k][i]) = 0L; + for (j = 0; j < 7; j++) { + inbit = 8 * k + j; + if (i & bits8[j + 1]) { + if ((obit = inv_key_perm[inbit]) == 255) + continue; + if (obit >= 28) + *ir |= bits28[obit - 28]; + } + } + } + } +} + +static void +setup_comp_maskl(void) +{ + int i, j, k, inbit, obit; + my_u_int32_t *il; + + for (k = 0; k < 8; k++) { + for (i = 0; i < 128; i++) { + *(il = &common[k][i]) = 0L; + for (j = 0; j < 7; j++) { + inbit = 7 * k + j; + if (i & bits8[j + 1]) { + if ((obit=inv_comp_perm[inbit]) == 255) + continue; + if (obit < 24) + *il |= bits24[obit]; + } + } + } + } +} + +static void +setup_comp_maskr(void) +{ + int i, j, k, inbit, obit; + my_u_int32_t *ir; + + for (k = 0; k < 8; k++) { + for (i = 0; i < 128; i++) { + *(ir = &common[k][i]) = 0L; + for (j = 0; j < 7; j++) { + inbit = 7 * k + j; + if (i & bits8[j + 1]) { + if ((obit=inv_comp_perm[inbit]) == 255) + continue; + if (obit >= 24) + *ir |= bits24[obit - 24]; + } + } + } + } +} + +static void +setup_psbox(void) +{ + int i, j, b; + my_u_int32_t *p; + + for (b = 0; b < 4; b++) + for (i = 0; i < 256; i++) { + *(p = &common[b][i]) = 0L; + for (j = 0; j < 8; j++) { + if (i & bits8[j]) + *p |= bits32[un_pbox[8 * b + j]]; + } + } +} + +#endif + +static void +setup_salt(my_u_int32_t salt) +{ + my_u_int32_t obit, saltbit; + int i; + + if (salt == old_salt) + return; + old_salt = salt; + + saltbits = 0L; + saltbit = 1; + obit = 0x800000; + for (i = 0; i < 24; i++) { + if (salt & saltbit) + saltbits |= obit; + saltbit <<= 1; + obit >>= 1; + } +} + + +static my_u_int32_t char_to_int(const char *key) +{ + my_u_int32_t byte0,byte1,byte2,byte3; + byte0 = (my_u_int32_t) (my_u_char_t) key[0]; + byte1 = (my_u_int32_t) (my_u_char_t) key[1]; + byte2 = (my_u_int32_t) (my_u_char_t) key[2]; + byte3 = (my_u_int32_t) (my_u_char_t) key[3]; + + return byte0 << 24 | byte1 << 16 | byte2 << 8 | byte3 ; +} + + +static int +des_setkey(const char *key) +{ + my_u_int32_t k0, k1, rawkey0, rawkey1; + int shifts, round; + + des_init(); + + /* rawkey0 = ntohl(*(const my_u_int32_t *) key); + * rawkey1 = ntohl(*(const my_u_int32_t *) (key + 4)); + */ + + rawkey0 = char_to_int(key); + rawkey1 = char_to_int(key+4); + + if ((rawkey0 | rawkey1) + && rawkey0 == old_rawkey0 + && rawkey1 == old_rawkey1) { + /* + * Already setup for this key. + * This optimisation fails on a zero key (which is weak and + * has bad parity anyway) in order to simplify the starting + * conditions. + */ + return(0); + } + old_rawkey0 = rawkey0; + old_rawkey1 = rawkey1; + + /* + * Do key permutation and split into two 28-bit subkeys. + */ + +#ifdef LOWSPACE + setup_key_perm_maskl(); + k0 = common[0][rawkey0 >> 25] + | common[1][(rawkey0 >> 17) & 0x7f] + | common[2][(rawkey0 >> 9) & 0x7f] + | common[3][(rawkey0 >> 1) & 0x7f] + | common[4][rawkey1 >> 25] + | common[5][(rawkey1 >> 17) & 0x7f] + | common[6][(rawkey1 >> 9) & 0x7f] + | common[7][(rawkey1 >> 1) & 0x7f]; + setup_key_perm_maskr(); + k1 = common[0][rawkey0 >> 25] + | common[1][(rawkey0 >> 17) & 0x7f] + | common[2][(rawkey0 >> 9) & 0x7f] + | common[3][(rawkey0 >> 1) & 0x7f] + | common[4][rawkey1 >> 25] + | common[5][(rawkey1 >> 17) & 0x7f] + | common[6][(rawkey1 >> 9) & 0x7f] + | common[7][(rawkey1 >> 1) & 0x7f]; +#else + k0 = key_perm_maskl[0][rawkey0 >> 25] + | key_perm_maskl[1][(rawkey0 >> 17) & 0x7f] + | key_perm_maskl[2][(rawkey0 >> 9) & 0x7f] + | key_perm_maskl[3][(rawkey0 >> 1) & 0x7f] + | key_perm_maskl[4][rawkey1 >> 25] + | key_perm_maskl[5][(rawkey1 >> 17) & 0x7f] + | key_perm_maskl[6][(rawkey1 >> 9) & 0x7f] + | key_perm_maskl[7][(rawkey1 >> 1) & 0x7f]; + k1 = key_perm_maskr[0][rawkey0 >> 25] + | key_perm_maskr[1][(rawkey0 >> 17) & 0x7f] + | key_perm_maskr[2][(rawkey0 >> 9) & 0x7f] + | key_perm_maskr[3][(rawkey0 >> 1) & 0x7f] + | key_perm_maskr[4][rawkey1 >> 25] + | key_perm_maskr[5][(rawkey1 >> 17) & 0x7f] + | key_perm_maskr[6][(rawkey1 >> 9) & 0x7f] + | key_perm_maskr[7][(rawkey1 >> 1) & 0x7f]; +#endif + + /* + * Rotate subkeys and do compression permutation. + */ + shifts = 0; + for (round = 0; round < 16; round++) { + my_u_int32_t t0, t1; + + shifts += key_shifts[round]; + + t0 = (k0 << shifts) | (k0 >> (28 - shifts)); + t1 = (k1 << shifts) | (k1 >> (28 - shifts)); + +#ifdef LOWSPACE + setup_comp_maskl(); + de_keysl[15 - round] = + en_keysl[round] = common[0][(t0 >> 21) & 0x7f] + | common[1][(t0 >> 14) & 0x7f] + | common[2][(t0 >> 7) & 0x7f] + | common[3][t0 & 0x7f] + | common[4][(t1 >> 21) & 0x7f] + | common[5][(t1 >> 14) & 0x7f] + | common[6][(t1 >> 7) & 0x7f] + | common[7][t1 & 0x7f]; + + setup_comp_maskr(); + de_keysr[15 - round] = + en_keysr[round] = common[0][(t0 >> 21) & 0x7f] + | common[1][(t0 >> 14) & 0x7f] + | common[2][(t0 >> 7) & 0x7f] + | common[3][t0 & 0x7f] + | common[4][(t1 >> 21) & 0x7f] + | common[5][(t1 >> 14) & 0x7f] + | common[6][(t1 >> 7) & 0x7f] + | common[7][t1 & 0x7f]; +#else + de_keysl[15 - round] = + en_keysl[round] = comp_maskl[0][(t0 >> 21) & 0x7f] + | comp_maskl[1][(t0 >> 14) & 0x7f] + | comp_maskl[2][(t0 >> 7) & 0x7f] + | comp_maskl[3][t0 & 0x7f] + | comp_maskl[4][(t1 >> 21) & 0x7f] + | comp_maskl[5][(t1 >> 14) & 0x7f] + | comp_maskl[6][(t1 >> 7) & 0x7f] + | comp_maskl[7][t1 & 0x7f]; + + de_keysr[15 - round] = + en_keysr[round] = comp_maskr[0][(t0 >> 21) & 0x7f] + | comp_maskr[1][(t0 >> 14) & 0x7f] + | comp_maskr[2][(t0 >> 7) & 0x7f] + | comp_maskr[3][t0 & 0x7f] + | comp_maskr[4][(t1 >> 21) & 0x7f] + | comp_maskr[5][(t1 >> 14) & 0x7f] + | comp_maskr[6][(t1 >> 7) & 0x7f] + | comp_maskr[7][t1 & 0x7f]; +#endif + } + return(0); +} + + +static int +do_des( my_u_int32_t l_in, my_u_int32_t r_in, my_u_int32_t *l_out, my_u_int32_t *r_out, int count) +{ + /* + * l_in, r_in, l_out, and r_out are in pseudo-"big-endian" format. + */ + my_u_int32_t l, r, *kl, *kr, *kl1, *kr1; + my_u_int32_t f, r48l, r48r; + int round; + + if (count == 0) { + return(1); + } else if (count > 0) { + /* + * Encrypting + */ + kl1 = en_keysl; + kr1 = en_keysr; + } else { + /* + * Decrypting + */ + count = -count; + kl1 = de_keysl; + kr1 = de_keysr; + } + + /* + * Do initial permutation (IP). + */ + +#ifdef LOWSPACE + setup_ip_maskl(); + l = common[0][l_in >> 24] + | common[1][(l_in >> 16) & 0xff] + | common[2][(l_in >> 8) & 0xff] + | common[3][l_in & 0xff] + | common[4][r_in >> 24] + | common[5][(r_in >> 16) & 0xff] + | common[6][(r_in >> 8) & 0xff] + | common[7][r_in & 0xff]; + setup_ip_maskr(); + r = common[0][l_in >> 24] + | common[1][(l_in >> 16) & 0xff] + | common[2][(l_in >> 8) & 0xff] + | common[3][l_in & 0xff] + | common[4][r_in >> 24] + | common[5][(r_in >> 16) & 0xff] + | common[6][(r_in >> 8) & 0xff] + | common[7][r_in & 0xff]; +#else + l = ip_maskl[0][l_in >> 24] + | ip_maskl[1][(l_in >> 16) & 0xff] + | ip_maskl[2][(l_in >> 8) & 0xff] + | ip_maskl[3][l_in & 0xff] + | ip_maskl[4][r_in >> 24] + | ip_maskl[5][(r_in >> 16) & 0xff] + | ip_maskl[6][(r_in >> 8) & 0xff] + | ip_maskl[7][r_in & 0xff]; + r = ip_maskr[0][l_in >> 24] + | ip_maskr[1][(l_in >> 16) & 0xff] + | ip_maskr[2][(l_in >> 8) & 0xff] + | ip_maskr[3][l_in & 0xff] + | ip_maskr[4][r_in >> 24] + | ip_maskr[5][(r_in >> 16) & 0xff] + | ip_maskr[6][(r_in >> 8) & 0xff] + | ip_maskr[7][r_in & 0xff]; +#endif + + while (count--) { + /* + * Do each round. + */ + kl = kl1; + kr = kr1; + round = 16; + while (round--) { + /* + * Expand R to 48 bits (simulate the E-box). + */ + r48l = ((r & 0x00000001) << 23) + | ((r & 0xf8000000) >> 9) + | ((r & 0x1f800000) >> 11) + | ((r & 0x01f80000) >> 13) + | ((r & 0x001f8000) >> 15); + + r48r = ((r & 0x0001f800) << 7) + | ((r & 0x00001f80) << 5) + | ((r & 0x000001f8) << 3) + | ((r & 0x0000001f) << 1) + | ((r & 0x80000000) >> 31); + /* + * Do salting for crypt() and friends, and + * XOR with the permuted key. + */ + f = (r48l ^ r48r) & saltbits; + r48l ^= f ^ *kl++; + r48r ^= f ^ *kr++; + /* + * Do sbox lookups (which shrink it back to 32 bits) + * and do the pbox permutation at the same time. + */ + +#ifdef LOWSPACE + setup_psbox(); + f = common[0][m_sbox[0][r48l >> 12]] + | common[1][m_sbox[1][r48l & 0xfff]] + | common[2][m_sbox[2][r48r >> 12]] + | common[3][m_sbox[3][r48r & 0xfff]]; +#else + f = psbox[0][m_sbox[0][r48l >> 12]] + | psbox[1][m_sbox[1][r48l & 0xfff]] + | psbox[2][m_sbox[2][r48r >> 12]] + | psbox[3][m_sbox[3][r48r & 0xfff]]; +#endif + /* + * Now that we've permuted things, complete f(). + */ + f ^= l; + l = r; + r = f; + } + r = l; + l = f; + } + /* + * Do final permutation (inverse of IP). + */ + +#ifdef LOWSPACE + setup_fp_maskl(); + *l_out = common[0][l >> 24] + | common[1][(l >> 16) & 0xff] + | common[2][(l >> 8) & 0xff] + | common[3][l & 0xff] + | common[4][r >> 24] + | common[5][(r >> 16) & 0xff] + | common[6][(r >> 8) & 0xff] + | common[7][r & 0xff]; + setup_fp_maskr(); + *r_out = common[0][l >> 24] + | common[1][(l >> 16) & 0xff] + | common[2][(l >> 8) & 0xff] + | common[3][l & 0xff] + | common[4][r >> 24] + | common[5][(r >> 16) & 0xff] + | common[6][(r >> 8) & 0xff] + | common[7][r & 0xff]; +#else + *l_out = fp_maskl[0][l >> 24] + | fp_maskl[1][(l >> 16) & 0xff] + | fp_maskl[2][(l >> 8) & 0xff] + | fp_maskl[3][l & 0xff] + | fp_maskl[4][r >> 24] + | fp_maskl[5][(r >> 16) & 0xff] + | fp_maskl[6][(r >> 8) & 0xff] + | fp_maskl[7][r & 0xff]; + *r_out = fp_maskr[0][l >> 24] + | fp_maskr[1][(l >> 16) & 0xff] + | fp_maskr[2][(l >> 8) & 0xff] + | fp_maskr[3][l & 0xff] + | fp_maskr[4][r >> 24] + | fp_maskr[5][(r >> 16) & 0xff] + | fp_maskr[6][(r >> 8) & 0xff] + | fp_maskr[7][r & 0xff]; +#endif + return(0); +} + + +#if 0 +static int +des_cipher(const char *in, char *out, my_u_int32_t salt, int count) +{ + my_u_int32_t l_out, r_out, rawl, rawr; + int retval; + union { + my_u_int32_t *ui32; + const char *c; + } trans; + + des_init(); + + setup_salt(salt); + + trans.c = in; + rawl = ntohl(*trans.ui32++); + rawr = ntohl(*trans.ui32); + + retval = do_des(rawl, rawr, &l_out, &r_out, count); + + trans.c = out; + *trans.ui32++ = htonl(l_out); + *trans.ui32 = htonl(r_out); + return(retval); +} +#endif + + +void +setkey(const char *key) +{ + int i, j; + my_u_int32_t packed_keys[2]; + my_u_char_t *p; + + p = (my_u_char_t *) packed_keys; + + for (i = 0; i < 8; i++) { + p[i] = 0; + for (j = 0; j < 8; j++) + if (*key++ & 1) + p[i] |= bits8[j]; + } + des_setkey(p); +} + + +void +encrypt(char *block, int flag) +{ + my_u_int32_t io[2]; + my_u_char_t *p; + int i, j; + + des_init(); + + setup_salt(0L); + p = block; + for (i = 0; i < 2; i++) { + io[i] = 0L; + for (j = 0; j < 32; j++) + if (*p++ & 1) + io[i] |= bits32[j]; + } + do_des(io[0], io[1], io, io + 1, flag ? -1 : 1); + for (i = 0; i < 2; i++) + for (j = 0; j < 32; j++) + block[(i << 5) | j] = (io[i] & bits32[j]) ? 1 : 0; +} + +char *crypt(const char *key, const char *setting) +{ + my_u_int32_t count, salt, l, r0, r1, keybuf[2]; + my_u_char_t *p, *q; + static char output[21]; + + des_init(); + + /* + * Copy the key, shifting each character up by one bit + * and padding with zeros. + */ + q = (my_u_char_t *)keybuf; + while (q - (my_u_char_t *)keybuf - 8) { + *q++ = *key << 1; + if (*(q - 1)) + key++; + } + if (des_setkey((char *)keybuf)) + return(NULL); + +#if 0 + if (*setting == _PASSWORD_EFMT1) { + int i; + /* + * "new"-style: + * setting - underscore, 4 bytes of count, 4 bytes of salt + * key - unlimited characters + */ + for (i = 1, count = 0L; i < 5; i++) + count |= ascii_to_bin(setting[i]) << ((i - 1) * 6); + + for (i = 5, salt = 0L; i < 9; i++) + salt |= ascii_to_bin(setting[i]) << ((i - 5) * 6); + + while (*key) { + /* + * Encrypt the key with itself. + */ + if (des_cipher((char *)keybuf, (char *)keybuf, 0L, 1)) + return(NULL); + /* + * And XOR with the next 8 characters of the key. + */ + q = (my_u_char_t *)keybuf; + while (q - (my_u_char_t *)keybuf - 8 && *key) + *q++ ^= *key++ << 1; + + if (des_setkey((char *)keybuf)) + return(NULL); + } + strncpy(output, setting, 9); + + /* + * Double check that we weren't given a short setting. + * If we were, the above code will probably have created + * wierd values for count and salt, but we don't really care. + * Just make sure the output string doesn't have an extra + * NUL in it. + */ + output[9] = '\0'; + p = (my_u_char_t *)output + strlen(output); + } else +#endif + { + /* + * "old"-style: + * setting - 2 bytes of salt + * key - up to 8 characters + */ + count = 25; + + salt = (ascii_to_bin(setting[1]) << 6) + | ascii_to_bin(setting[0]); + + output[0] = setting[0]; + /* + * If the encrypted password that the salt was extracted from + * is only 1 character long, the salt will be corrupted. We + * need to ensure that the output string doesn't have an extra + * NUL in it! + */ + output[1] = setting[1] ? setting[1] : output[0]; + + p = (my_u_char_t *)output + 2; + } + setup_salt(salt); + /* + * Do it. + */ + if (do_des(0L, 0L, &r0, &r1, (int)count)) + return(NULL); + /* + * Now encode the result... + */ + l = (r0 >> 8); + *p++ = ascii64[(l >> 18) & 0x3f]; + *p++ = ascii64[(l >> 12) & 0x3f]; + *p++ = ascii64[(l >> 6) & 0x3f]; + *p++ = ascii64[l & 0x3f]; + + l = (r0 << 16) | ((r1 >> 16) & 0xffff); + *p++ = ascii64[(l >> 18) & 0x3f]; + *p++ = ascii64[(l >> 12) & 0x3f]; + *p++ = ascii64[(l >> 6) & 0x3f]; + *p++ = ascii64[l & 0x3f]; + + l = r1 << 2; + *p++ = ascii64[(l >> 12) & 0x3f]; + *p++ = ascii64[(l >> 6) & 0x3f]; + *p++ = ascii64[l & 0x3f]; + *p = 0; + + return(output); +} + diff --git a/syslinux/menu/libmenu/des.h b/syslinux/menu/libmenu/des.h new file mode 100644 index 0000000..a03e58a --- /dev/null +++ b/syslinux/menu/libmenu/des.h @@ -0,0 +1,9 @@ + +#ifndef _DES_H_ +#define _DES_H_ + +// des crypt +extern char *crypt (const char *key, const char *salt); + +#endif + diff --git a/syslinux/menu/libmenu/help.c b/syslinux/menu/libmenu/help.c new file mode 100644 index 0000000..d591156 --- /dev/null +++ b/syslinux/menu/libmenu/help.c @@ -0,0 +1,84 @@ +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#include "help.h" +#include <stdio.h> +#include "string.h" + +char helpbasedir[HELPDIRLEN]; // name of help directory limited to HELPDIRLEN + +void showhelp(const char *filename) +{ + char nc,nr; + FILE *f; + char line[512]; // Max length of a line + + nc = getnumcols(); + nr = getnumrows(); + cls(); + drawbox(0,0,nr,nc-1,HELPPAGE,0x07,HELPBOX); + + drawhorizline(2,0,nc-1,HELPPAGE,0x07,HELPBOX,0); // dumb==0 + if (filename == NULL) { // print file contents + gotoxy(HELP_BODY_ROW,HELP_LEFT_MARGIN,HELPPAGE); + cswprint("Help system not initialized",0x07,HELP_LEFT_MARGIN); + return; + } + + f = fopen(filename,"r"); + if (!f) { // No such file + sprintf(line, "File %s not found",filename); + gotoxy(HELP_BODY_ROW,HELP_LEFT_MARGIN,HELPPAGE); + cswprint(line,0x07,HELP_LEFT_MARGIN); + return; + } + + // Now we have a file just print it. + fgets(line,sizeof line,f); // Get first line (TITLE) + gotoxy(1,(nc-strlen(line))/2,HELPPAGE); + csprint(line,0x07); + + gotoxy(HELP_BODY_ROW,HELP_LEFT_MARGIN,HELPPAGE); + while ( fgets(line, sizeof line, f) ) cswprint(line,0x07,HELP_LEFT_MARGIN); + fclose(f); +} + +void runhelpsystem(unsigned int helpid) +{ + char dp; + char scan; + char filename[HELPDIRLEN+16]; + + dp = getdisppage(); + if (dp != HELPPAGE) setdisppage(HELPPAGE); + if (helpbasedir[0] != 0) { + sprintf(filename,"%s/hlp%05d.txt",helpbasedir,helpid); + showhelp(filename); + } + else showhelp (NULL); + while (1) { + inputc(&scan); + if (scan == ESCAPE) break; + } + if (dp != HELPPAGE) setdisppage(dp); +} + +void init_help(const char *helpdir) +{ + if (helpdir != NULL) + strcpy(helpbasedir,helpdir); + else helpbasedir[0] = 0; +} + +void close_help(void) +{ +} diff --git a/syslinux/menu/libmenu/help.h b/syslinux/menu/libmenu/help.h new file mode 100644 index 0000000..45ef9d6 --- /dev/null +++ b/syslinux/menu/libmenu/help.h @@ -0,0 +1,39 @@ +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#ifndef __HELP_H_ +#define __HELP_H_ + +#include "menu.h" +#include "com32io.h" +#include "tui.h" +#include <string.h> + +// How many rows for the title +#define HELP_TITLE_HEIGHT 1 +#define HELP_BODY_ROW (HELP_TITLE_HEIGHT+3) +#define HELP_LEFT_MARGIN 2 +#define HELPBOX BOX_SINSIN +#define HELPDIRLEN 64 + +// Display one screen of help information +void showhelp(const char *filename); + +// Start the help system using id helpid +void runhelpsystem(unsigned int helpid); + +// Directory where help files are located +void init_help(const char *helpdir); +// Free internal datastructures +void close_help(void); + +#endif diff --git a/syslinux/menu/libmenu/menu.c b/syslinux/menu/libmenu/menu.c new file mode 100644 index 0000000..7d7e76d --- /dev/null +++ b/syslinux/menu/libmenu/menu.c @@ -0,0 +1,1148 @@ +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#include "menu.h" +#include <stdlib.h> + +// Local Variables +static pt_menusystem ms; // Pointer to the menusystem +char TITLESTR[] = "COMBOOT Menu System for SYSLINUX developed by Murali Krishnan Ganapathy"; +char TITLELONG[] = " TITLE too long "; +char ITEMLONG[] = " ITEM too long "; +char ACTIONLONG[] = " ACTION too long "; +char STATUSLONG[] = " STATUS too long "; +char EMPTYSTR[] = ""; + +/* Forward declarations */ +int calc_visible(pt_menu menu,int first); +int next_visible(pt_menu menu,int index); +int prev_visible(pt_menu menu,int index); +int next_visible_sep(pt_menu menu,int index); +int prev_visible_sep(pt_menu menu,int index); +int calc_first_early(pt_menu menu,int curr); +int calc_first_late(pt_menu menu,int curr); +int isvisible(pt_menu menu,int first, int curr); + + +/* Basic Menu routines */ + +// This is same as inputc except it honors the ontimeout handler +// and calls it when needed. For the callee, there is no difference +// as this will not return unless a key has been pressed. +char getch(char *scan) +{ + unsigned long i; + TIMEOUTCODE c; + + // Wait until keypress if no handler specified + if (ms->ontimeout==NULL) return inputc(scan); + + while (1) // Forever do + { + for (i=0; i < ms->tm_numsteps; i++) + { + if (checkkbdbuf()) return inputc(scan); + sleep(ms->tm_stepsize); + } + c = ms->ontimeout(); + switch(c) + { + case CODE_ENTER: // Pretend user hit enter + *scan = ENTERA; + return '\015'; // \015 octal = 13 + case CODE_ESCAPE: // Pretend user hit escape + *scan = ESCAPE; + return '\033'; // \033 octal = 27 + default: + break; + } + } + return 0; +} + +/* Print a menu item */ +/* attr[0] is non-hilite attr, attr[1] is highlight attr */ +void printmenuitem(const char *str,uchar* attr) +{ + uchar page = getdisppage(); + uchar row,col; + int hlite=NOHLITE; // Initially no highlighting + + getpos(&row,&col,page); + while ( *str ) { + switch (*str) + { + case '\b': + --col; + break; + case '\n': + ++row; + break; + case '\r': + col=0; + break; + case BELL: // No Bell Char + break; + case ENABLEHLITE: // Switch on highlighting + hlite = HLITE; + break; + case DISABLEHLITE: // Turn off highlighting + hlite = NOHLITE; + break; + default: + putch(*str, attr[hlite], page); + ++col; + } + if (col > getnumcols()) + { + ++row; + col=0; + } + if (row > getnumrows()) + { + scrollup(); + row= getnumrows(); + } + gotoxy(row,col,page); + str++; + } +} + +int find_shortcut(pt_menu menu,uchar shortcut, int index) +// Find the next index with specified shortcut key +{ + int ans; + pt_menuitem mi; + + // Garbage in garbage out + if ((index <0) || (index >= menu->numitems)) return index; + ans = index+1; + // Go till end of menu + while (ans < menu->numitems) + { + mi = menu->items[ans]; + if ((mi->action == OPT_INVISIBLE) || (mi->action == OPT_SEP) + || (mi->shortcut != shortcut)) + ans ++; + else return ans; + } + // Start at the beginning and try again + ans = 0; + while (ans < index) + { + mi = menu->items[ans]; + if ((mi->action == OPT_INVISIBLE) || (mi->action == OPT_SEP) + || (mi->shortcut != shortcut)) + ans ++; + else return ans; + } + return index; // Sorry not found +} + +// print the menu starting from FIRST +// will print a maximum of menu->menuheight items +void printmenu(pt_menu menu, int curr, uchar top, uchar left, uchar first) +{ + int x,row; // x = index, row = position from top + int numitems,menuwidth; + char fchar[5],lchar[5]; // The first and last char in for each entry + const char *str; // and inbetween the item or a seperator is printed + uchar *attr; // attribute attr + char sep[MENULEN];// and inbetween the item or a seperator is printed + pt_menuitem ci; + + numitems = calc_visible(menu,first); + if (numitems > menu->menuheight) numitems = menu->menuheight; + + menuwidth = menu->menuwidth+3; + clearwindow(top,left-2, top+numitems+1, left+menuwidth+1, + ms->menupage, ms->fillchar, ms->shadowattr); + drawbox(top-1,left-3,top+numitems,left+menuwidth, + ms->menupage,ms->normalattr[NOHLITE],ms->menubt); + memset(sep,ms->box_horiz,menuwidth); // String containing the seperator string + sep[menuwidth-1] = 0; + // Menu title + x = (menuwidth - strlen(menu->title) - 1) >> 1; + gotoxy(top-1,left+x,ms->menupage); + printmenuitem(menu->title,ms->normalattr); + row = -1; // 1 less than inital value of x + for (x=first; x < menu->numitems; x++) + { + ci = menu->items[x]; + if (ci->action == OPT_INVISIBLE) continue; + row++; + if (row >= numitems) break; // Already have enough number of items + // Setup the defaults now + lchar[0] = fchar[0] = ' '; + lchar[1] = fchar[1] = '\0'; // fchar and lchar are just spaces + str = ci->item; // Pointer to item string + attr = (x==curr ? ms->reverseattr : ms->normalattr); // Normal attributes + switch (ci->action) // set up attr,str,fchar,lchar for everything + { + case OPT_INACTIVE: + attr = (x==curr? ms->revinactattr : ms->inactattr); + break; + case OPT_SUBMENU: + lchar[0] = SUBMENUCHAR; lchar[1] = 0; + break; + case OPT_RADIOMENU: + lchar[0] = RADIOMENUCHAR; lchar[1] = 0; + break; + case OPT_CHECKBOX: + lchar[0] = (ci->itemdata.checked ? CHECKED : UNCHECKED); + lchar[1] = 0; + break; + case OPT_SEP: + fchar[0] = '\b'; fchar[1] = ms->box_ltrt; fchar[2] = ms->box_horiz; fchar[3] = ms->box_horiz; fchar[4] = 0; + lchar[0] = ms->box_horiz; lchar[1] = ms->box_rtlt; lchar[2] = 0; + str = sep; + break; + case OPT_EXITMENU: + fchar[0] = EXITMENUCHAR; fchar[1] = 0; + break; + default: // Just to keep the compiler happy + break; + } + gotoxy(top+row,left-2,ms->menupage); + cprint(ms->spacechar,attr[NOHLITE],menuwidth+2,ms->menupage); // Wipe area with spaces + gotoxy(top+row,left-2,ms->menupage); + csprint(fchar,attr[NOHLITE]); // Print first part + gotoxy(top+row,left,ms->menupage); + printmenuitem(str,attr); // Print main part + gotoxy(top+row,left+menuwidth-1,ms->menupage); // Last char if any + csprint(lchar,attr[NOHLITE]); // Print last part + } + // Check if we need to MOREABOVE and MOREBELOW to be added + // reuse x + row = 0; + x = next_visible_sep(menu,0); // First item + if (! isvisible(menu,first,x)) // There is more above + { + row = 1; + gotoxy(top,left+menuwidth,ms->menupage); + cprint(MOREABOVE,ms->normalattr[NOHLITE],1,ms->menupage); + } + x = prev_visible_sep(menu,menu->numitems); // last item + if (! isvisible(menu,first,x)) // There is more above + { + row = 1; + gotoxy(top+numitems-1,left+menuwidth,ms->menupage); + cprint(MOREBELOW,ms->normalattr[NOHLITE],1,ms->menupage); + } + // Add a scroll box + x = ((numitems-1)*curr)/(menu->numitems); + if ((x>0) && (row==1)) { + gotoxy(top+x,left+menuwidth,ms->menupage); + cprint(SCROLLBOX,ms->normalattr[NOHLITE],1,ms->menupage); + } + if (ms->handler) ms->handler(ms,menu->items[curr]); +} + +// Difference between this and regular menu, is that only +// OPT_INVISIBLE, OPT_SEP are honoured +void printradiomenu(pt_menu menu, int curr, uchar top, uchar left, int first) +{ + int x,row; // x = index, row = position from top + int numitems,menuwidth; + char fchar[5],lchar[5]; // The first and last char in for each entry + const char *str; // and inbetween the item or a seperator is printed + uchar *attr; // all in the attribute attr + char sep[MENULEN];// and inbetween the item or a seperator is printed + pt_menuitem ci; + + numitems = calc_visible(menu,first); + if (numitems > menu->menuheight) numitems = menu->menuheight; + + menuwidth = menu->menuwidth+3; + clearwindow(top,left-2, top+numitems+1, left+menuwidth+1, + ms->menupage, ms->fillchar, ms->shadowattr); + drawbox(top-1,left-3,top+numitems,left+menuwidth, + ms->menupage,ms->normalattr[NOHLITE],ms->menubt); + memset(sep,ms->box_horiz,menuwidth); // String containing the seperator string + sep[menuwidth-1] = 0; + // Menu title + x = (menuwidth - strlen(menu->title) - 1) >> 1; + gotoxy(top-1,left+x,ms->menupage); + printmenuitem(menu->title,ms->normalattr); + row = -1; // 1 less than inital value of x + for (x=first; x < menu->numitems; x++) + { + ci = menu->items[x]; + if (ci->action == OPT_INVISIBLE) continue; + row++; + if (row > numitems) break; + // Setup the defaults now + fchar[0] = RADIOUNSEL; fchar[1]='\0'; // Unselected ( ) + lchar[0] = '\0'; // Nothing special after + str = ci->item; // Pointer to item string + attr = ms->normalattr; // Always same attribute + fchar[0] = (x==curr ? RADIOSEL : RADIOUNSEL); + switch (ci->action) // set up attr,str,fchar,lchar for everything + { + case OPT_INACTIVE: + attr = ms->inactattr; + break; + case OPT_SEP: + fchar[0] = '\b'; fchar[1] = ms->box_ltrt; fchar[2] = ms->box_horiz; fchar[3] = ms->box_horiz; fchar[4] = 0; + lchar[0] = ms->box_horiz; lchar[1] = ms->box_rtlt; lchar[3] = 0; + str = sep; + break; + default: // To keep the compiler happy + break; + } + gotoxy(top+row,left-2,ms->menupage); + cprint(ms->spacechar,attr[NOHLITE],menuwidth+2,ms->menupage); // Wipe area with spaces + gotoxy(top+row,left-2,ms->menupage); + csprint(fchar,attr[NOHLITE]); // Print first part + gotoxy(top+row,left,ms->menupage); + printmenuitem(str,attr); // Print main part + gotoxy(top+row,left+menuwidth-1,ms->menupage); // Last char if any + csprint(lchar,attr[NOHLITE]); // Print last part + } + // Check if we need to MOREABOVE and MOREBELOW to be added + // reuse x + row = 0; + x = next_visible_sep(menu,0); // First item + if (! isvisible(menu,first,x)) // There is more above + { + row = 1; + gotoxy(top,left+menuwidth,ms->menupage); + cprint(MOREABOVE,ms->normalattr[NOHLITE],1,ms->menupage); + } + x = prev_visible_sep(menu,menu->numitems); // last item + if (! isvisible(menu,first,x)) // There is more above + { + row = 1; + gotoxy(top+numitems-1,left+menuwidth,ms->menupage); + cprint(MOREBELOW,ms->normalattr[NOHLITE],1,ms->menupage); + } + // Add a scroll box + x = ((numitems-1)*curr)/(menu->numitems); + if ((x > 0) && (row == 1)) + { + gotoxy(top+x,left+menuwidth,ms->menupage); + cprint(SCROLLBOX,ms->normalattr[NOHLITE],1,ms->menupage); + } + if (ms->handler) ms->handler(ms,menu->items[curr]); +} + +void cleanupmenu(pt_menu menu, uchar top,uchar left,int numitems) +{ + if (numitems > menu->menuheight) numitems = menu->menuheight; + clearwindow(top,left-2, top+numitems+1, left+menu->menuwidth+4, + ms->menupage, ms->fillchar, ms->fillattr); // Clear the shadow + clearwindow(top-1, left-3, top+numitems, left+menu->menuwidth+3, + ms->menupage, ms->fillchar, ms->fillattr); // main window +} + +/* Handle a radio menu */ +pt_menuitem getradiooption(pt_menu menu, uchar top, uchar left, uchar startopt) + // Return item chosen or NULL if ESC was hit. +{ + int curr,i,first,tmp; + uchar asc,scan; + uchar numitems; + pt_menuitem ci; // Current item + + numitems = calc_visible(menu,0); + // Setup status line + gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage); + cprint(ms->spacechar,ms->statusattr[NOHLITE],ms->numcols,ms->menupage); + + // Initialise current menu item + curr = next_visible(menu,startopt); + + gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage); + cprint(ms->spacechar,ms->statusattr[NOHLITE],ms->numcols,1); + gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage); + printmenuitem(menu->items[curr]->status,ms->statusattr); + first = calc_first_early(menu,curr); + while (1) // Forever + { + printradiomenu(menu,curr,top,left,first); + ci = menu->items[curr]; + + asc = getch(&scan); + switch (scan) + { + case HOMEKEY: + curr = next_visible(menu,0); + first = calc_first_early(menu,curr); + break; + case ENDKEY: + curr = prev_visible(menu,numitems-1); + first = calc_first_late(menu,curr); + break; + case PAGEDN: + for (i=0; i < 5; i++) curr = next_visible(menu,curr+1); + first = calc_first_late(menu,curr); + break; + case PAGEUP: + for (i=0; i < 5; i++) curr = prev_visible(menu,curr-1); + first = calc_first_early(menu,curr); + break; + case UPARROW: + curr = prev_visible(menu,curr-1); + if (curr < first) first = calc_first_early(menu,curr); + break; + case DNARROW: + curr = next_visible(menu,curr+1); + if (! isvisible(menu,first,curr)) + first = calc_first_late(menu,curr); + break; + case LTARROW: + case ESCAPE: + return NULL; + break; + case RTARROW: + case ENTERA: + case ENTERB: + if (ci->action == OPT_INACTIVE) break; + if (ci->action == OPT_SEP) break; + return ci; + break; + default: + // Check if this is a shortcut key + if (((asc >= 'A') && (asc <= 'Z')) || + ((asc >= 'a') && (asc <= 'z')) || + ((asc >= '0') && (asc <= '9'))) + { + tmp = find_shortcut(menu,asc,curr); + if ((tmp > curr) && (! isvisible(menu,first,tmp))) + first = calc_first_late(menu,tmp); + if (tmp < curr) + first = calc_first_early(menu,tmp); + curr = tmp; + } + else { + if (ms->keys_handler) // Call extra keys handler + ms->keys_handler(ms,menu->items[curr],(scan << 8) | asc); + } + break; + } + // Update status line + gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage); + cprint(ms->spacechar,ms->statusattr[NOHLITE],ms->numcols,ms->menupage); + printmenuitem(menu->items[curr]->status,ms->statusattr); + } + return NULL; // Should never come here +} + +/* Handle one menu */ +pt_menuitem getmenuoption(pt_menu menu, uchar top, uchar left, uchar startopt) + // Return item chosen or NULL if ESC was hit. +{ + int curr,i,first,tmp; + uchar asc,scan; + uchar numitems; + pt_menuitem ci; // Current item + t_handler_return hr; // Return value of handler + + numitems = calc_visible(menu,0); + // Setup status line + gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage); + cprint(ms->spacechar,ms->statusattr[NOHLITE],ms->numcols,ms->menupage); + + // Initialise current menu item + curr = next_visible(menu,startopt); + + gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage); + cprint(ms->spacechar,ms->statusattr[NOHLITE],ms->numcols,1); + gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage); + printmenuitem(menu->items[curr]->status,ms->statusattr); + first = calc_first_early(menu,curr); + while (1) // Forever + { + printmenu(menu,curr,top,left,first); + ci = menu->items[curr]; + asc = getch(&scan); + switch (scan) + { + case HOMEKEY: + curr = next_visible(menu,0); + first = calc_first_early(menu,curr); + break; + case ENDKEY: + curr = prev_visible(menu,numitems-1); + first = calc_first_late(menu,curr); + break; + case PAGEDN: + for (i=0; i < 5; i++) curr = next_visible(menu,curr+1); + first = calc_first_late(menu,curr); + break; + case PAGEUP: + for (i=0; i < 5; i++) curr = prev_visible(menu,curr-1); + first = calc_first_early(menu,curr); + break; + case UPARROW: + curr = prev_visible(menu,curr-1); + if (curr < first) first = calc_first_early(menu,curr); + break; + case DNARROW: + curr = next_visible(menu,curr+1); + if (! isvisible(menu,first,curr)) + first = calc_first_late(menu,curr); + break; + case LTARROW: + case ESCAPE: + return NULL; + break; + case RTARROW: + case ENTERA: + case ENTERB: + if (ci->action == OPT_INACTIVE) break; + if (ci->action == OPT_CHECKBOX) break; + if (ci->action == OPT_SEP) break; + if (ci->action == OPT_EXITMENU) return NULL; // As if we hit Esc + // If we are going into a radio menu, dont call handler, return ci + if (ci->action == OPT_RADIOMENU) return ci; + if (ci->handler != NULL) // Do we have a handler + { + hr = ci->handler(ms,ci); + if (hr.refresh) // Do we need to refresh + { + // Cleanup menu using old number of items + cleanupmenu(menu,top,left,numitems); + // Recalculate the number of items + numitems = calc_visible(menu,0); + // Reprint the menu + printmenu(menu,curr,top,left,first); + } + if (hr.valid) return ci; + } + else return ci; + break; + case SPACEKEY: + if (ci->action != OPT_CHECKBOX) break; + ci->itemdata.checked = !ci->itemdata.checked; + if (ci->handler != NULL) // Do we have a handler + { + hr = ci->handler(ms,ci); + if (hr.refresh) // Do we need to refresh + { + // Cleanup menu using old number of items + cleanupmenu(menu,top,left,numitems); + // Recalculate the number of items + numitems = calc_visible(menu,0); + // Reprint the menu + printmenu(menu,curr,top,left,first); + } + } + break; + default: + // Check if this is a shortcut key + if (((asc >= 'A') && (asc <= 'Z')) || + ((asc >= 'a') && (asc <= 'z')) || + ((asc >= '0') && (asc <= '9'))) + { + tmp = find_shortcut(menu,asc,curr); + if ((tmp > curr) && (! isvisible(menu,first,tmp))) + first = calc_first_late(menu,tmp); + if (tmp < curr) + first = calc_first_early(menu,tmp); + curr = tmp; + } + else { + if (ms->keys_handler) // Call extra keys handler + ms->keys_handler(ms,menu->items[curr],(scan << 8) | asc); + } + break; + } + // Update status line + gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage); + cprint(ms->spacechar,ms->statusattr[NOHLITE],ms->numcols,ms->menupage); + printmenuitem(menu->items[curr]->status,ms->statusattr); + } + return NULL; // Should never come here +} + +/* Handle the entire system of menu's. */ +pt_menuitem runmenusystem(uchar top, uchar left, pt_menu cmenu, uchar startopt, uchar menutype) + /* + * cmenu + * Which menu should be currently displayed + * top,left + * What is the position of the top,left corner of the menu + * startopt + * which menu item do I start with + * menutype + * NORMALMENU or RADIOMENU + * + * Return Value: + * Returns a pointer to the final item chosen, or NULL if nothing chosen. + */ +{ + pt_menuitem opt,choice; + uchar startat,mt; + uchar row,col; + + if (cmenu == NULL) return NULL; + startover: + // Set the menu height + cmenu->menuheight = ms->maxrow - top-3; + if (cmenu->menuheight > ms->maxmenuheight) + cmenu->menuheight = ms->maxmenuheight; + if (menutype == NORMALMENU) + opt = getmenuoption(cmenu,top,left,startopt); + else // menutype == RADIOMENU + opt = getradiooption(cmenu,top,left,startopt); + + if (opt == NULL) + { + // User hit Esc + cleanupmenu(cmenu,top,left,calc_visible(cmenu,0)); + return NULL; + } + // Are we done with the menu system? + if ((opt->action != OPT_SUBMENU) && (opt->action != OPT_RADIOMENU)) + { + cleanupmenu(cmenu,top,left,calc_visible(cmenu,0)); + return opt; // parent cleanup other menus + } + // Either radiomenu or submenu + // Do we have a valid menu number? The next hack uses the fact that + // itemdata.submenunum = itemdata.radiomenunum (since enum data type) + if (opt->itemdata.submenunum >= ms->nummenus) // This is Bad.... + { + gotoxy(12,12,ms->menupage); // Middle of screen + csprint("ERROR: Invalid submenu requested.",0x07); + cleanupmenu(cmenu,top,left,calc_visible(cmenu,0)); + return NULL; // Pretend user hit esc + } + // Call recursively for submenu + // Position the submenu below the current item, + // covering half the current window (horizontally) + row = ms->menus[(unsigned int)opt->itemdata.submenunum]->row; + col = ms->menus[(unsigned int)opt->itemdata.submenunum]->col; + if (row == 0xFF) row = top+opt->index+2; + if (col == 0xFF) col = left+3+(cmenu->menuwidth >> 1); + mt = (opt->action == OPT_SUBMENU ? NORMALMENU : RADIOMENU ); + startat = 0; + if ((opt->action == OPT_RADIOMENU) && (opt->data != NULL)) + startat = ((t_menuitem *)opt->data)->index; + + choice = runmenusystem(row, col, + ms->menus[(unsigned int)opt->itemdata.submenunum], + startat, mt ); + if (opt->action == OPT_RADIOMENU) + { + if (choice != NULL) opt->data = (void *)choice; // store choice in data field + if (opt->handler != NULL) opt->handler(ms,opt); + choice = NULL; // Pretend user hit esc + } + if (choice==NULL) // User hit Esc in submenu + { + // Startover + startopt = opt->index; + goto startover; + } + else + { + cleanupmenu(cmenu,top,left,calc_visible(cmenu,0)); + return choice; + } +} + +/* User Callable functions */ + +pt_menuitem showmenus(uchar startmenu) +{ + pt_menuitem rv; + uchar oldpage,tpos; + + // Setup screen for menusystem + oldpage = getdisppage(); + setdisppage(ms->menupage); + cls(); + clearwindow(ms->minrow, ms->mincol, ms->maxrow, ms->maxcol, + ms->menupage, ms->fillchar, ms->fillattr); + tpos = (ms->numcols - strlen(ms->title) - 1) >> 1; // center it on line + gotoxy(ms->minrow,ms->mincol,ms->menupage); + cprint(ms->tfillchar,ms->titleattr,ms->numcols,ms->menupage); + gotoxy(ms->minrow,ms->mincol+tpos,ms->menupage); + csprint(ms->title,ms->titleattr); + + cursoroff(); // Doesn't seem to work? + + // Go, main menu cannot be a radio menu + rv = runmenusystem(ms->minrow+MENUROW, ms->mincol+MENUCOL, + ms->menus[(unsigned int)startmenu], 0, NORMALMENU); + + // Hide the garbage we left on the screen + cursoron(); + if (oldpage == ms->menupage) cls(); else setdisppage(oldpage); + + // Return user choice + return rv; +} + +pt_menusystem init_menusystem(const char *title) +{ + int i; + + ms = NULL; + ms = (pt_menusystem) malloc(sizeof(t_menusystem)); + if (ms == NULL) return NULL; + ms->nummenus = 0; + // Initialise all menu pointers + for (i=0; i < MAXMENUS; i++) ms->menus[i] = NULL; + + ms->title = (char *)malloc(TITLELEN+1); + if (title == NULL) + strcpy(ms->title,TITLESTR); // Copy string + else strcpy(ms->title,title); + + // Timeout settings + ms->tm_stepsize = TIMEOUTSTEPSIZE; + ms->tm_numsteps = TIMEOUTNUMSTEPS; + + ms->normalattr[NOHLITE] = NORMALATTR; + ms->normalattr[HLITE] = NORMALHLITE; + + ms->reverseattr[NOHLITE] = REVERSEATTR; + ms->reverseattr[HLITE] = REVERSEHLITE; + + ms->inactattr[NOHLITE] = INACTATTR; + ms->inactattr[HLITE] = INACTHLITE; + + ms->revinactattr[NOHLITE] = REVINACTATTR; + ms->revinactattr[HLITE] = REVINACTHLITE; + + ms->statusattr[NOHLITE] = STATUSATTR; + ms->statusattr[HLITE] = STATUSHLITE; + + ms->statline = STATLINE; + ms->tfillchar= TFILLCHAR; + ms->titleattr= TITLEATTR; + + ms->fillchar = FILLCHAR; + ms->fillattr = FILLATTR; + ms->spacechar= SPACECHAR; + ms->shadowattr = SHADOWATTR; + + ms->menupage = MENUPAGE; // Usually no need to change this at all + + // Initialise all handlers + ms->handler = NULL; + ms->keys_handler = NULL; + ms->ontimeout=NULL; // No timeout handler + + // Setup ACTION_{,IN}VALID + ACTION_VALID.valid=1; + ACTION_VALID.refresh=0; + ACTION_INVALID.valid = 0; + ACTION_INVALID.refresh = 0; + + // Figure out the size of the screen we are in now. + // By default we use the whole screen for our menu + ms->minrow = ms->mincol = 0; + ms->numcols = getnumcols(); + ms->numrows = getnumrows(); + ms->maxcol = ms->numcols - 1; + ms->maxrow = ms->numrows - 1; + + // How many entries per menu can we display at a time + ms->maxmenuheight = ms->maxrow - ms->minrow - 3; + if (ms->maxmenuheight > MAXMENUHEIGHT) + ms->maxmenuheight= MAXMENUHEIGHT; + + // Set up the look of the box + set_box_type(MENUBOXTYPE); + return ms; +} + +void set_normal_attr(uchar normal, uchar selected, uchar inactivenormal, uchar inactiveselected) +{ + if (normal != 0xFF) ms->normalattr[0] = normal; + if (selected != 0xFF) ms->reverseattr[0] = selected; + if (inactivenormal != 0xFF) ms->inactattr[0] = inactivenormal; + if (inactiveselected != 0xFF) ms->revinactattr[0] = inactiveselected; +} + +void set_normal_hlite(uchar normal, uchar selected, uchar inactivenormal, uchar inactiveselected) +{ + if (normal != 0xFF) ms->normalattr[1] = normal; + if (selected != 0xFF) ms->reverseattr[1] = selected; + if (inactivenormal != 0xFF) ms->inactattr[1] = inactivenormal; + if (inactiveselected != 0xFF) ms->revinactattr[1] = inactiveselected; +} + +void set_status_info(uchar statusattr, uchar statushlite, uchar statline) +{ + if (statusattr != 0xFF) ms->statusattr[NOHLITE] = statusattr; + if (statushlite!= 0xFF) ms->statusattr[HLITE] = statushlite; + // statline is relative to minrow + if (statline >= ms->numrows) statline = ms->numrows - 1; + ms->statline = statline; // relative to ms->minrow, 0 based +} + +void set_title_info(uchar tfillchar, uchar titleattr) +{ + if (tfillchar != 0xFF) ms->tfillchar = tfillchar; + if (titleattr != 0xFF) ms->titleattr = titleattr; +} + +void set_misc_info(uchar fillchar, uchar fillattr,uchar spacechar, uchar shadowattr) +{ + if (fillchar != 0xFF) ms->fillchar = fillchar; + if (fillattr != 0xFF) ms->fillattr = fillattr; + if (spacechar != 0xFF) ms->spacechar = spacechar; + if (shadowattr!= 0xFF) ms->shadowattr= shadowattr; +} + +void set_box_type(boxtype bt) +{ + uchar *bxc; + ms->menubt = bt; + bxc = getboxchars(bt); + ms->box_horiz = bxc[BOX_HORIZ]; // The char used to draw top line + ms->box_ltrt = bxc[BOX_LTRT]; + ms->box_rtlt = bxc[BOX_RTLT]; +} + +void set_menu_options(uchar maxmenuheight) +{ + if (maxmenuheight != 0xFF) ms->maxmenuheight = maxmenuheight; +} + +// Set the window which menusystem should use +void set_window_size(uchar top, uchar left, uchar bot, uchar right) +{ + + uchar nr,nc; + if ((top > bot) || (left > right)) return; // Sorry no change will happen here + nr = getnumrows(); + nc = getnumcols(); + if (bot >= nr) bot = nr-1; + if (right >= nc) right = nc-1; + ms->minrow = top; + ms->mincol = left; + ms->maxrow = bot; + ms->maxcol = right; + ms->numcols = right - left + 1; + ms->numrows = bot - top + 1; + if (ms->statline >= ms->numrows) ms->statline = ms->numrows - 1; // Clip statline if need be +} + +void reg_handler( t_handler htype, void * handler) +{ + // If bad value set to default screen handler + switch(htype) { + case HDLR_KEYS: + ms->keys_handler = (t_keys_handler) handler; + break; + default: + ms->handler = (t_menusystem_handler) handler; + break; + } +} + +void unreg_handler(t_handler htype) +{ + switch(htype) { + case HDLR_KEYS: + ms->keys_handler = NULL; + break; + default: + ms->handler = NULL; + break; + } +} + +void reg_ontimeout(t_timeout_handler handler, unsigned int numsteps, unsigned int stepsize) +{ + ms->ontimeout = handler; + if (numsteps != 0) ms->tm_numsteps = numsteps; + if (stepsize != 0) ms->tm_stepsize = stepsize; +} + +void unreg_ontimeout() +{ + ms->ontimeout = NULL; +} + +int next_visible(pt_menu menu, int index) +{ + int ans; + if (index < 0) ans = 0 ; + else if (index >= menu->numitems) ans = menu->numitems-1; + else ans = index; + while ((ans < menu->numitems-1) && + ((menu->items[ans]->action == OPT_INVISIBLE) || + (menu->items[ans]->action == OPT_SEP))) + ans++; + return ans; +} + +int prev_visible(pt_menu menu, int index) // Return index of prev visible +{ + int ans; + if (index < 0) ans = 0; + else if (index >= menu->numitems) ans = menu->numitems-1; + else ans = index; + while ((ans > 0) && + ((menu->items[ans]->action == OPT_INVISIBLE) || + (menu->items[ans]->action == OPT_SEP))) + ans--; + return ans; +} + +int next_visible_sep(pt_menu menu, int index) +{ + int ans; + if (index < 0) ans = 0 ; + else if (index >= menu->numitems) ans = menu->numitems-1; + else ans = index; + while ((ans < menu->numitems-1) && + (menu->items[ans]->action == OPT_INVISIBLE)) + ans++; + return ans; +} + +int prev_visible_sep(pt_menu menu, int index) // Return index of prev visible +{ + int ans; + if (index < 0) ans = 0; + else if (index >= menu->numitems) ans = menu->numitems-1; + else ans = index; + while ((ans > 0) && + (menu->items[ans]->action == OPT_INVISIBLE)) + ans--; + return ans; +} + +int calc_visible(pt_menu menu,int first) +{ + int ans,i; + + if (menu == NULL) return 0; + ans = 0; + for (i=first; i < menu->numitems; i++) + if (menu->items[i]->action != OPT_INVISIBLE) ans++; + return ans; +} + +// is curr visible if first entry is first? +int isvisible(pt_menu menu,int first, int curr) +{ + if (curr < first) return 0; + return (calc_visible(menu,first)-calc_visible(menu,curr) < menu->menuheight); +} + +// Calculate the first entry to be displayed +// so that curr is visible and make curr as late as possible +int calc_first_late(pt_menu menu,int curr) +{ + int ans,i,nv; + + nv = calc_visible(menu,0); + if (nv <= menu->menuheight) return 0; + // Start with curr and go back menu->menuheight times + ans = curr+1; + for (i=0; i < menu->menuheight; i++) + ans = prev_visible_sep(menu,ans-1); + return ans; +} + +// Calculate the first entry to be displayed +// so that curr is visible and make curr as early as possible +int calc_first_early(pt_menu menu,int curr) +{ + int ans,i,nv; + + nv = calc_visible(menu,0); + if (nv <= menu->menuheight) return 0; + // Start with curr and go back till >= menu->menuheight + // items are visible + nv = calc_visible(menu,curr); // Already nv of them are visible + ans = curr; + for (i=0; i < menu->menuheight - nv; i++) + ans = prev_visible_sep(menu,ans-1); + return ans; +} + +// Create a new menu and return its position +uchar add_menu(const char *title, int maxmenusize) +{ + int num,i; + pt_menu m; + + num = ms->nummenus; + if (num >= MAXMENUS) return -1; + m = NULL; + m = (pt_menu) malloc(sizeof(t_menu)); + if (m == NULL) return -1; + ms->menus[num] = m; + m->numitems = 0; + m->row = 0xFF; + m->col = 0xFF; + if (maxmenusize < 1) + m->maxmenusize = MAXMENUSIZE; + else m->maxmenusize = maxmenusize; + m->items = (pt_menuitem *) malloc(sizeof(pt_menuitem)*(m->maxmenusize)); + for (i=0; i < m->maxmenusize; i++) m->items[i] = NULL; + + m->title = (char *)malloc(MENULEN+1); + if (title) + { + if (strlen(title) > MENULEN - 2) + strcpy(m->title,TITLELONG); + else strcpy(m->title,title); + } + else strcpy(m->title,EMPTYSTR); + m ->menuwidth = strlen(m->title); + ms->nummenus ++; + return ms->nummenus - 1; +} + +void set_menu_pos(uchar row,uchar col) // Set the position of this menu. +{ + pt_menu m; + + m = ms->menus[ms->nummenus-1]; + m->row = row; + m->col = col; +} + +pt_menuitem add_sep() // Add a separator to current menu +{ + pt_menuitem mi; + pt_menu m; + + m = (ms->menus[ms->nummenus-1]); + mi = NULL; + mi = (pt_menuitem) malloc(sizeof(t_menuitem)); + if (mi == NULL) return NULL; + m->items[(unsigned int)m->numitems] = mi; + mi->handler = NULL; // No handler + mi->item = mi->status = mi->data = NULL; + mi->action = OPT_SEP; + mi->index = m->numitems++; + mi->parindex = ms->nummenus-1; + mi->shortcut = 0; + mi->helpid=0; + return mi; +} + +// Add item to the "current" menu +pt_menuitem add_item(const char *item, const char *status, t_action action, + const char *data, uchar itemdata) +{ + pt_menuitem mi; + pt_menu m; + const char *str; + uchar inhlite=0; // Are we inside hlite area + + m = (ms->menus[ms->nummenus-1]); + mi = NULL; + mi = (pt_menuitem) malloc(sizeof(t_menuitem)); + if (mi == NULL) return NULL; + m->items[(unsigned int) m->numitems] = mi; + mi->handler = NULL; // No handler + + // Allocate space to store stuff + mi->item = (char *)malloc(MENULEN+1); + mi->status = (char *)malloc(STATLEN+1); + mi->data = (char *)malloc(ACTIONLEN+1); + + if (item) { + if (strlen(item) > MENULEN) { + strcpy(mi->item,ITEMLONG); + } else { + strcpy(mi->item,item); + } + if (strlen(mi->item) > m->menuwidth) m->menuwidth = strlen(mi->item); + } else strcpy(mi->item,EMPTYSTR); + + if (status) { + if (strlen(status) > STATLEN) { + strcpy(mi->status,STATUSLONG); + } else { + strcpy(mi->status,status); + } + } else strcpy(mi->status,EMPTYSTR); + + mi->action=action; + str = mi->item; + mi->shortcut = 0; + mi->helpid = 0xFFFF; + inhlite = 0; // We have not yet seen an ENABLEHLITE char + // Find the first char in [A-Za-z0-9] after ENABLEHLITE and not arg to control char + while (*str) + { + if (*str == ENABLEHLITE) + { + inhlite=1; + } + if (*str == DISABLEHLITE) + { + inhlite = 0; + } + if ( (inhlite == 1) && + (((*str >= 'A') && (*str <= 'Z')) || + ((*str >= 'a') && (*str <= 'z')) || + ((*str >= '0') && (*str <= '9')))) + { + mi->shortcut=*str; + break; + } + ++str; + } + if ((mi->shortcut >= 'A') && (mi->shortcut <= 'Z')) // Make lower case + mi->shortcut = mi->shortcut -'A'+'a'; + + if (data) { + if (strlen(data) > ACTIONLEN) { + strcpy(mi->data,ACTIONLONG); + } else { + strcpy(mi->data,data); + } + } else strcpy(mi->data,EMPTYSTR); + + switch (action) + { + case OPT_SUBMENU: + mi->itemdata.submenunum = itemdata; + break; + case OPT_CHECKBOX: + mi->itemdata.checked = itemdata; + break; + case OPT_RADIOMENU: + mi->itemdata.radiomenunum = itemdata; + mi->data = NULL; // No selection made + break; + default: // to keep the compiler happy + break; + } + mi->index = m->numitems++; + mi->parindex = ms->nummenus-1; + return mi; +} + +// Set the shortcut key for the current item +void set_item_options(uchar shortcut,int helpid) +{ + pt_menuitem mi; + pt_menu m; + + m = (ms->menus[ms->nummenus-1]); + if (m->numitems <= 0) return; + mi = m->items[(unsigned int) m->numitems-1]; + + if (shortcut != 0xFF) mi->shortcut = shortcut; + if (helpid != 0xFFFF) mi->helpid = helpid; +} + +// Free internal datasutructures +void close_menusystem(void) +{ +} diff --git a/syslinux/menu/libmenu/menu.h b/syslinux/menu/libmenu/menu.h new file mode 100644 index 0000000..1e0a619 --- /dev/null +++ b/syslinux/menu/libmenu/menu.h @@ -0,0 +1,287 @@ +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* This program can be compiled for DOS with the OpenWatcom compiler + * (http://www.openwatcom.org/): + * + * wcl -3 -osx -mt <filename>.c + */ + +#ifndef __MENU_H__ +#define __MENU_H__ + +#include "com32io.h" +#include "tui.h" +#include "syslnx.h" +#include "scancodes.h" +#include <string.h> + +// TIMEOUT PARAMETERS +/* If no key is pressed within TIMEOUTNUMSTEPS * TIMEOUTSTEPSIZE milliseconds + and if a timeout handler is registered, then that will be called. + The handler should either either take control from there on, or return without + producing any change in the current video settings. + + For e.g. the handler could + * Could just quit the menu program + * beep and return. + + TIMEOUTSTEPSIZE is the interval for which the program sleeps without checking for + any keystroke. So increasing this will make the response of the system slow. + Decreasing this will make a lot of interrupt calls using up your CPU. Default + value of TIMEOUTSTEPSIZE of 0.1 seconds should be right in most cases. + + TIMEOUTNUMSTEPS of 3000 corresponds to a wait time of 300 seconds or 5 minutes +*/ + +#define TIMEOUTSTEPSIZE 10 +#define TIMEOUTNUMSTEPS 30000L + +// Attributes +#define NORMALATTR 0x17 +#define NORMALHLITE 0x1F // Normal Highlight attribute +#define REVERSEATTR 0x70 +#define REVERSEHLITE 0x78 // Reverse Hightlight attribute +#define INACTATTR 0x18 +#define INACTHLITE 0x10 // Inactive Highlight attribute +#define REVINACTATTR 0x78 +#define REVINACTHLITE 0x70 // Reverse Inactive Highlight attr + +#define STATUSATTR 0x74 +#define STATUSHLITE 0x7B // Status highlight + +#define FILLCHAR 177 +#define FILLATTR 0x01 +#define SHADOWATTR 0x00 +#define SPACECHAR ' ' + +#define TFILLCHAR ' ' +#define TITLEATTR 0x70 + +#define ENABLEHLITE '<' // Char which turns on highlight +#define DISABLEHLITE '>' // Char which turns off highlight +#define NOHLITE 0 // The offset into attrib array for non-hilite +#define HLITE 1 // The offset for Hlite attrib + +#define MOREABOVE 24 // char to print when more menu items available above +#define MOREBELOW 25 // more items available below +#define SCROLLBOX 176 // Filled char to display + +// Attributes of the menu system +#define MAXMENUS 10 // Maximum number of menu's allowed +#define MAXMENUSIZE 30 // Default value for max num of entries in each menu +#define MAXMENUHEIGHT 14 // Maximum number of entries displayed +#define MENUBOXTYPE BOX_SINSIN // Default box type Look at tui.h for other values + +// Upper bounds on lengths +// We copy the given string, so user can reuse the space used to store incoming arguments. +#define MENULEN 40 // Each menu entry is atmost MENULEN chars +#define STATLEN 80 // Maximum length of status string +#define TITLELEN 80 // Maximum length of title string +#define ACTIONLEN 255 // Maximum length of an action string + +// Layout of menu +#define MENUROW 3 // Row where menu is displayed (relative to window) +#define MENUCOL 4 // Col where menu is displayed (relative to window) +#define MENUPAGE 1 // show in display page 1 +#define HELPPAGE 2 // Use this page for any additional information +#define STATLINE 24 // Line number where status line starts (relative to window) + +// Used for printing debugging messages +#define DEBUGLINE 23 // debugging info goes here + +// Other Chars +#define SUBMENUCHAR 175 // This is >> symbol +#define RADIOMENUCHAR '>' // > symbol for radio menu? +#define EXITMENUCHAR 174 // This is << symbol +#define CHECKED 251 // Check mark +#define UNCHECKED 250 // Light bullet +#define RADIOSEL '.' // Current Radio Selection +#define RADIOUNSEL ' ' // Radio option not selected + +typedef unsigned char uchar; + +// Types of menu's +#define NORMALMENU 1 +#define RADIOMENU 2 + +typedef enum {OPT_INACTIVE, OPT_SUBMENU, OPT_RUN, OPT_EXITMENU, OPT_CHECKBOX, + OPT_RADIOMENU, OPT_SEP, OPT_INVISIBLE, + OPT_RADIOITEM} t_action; + +typedef union { + uchar submenunum; // For submenu's + uchar checked; // For check boxes + uchar radiomenunum; // Item mapping to a radio menu +} t_itemdata; + +struct s_menuitem; +struct s_menu; +struct s_menusystem; + +typedef struct { + unsigned int valid :1; // Is action valid? + unsigned int refresh:1; // Should we recompute menu stuff? + unsigned int reserved:6; // For future expansion +} t_handler_return; + +t_handler_return ACTION_VALID,ACTION_INVALID; // Specific values + +typedef t_handler_return (*t_item_handler)(struct s_menusystem *, struct s_menuitem *); +typedef void (*t_menusystem_handler)(struct s_menusystem *, struct s_menuitem *); +typedef void (*t_keys_handler)(struct s_menusystem *, struct s_menuitem *, + unsigned int scancode); + // Last parameter = HIGH BYTE = scan code , LOW BYTE = ASCII CODE + +typedef enum {HDLR_SCREEN, HDLR_KEYS } t_handler; +// Types of handlers for menu system + +// TIMEOUT is the list of possible values which can be returned by the handler +// instructing the menusystem what to do. The default is CODE_WAIT +typedef enum {CODE_WAIT, CODE_ENTER, CODE_ESCAPE } TIMEOUTCODE; +typedef TIMEOUTCODE (*t_timeout_handler)(void); + +typedef struct s_menuitem { + char *item; + char *status; + char *data; // string containing kernel to run.. but... + // for radio menu's this is a pointer to the item selected or NULL (initially) + void * extra_data; // Any other data user can point to + t_item_handler handler; // Pointer to function of type menufn + t_action action; + t_itemdata itemdata; // Data depends on action value + unsigned int helpid; // context sensitive help system ID + uchar shortcut; // one of [A-Za-z0-9] shortcut for this menu item + uchar index; // Index within the menu array + uchar parindex; // Index of the menu in which this item appears. +} t_menuitem; + +typedef t_menuitem *pt_menuitem; // Pointer to type menuitem + +typedef struct s_menu { + pt_menuitem *items; // pointer to array of pointer to menuitems + char *title; + int maxmenusize; // the size of array allocated + uchar numitems; // how many items do we actually have + uchar menuwidth; + uchar row,col; // Position where this menu should be displayed + uchar menuheight; // Maximum number of items to be displayed +} t_menu; + +typedef t_menu *pt_menu; // Pointer to type menu + +typedef struct s_menusystem { + pt_menu menus[MAXMENUS]; + char *title; + t_menusystem_handler handler; // Menu system handler + t_keys_handler keys_handler; // Handler for unknown keys + t_timeout_handler ontimeout; // Timeout handler + unsigned long tm_numsteps; + // Time to wait for key press=numsteps * stepsize milliseconds + unsigned int tm_stepsize; // Timeout step size (in milliseconds) + + int maxmenuheight; + uchar nummenus; + uchar normalattr[2]; // [0] is non-hlite attr, [1] is hlite attr + uchar reverseattr[2]; + uchar inactattr[2]; + uchar revinactattr[2]; + uchar statusattr[2]; + uchar fillchar; + uchar fillattr; + uchar spacechar; + uchar tfillchar; + uchar titleattr; + uchar shadowattr; + uchar statline; + uchar menupage; + uchar maxrow,minrow,numrows; // Number of rows in the window + uchar maxcol,mincol,numcols; // Number of columns in the window + + // Menu box look + boxtype menubt; // What type of boxes should be drawn + char box_horiz,box_ltrt,box_rtlt; // Some chars of the box, for redrawing portions of the box + +} t_menusystem; + +typedef t_menusystem *pt_menusystem; // Pointer to type menusystem + +/************************************************************************ + * IMPORTANT INFORMATION + * + * All functions which take a string as argument store the pointer + * for later use. So if you have alloc'ed a space for the string + * and are passing it to any of these functions, DO NOT deallocate it. + * + * If they are constant strings, you may receive warning from the compiler + * about "converting from char const * to char *". Ignore these errors. + * + * This hack/trick of storing these pointers will help in reducing the size + * of the internal structures by a lot. + * + *************************************************************************** + */ + +pt_menuitem showmenus(uchar startmenu); + +pt_menusystem init_menusystem(const char *title); +void close_menusystem(); // Deallocate memory used + +void set_normal_attr(uchar normal, uchar selected, uchar inactivenormal, uchar inactiveselected); + +void set_normal_hlite(uchar normal, uchar selected, uchar inactivenormal, uchar inactiveselected); + +void set_status_info(uchar statusattr, uchar statushlite, uchar statline); + +void set_title_info(uchar tfillchar, uchar titleattr); + +void set_misc_info(uchar fillchar, uchar fillattr,uchar spacechar, uchar shadowattr); +void set_box_type(boxtype bt); + +void set_window_size(uchar top, uchar left, uchar bot, uchar right); // Set the window which menusystem should use + +void set_menu_options(uchar maxmenuheight); +// maximum height of a menu + +void reg_handler(t_handler htype, void * handler); // Register handler + +void unreg_handler( t_handler htype); + +void reg_ontimeout(t_timeout_handler, unsigned int numsteps, unsigned int stepsize); +// Set timeout handler, set 0 for default values. +// So stepsize=0 means numsteps is measured in centiseconds. +void unreg_ontimeout(); + +// Create a new menu and return its position +uchar add_menu(const char *title, int maxmenusize); + +void set_menu_pos(uchar row,uchar col); // Set the position of this menu. + +// Add item to the "current" menu +pt_menuitem add_item(const char *item, const char *status, t_action action, const char *data, uchar itemdata); + +// Set shortcut key and help id +void set_item_options(uchar shortcut,int helpid); + +// Set the shortcut key for the current item +static inline void set_shortcut(uchar shortcut) +{ + set_item_options(shortcut,0xFFFF); +} + +// Add a separator to the "current" menu +pt_menuitem add_sep(); + +// Main function for the user's config file +int menumain(char *cmdline); + +#endif diff --git a/syslinux/menu/libmenu/passwords.c b/syslinux/menu/libmenu/passwords.c new file mode 100644 index 0000000..d7ada29 --- /dev/null +++ b/syslinux/menu/libmenu/passwords.c @@ -0,0 +1,140 @@ +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Bostom MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#include "passwords.h" +#include "des.h" +#include "string.h" +#include <stdlib.h> +#include <stdio.h> +#include "tui.h" + +#define MAX_LINE 512 +// Max line length in a pwdfile +p_pwdentry userdb[MAX_USERS]; // Array of pointers +int numusers; // Actual number of users + +// returns true or false, i.e. 1 or 0 +char authenticate_user(const char * username, const char* pwd) +{ + char salt[12]; + int i, password_ok; + + password_ok=0; + + for (i=0; i< numusers; i++) { + if (userdb[i] == NULL) continue; + if (strcmp(username,userdb[i]->username)==0) { + strcpy(salt, userdb[i]->pwdhash); + salt[2] = '\0'; + if (strcmp(userdb[i]->pwdhash,crypt(pwd,salt))==0) return 1; + } + } + return 0; +} + +// Does user USERNAME have permission PERM +char isallowed(const char *username, const char *perm) +{ + int i; + char *dperm; + char *tmp; + + if (strcmp(username,GUEST_USER) == 0) return 0; + dperm = (char *) malloc(strlen(perm)+3); + strcpy(dperm+1,perm); + dperm[0] = ':'; + dperm[strlen(perm)+1]=':'; + dperm[strlen(perm)+2]=0; + // Now dperm = ":perm:" + for (i=0; i < numusers; i++) { + if (strcmp(userdb[i]->username,username)==0) // Found the user + { + if (userdb[i]->perms == NULL) return 0; // No permission + tmp = strstr(userdb[i]->perms,dperm); // Search for permission + free (dperm); // Release memory + if (tmp == NULL) return 0; else return 1; + } + } + // User not found return 0 + free (dperm); + return 0; +} + +// Initialise the list of of user passwords permissions from file +void init_passwords(const char *filename) +{ + int i; + char line[MAX_LINE], *p,*user,*pwdhash,*perms; + FILE *f; + + for (i=0; i < MAX_USERS; i++) userdb[i] = NULL; + numusers = 0; + + if ( !filename ) return; // No filename specified + + f = fopen(filename,"r"); + if ( !f ) return; // File does not exist + + // Process each line + while ( fgets(line, sizeof line, f) ) { + // Replace EOLN with \0 + p = strchr(line, '\r'); + if ( p ) *p = '\0'; + p = strchr(line, '\n'); + if ( p ) *p = '\0'; + + // If comment line or empty ignore line + p = line; + while (*p==' ') p++; // skip initial spaces + if ( (*p == '#') || (*p == '\0')) continue; // Skip comment lines + + user = p; // This is where username starts + p = strchr(user,':'); + if (p == NULL) continue; // Malformed line skip + *p = '\0'; + pwdhash = p+1; + if (*pwdhash == 0) continue; // Malformed line (no password specified) + p = strchr(pwdhash,':'); + if (p == NULL) { // No perms specified + perms = NULL; + } else { + *p = '\0'; + perms = p+1; + if (*perms == 0) perms = NULL; + } + // At this point we have user,pwdhash and perms setup + userdb[numusers] = (p_pwdentry)malloc(sizeof(pwdentry)); + strcpy(userdb[numusers]->username,user); + strcpy(userdb[numusers]->pwdhash,pwdhash); + if (perms == NULL) + userdb[numusers]->perms = NULL; + else { + userdb[numusers]->perms = (char *)malloc(strlen(perms)+3); + (userdb[numusers]->perms)[0] = ':'; + strcpy(userdb[numusers]->perms + 1,perms); + (userdb[numusers]->perms)[strlen(perms)+1] = ':'; + (userdb[numusers]->perms)[strlen(perms)+2] = 0; + // Now perms field points to ":perms:" + } + numusers++; + } + fclose(f); +} + +void close_passwords() +{ + int i; + + for (i=0; i < numusers; i++) + if (userdb[i] != NULL) free(userdb[i]); + numusers = 0; +} diff --git a/syslinux/menu/libmenu/passwords.h b/syslinux/menu/libmenu/passwords.h new file mode 100644 index 0000000..1e68e3e --- /dev/null +++ b/syslinux/menu/libmenu/passwords.h @@ -0,0 +1,27 @@ +#ifndef _PASSWORDS_H_ +#define _PASSWORDS_H_ + +char authenticate_user(const char * username, const char* pwd); + +char isallowed(const char *username, const char * perm); + +// Initialise the list of of user passwords permissions from file +void init_passwords(const char *filename); +// Free all space used for internal data structures +void close_passwords(); + +#define MAX_USERS 128 // Maximum number of users +#define USERNAME_LENGTH 12 // Max length of user name +#define PWDHASH_LENGTH 40 // Max lenght of pwd hash + +typedef struct { + char username[USERNAME_LENGTH+1]; + char pwdhash[PWDHASH_LENGTH+1]; + char *perms; // pointer to string containing ":" delimited permissions +} pwdentry; + +typedef pwdentry *p_pwdentry; + +#define GUEST_USER "guest" + +#endif diff --git a/syslinux/menu/libmenu/scancodes.h b/syslinux/menu/libmenu/scancodes.h new file mode 100644 index 0000000..8331884 --- /dev/null +++ b/syslinux/menu/libmenu/scancodes.h @@ -0,0 +1,75 @@ +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#ifndef __SCANCODES_H__ +#define __SCANCODES_H__ + +// Scancodes of some keys +#define ESCAPE 1 +#define ENTERA 28 +#define ENTERB 224 + +#define HOMEKEY 71 +#define UPARROW 72 +#define PAGEUP 73 +#define LTARROW 75 +#define RTARROW 77 +#define ENDKEY 79 +#define DNARROW 80 +#define PAGEDN 81 +#define INSERT 82 +#define DELETE 83 +#define SPACEKEY 57 // Scan code for SPACE + +#define CTRLLT 0x73 +#define CTRLRT 0x74 + +#define F1 0x3B +#define F2 0x3C +#define F3 0x3D +#define F4 0x3E +#define F5 0x3F +#define F6 0x40 +#define F7 0x41 +#define F8 0x42 +#define F9 0x43 +#define F10 0x44 +#define F11 0x85 +#define F12 0x86 + +#define CTRLF1 0x5E +#define CTRLF2 0x5F +#define CTRLF3 0x60 +#define CTRLF4 0x61 +#define CTRLF5 0x62 +#define CTRLF6 0x63 +#define CTRLF7 0x64 +#define CTRLF8 0x65 +#define CTRLF9 0x66 +#define CTRLF10 0x67 +#define CTRLF11 0x89 +#define CTRLF12 0x8A + +#define ALTF1 0x68 +#define ALTF2 0x69 +#define ALTF3 0x6A +#define ALTF4 0x6B +#define ALTF5 0x6C +#define ALTF6 0x6D +#define ALTF7 0x6E +#define ALTF8 0x6F +#define ALTF9 0x70 +#define ALTF10 0x71 +#define ALTF11 0x8B +#define ALTF12 0x8C + +#endif diff --git a/syslinux/menu/libmenu/syslnx.c b/syslinux/menu/libmenu/syslnx.c new file mode 100644 index 0000000..66a11ae --- /dev/null +++ b/syslinux/menu/libmenu/syslnx.c @@ -0,0 +1,44 @@ +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#include <string.h> +#include <com32.h> +#include "syslnx.h" + +com32sys_t inreg,outreg; // Global registers for this module + +char issyslinux(void) +{ + REG_EAX(inreg) = 0x00003000; + REG_EBX(inreg) = REG_ECX(inreg) = REG_EDX(inreg) = 0xFFFFFFFF; + __intcall(0x21,&inreg,&outreg); + return (REG_EAX(outreg) == 0x59530000) && + (REG_EBX(outreg) == 0x4c530000) && + (REG_ECX(outreg) == 0x4e490000) && + (REG_EDX(outreg) == 0x58550000); +} + +void runsyslinuxcmd(const char *cmd) +{ + strcpy(__com32.cs_bounce, cmd); + REG_AX(inreg) = 0x0003; // Run command + REG_BX(inreg) = OFFS(__com32.cs_bounce); + inreg.es = SEG(__com32.cs_bounce); + __intcall(0x22, &inreg, &outreg); +} + +void gototxtmode(void) +{ + REG_AX(inreg) = 0x0005; + __intcall(0x22,&inreg,&outreg); +} + diff --git a/syslinux/menu/libmenu/syslnx.h b/syslinux/menu/libmenu/syslnx.h new file mode 100644 index 0000000..7d0281b --- /dev/null +++ b/syslinux/menu/libmenu/syslnx.h @@ -0,0 +1,47 @@ +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#ifndef __SYSLNX_H__ +#define __SYSLNX_H__ + +#include <com32.h> + +//Macros which help user not have to remember the structure of register +// Data structure + +#define REG_AH(x) ((x).eax.b[1]) +#define REG_AL(x) ((x).eax.b[0]) +#define REG_AX(x) ((x).eax.w[0]) +#define REG_EAX(x) ((x).eax.l) + +#define REG_BH(x) ((x).ebx.b[1]) +#define REG_BL(x) ((x).ebx.b[0]) +#define REG_BX(x) ((x).ebx.w[0]) +#define REG_EBX(x) ((x).ebx.l) + +#define REG_CH(x) ((x).ecx.b[1]) +#define REG_CL(x) ((x).ecx.b[0]) +#define REG_CX(x) ((x).ecx.w[0]) +#define REG_ECX(x) ((x).ecx.l) + +#define REG_DH(x) ((x).edx.b[1]) +#define REG_DL(x) ((x).edx.b[0]) +#define REG_DX(x) ((x).edx.w[0]) +#define REG_EDX(x) ((x).edx.l) + +char issyslinux(void); /* Check if syslinux is running */ + +void runsyslinuxcmd(const char *cmd); /* Run specified command */ + +void gototxtmode(void); /* Change mode to text mode */ + +#endif diff --git a/syslinux/menu/libmenu/tui.c b/syslinux/menu/libmenu/tui.c new file mode 100644 index 0000000..ad19f46 --- /dev/null +++ b/syslinux/menu/libmenu/tui.c @@ -0,0 +1,360 @@ +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#include <string.h> +#include <com32.h> +#include "tui.h" +#include "syslnx.h" +#include "com32io.h" +#include "scancodes.h" +#include <stdlib.h> + +com32sys_t inreg,outreg; // Global register sets for use + +char bkspstr[] = " \b$"; +char eolstr[] = "\n$"; +#define GETSTRATTR 0x07 + +// Reads a line of input from stdin. Replace CR with NUL byte +// password <> 0 implies not echoed on screen +// showoldvalue <> 0 implies currentvalue displayed first +// If showoldvalue <> 0 then caller responsibility to ensure that +// str is NULL terminated. +void getuserinput(char *stra, unsigned int size, unsigned int password, + unsigned int showoldvalue) +{ + unsigned char c,scan; + char *p,*q; // p = current char of string, q = tmp + char *last; // The current last char of string + char *str; // pointer to string which is going to be allocated + char page; + char row,col; + char start,end; // Cursor shape + char fudge; // How many chars should be removed from output + char insmode; // Are we in insert or overwrite + + page = getdisppage(); + getpos(&row,&col,page); // Get current position + getcursorshape(&start,&end); + insmode = 1; + + str = (char *)malloc(size+1); // Allocate memory to store user input + memset(str,0,size+1); // Zero it out + if (password != 0) showoldvalue = 0; // Password's never displayed + + if (showoldvalue != 0) strcpy(str,stra); // If show old value copy current value + + last = str; + while (*last) {last++;} // Find the terminating null byte + p = str+ strlen(str); + + if (insmode == 0) + setcursorshape(1,7); // Block cursor + else setcursorshape(6,7); // Normal cursor + + // Invariants: p is the current char + // col is the corresponding column on the screen + if (password == 0) // Not a password, print initial value + { + gotoxy(row,col,page); + csprint(str,GETSTRATTR); + } + while (1) { // Do forever + c = inputc(&scan); + if (c == '\r') break; // User hit Enter getout of loop + if (scan == ESCAPE) // User hit escape getout and nullify string + { *str = 0; + break; + } + fudge = 0; + // if scan code is regognized do something + // else if char code is recognized do something + // else ignore + switch(scan) { + case HOMEKEY: + p = str; + break; + case ENDKEY: + p = last; + break; + case LTARROW: + if (p > str) p--; + break; + case CTRLLT: + if (p==str) break; + if (*p == ' ') + while ((p > str) && (*p == ' ')) p--; + else { + if (*(p-1) == ' ') { + p--; + while ((p > str) && (*p == ' ')) p--; + } + } + while ((p > str) && ((*p == ' ') || (*(p-1) != ' '))) p--; + break; + case RTARROW: + if (p < last) p++; + break; + case CTRLRT: + if (*p==0) break; // At end of string + if (*p != ' ') + while ((*p!=0) && (*p != ' ')) p++; + while ((*p!=0) && ((*p == ' ') && (*(p+1) != ' '))) p++; + if (*p==' ') p++; + break; + case DELETE: + q = p; + while (*(q+1)) {*q = *(q+1); q++; } + if (last > str) last--; + fudge = 1; + break; + case INSERT: + insmode = 1-insmode; // Switch mode + if (insmode == 0) + setcursorshape(1,7); // Block cursor + else setcursorshape(6,7); // Normal cursor + break; + + default: // Unrecognized scan code, look at the ascii value + switch (c) { + case '\b': // Move over by one + q=p; + while ( q <= last ) { *(q-1)=*q; q++;} + if (last > str) last--; + if (p > str) p--; + fudge = 1; + break; + case '\x15': /* Ctrl-U: kill input */ + fudge = last-str; + while ( p > str ) *p--=0; + p = str; *p=0; last = str; + break; + default: // Handle insert and overwrite mode + if ((c >= ' ') && (c < 128) && + ((unsigned int)(p-str) < size-1) ) { + if (insmode == 0) { // Overwrite mode + if (p==last) last++; + *last = 0; + *p++ = c; + } else { // Insert mode + if (p==last) { // last char + last++; + *last=0; + *p++=c; + } else { // Non-last char + q=last++; + while (q >= p) { *q=*(q-1); q--;} + *p++=c; + } + } + } + else beep(); + } + break; + } + // Now the string has been modified, print it + if (password == 0) { + gotoxy(row,col,page); + csprint(str,GETSTRATTR); + if (fudge > 0) cprint(' ',GETSTRATTR,fudge,page); + gotoxy(row,col+(p-str),page); + } + } + *p = '\0'; + if (password == 0) csprint("\r\n",GETSTRATTR); + setcursorshape(start,end); // Block cursor + // If user hit ESCAPE so return without any changes + if (scan != ESCAPE) strcpy(stra,str); + free(str); +} + +/* Print a C string (NUL-terminated) */ +void cswprint(const char *str,char attr,char left) +{ + char page = getdisppage(); + char newattr=0,cha,chb; + char row,col; + char nr,nc; + + nr = getnumrows(); + nc = getnumcols(); + getpos(&row,&col,page); + while ( *str ) { + switch (*str) + { + case '\b': + --col; + break; + case '\n': + ++row; + col = left; + break; + case '\r': + //col=left; + break; + case BELL: // Bell Char + beep(); + break; + case CHRELATTR: // change attribute (relatively) + case CHABSATTR: // change attribute (absolute) + cha = *(str+1); + chb = *(str+2); + if ((((cha >= '0') && (cha <= '9')) || + ((cha >= 'A') && (cha <= 'F'))) && + (((chb >= '0') && (chb <= '9')) || + ((chb >= 'A') && (chb <= 'F')))) // Next two chars are legal + { + if ((cha >= 'A') && (cha <= 'F')) + cha = cha - 'A'+10; + else cha = cha - '0'; + if ((chb >= 'A') && (chb <= 'F')) + chb = chb - 'A'+10; + else chb = chb - '0'; + newattr = (cha << 4) + chb; + attr = (*str == CHABSATTR ? newattr : attr ^ newattr); + str += 2; // Will be incremented again later + } + break; + default: + putch(*str, attr, page); + ++col; + } + if (col >= nc) + { + ++row; + col=left; + } + if (row > nr) + { + scrollup(); + row= nr; + } + gotoxy(row,col,page); + str++; + } +} + +void clearwindow(char top, char left, char bot, char right, char page, char fillchar, char fillattr) +{ + char x; + for (x=top; x < bot+1; x++) + { + gotoxy(x,left,page); + cprint(fillchar,fillattr,right-left+1,page); + } +} + +void cls(void) +{ + unsigned char dp = getdisppage(); + gotoxy(0,0,dp); + cprint(' ',GETSTRATTR,(1+getnumrows())*getnumcols(),dp); +} + +//////////////////////////////Box Stuff + +// This order of numbers must match +// the values of BOX_TOPLEFT,... in the header file + +unsigned char SINSIN_CHARS[] = {218,192,191,217, //Corners + 196,179, // Horiz and Vertical + 195,180,194,193,197}; // Connectors & Middle + +unsigned char DBLDBL_CHARS[] = {201,200,187,188, // Corners + 205,186, // Horiz and Vertical + 199,182,203,202,206}; // Connectors & Middle + +unsigned char SINDBL_CHARS[] = {214,211,183,189, // Corners + 196,186, // Horiz & Vert + 199,182,210,208,215}; // Connectors & Middle + +unsigned char DBLSIN_CHARS[] = {213,212,184,190, // Corners + 205,179, // Horiz & Vert + 198,181,209,207,216}; // Connectors & Middle + +unsigned char * getboxchars(boxtype bt) +{ + switch (bt) + { + case BOX_SINSIN: + return SINSIN_CHARS; + break; + case BOX_DBLDBL: + return DBLDBL_CHARS; + break; + case BOX_SINDBL: + return SINDBL_CHARS; + break; + case BOX_DBLSIN: + return DBLSIN_CHARS; + break; + default: + return SINSIN_CHARS; + break; + } + return SINSIN_CHARS; +} + +// Draw box and lines +void drawbox(char top,char left,char bot, char right, + char page, char attr,boxtype bt) +{ + unsigned char *box_chars; // pointer to array of box chars + unsigned char x; + + box_chars = getboxchars(bt); + // Top border + gotoxy(top,left,page); + cprint(box_chars[BOX_TOPLEFT],attr,1,page); + gotoxy(top,left+1,page); + cprint(box_chars[BOX_TOP],attr,right-left,page); + gotoxy(top,right,page); + cprint(box_chars[BOX_TOPRIGHT],attr,1,page); + // Bottom border + gotoxy(bot,left,page); + cprint(box_chars[BOX_BOTLEFT],attr,1,page); + gotoxy(bot,left+1,page); + cprint(box_chars[BOX_BOT],attr,right-left,page); + gotoxy(bot,right,page); + cprint(box_chars[BOX_BOTRIGHT],attr,1,page); + // Left & right borders + for (x=top+1; x < bot; x++) + { + gotoxy(x,left,page); + cprint(box_chars[BOX_LEFT],attr,1,page); + gotoxy(x,right,page); + cprint(box_chars[BOX_RIGHT],attr,1,page); + } +} + +void drawhorizline(char top, char left, char right, char page, char attr, + boxtype bt, char dumb) +{ + unsigned char start,end; + unsigned char *box_chars = getboxchars(bt); + if (dumb==0) { + start = left+1; + end = right-1; + } else { + start = left; + end = right; + } + gotoxy(top,start,page); + cprint(box_chars[BOX_HORIZ],attr,end-start+1,page); + if (dumb == 0) + { + gotoxy(top,left,page); + cprint(box_chars[BOX_LTRT],attr,1,page); + gotoxy(top,right,page); + cprint(box_chars[BOX_RTLT],attr,1,page); + } +} diff --git a/syslinux/menu/libmenu/tui.h b/syslinux/menu/libmenu/tui.h new file mode 100644 index 0000000..07020ad --- /dev/null +++ b/syslinux/menu/libmenu/tui.h @@ -0,0 +1,85 @@ +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#ifndef __TUI_H__ +#define __TUI_H__ + +#include <com32.h> +#include "com32io.h" + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#define BELL 0x07 +// CHRELATTR = ^N, CHABSATTR = ^O +#define CHABSATTR 15 +#define CHRELATTR 14 + +void clearwindow(char top, char left, char bot, char right, + char page, char fillchar, char fillattr); + +void cls(void); /* Clears the entire current screen page */ + +// Generic user input, +// password = 0 iff chars echoed on screen +// showoldvalue <> 0 iff current displayed for editing +void getuserinput(char *str, unsigned int size, + unsigned int password, unsigned int showoldvalue); + +static inline void getstring(char *str, unsigned int size) +{ + getuserinput(str,size,0,0); +} + +static inline void editstring(char *str, unsigned int size) +{ + getuserinput(str,size,0,1); +} + +static inline void getpwd(char * str, unsigned int size) +{ + getuserinput(str,size,1,0); +} + +// Box drawing Chars offsets into array +#define BOX_TOPLEFT 0x0 +#define BOX_BOTLEFT 0x1 +#define BOX_TOPRIGHT 0x2 +#define BOX_BOTRIGHT 0x3 +#define BOX_TOP 0x4 // TOP = BOT = HORIZ +#define BOX_BOT 0x4 +#define BOX_HORIZ 0x4 +#define BOX_LEFT 0x5 +#define BOX_RIGHT 0x5 +#define BOX_VERT 0x5 // LEFT=RIGHT=VERT +#define BOX_LTRT 0x6 +#define BOX_RTLT 0x7 +#define BOX_TOPBOT 0x8 +#define BOX_BOTTOP 0x9 +#define BOX_MIDDLE 0xA + +typedef enum {BOX_SINSIN,BOX_DBLDBL, BOX_SINDBL, BOX_DBLSIN} boxtype; + +unsigned char * getboxchars(boxtype bt); + +void drawbox(char top,char left,char bot, char right, + char page, char attr,boxtype bt); + +// Draw a horizontal line +// dumb == 1, means just draw the line +// dumb == 0 means check the first and last positions and depending on what is +// currently on the screen make it a LTRT and/or RTLT appropriately. +void drawhorizline(char top, char left, char right, char page, char attr, + boxtype bt, char dumb); + +#endif diff --git a/syslinux/menu/password b/syslinux/menu/password new file mode 100644 index 0000000..00fc7cb --- /dev/null +++ b/syslinux/menu/password @@ -0,0 +1,19 @@ +# This file should be available as /isolinux/password +# for complex.c to use. +# +# All lines starting with # and empty lines are ignored +# +# All non-comment lines here are of the form +# USERNAME:PWDHASH:PERM1:PERM2:...: +# +# where USERNAME is maximum of 12 chars, +# PWDHASH is maximum of 40 chars (DES ENCRYPTED) +# PERM1,... are arbitrary strings +# +# The current lines correspond to +# user1:secret1, user2:secret2, user3:secret3 + +user1:LcMRo3YZGtP0c:editcmd +user2:FqewzyxP78a7A: +user3:MKjmc.IHoXBNU:root + diff --git a/syslinux/menu/simple.c b/syslinux/menu/simple.c new file mode 100644 index 0000000..2458909 --- /dev/null +++ b/syslinux/menu/simple.c @@ -0,0 +1,78 @@ +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +#include "menu.h" +#include "com32io.h" +#include <string.h> + +int main(void) +{ + t_menuitem * curr; + + char TESTING,RESCUE,MAIN; /* The menus we're going to declare */ + + // Change the video mode here + // setvideomode(0) + + // Choose the default title and setup default values for all attributes.... + init_menusystem(NULL); + set_window_size(1,1,23,78); // Leave one row/col border all around + + // Choose the default values for all attributes and char's + // -1 means choose defaults (Actually the next 4 lines are not needed) + //set_normal_attr (-1,-1,-1,-1); + //set_status_info (-1,-1); + //set_title_info (-1,-1); + //set_misc_info(-1,-1,-1,-1); + + // menuindex = add_menu(" Menu Title ",-1); + // add_item("Item string","Status String",TYPE,"any string",NUM) + // TYPE = OPT_RUN | OPT_EXITMENU | OPT_SUBMENU | OPT_CHECKBOX | OPT_INACTIVE + // "any string" not used by the menu system, useful for storing kernel names + // NUM = index of submenu if OPT_SUBMENU, + // 0/1 default checked state if OPT_CHECKBOX + // unused otherwise. + + TESTING = add_menu(" Testing ",-1); + add_item("Self Loop","Go to testing",OPT_SUBMENU,NULL,TESTING); + add_item("Memory Test","Perform extensive memory testing",OPT_RUN, "memtest",0); + add_item("Exit this menu","Go one level up",OPT_EXITMENU,"exit",0); + + RESCUE = add_menu(" Rescue Options ",-1); + add_item("Linux Rescue","linresc",OPT_RUN,"linresc",0); + add_item("Dos Rescue","dosresc",OPT_RUN,"dosresc",0); + add_item("Windows Rescue","winresc",OPT_RUN,"winresc",0); + add_item("Exit this menu","Go one level up",OPT_EXITMENU,"exit",0); + + MAIN = add_menu(" Main Menu ",-1); + add_item("Prepare","prep",OPT_RUN,"prep",0); + add_item("Rescue options...","Troubleshoot a system",OPT_SUBMENU,NULL,RESCUE); + add_item("Testing...","Options to test hardware",OPT_SUBMENU,NULL,TESTING); + add_item("Exit to prompt", "Exit the menu system", OPT_EXITMENU, "exit", 0); + + curr = showmenus(MAIN); // Initial menu is the one with index MAIN + if (curr) + { + if (curr->action == OPT_RUN) + { + if (issyslinux()) runsyslinuxcmd(curr->data); + else csprint(curr->data,0x07); + return 1; + } + csprint("Error in programming!",0x07); + } + return 0; +} diff --git a/syslinux/mkdiskimage.in b/syslinux/mkdiskimage.in new file mode 100755 index 0000000..41b1c16 --- /dev/null +++ b/syslinux/mkdiskimage.in @@ -0,0 +1,263 @@ +#!/usr/bin/perl +## ----------------------------------------------------------------------- +## $Id: mkdiskimage.in,v 1.14 2004/12/30 23:41:01 hpa Exp $ +## +## Copyright 2002-2004 H. Peter Anvin - All Rights Reserved +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, Inc., 53 Temple Place Ste 330, +## Boston MA 02111-1307, USA; either version 2 of the License, or +## (at your option) any later version; incorporated herein by reference. +## +## ----------------------------------------------------------------------- + +# +# Creates a blank MS-DOS formatted hard disk image +# + +use bytes; +use integer; +use Fcntl; +use Errno; +use Cwd; +use IO::Handle; # For flush() + +sub absolute_path($) { + my($f) = @_; + my($c); + + return $f if ( $f =~ /^\// ); + $c = cwd(); + $c = '' if ( $c eq '/' ); + return $c.'/'.$f; +} + +sub is_linux() { + return !!eval '{ '. + 'use POSIX; '. + '($sysname, $nodename, $release, $version, $machine) = POSIX::uname(); '. + "return \$sysname eq \'Linux\'; }"; +} + + +$is_linux = is_linux(); +if ( $is_linux ) { + # IOCTL numbers + $BLKRRPART = 0x125f; + $BLKGETSIZE = 0x1260; +} + +%opt = (); +@args = (); + +for $a ( @ARGV ) { + if ( $a =~ /^\-/ ) { + foreach $o ( split(//, substr($a,1)) ) { + $opt{$o} = 1; + } + } else { + push(@args, $a); + } +} + +($file,$c,$h,$s) = @args; +$c += 0; $h += 0; $s += 0; + +$pentry = 1; +$pentry = 2 if ( $opt{'2'} ); +$pentry = 3 if ( $opt{'3'} ); +$pentry = 4 if ( $opt{'4'} ); + +if ( $opt{'M'} ) { + # Specify size in megabytes, not in cylinders + $c = ($c*1024*2)/($h*$s); +} + +$is_open = 0; + +if ( $c == 0 ) { + $len = 0; + if ( sysopen(OUTPUT, $file, O_RDWR, 0666) ) { + $is_open = 1; + + if ( (@filestat = stat(OUTPUT)) && S_ISREG($filestat[2]) ) { + $len = $filestat[7] >> 9; + } elsif ( $is_linux && S_ISBLK($filestat[2]) ) { + $blksize = pack("L!", 0); + if ( ioctl(OUTPUT, $BLKGETSIZE, $blksize) == 0 ) { + $len = unpack("L!", $blksize); # In 512-byte sectors! + } + } + } + + if ( !$len ) { + print STDERR "$0: $file: don't know how to determine the size of this device\n"; + exit 1; + } + + $c = $len/($h*$s); +} + +if ( !$file || $c < 1 || $c > 1024 || + $h < 1 || $h > 256 || $s < 1 || $s > 63 ) { + print STDERR "Usage: $0 [-doF4] file c h s (max: 1024 256 63)\n"; + print STDERR " -d add DOSEMU header\n"; + print STDERR " -o print filesystem offset to stdout\n"; + print STDERR " -F format partition as FAT32\n"; + print STDERR " -M \"c\" argument is megabytes, calculate cylinders\n"; + print STDERR " -4 use partition entry 4 (standard for zipdisks)\n"; + exit 1; +} + +$cylsize = $h*$s*512; + +if ( !$is_open ) { + sysopen(OUTPUT, $file, O_CREAT|O_RDWR|O_TRUNC, 0666) + or die "$0: Cannot open: $file\n"; +} +binmode OUTPUT; + +# Print out DOSEMU header, if requested +if ( $opt{'d'} ) { + $emuhdr = "DOSEMU\0" . pack("VVVV", $h, $s, $c, 128); + $emuhdr .= "\0" x (128 - length($emuhdr)); + print OUTPUT $emuhdr; +} + +# Print the MBR and partition table +$mbr = ''; +while ( $line = <DATA> ) { + chomp $line; + foreach $byte ( split(/\s+/, $line) ) { + $mbr .= chr(hex($byte)); + } +} +if ( length($mbr) > 446 ) { + die "$0: Bad MBR code\n"; +} + +$mbr .= "\0" x (446 - length($mbr)); + +print OUTPUT $mbr; + +# Print partition table +$psize = $c*$h*$s-$s; +$bhead = ($h > 1) ? 1 : 0; +$bsect = 1; +$bcyl = ($h > 1) ? 0 : 1; +$ehead = $h-1; +$esect = $s + ((($c-1) & 0x300) >> 2); +$ecyl = ($c-1) & 0xff; +if ( $psize > 65536 ) { + $fstype = 0x06; +} else { + $fstype = 0x04; +} +for ( $i = 1 ; $i <= 4 ; $i++ ) { + if ( $i == $pentry ) { + print OUTPUT pack("CCCCCCCCVV", 0x80, $bhead, $bsect, $bcyl, $fstype, + $ehead, $esect, $ecyl, $s, $psize); + } else { + print OUTPUT "\0" x 16; + } +} +print OUTPUT "\x55\xaa"; + +# Output blank file +$totalsize = $c*$h*$s; +$tracks = $c*$h; + +$track = "\0" x (512*$s); + +# Print fractional track +print OUTPUT "\0" x (512 * ($s-1)); + +for ( $i = 1 ; $i < $tracks ; $i++ ) { + print OUTPUT $track; +} + +# Print mtools temp file +$n = 0; +while ( !defined($tmpdir) ) { + $tmpdir = "/tmp/mkdiskimage.$$.".($n++); + if ( !mkdir($tmpdir, 0700) ) { + die "$0: Failed to make temp directory: $tmpdir\n" + if ( $! != EEXIST ); + undef $tmpdir; + } +} + +$cfgfile = $tmpdir.'/mtools.conf'; +$imglink = $tmpdir.'/disk.img'; +die "$0: Failed to create symlink $imglink\n" + if ( !symlink(absolute_path($file), $imglink) ); + +$header_size = ($opt{'d'} ? 128 : 0); + +# Start of filesystem +$offset = $s*512 + $header_size; + +# Start of partition table entry +$pstart = $header_size + 446 + 16*($pentry-1); + +open(MCONFIG, "> ${cfgfile}") or die "$0: Cannot make mtools config\n"; +print MCONFIG "drive z:\n"; +print MCONFIG "file=\"${imglink}\"\n"; +print MCONFIG "cylinders=${c}\n"; +print MCONFIG "heads=${h}\n"; +print MCONFIG "sectors=${s}\n"; +print MCONFIG "offset=${offset}\n"; +print MCONFIG "mformat_only\n"; +close(MCONFIG); + +# Output the filesystem offset to stdout if appropriate +if ( $opt{'o'} ) { + print $offset, "\n"; +} + +$ENV{'MTOOLSRC'} = $cfgfile; +if ( $opt{'F'} ) { + system('mformat', '-F', 'z:'); +} else { + system('mformat', 'z:'); +} + +# Clean up in /tmp +unlink($cfgfile); +unlink($imglink); +rmdir($tmpdir); + +# MTOOLS doesn't write the bsHiddenSecs field correctly +seek(OUTPUT, $offset + 0x1c, 0); +print OUTPUT pack("V", ($offset-$header_size)>>9); + +# Set the partition type +if ( $opt{'F'} ) { + $fstype = 0x0b; # FAT32 +} else { + if ( $psize > 65536 ) { + $fstype = 0x06; # FAT16 > 32MB + } else { + $fstype = 0x04; # FAT16 <= 32MB + } + seek(OUTPUT, $offset + 0x36, 0); + read(OUTPUT, $fsname, 8); + + # FAT12: adjust partition type + if ( $fsname eq 'FAT12 ' ) { + $fstype = 0x01; # FAT12 + } +} +seek(OUTPUT, $pstart+4, 0); +print OUTPUT pack("C", $fstype); + +flush OUTPUT; + +# Just in case this is a block device, try to flush the partition table +if ( $is_linux ) { + ioctl(OUTPUT, $BLKRRPART, 0); +}; + +exit 0; +__END__ diff --git a/syslinux/mtools/Makefile b/syslinux/mtools/Makefile new file mode 100644 index 0000000..920c85a --- /dev/null +++ b/syslinux/mtools/Makefile @@ -0,0 +1,40 @@ +CC = gcc +OPTFLAGS = -g -Os +INCLUDES = -I. -I.. -I../libfat +CFLAGS = -W -Wall -D_FILE_OFFSET_BITS=64 $(OPTFLAGS) $(INCLUDES) +LDFLAGS = -s + +SRCS = syslinux.c ../syslxmod.c ../bootsect_bin.c ../ldlinux_bin.c $(wildcard ../libfat/*.c) +OBJS = $(patsubst %.c,%.o,$(notdir $(SRCS))) + +.SUFFIXES: .c .o .i .s .S + +VPATH = .:..:../libfat + +all: installer + +tidy: + -rm -f *.o *.i *.s *.a .*.d + +clean: tidy + -rm -f syslinux + +spotless: clean + -rm -f *~ + +installer: syslinux + +syslinux: $(OBJS) + $(CC) $(LDFLAGS) -o $@ $^ + +%.o: %.c + $(CC) -Wp,-MT,$@,-MMD,.$@.d $(CFLAGS) -c -o $@ $< +%.i: %.c + $(CC) $(CFLAGS) -E -o $@ $< +%.s: %.c + $(CC) $(CFLAGS) -S -o $@ $< + +-include .*.d + + + diff --git a/syslinux/mtools/syslinux.c b/syslinux/mtools/syslinux.c new file mode 100644 index 0000000..096a1d7 --- /dev/null +++ b/syslinux/mtools/syslinux.c @@ -0,0 +1,294 @@ +#ident "$Id: syslinux.c,v 1.6 2005/01/04 03:27:43 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 1998-2004 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * syslinux.c - Linux installer program for SYSLINUX + * + * This program now requires mtools. It turned out to be a lot + * easier to deal with than dealing with needing mount privileges. + * We need device write permission anyway. + */ + +#define _XOPEN_SOURCE 500 /* Required on glibc 2.x */ +#define _BSD_SOURCE +#include <alloca.h> +#include <errno.h> +#include <fcntl.h> +#include <inttypes.h> +#include <mntent.h> +#include <paths.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <syslog.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> + +#include "syslinux.h" +#include "libfat.h" + +char *program; /* Name of program */ +char *device; /* Device to install to */ +pid_t mypid; +off_t filesystem_offset = 0; /* Offset of filesystem */ + +void __attribute__((noreturn)) usage(void) +{ + fprintf(stderr, "Usage: %s [-sf] [-o offset] device\n", program); + exit(1); +} + +void __attribute__((noreturn)) die(const char *msg) +{ + fprintf(stderr, "%s: %s\n", program, msg); + exit(1); +} + +/* + * read/write wrapper functions + */ +ssize_t xpread(int fd, void *buf, size_t count, off_t offset) +{ + char *bufp = (char *)buf; + ssize_t rv; + ssize_t done = 0; + + while ( count ) { + rv = pread(fd, bufp, count, offset); + if ( rv == 0 ) { + die("short read"); + } else if ( rv == -1 ) { + if ( errno == EINTR ) { + continue; + } else { + die(strerror(errno)); + } + } else { + bufp += rv; + offset += rv; + done += rv; + count -= rv; + } + } + + return done; +} + +ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset) +{ + const char *bufp = (const char *)buf; + ssize_t rv; + ssize_t done = 0; + + while ( count ) { + rv = pwrite(fd, bufp, count, offset); + if ( rv == 0 ) { + die("short write"); + } else if ( rv == -1 ) { + if ( errno == EINTR ) { + continue; + } else { + die(strerror(errno)); + } + } else { + bufp += rv; + offset += rv; + done += rv; + count -= rv; + } + } + + return done; +} + +/* + * Version of the read function suitable for libfat + */ +int libfat_xpread(intptr_t pp, void *buf, size_t secsize, libfat_sector_t sector) +{ + off_t offset = (off_t)sector * secsize + filesystem_offset; + return xpread(pp, buf, secsize, offset); +} + + +int main(int argc, char *argv[]) +{ + static unsigned char sectbuf[512]; + int dev_fd; + struct stat st; + int status; + char **argp, *opt; + int force = 0; /* -f (force) option */ + char mtools_conf[] = "/tmp/syslinux-mtools-XXXXXX"; + int mtc_fd; + FILE *mtc, *mtp; + struct libfat_filesystem *fs; + libfat_sector_t s, *secp, sectors[65]; /* 65 is maximum possible */ + int32_t ldlinux_cluster; + int nsectors; + const char *errmsg; + + (void)argc; /* Unused */ + + mypid = getpid(); + program = argv[0]; + + device = NULL; + + for ( argp = argv+1 ; *argp ; argp++ ) { + if ( **argp == '-' ) { + opt = *argp + 1; + if ( !*opt ) + usage(); + + while ( *opt ) { + if ( *opt == 's' ) { + syslinux_make_stupid(); /* Use "safe, slow and stupid" code */ + } else if ( *opt == 'f' ) { + force = 1; /* Force install */ + } else if ( *opt == 'o' && argp[1] ) { + filesystem_offset = (off_t)strtoull(*++argp, NULL, 0); /* Byte offset */ + } else { + usage(); + } + opt++; + } + } else { + if ( device ) + usage(); + device = *argp; + } + } + + if ( !device ) + usage(); + + /* + * First make sure we can open the device at all, and that we have + * read/write permission. + */ + dev_fd = open(device, O_RDWR); + if ( dev_fd < 0 || fstat(dev_fd, &st) < 0 ) { + perror(device); + exit(1); + } + + if ( !force && !S_ISBLK(st.st_mode) && !S_ISREG(st.st_mode) ) { + fprintf(stderr, "%s: not a block device or regular file (use -f to override)\n", device); + exit(1); + } + + xpread(dev_fd, sectbuf, 512, filesystem_offset); + + /* + * Check to see that what we got was indeed an MS-DOS boot sector/superblock + */ + if( (errmsg = syslinux_check_bootsect(sectbuf)) ) { + die(errmsg); + } + + /* + * Create an mtools configuration file + */ + mtc_fd = mkstemp(mtools_conf); + if ( mtc_fd < 0 || !(mtc = fdopen(mtc_fd, "w")) ) { + perror(program); + exit(1); + } + fprintf(mtc, + "MTOOLS_NO_VFAT=1\n" + "MTOOLS_SKIP_CHECK=1\n" /* Needed for some flash memories */ + "drive s:\n" + " file=\"/proc/%lu/fd/%d\"\n" + " offset=%llu\n", + (unsigned long)mypid, + dev_fd, + (unsigned long long)filesystem_offset); + fclose(mtc); + + /* + * Run mtools to create the LDLINUX.SYS file + */ + if ( setenv("MTOOLSRC", mtools_conf, 1) ) { + perror(program); + exit(1); + } + + /* This command may fail legitimately */ + system("mattrib -h -r -s s:ldlinux.sys 2>/dev/null"); + + mtp = popen("mcopy -D o -D O -o - s:ldlinux.sys", "w"); + if ( !mtp || + (fwrite(syslinux_ldlinux, 1, syslinux_ldlinux_len, mtp) + != syslinux_ldlinux_len) || + (status = pclose(mtp), !WIFEXITED(status) || WEXITSTATUS(status)) ) { + die("failed to create ldlinux.sys"); + } + + status = system("mattrib +r +h +s s:ldlinux.sys"); + + if ( !WIFEXITED(status) || WEXITSTATUS(status) ) { + fprintf(stderr, + "%s: warning: failed to set system bit on ldlinux.sys\n", + program); + } + + unlink(mtools_conf); + + /* + * Now, use libfat to create a block map + */ + fs = libfat_open(libfat_xpread, dev_fd); + ldlinux_cluster = libfat_searchdir(fs, 0, "LDLINUX SYS", NULL); + secp = sectors; + nsectors = 0; + s = libfat_clustertosector(fs, ldlinux_cluster); + while ( s && nsectors < 65 ) { + *secp++ = s; + nsectors++; + s = libfat_nextsector(fs, s); + } + libfat_close(fs); + + /* + * Patch ldlinux.sys and the boot sector + */ + syslinux_patch(sectors, nsectors); + + /* + * Write the now-patched first sector of ldlinux.sys + */ + xpwrite(dev_fd, syslinux_ldlinux, 512, filesystem_offset + ((off_t)sectors[0] << 9)); + + /* + * To finish up, write the boot sector + */ + + /* Read the superblock again since it might have changed while mounted */ + xpread(dev_fd, sectbuf, 512, filesystem_offset); + + /* Copy the syslinux code into the boot sector */ + syslinux_make_bootsect(sectbuf); + + /* Write new boot sector */ + xpwrite(dev_fd, sectbuf, 512, filesystem_offset); + + close(dev_fd); + sync(); + + /* Done! */ + + return 0; +} diff --git a/syslinux/now.pl b/syslinux/now.pl new file mode 100644 index 0000000..e2295eb --- /dev/null +++ b/syslinux/now.pl @@ -0,0 +1,22 @@ +#!/usr/bin/perl +# $Id: now.pl,v 1.5 1999/09/17 07:28:45 hpa Exp $ +# +# Print the time (possibly the mtime of a file) as a hexadecimal integer +# If more than one file, print the mtime of the *newest* file. +# + +undef $now; + +foreach $file ( @ARGV ) { + ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime, + $ctime,$blksize,$blocks) = stat($file); + if ( !defined($now) || $now < $mtime ) { + $now = $mtime; + } +} + +if ( !defined($now) ) { + $now = time; +} + +printf "0x%08x\n", $now; diff --git a/syslinux/parsecmd.inc b/syslinux/parsecmd.inc new file mode 100644 index 0000000..a26de1d --- /dev/null +++ b/syslinux/parsecmd.inc @@ -0,0 +1,113 @@ +;; $Id: parsecmd.inc,v 1.10 2004/12/21 06:30:55 hpa Exp $ +;; ----------------------------------------------------------------------- +;; +;; Copyright 1994-2002 H. Peter Anvin - All Rights Reserved +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +;; Boston MA 02111-1307, USA; either version 2 of the License, or +;; (at your option) any later version; incorporated herein by reference. +;; +;; ----------------------------------------------------------------------- + +;; +;; parsecmd.inc +;; +;; Command line parser code +;; + + section .text + +; ------------------------------------------------------------------------- +; getcommand: Get a keyword from the current "getc" file and match it +; against a list of keywords (keywd_table). Each entry in +; that table should have the following form: +; <32 bit hash value> <16 bit handler offset> +; +; The handler is called, and upon return this function +; returns with CF = 0. On EOF, this function returns +; with CF = 1. +; ------------------------------------------------------------------------- + +getcommand: +.find: + call skipspace ; Skip leading whitespace + jz .eof ; End of file + jc .find ; End of line: try again + + or al,20h ; Convert to lower case + movzx ebx,al ; Hash for a one-char keyword +.read_loop: + push ebx + call getc + pop ebx + jc .eof + cmp al,' ' ; Whitespace + jbe .done + or al,20h + rol ebx,5 + xor bl,al + jmp short .read_loop +.done: call ungetc + call skipspace + jz .eof + jc .noparm + call ungetc ; Return nonwhitespace char to buf + mov si,keywd_table + mov cx,keywd_count +.table_search: + lodsd + cmp ebx,eax + je .found_keywd + lodsd ; Skip entrypoint/argument + loop .table_search + + ; Otherwise unrecognized keyword + mov si,err_badcfg + jmp short .error + + ; No parameter +.noparm: + mov si,err_noparm + mov al,10 ; Already at EOL +.error: + call cwritestr + jmp short .skipline + +.found_keywd: lodsw ; Load argument into ax + call [si] + clc + ret + +.eof: stc + ret + +.skipline: cmp al,10 ; Search for LF + je .find + call getc + jc .eof + jmp short .skipline + + section .bss + alignb 4 +vk_size equ (vk_end + 3) & ~3 +VKernelBuf: resb vk_size ; "Current" vkernel +AppendBuf resb max_cmd_len+1 ; append= +Ontimeout resb max_cmd_len+1 ; ontimeout +Onerror resb max_cmd_len+1 ; onerror +KbdMap resb 256 ; Keyboard map +FKeyName resb 10*FILENAME_MAX ; File names for F-key help +KernelCNameLen resw 1 ; Length of unmangled kernel name +InitRDCNameLen resw 1 ; Length of unmangled initrd name +%if IS_SYSLINUX +KernelName resb FILENAME_MAX+1 ; Mangled name for kernel +KernelCName resb FILENAME_MAX+2 ; Unmangled kernel name +InitRDCName resb FILENAME_MAX+2 ; Unmangled initrd name +%else +KernelName resb FILENAME_MAX ; Mangled name for kernel +KernelCName resb FILENAME_MAX ; Unmangled kernel name +InitRDCName resb FILENAME_MAX ; Unmangled initrd name +%endif +MNameBuf resb FILENAME_MAX +InitRD resb FILENAME_MAX diff --git a/syslinux/parseconfig.inc b/syslinux/parseconfig.inc new file mode 100644 index 0000000..2b1e687 --- /dev/null +++ b/syslinux/parseconfig.inc @@ -0,0 +1,374 @@ +;; $Id: parseconfig.inc,v 1.22 2005/04/06 09:53:39 hpa Exp $ +;; ----------------------------------------------------------------------- +;; +;; Copyright 1994-2004 H. Peter Anvin - All Rights Reserved +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +;; Boston MA 02111-1307, USA; either version 2 of the License, or +;; (at your option) any later version; incorporated herein by reference. +;; +;; ----------------------------------------------------------------------- + +;; +;; parseconfig.inc +;; +;; Configuration file operations +;; + + section .text +; +; "default" command +; +pc_default: mov di,default_cmd + call getline + mov byte [di-1],0 ; null-terminate + ret + +; +; "ontimeout" command +; +pc_ontimeout: mov di,Ontimeout + call getline + sub di,Ontimeout+1 ; Don't need final space + mov [OntimeoutLen],di + ret + +; +; "onerror" command +; +pc_onerror: mov di,Onerror + call getline + sub di,Onerror + mov [OnerrorLen],di + ret + +; +; "append" command +; +pc_append: cmp byte [VKernel],0 + ja .vk + mov di,AppendBuf + call getline + sub di,AppendBuf +.app1: mov [AppendLen],di + ret +.vk: mov di,VKernelBuf+vk_append ; "append" command (vkernel) + call getline + sub di,VKernelBuf+vk_append + cmp di,byte 2 + jne .app2 + cmp byte [VKernelBuf+vk_append],'-' + jne .app2 + xor di,di ; If "append -" -> null string +.app2: mov [VKernelBuf+vk_appendlen],di + ret + +; +; "ipappend" command (PXELINUX only) +; +%if IS_PXELINUX +pc_ipappend: call getint + jc .err + cmp byte [VKernel],0 + jne .vk + mov [IPAppend],bl +.err: ret +.vk: mov [VKernelBuf+vk_ipappend],bl + ret +%endif + +; +; "localboot" command (PXELINUX, ISOLINUX) +; +%if IS_PXELINUX || IS_ISOLINUX +pc_localboot: call getint + cmp byte [VKernel],0 ; ("label" section only) + je .err + mov di,VKernelBuf+vk_rname + xor ax,ax + mov cx,FILENAME_MAX + rep stosb ; Null kernel name +%if IS_PXELINUX + ; PXELINUX uses the first 4 bytes of vk_rname for the + ; mangled IP address + mov [VKernelBuf+vk_rname+5], bx ; Return type +%else + mov [VKernelBuf+vk_rname+1], bx ; Return type +%endif +.err: ret +%endif + +; +; "kernel" command +pc_kernel: cmp byte [VKernel],0 + je .err ; ("label" section only) + call pc_getline + mov di,VKernelBuf+vk_rname + call mangle_name +.err: ret + +; +; "timeout" command +; +pc_timeout: call getint + jc .err + mov ax,0D215h ; There are approx 1.D215h + mul bx ; clock ticks per 1/10 s + add bx,dx + mov [KbdTimeOut],bx +.err: ret + +; +; Generic integer variable setting commands: +; "prompt", "implicit" +; +pc_setint16: + push ax + call getint + pop si + jc .err + mov [si],bx +.err: ret + +; +; Generic file-processing commands: +; "display", "font", "kbdmap" +; +pc_filecmd: push ax ; Function to tailcall + call pc_getline + mov di,MNameBuf + push di + call mangle_name + pop di + call searchdir ; tailcall + jnz .ok + pop ax ; Drop the successor function +.ok: ret ; Tailcall if OK, error return + +; +; "serial" command +; +pc_serial: call getint + jc .err + push bx ; Serial port # + call skipspace + jnc .ok + pop bx +.err: ret +.ok: + call ungetc + call getint + mov [FlowControl], word 0 ; Default to no flow control + jc .nobaud +.valid_baud: + push ebx + call skipspace + jc .no_flow + call ungetc + call getint ; Hardware flow control? + jnc .valid_flow +.no_flow: + xor bx,bx ; Default -> no flow control +.valid_flow: + and bh,0Fh ; FlowIgnore + shl bh,4 + mov [FlowIgnore],bh + mov bh,bl + and bx,0F003h ; Valid bits + mov [FlowControl],bx + pop ebx ; Baud rate + jmp short .parse_baud +.nobaud: + mov ebx,DEFAULT_BAUD ; No baud rate given +.parse_baud: + pop di ; Serial port # + cmp ebx,byte 75 + jb .err ; < 75 baud == bogus + mov eax,BAUD_DIVISOR + cdq + div ebx + mov [BaudDivisor],ax + push ax ; Baud rate divisor + cmp di,3 + ja .port_is_io ; If port > 3 then port is I/O addr + shl di,1 + mov di,[di+serial_base] ; Get the I/O port from the BIOS +.port_is_io: + mov [SerialPort],di + lea dx,[di+3] ; DX -> LCR + mov al,83h ; Enable DLAB + call slow_out + pop ax ; Divisor + mov dx,di ; DX -> LS + call slow_out + inc dx ; DX -> MS + mov al,ah + call slow_out + mov al,03h ; Disable DLAB + add dx,byte 2 ; DX -> LCR + call slow_out + in al,dx ; Read back LCR (detect missing hw) + cmp al,03h ; If nothing here we'll read 00 or FF + jne .serial_port_bad ; Assume serial port busted + sub dx,byte 2 ; DX -> IER + xor al,al ; IRQ disable + call slow_out + + add dx,byte 3 ; DX -> MCR + in al,dx + or al,[FlowOutput] ; Assert bits + call slow_out + + ; Show some life + mov si,syslinux_banner + call write_serial_str + mov si,copyright_str + call write_serial_str + ret + +.serial_port_bad: + mov [SerialPort], word 0 + ret + +; +; "F"-key command +; +pc_fkey: push ax + call pc_getline + pop di + call mangle_name ; Mangle file name + ret + +; +; "label" command +; +pc_label: call commit_vk ; Commit any current vkernel + mov di,VKernelBuf ; Erase the vkernelbuf for better compression + mov cx,(vk_size >> 1) + xor ax,ax + rep stosw + call pc_getline + mov di,VKernelBuf+vk_vname + call mangle_name ; Mangle virtual name + mov byte [VKernel],1 ; We've seen a "label" statement + mov si,VKernelBuf+vk_vname ; By default, rname == vname + mov di,VKernelBuf+vk_rname + mov cx,FILENAME_MAX + rep movsb + mov si,AppendBuf ; Default append==global append + mov di,VKernelBuf+vk_append + mov cx,[AppendLen] + mov [VKernelBuf+vk_appendlen],cx + rep movsb +%if IS_PXELINUX ; PXELINUX only + mov al,[IPAppend] ; Default ipappend==global ipappend + mov [VKernelBuf+vk_ipappend],al +%endif + ret + +; +; "say" command +; +pc_say: call pc_getline ; "say" command + call writestr + jmp crlf ; tailcall + +; +; "noescape" command +; +pc_noescape: + mov byte [KbdFlags],0 + ; Fall into pc_getline + +; +; Comment line +; +pc_comment: ; Fall into pc_getline + +; +; Common subroutine: load line into trackbuf; returns with SI -> trackbuf +; +pc_getline: mov di,trackbuf + push di + call getline + xor al,al + stosb ; Null-terminate + pop si + ret + +; +; Main loop for configuration file parsing +; +parse_config: + mov di,VKernelBuf ; Clear VKernelBuf at start + xor ax,ax + mov cx,vk_size + rep stosb +.again: + call getcommand + jnc .again ; If not EOF do it again + ; + ; The fall through to commit_vk to commit any final + ; VKernel being read + ; +; +; commit_vk: Store the current VKernelBuf into buffer segment +; +commit_vk: + ; For better compression, clean up the append field + mov ax,[VKernelBuf+vk_appendlen] + mov di,VKernelBuf+vk_append + add di,ax + mov cx,max_cmd_len+1 + sub cx,ax + xor ax,ax + rep stosb + + ; Pack temporarily into trackbuf + mov si,VKernelBuf + mov di,trackbuf + mov cx,vk_size + call rllpack + ; Now DX = number of bytes + mov di,[VKernelBytes] + mov cx,dx + add dx,di + jc .overflow ; If > 1 segment + mov [VKernelBytes],dx + mov si,trackbuf + push es + push word vk_seg + pop es + rep movsb + pop es + ret +.overflow: + mov si,vk_overflow_msg + call writestr + ret + + section .data +vk_overflow_msg db 'Out of memory parsing config file', CR, LF, 0 + + align 2, db 0 +AppendLen dw 0 ; Bytes in append= command +OntimeoutLen dw 0 ; Bytes in ontimeout command +OnerrorLen dw 0 ; Bytes in onerror command +KbdTimeOut dw 0 ; Keyboard timeout (if any) +CmdLinePtr dw cmd_line_here ; Command line advancing pointer +ForcePrompt dw 0 ; Force prompt +AllowImplicit dw 1 ; Allow implicit kernels +AllowOptions dw 1 ; User-specified options allowed +SerialPort dw 0 ; Serial port base (or 0 for no serial port) +VKernelBytes dw 0 ; Number of bytes used by vkernels +VKernel db 0 ; Have we seen any "label" statements? + + section .bss + alignb 4 ; For the good of REP MOVSD +command_line resb max_cmd_len+2 ; Command line buffer + alignb 4 +default_cmd resb max_cmd_len+1 ; "default" command line + +%include "rllpack.inc" diff --git a/syslinux/ppmtolss16 b/syslinux/ppmtolss16 new file mode 100755 index 0000000..1708f15 --- /dev/null +++ b/syslinux/ppmtolss16 @@ -0,0 +1,398 @@ +#!/usr/bin/perl +## $Id: ppmtolss16,v 1.12 2004/12/14 23:03:28 hpa Exp $ +## ----------------------------------------------------------------------- +## +## Copyright 2004 H. Peter Anvin - All Rights Reserved +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, Inc., 53 Temple Place Ste 330, +## Boston MA 02111-1307, USA; either version 2 of the License, or +## (at your option) any later version; incorporated herein by reference. +## +## ----------------------------------------------------------------------- + +## +## ppmtolss16 +## +## Convert a PNM file with max 16 colors to a simple RLE-based format: +## +## uint32 0x1413f33d ; magic (littleendian) +## uint16 xsize ; littleendian +## uint16 ysize ; littleendian +## 16 x uint8 r,g,b ; color map, in 6-bit format (each byte is 0..63) +## +## Then, a sequence of nybbles: +## +## N ... if N is != previous pixel, one pixel of color N +## ... otherwise run sequence follows ... +## M ... if M > 0 then run length is M+1 +## ... otherwise run sequence is encoded in two nybbles, +## littleendian, +17 +## +## The nybble sequences are on a per-row basis; runs may not extend +## across rows and odd-nybble rows are zero-padded. +## +## At the start of row, the "previous pixel" is assumed to be zero. +## +## Usage: +## +## ppmtolss16 [#rrggbb=i ...] < input.ppm > output.rle +## +## Command line options of the form #rrggbb=i indicate that +## the color #rrggbb (hex) should be assigned index i (decimal) +## + +eval { use bytes; }; +eval { binmode STDIN; }; +eval { binmode STDOUT; }; + +$magic = 0x1413f33d; + +# Get a token from the PPM header. Ignore comments and leading +# and trailing whitespace, as is required by the spec. +# This routine eats exactly one character of trailing whitespace, +# unless it is a comment (in which case it eats the comment up +# to and including the end of line.) +sub get_token() { + my($token, $ch); + my($ch); + + do { + $ch = getc(STDIN); + return undef if ( !defined($ch) ); # EOF + if ( $ch eq '#' ) { + do { + $ch = getc(STDIN); + return undef if ( !defined($ch) ); + } while ( $ch ne "\n" ); + } + } while ( $ch =~ /^[ \t\n\v\f\r]$/ ); + + $token = $ch; + while ( 1 ) { + $ch = getc(STDIN); + last if ( $ch =~ /^[ \t\n\v\f\r\#]$/ ); + $token .= $ch; + } + if ( $ch eq '#' ) { + do { + $ch = getc(STDIN); + } while ( defined($ch) && $ch ne "\n" ); + } + return $token; +} + +# Get a token, and make sure it is numeric (and exists) +sub get_numeric_token() { + my($token) = get_token(); + + if ( $token !~ /^[0-9]+$/ ) { + print STDERR "Format error on input\n"; + exit 1; + } + + return $token + 0; +} + +# Must be called before each pixel row is read +sub start_new_row() { + $getrgb_leftover_bit_cnt = 0; + $getrgb_leftover_bit_val = 0; +} + +# Get a single RGB token depending on the PNM type +sub getrgb($) { + my($form) = @_; + my($rgb,$r,$g,$b); + + if ( $form == 6 ) { + # Raw PPM, most common + return undef unless ( read(STDIN,$rgb,3) == 3 ); + return unpack("CCC", $rgb); + } elsif ( $form == 3 ) { + # Plain PPM + $r = get_numeric_token(); + $g = get_numeric_token(); + $b = get_numeric_token(); + return ($r,$g,$b); + } elsif ( $form == 5 ) { + # Raw PGM + return undef unless ( read(STDIN,$rgb,1) == 1 ); + $r = unpack("C", $rgb); + return ($r,$r,$r); + } elsif ( $form == 2 ) { + # Plain PGM + $r = get_numeric_token(); + return ($r,$r,$r); + } elsif ( $form == 4 ) { + # Raw PBM + if ( !$getrgb_leftover_bit_cnt ) { + return undef unless ( read(STDIN,$rgb,1) == 1 ); + $getrgb_leftover_bit_val = unpack("C", $rgb); + $getrgb_leftover_bit_cnt = 8; + } + $r = ( $getrgb_leftover_bit_val & 0x80 ) ? 0x00 : 0xff; + $getrgb_leftover_bit_val <<= 1; + $getrgb_leftover_bit_cnt--; + + return ($r,$r,$r); + } elsif ( $form == 1 ) { + # Plain PBM + my($ch); + + do { + $ch = getc(STDIN); + return undef if ( !defined($ch) ); + return (255,255,255) if ( $ch eq '0' ); # White + return (0,0,0) if ( $ch eq '1'); # Black + if ( $ch eq '#' ) { + do { + $ch = getc(STDIN); + return undef if ( !defined($ch) ); + } while ( $ch ne "\n" ); + } + } while ( $ch =~ /^[ \t\n\v\f\r]$/ ); + return undef; + } else { + die "Internal error: unknown format: $form\n"; + } +} + +sub rgbconvert($$$$) { + my($r,$g,$b,$maxmult) = @_; + my($rgb); + + $r = int($r*$maxmult); + $g = int($g*$maxmult); + $b = int($b*$maxmult); + $rgb = pack("CCC", $r, $g, $b); + return $rgb; +} + +foreach $arg ( @ARGV ) { + if ( $arg =~ /^\#([0-9a-f])([0-9a-f])([0-9a-f])=([0-9]+)$/i ) { + $r = hex($1) << 4; + $g = hex($2) << 4; + $b = hex($3) << 4; + $i = $4 + 0; + } elsif ( $arg =~ /^\#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})=([0-9]+)$/i ) { + $r = hex($1); + $g = hex($2); + $b = hex($3); + $i = $4 + 0; + } elsif ( $arg =~ /^\#([0-9a-f]{3})([0-9a-f]{3})([0-9a-f]{3})=([0-9]+)$/i ) { + $r = hex($1) >> 4; + $g = hex($2) >> 4; + $b = hex($3) >> 4; + $i = $4 + 0; + } elsif ( $arg =~ /^\#([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})=([0-9]+)$/i ) { + $r = hex($1) >> 8; + $g = hex($2) >> 8; + $b = hex($3) >> 8; + $i = $4 + 0; + } else { + print STDERR "$0: Unknown argument: $arg\n"; + next; + } + + if ( $i > 15 ) { + print STDERR "$0: Color index out of range: $arg\n"; + next; + } + + $rgb = rgbconvert($r, $g, $b, 64/256); + + if ( defined($index_forced{$i}) ) { + print STDERR "$0: More than one color index $i\n"; + exit(1); + } + $index_forced{$i} = $rgb; + $force_index{$rgb} = $i; +} + +$form = get_token(); +die "$0: stdin is not a PNM file" if ( $form !~ /^P([1-6])$/ ); +$form = $1+0; + +$xsize = get_numeric_token(); +$ysize = get_numeric_token(); +if ( $form == 1 || $form == 4 ) { + $maxcol = 255; # Internal convention +} else { + $maxcol = get_numeric_token(); +} +$maxmult = 64/($maxcol+1); # Equal buckets conversion + +@data = (); + +for ( $y = 0 ; $y < $ysize ; $y++ ) { + start_new_row(); + for ( $x = 0 ; $x < $xsize ; $x++ ) { + die "$0: Premature EOF at ($x,$y) of ($xsize,$ysize)\n" + if ( !defined(@pnmrgb = getrgb($form)) ); + # Convert to 6-bit representation + $rgb = rgbconvert($pnmrgb[0], $pnmrgb[1], $pnmrgb[2], $maxmult); + $color_count{$rgb}++; + push(@data, $rgb); + } +} + +# Sort list of colors according to freqency +@colors = sort { $color_count{$b} <=> $color_count{$a} } keys(%color_count); + +# Now we have our pick of colors. Sort according to intensity; +# this is more or less an ugly hack to cover for the fact that +# using PPM as input doesn't let the user set the color map, +# which the user really needs to be able to do. + +sub by_intensity() { + my($ra,$ga,$ba) = unpack("CCC", $a); + my($rb,$gb,$bb) = unpack("CCC", $b); + + my($ia) = $ra*0.299 + $ga*0.587 + $ba*0.114; + my($ib) = $rb*0.299 + $gb*0.587 + $bb*0.114; + + return ( $ia <=> $ib ) if ( $ia != $ib ); + + # If same, sort based on RGB components, + # with highest priority given to G, then R, then B. + + return ( $ga <=> $gb ) if ( $ga != $gb ); + return ( $ra <=> $rb ) if ( $ra != $rb ); + return ( $ba <=> $bb ); +} + +@icolors = sort by_intensity @colors; + +# Insert forced colors into "final" array +@colors = (undef) x 16; +foreach $rgb ( keys(%force_index) ) { + $i = $force_index{$rgb}; + $colors[$i] = $rgb; + $color_index{$rgb} = $i; +} + +undef %force_index; + +# Insert remaining colors in the remaining slots, +# in luminosity-sorted order +$nix = 0; +while ( scalar(@icolors) ) { + # Advance to the next free slot + $nix++ while ( defined($colors[$nix]) && $nix < 16 ); + last if ( $nix >= 16 ); + $rgb = shift @icolors; + if ( !defined($color_index{$rgb}) ) { + $colors[$nix] = $rgb; + $color_index{$rgb} = $nix; + } +} + +while ( scalar(@icolors) ) { + $rgb = shift @icolors; + $lost++ if ( !defined($color_index{$rgb}) ); +} + +if ( $lost ) { + printf STDERR + "$0: Warning: color palette truncated (%d colors ignored)\n", $lost; +} + +undef @icolors; + +# Output header +print pack("Vvv", $magic, $xsize, $ysize); + +# Output color map +for ( $i = 0 ; $i < 16 ; $i++ ) { + if ( defined($colors[$i]) ) { + print $colors[$i]; + } else { + # Padding for unused color entries + print pack("CCC", 63*$i/15, 63*$i/15, 63*$i/15); + } +} + +sub output_nybble($) { + my($ny) = @_; + + if ( !defined($ny) ) { + if ( defined($nybble_tmp) ) { + $ny = 0; # Force the last byte out + } else { + return; + } + } + + $ny = $ny & 0x0F; + + if ( defined($nybble_tmp) ) { + $ny = ($ny << 4) | $nybble_tmp; + print chr($ny); + $bytes++; + undef $nybble_tmp; + } else { + $nybble_tmp = $ny; + } +} + +sub output_run($$$) { + my($last,$this,$run) = @_; + + if ( $this != $last ) { + output_nybble($this); + $run--; + } + while ( $run ) { + if ( $run >= 16 ) { + output_nybble($this); + output_nybble(0); + if ( $run > 271 ) { + $erun = 255; + $run -= 271; + } else { + $erun = $run-16; + $run = 0; + } + output_nybble($erun); + output_nybble($erun >> 4); + } else { + output_nybble($this); + output_nybble($run); + $run = 0; + } + } +} + +$bytes = 0; +undef $nybble_tmp; + +for ( $y = 0 ; $y < $ysize ; $y++ ) { + $last = $prev = 0; + $run = 0; + for ( $x = 0 ; $x < $xsize ; $x++ ) { + $rgb = shift(@data); + $i = $color_index{$rgb} + 0; + if ( $i == $last ) { + $run++; + } else { + output_run($prev, $last, $run); + $prev = $last; + $last = $i; + $run = 1; + } + } + # Output final datum for row; we're always at least one pixel behind + output_run($prev, $last, $run); + output_nybble(undef); # Flush row +} + +$pixels = $xsize * $ysize; +$size = ($pixels+1)/2; +printf STDERR "%d pixels, %d bytes, (%2.2f%% compression)\n", + $pixels, $bytes, 100*($size-$bytes)/$size; + + + + diff --git a/syslinux/pxe.inc b/syslinux/pxe.inc new file mode 100644 index 0000000..0ac225a --- /dev/null +++ b/syslinux/pxe.inc @@ -0,0 +1,145 @@ +;; ----------------------------------------------------------------------- +;; +;; Copyright 1999-2004 H. Peter Anvin - All Rights Reserved +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +;; Boston MA 02111-1307, USA; either version 2 of the License, or +;; (at your option) any later version; incorporated herein by reference. +;; +;; ----------------------------------------------------------------------- +;; $Id: pxe.inc,v 1.5 2004/12/14 23:03:28 hpa Exp $ + +;; +;; pxe.inc +;; +;; PXE opcodes +;; + +%ifndef _PXE_INC +%define _PXE_INC 1 + +%define PXENV_TFTP_OPEN 0020h +%define PXENV_TFTP_CLOSE 0021h +%define PXENV_TFTP_READ 0022h +%define PXENV_TFTP_READ_FILE 0023h +%define PXENV_TFTP_READ_FILE_PMODE 0024h +%define PXENV_TFTP_GET_FSIZE 0025h + +%define PXENV_UDP_OPEN 0030h +%define PXENV_UDP_CLOSE 0031h +%define PXENV_UDP_READ 0032h +%define PXENV_UDP_WRITE 0033h + +%define PXENV_START_UNDI 0000h +%define PXENV_UNDI_STARTUP 0001h +%define PXENV_UNDI_CLEANUP 0002h +%define PXENV_UNDI_INITIALIZE 0003h +%define PXENV_UNDI_RESET_NIC 0004h +%define PXENV_UNDI_SHUTDOWN 0005h +%define PXENV_UNDI_OPEN 0006h +%define PXENV_UNDI_CLOSE 0007h +%define PXENV_UNDI_TRANSMIT 0008h +%define PXENV_UNDI_SET_MCAST_ADDR 0009h +%define PXENV_UNDI_SET_STATION_ADDR 000Ah +%define PXENV_UNDI_SET_PACKET_FILTER 000Bh +%define PXENV_UNDI_GET_INFORMATION 000Ch +%define PXENV_UNDI_GET_STATISTICS 000Dh +%define PXENV_UNDI_CLEAR_STATISTICS 000Eh +%define PXENV_UNDI_INITIATE_DIAGS 000Fh +%define PXENV_UNDI_FORCE_INTERRUPT 0010h +%define PXENV_UNDI_GET_MCAST_ADDR 0011h +%define PXENV_UNDI_GET_NIC_TYPE 0012h +%define PXENV_UNDI_GET_IFACE_INFO 0013h +%define PXENV_UNDI_ISR 0014h +%define PXENV_STOP_UNDI 0015h ; Overlap...? +%define PXENV_UNDI_GET_STATE 0015h ; Overlap...? + +%define PXENV_UNLOAD_STACK 0070h +%define PXENV_GET_CACHED_INFO 0071h +%define PXENV_RESTART_DHCP 0072h +%define PXENV_RESTART_TFTP 0073h +%define PXENV_MODE_SWITCH 0074h +%define PXENV_START_BASE 0075h +%define PXENV_STOP_BASE 0076h + +%define PXENV_EXIT_SUCCESS 0x0000 +%define PXENV_EXIT_FAILURE 0x0001 + +%define PXENV_STATUS_SUCCESS 0x00 +%define PXENV_STATUS_FAILURE 0x01 +%define PXENV_STATUS_BAD_FUNC 0x02 +%define PXENV_STATUS_UNSUPPORTED 0x03 +%define PXENV_STATUS_KEEP_UNDI 0x04 +%define PXENV_STATUS_KEEP_ALL 0x05 +%define PXENV_STATUS_OUT_OF_RESOURCES 0x06 +%define PXENV_STATUS_ARP_TIMEOUT 0x11 +%define PXENV_STATUS_UDP_CLOSED 0x18 +%define PXENV_STATUS_UDP_OPEN 0x19 +%define PXENV_STATUS_TFTP_CLOSED 0x1A +%define PXENV_STATUS_TFTP_OPEN 0x1B +%define PXENV_STATUS_MCOPY_PROBLEM 0x20 +%define PXENV_STATUS_BIS_INTEGRITY_FAILURE 0x21 +%define PXENV_STATUS_BIS_VALIDATE_FAILURE 0x22 +%define PXENV_STATUS_BIS_INIT_FAILURE 0x23 +%define PXENV_STATUS_BIS_SHUTDOWN_FAILURE 0x24 +%define PXENV_STATUS_BIS_GBOA_FAILURE 0x25 +%define PXENV_STATUS_BIS_FREE_FAILURE 0x26 +%define PXENV_STATUS_BIS_GSI_FAILURE 0x27 +%define PXENV_STATUS_BIS_BAD_CKSUM 0x28 +%define PXENV_STATUS_TFTP_CANNOT_ARP_ADDRESS 0x30 +%define PXENV_STATUS_TFTP_OPEN_TIMEOUT 0x32 + +%define PXENV_STATUS_TFTP_UNKNOWN_OPCODE 0x33 +%define PXENV_STATUS_TFTP_READ_TIMEOUT 0x35 +%define PXENV_STATUS_TFTP_ERROR_OPCODE 0x36 +%define PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION 0x38 +%define PXENV_STATUS_TFTP_CANNOT_READ_FROM_CONNECTION 0x39 +%define PXENV_STATUS_TFTP_TOO_MANY_PACKAGES 0x3A +%define PXENV_STATUS_TFTP_FILE_NOT_FOUND 0x3B +%define PXENV_STATUS_TFTP_ACCESS_VIOLATION 0x3C +%define PXENV_STATUS_TFTP_NO_MCAST_ADDRESS 0x3D +%define PXENV_STATUS_TFTP_NO_FILESIZE 0x3E +%define PXENV_STATUS_TFTP_INVALID_PACKET_SIZE 0x3F +%define PXENV_STATUS_DHCP_TIMEOUT 0x51 +%define PXENV_STATUS_DHCP_NO_IP_ADDRESS 0x52 +%define PXENV_STATUS_DHCP_NO_BOOTFILE_NAME 0x53 +%define PXENV_STATUS_DHCP_BAD_IP_ADDRESS 0x54 +%define PXENV_STATUS_UNDI_INVALID_FUNCTION 0x60 +%define PXENV_STATUS_UNDI_MEDIATEST_FAILED 0x61 +%define PXENV_STATUS_UNDI_CANNOT_INIT_NIC_FOR_MCAST 0x62 +%define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC 0x63 +%define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_PHY 0x64 +%define PXENV_STATUS_UNDI_CANNOT_READ_CONFIG_DATA 0x65 +%define PXENV_STATUS_UNDI_CANNOT_READ_INIT_DATA 0x66 +%define PXENV_STATUS_UNDI_BAD_MAC_ADDRESS 0x67 +%define PXENV_STATUS_UNDI_BAD_EEPROM_CHECKSUM 0x68 +%define PXENV_STATUS_UNDI_ERROR_SETTING_ISR 0x69 +%define PXENV_STATUS_UNDI_INVALID_STATE 0x6A +%define PXENV_STATUS_UNDI_TRANSMIT_ERROR 0x6B +%define PXENV_STATUS_UNDI_INVALID_PARAMETER 0x6C +%define PXENV_STATUS_BSTRAP_PROMPT_MENU 0x74 +%define PXENV_STATUS_BSTRAP_MCAST_ADDR 0x76 +%define PXENV_STATUS_BSTRAP_MISSING_LIST 0x77 +%define PXENV_STATUS_BSTRAP_NO_RESPONSE 0x78 +%define PXENV_STATUS_BSTRAP_FILE_TOO_BIG 0x79 +%define PXENV_STATUS_BINL_CANCELED_BY_KEYSTROKE 0xA0 +%define PXENV_STATUS_BINL_NO_PXE_SERVER 0xA1 +%define PXENV_STATUS_NOT_AVAILABLE_IN_PMODE 0xA2 +%define PXENV_STATUS_NOT_AVAILABLE_IN_RMODE 0xA3 +%define PXENV_STATUS_BUSD_DEVICE_NOT_SUPPORTED 0xB0 +%define PXENV_STATUS_LOADER_NO_FREE_BASE_MEMORY 0xC0 +%define PXENV_STATUS_LOADER_NO_BC_ROMID 0xC1 +%define PXENV_STATUS_LOADER_BAD_BC_ROMID 0xC2 +%define PXENV_STATUS_LOADER_BAD_BC_RUNTIME_IMAGE 0xC3 +%define PXENV_STATUS_LOADER_NO_UNDI_ROMID 0xC4 +%define PXENV_STATUS_LOADER_BAD_UNDI_ROMID 0xC5 +%define PXENV_STATUS_LOADER_BAD_UNDI_DRIVER_IMAGE 0xC6 +%define PXENV_STATUS_LOADER_NO_PXE_STRUCT 0xC8 +%define PXENV_STATUS_LOADER_NO_PXENV_STRUCT 0xC9 +%define PXENV_STATUS_LOADER_UNDI_START 0xCA +%define PXENV_STATUS_LOADER_BC_START 0xCB + +%endif ; _PXE_INC + diff --git a/syslinux/pxelinux.0 b/syslinux/pxelinux.0 new file mode 100644 index 0000000000000000000000000000000000000000..b7d967b7850c92b5604a2de1970d620955430158 GIT binary patch literal 12952 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 V7r$6Mv1DS2zj&zl$6{=+{|CrfmBs)7 literal 0 HcmV?d00001 diff --git a/syslinux/pxelinux.asm b/syslinux/pxelinux.asm new file mode 100644 index 0000000..fda128c --- /dev/null +++ b/syslinux/pxelinux.asm @@ -0,0 +1,2606 @@ +; -*- fundamental -*- (asm-mode sucks) +; $Id: pxelinux.asm,v 1.168 2005/01/20 18:43:22 hpa Exp $ +; **************************************************************************** +; +; pxelinux.asm +; +; A program to boot Linux kernels off a TFTP server using the Intel PXE +; network booting API. It is based on the SYSLINUX boot loader for +; MS-DOS floppies. +; +; Copyright (C) 1994-2005 H. Peter Anvin +; +; This program is free software; you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +; Boston MA 02111-1307, USA; either version 2 of the License, or +; (at your option) any later version; incorporated herein by reference. +; +; **************************************************************************** + +%define IS_PXELINUX 1 +%include "macros.inc" +%include "config.inc" +%include "kernel.inc" +%include "bios.inc" +%include "tracers.inc" +%include "pxe.inc" +%include "layout.inc" + +; +; Some semi-configurable constants... change on your own risk. +; +my_id equ pxelinux_id +FILENAME_MAX_LG2 equ 7 ; log2(Max filename size Including final null) +FILENAME_MAX equ (1 << FILENAME_MAX_LG2) +NULLFILE equ 0 ; Zero byte == null file name +NULLOFFSET equ 4 ; Position in which to look +REBOOT_TIME equ 5*60 ; If failure, time until full reset +%assign HIGHMEM_SLOP 128*1024 ; Avoid this much memory near the top +MAX_OPEN_LG2 equ 5 ; log2(Max number of open sockets) +MAX_OPEN equ (1 << MAX_OPEN_LG2) +PKTBUF_SIZE equ (65536/MAX_OPEN) ; Per-socket packet buffer size +TFTP_PORT equ htons(69) ; Default TFTP port +PKT_RETRY equ 6 ; Packet transmit retry count +PKT_TIMEOUT equ 12 ; Initial timeout, timer ticks @ 55 ms +; Desired TFTP block size +; For Ethernet MTU is normally 1500. Unfortunately there seems to +; be a fair number of networks with "substandard" MTUs which break. +; The code assumes TFTP_LARGEBLK <= 2K. +TFTP_MTU equ 1472 +TFTP_LARGEBLK equ (TFTP_MTU-20-8-4) ; MTU - IP hdr - UDP hdr - TFTP hdr +; Standard TFTP block size +TFTP_BLOCKSIZE_LG2 equ 9 ; log2(bytes/block) +TFTP_BLOCKSIZE equ (1 << TFTP_BLOCKSIZE_LG2) +%assign USE_PXE_PROVIDED_STACK 1 ; Use stack provided by PXE? + +SECTOR_SHIFT equ TFTP_BLOCKSIZE_LG2 +SECTOR_SIZE equ TFTP_BLOCKSIZE + +; +; This is what we need to do when idle +; +%macro RESET_IDLE 0 + call reset_idle +%endmacro +%macro DO_IDLE 0 + call check_for_arp +%endmacro + +; +; TFTP operation codes +; +TFTP_RRQ equ htons(1) ; Read request +TFTP_WRQ equ htons(2) ; Write request +TFTP_DATA equ htons(3) ; Data packet +TFTP_ACK equ htons(4) ; ACK packet +TFTP_ERROR equ htons(5) ; ERROR packet +TFTP_OACK equ htons(6) ; OACK packet + +; +; TFTP error codes +; +TFTP_EUNDEF equ htons(0) ; Unspecified error +TFTP_ENOTFOUND equ htons(1) ; File not found +TFTP_EACCESS equ htons(2) ; Access violation +TFTP_ENOSPACE equ htons(3) ; Disk full +TFTP_EBADOP equ htons(4) ; Invalid TFTP operation +TFTP_EBADID equ htons(5) ; Unknown transfer +TFTP_EEXISTS equ htons(6) ; File exists +TFTP_ENOUSER equ htons(7) ; No such user +TFTP_EOPTNEG equ htons(8) ; Option negotiation failure + +; +; The following structure is used for "virtual kernels"; i.e. LILO-style +; option labels. The options we permit here are `kernel' and `append +; Since there is no room in the bottom 64K for all of these, we +; stick them at vk_seg:0000 and copy them down before we need them. +; + struc vkernel +vk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!** +vk_rname: resb FILENAME_MAX ; Real name +vk_ipappend: resb 1 ; "IPAPPEND" flag + resb 1 ; Pad +vk_appendlen: resw 1 + alignb 4 +vk_append: resb max_cmd_len+1 ; Command line + alignb 4 +vk_end: equ $ ; Should be <= vk_size + endstruc + +; +; Segment assignments in the bottom 640K +; 0000h - main code/data segment (and BIOS segment) +; +real_mode_seg equ 4000h +vk_seg equ 3000h ; Virtual kernels +xfer_buf_seg equ 2000h ; Bounce buffer for I/O to high mem +pktbuf_seg equ 1000h ; Packet buffers segments +comboot_seg equ real_mode_seg ; COMBOOT image loading zone + +; +; BOOTP/DHCP packet pattern +; + struc bootp_t +bootp: +.opcode resb 1 ; BOOTP/DHCP "opcode" +.hardware resb 1 ; ARP hardware type +.hardlen resb 1 ; Hardware address length +.gatehops resb 1 ; Used by forwarders +.ident resd 1 ; Transaction ID +.seconds resw 1 ; Seconds elapsed +.flags resw 1 ; Broadcast flags +.cip resd 1 ; Client IP +.yip resd 1 ; "Your" IP +.sip resd 1 ; Next server IP +.gip resd 1 ; Relay agent IP +.macaddr resb 16 ; Client MAC address +.sname resb 64 ; Server name (optional) +.bootfile resb 128 ; Boot file name +.option_magic resd 1 ; Vendor option magic cookie +.options resb 1260 ; Vendor options + endstruc + +BOOTP_OPTION_MAGIC equ htonl(0x63825363) ; See RFC 2132 + +; +; TFTP connection data structure. Each one of these corresponds to a local +; UDP port. The size of this structure must be a power of 2. +; HBO = host byte order; NBO = network byte order +; (*) = written by options negotiation code, must be dword sized +; + struc open_file_t +tftp_localport resw 1 ; Local port number (0 = not in use) +tftp_remoteport resw 1 ; Remote port number +tftp_remoteip resd 1 ; Remote IP address +tftp_filepos resd 1 ; Bytes downloaded (including buffer) +tftp_filesize resd 1 ; Total file size(*) +tftp_blksize resd 1 ; Block size for this connection(*) +tftp_bytesleft resw 1 ; Unclaimed data bytes +tftp_lastpkt resw 1 ; Sequence number of last packet (NBO) +tftp_dataptr resw 1 ; Pointer to available data + resw 2 ; Currently unusued + ; At end since it should not be zeroed on socked close +tftp_pktbuf resw 1 ; Packet buffer offset + endstruc +%ifndef DEPEND +%if (open_file_t_size & (open_file_t_size-1)) +%error "open_file_t is not a power of 2" +%endif +%endif + +; --------------------------------------------------------------------------- +; BEGIN CODE +; --------------------------------------------------------------------------- + +; +; Memory below this point is reserved for the BIOS and the MBR +; + section .earlybss +trackbufsize equ 8192 +trackbuf resb trackbufsize ; Track buffer goes here +getcbuf resb trackbufsize + ; ends at 4800h + + ; Put some large buffers here, before RBFG_brainfuck, + ; where we can still carefully control the address + ; assignments... + + alignb open_file_t_size +Files resb MAX_OPEN*open_file_t_size + + alignb FILENAME_MAX +BootFile resb 256 ; Boot file from DHCP packet +ConfigServer resd 1 ; Null prefix for mangled config name +ConfigName resb 256-4 ; Configuration file from DHCP option +PathPrefix resb 256 ; Path prefix derived from boot file +DotQuadBuf resb 16 ; Buffer for dotted-quad IP address +IPOption resb 80 ; ip= option buffer +InitStack resd 1 ; Pointer to reset stack + +; Warning here: RBFG build 22 randomly overwrites memory location +; [0x5680,0x576c), possibly more. It seems that it gets confused and +; screws up the pointer to its own internal packet buffer and starts +; writing a received ARP packet into low memory. +RBFG_brainfuck resb 0E00h + + section .bss + alignb 4 +RebootTime resd 1 ; Reboot timeout, if set by option +StrucPtr resd 1 ; Pointer to PXENV+ or !PXE structure +APIVer resw 1 ; PXE API version found +IPOptionLen resw 1 ; Length of IPOption +IdleTimer resw 1 ; Time to check for ARP? +LocalBootType resw 1 ; Local boot return code +PktTimeout resw 1 ; Timeout for current packet +RealBaseMem resw 1 ; Amount of DOS memory after freeing +OverLoad resb 1 ; Set if DHCP packet uses "overloading" + +; The relative position of these fields matter! +MACLen resb 1 ; MAC address len +MACType resb 1 ; MAC address type +MAC resb 16 ; Actual MAC address +BOOTIFStr resb 7 ; Space for "BOOTIF=" +MACStr resb 3*17 ; MAC address as a string + +; +; PXE packets which don't need static initialization +; + alignb 4 +pxe_unload_stack_pkt: +.status: resw 1 ; Status +.reserved: resw 10 ; Reserved +pxe_unload_stack_pkt_len equ $-pxe_unload_stack_pkt + + alignb 16 + ; BOOTP/DHCP packet buffer + + alignb 16 +packet_buf resb 2048 ; Transfer packet +packet_buf_size equ $-packet_buf + +; +; Constants for the xfer_buf_seg +; +; The xfer_buf_seg is also used to store message file buffers. We +; need two trackbuffers (text and graphics), plus a work buffer +; for the graphics decompressor. +; +xbs_textbuf equ 0 ; Also hard-coded, do not change +xbs_vgabuf equ trackbufsize +xbs_vgatmpbuf equ 2*trackbufsize + + section .text + ; + ; PXELINUX needs more BSS than the other derivatives; + ; therefore we relocate it from 7C00h on startup. + ; +StackBuf equ $ ; Base of stack if we use our own + +; +; Primary entry point. +; +bootsec equ $ +_start: + pushfd ; Paranoia... in case of return to PXE + pushad ; ... save as much state as possible + push ds + push es + push fs + push gs + + xor ax,ax + mov ds,ax + mov es,ax + + ; This is uglier than it should be, but works around + ; some NASM 0.98.38 bugs. + mov di,section..bcopy32.start + add di,__bcopy_size-4 + lea si,[di-(TEXT_START-7C00h)] + lea cx,[di-(TEXT_START-4)] + shr cx,2 + std ; Overlapping areas, copy backwards + rep movsd + + jmp 0:_start1 ; Canonicalize address +_start1: + mov bp,sp + les bx,[bp+48] ; ES:BX -> !PXE or PXENV+ structure + + ; That is all pushed onto the PXE stack. Save the pointer + ; to it and switch to an internal stack. + mov [InitStack],sp + mov [InitStack+2],ss + +%if USE_PXE_PROVIDED_STACK + ; Apparently some platforms go bonkers if we + ; set up our own stack... + mov [BaseStack],sp + mov [BaseStack+4],ss +%endif + + cli ; Paranoia + lss esp,[BaseStack] + + sti ; Stack set up and ready + cld ; Copy upwards + +; +; Initialize screen (if we're using one) +; + ; Now set up screen parameters + call adjust_screen + + ; Wipe the F-key area + mov al,NULLFILE + mov di,FKeyName + mov cx,10*(1 << FILENAME_MAX_LG2) + push es ; Save ES -> PXE structure + push ds ; ES <- DS + pop es + rep stosb + pop es ; Restore ES + +; +; Tell the user we got this far +; + mov si,syslinux_banner + call writestr + + mov si,copyright_str + call writestr + +; +; Assume API version 2.1, in case we find the !PXE structure without +; finding the PXENV+ structure. This should really look at the Base +; Code ROM ID structure in have_pxe, but this is adequate for now -- +; if we have !PXE, we have to be 2.1 or higher, and we don't care +; about higher versions than that. +; + mov word [APIVer],0201h + +; +; Now we need to find the !PXE structure. It's *supposed* to be pointed +; to by SS:[SP+4], but support INT 1Ah, AX=5650h method as well. +; FIX: ES:BX should point to the PXENV+ structure on entry as well. +; We should make that the second test, and not trash ES:BX... +; + cmp dword [es:bx], '!PXE' + je have_pxe + + ; Uh-oh, not there... try plan B + mov ax, 5650h + int 1Ah ; May trash regs + jc no_pxe + cmp ax,564Eh + jne no_pxe + + ; Okay, that gave us the PXENV+ structure, find !PXE + ; structure from that (if available) + cmp dword [es:bx], 'PXEN' + jne no_pxe + cmp word [es:bx+4], 'V+' + je have_pxenv + + ; Nothing there either. Last-ditch: scan memory + call memory_scan_for_pxe_struct ; !PXE scan + jnc have_pxe + call memory_scan_for_pxenv_struct ; PXENV+ scan + jnc have_pxenv + +no_pxe: mov si,err_nopxe + call writestr + jmp kaboom + +have_pxenv: + mov [StrucPtr],bx + mov [StrucPtr+2],es + + mov si,found_pxenv + call writestr + + mov si,apiver_str + call writestr + mov ax,[es:bx+6] + mov [APIVer],ax + call writehex4 + call crlf + + cmp ax,0201h ; API version 2.1 or higher + jb old_api + mov si,bx + mov ax,es + les bx,[es:bx+28h] ; !PXE structure pointer + cmp dword [es:bx],'!PXE' + je have_pxe + + ; Nope, !PXE structure missing despite API 2.1+, or at least + ; the pointer is missing. Do a last-ditch attempt to find it. + call memory_scan_for_pxe_struct + jnc have_pxe + + ; Otherwise, no dice, use PXENV+ structure + mov bx,si + mov es,ax + +old_api: ; Need to use a PXENV+ structure + mov si,using_pxenv_msg + call writestr + + mov eax,[es:bx+0Ah] ; PXE RM API + mov [PXENVEntry],eax + + mov si,undi_data_msg + call writestr + mov ax,[es:bx+20h] + call writehex4 + call crlf + mov si,undi_data_len_msg + call writestr + mov ax,[es:bx+22h] + call writehex4 + call crlf + mov si,undi_code_msg + call writestr + mov ax,[es:bx+24h] + call writehex4 + call crlf + mov si,undi_code_len_msg + call writestr + mov ax,[es:bx+26h] + call writehex4 + call crlf + + ; Compute base memory size from PXENV+ structure + xor esi,esi + movzx eax,word [es:bx+20h] ; UNDI data seg + cmp ax,[es:bx+24h] ; UNDI code seg + ja .use_data + mov ax,[es:bx+24h] + mov si,[es:bx+26h] + jmp short .combine +.use_data: + mov si,[es:bx+22h] +.combine: + shl eax,4 + add eax,esi + shr eax,10 ; Convert to kilobytes + mov [RealBaseMem],ax + + mov si,pxenventry_msg + call writestr + mov ax,[PXENVEntry+2] + call writehex4 + mov al,':' + call writechr + mov ax,[PXENVEntry] + call writehex4 + call crlf + jmp have_entrypoint + +have_pxe: + mov [StrucPtr],bx + mov [StrucPtr+2],es + + mov eax,[es:bx+10h] + mov [PXEEntry],eax + + mov si,undi_data_msg + call writestr + mov eax,[es:bx+2Ah] + call writehex8 + call crlf + mov si,undi_data_len_msg + call writestr + mov ax,[es:bx+2Eh] + call writehex4 + call crlf + mov si,undi_code_msg + call writestr + mov ax,[es:bx+32h] + call writehex8 + call crlf + mov si,undi_code_len_msg + call writestr + mov ax,[es:bx+36h] + call writehex4 + call crlf + + ; Compute base memory size from !PXE structure + xor esi,esi + mov eax,[es:bx+2Ah] + cmp eax,[es:bx+32h] + ja .use_data + mov eax,[es:bx+32h] + mov si,[es:bx+36h] + jmp short .combine +.use_data: + mov si,[es:bx+2Eh] +.combine: + add eax,esi + shr eax,10 + mov [RealBaseMem],ax + + mov si,pxeentry_msg + call writestr + mov ax,[PXEEntry+2] + call writehex4 + mov al,':' + call writechr + mov ax,[PXEEntry] + call writehex4 + call crlf + +have_entrypoint: + push cs + pop es ; Restore CS == DS == ES + +; +; Network-specific initialization +; + xor ax,ax + mov [LocalDomain],al ; No LocalDomain received + +; +; Now attempt to get the BOOTP/DHCP packet that brought us life (and an IP +; address). This lives in the DHCPACK packet (query info 2). +; +query_bootp: + mov di,pxe_bootp_query_pkt_2 + mov bx,PXENV_GET_CACHED_INFO + + call pxenv + push word [pxe_bootp_query_pkt_2.status] + jc .pxe_err1 + cmp ax,byte 0 + je .pxe_ok +.pxe_err1: + mov di,pxe_bootp_size_query_pkt + mov bx,PXENV_GET_CACHED_INFO + + call pxenv + jc .pxe_err +.pxe_size: + mov ax,[pxe_bootp_size_query_pkt.buffersize] + call writehex4 + call crlf + +.pxe_err: + mov si,err_pxefailed + call writestr + call writehex4 + mov al, ' ' + call writechr + pop ax ; Status + call writehex4 + call crlf + jmp kaboom ; We're dead + +.pxe_ok: + pop cx ; Forget status + mov cx,[pxe_bootp_query_pkt_2.buffersize] + call parse_dhcp ; Parse DHCP packet +; +; Save away MAC address (assume this is in query info 2. If this +; turns out to be problematic it might be better getting it from +; the query info 1 packet.) +; +.save_mac: + movzx cx,byte [trackbuf+bootp.hardlen] + mov [MACLen],cl + mov al,[trackbuf+bootp.hardware] + mov [MACType],al + mov si,trackbuf+bootp.macaddr + mov di,MAC + push cx + rep movsb + mov cx,MAC+16 + sub cx,di + xor ax,ax + rep stosb + + mov si,bootif_str + mov di,BOOTIFStr + mov cx,bootif_str_len + rep movsb + + pop cx + mov si,MACType + inc cx + mov bx,hextbl_lower +.hexify_mac: + lodsb + mov ah,al + shr al,4 + xlatb + stosb + mov al,ah + and al,0Fh + xlatb + stosb + mov al,'-' + stosb + loop .hexify_mac + mov [di-1],byte 0 ; Null-terminate and strip final colon + +; +; Now, get the boot file and other info. This lives in the CACHED_REPLY +; packet (query info 3). +; + mov [pxe_bootp_size_query_pkt.packettype], byte 3 + + mov di,pxe_bootp_query_pkt_3 + mov bx,PXENV_GET_CACHED_INFO + + call pxenv + push word [pxe_bootp_query_pkt_3.status] + jc .pxe_err1 + cmp ax,byte 0 + jne .pxe_err1 + + ; Packet loaded OK... + pop cx ; Forget status + mov cx,[pxe_bootp_query_pkt_3.buffersize] + call parse_dhcp ; Parse DHCP packet +; +; Generate ip= option +; + call genipopt + +; +; Print IP address +; + mov eax,[MyIP] + mov di,DotQuadBuf + push di + call gendotquad ; This takes network byte order input + + xchg ah,al ; Convert to host byte order + ror eax,16 ; (BSWAP doesn't work on 386) + xchg ah,al + + mov si,myipaddr_msg + call writestr + call writehex8 + mov al,' ' + call writechr + pop si ; DotQuadBuf + call writestr + call crlf + + mov si,IPOption + call writestr + call crlf + +; +; Check to see if we got any PXELINUX-specific DHCP options; in particular, +; if we didn't get the magic enable, do not recognize any other options. +; +check_dhcp_magic: + test byte [DHCPMagic], 1 ; If we didn't get the magic enable... + jnz .got_magic + mov byte [DHCPMagic], 0 ; If not, kill all other options +.got_magic: + + +; +; Initialize UDP stack +; +udp_init: + mov eax,[MyIP] + mov [pxe_udp_open_pkt.sip],eax + mov di,pxe_udp_open_pkt + mov bx,PXENV_UDP_OPEN + call pxenv + jc .failed + cmp word [pxe_udp_open_pkt.status], byte 0 + je .success +.failed: mov si,err_udpinit + call writestr + jmp kaboom +.success: + +; +; Common initialization code +; +%include "init.inc" +%include "cpuinit.inc" + +; +; Now we're all set to start with our *real* business. First load the +; configuration file (if any) and parse it. +; +; In previous versions I avoided using 32-bit registers because of a +; rumour some BIOSes clobbered the upper half of 32-bit registers at +; random. I figure, though, that if there are any of those still left +; they probably won't be trying to install Linux on them... +; +; The code is still ripe with 16-bitisms, though. Not worth the hassle +; to take'm out. In fact, we may want to put them back if we're going +; to boot ELKS at some point. +; + +; +; Store standard filename prefix +; +prefix: test byte [DHCPMagic], 04h ; Did we get a path prefix option + jnz .got_prefix + mov si,BootFile + mov di,PathPrefix + cld + call strcpy + mov cx,di + sub cx,PathPrefix+1 + std + lea si,[di-2] ; Skip final null! +.find_alnum: lodsb + or al,20h + cmp al,'.' ; Count . or - as alphanum + je .alnum + cmp al,'-' + je .alnum + cmp al,'0' + jb .notalnum + cmp al,'9' + jbe .alnum + cmp al,'a' + jb .notalnum + cmp al,'z' + ja .notalnum +.alnum: loop .find_alnum + dec si +.notalnum: mov byte [si+2],0 ; Zero-terminate after delimiter + cld +.got_prefix: + mov si,tftpprefix_msg + call writestr + mov si,PathPrefix + call writestr + call crlf + +; +; Load configuration file +; +find_config: + +; +; Begin looking for configuration file +; +config_scan: + mov di,ConfigServer + xor eax,eax + stosd ; The config file is always from the server + + test byte [DHCPMagic], 02h + jz .no_option + + ; We got a DHCP option, try it first + mov si,trying_msg + call writestr + ; mov di,ConfigName ; - already the case + mov si,di + call writestr + call crlf + mov di,ConfigServer + call open + jnz .success + +.no_option: + mov di,ConfigName + mov si,cfgprefix + mov cx,cfgprefix_len + rep movsb + + ; Try loading by MAC address + ; Have to guess config file name + push di + mov si,MACStr + mov cx,(3*17+1)/2 + rep movsw + mov si,trying_msg + call writestr + mov di,ConfigName + mov si,di + call writestr + call crlf + mov di,ConfigServer + call open + pop di + jnz .success + +.scan_ip: + mov cx,8 + mov eax,[MyIP] + xchg ah,al ; Convert to host byte order + ror eax,16 + xchg ah,al +.hexify_loop: rol eax,4 + push eax + and al,0Fh + cmp al,10 + jae .high +.low: add al,'0' + jmp short .char +.high: add al,'A'-10 +.char: stosb + pop eax + loop .hexify_loop + + mov cx,9 ; Up to 9 attempts + +.tryagain: mov byte [di],0 + cmp cx,byte 1 + jne .not_default + pusha + mov si,default_str + mov cx,default_len + rep movsb ; Copy "default" string + popa +.not_default: pusha + mov si,trying_msg + call writestr + mov di,ConfigName + mov si,di + call writestr + call crlf + mov di,ConfigServer + call open + popa + jnz .success + dec di + loop .tryagain + + jmp no_config_file + +.success: + +; +; Now we have the config file open. Parse the config file and +; run the user interface. +; +%include "ui.inc" + +; +; Linux kernel loading code is common. However, we need to define +; a couple of helper macros... +; + +; Handle "ipappend" option +%define HAVE_SPECIAL_APPEND +%macro SPECIAL_APPEND 0 + test byte [IPAppend],01h ; ip= + jz .noipappend1 + mov si,IPOption + mov cx,[IPOptionLen] + rep movsb + mov al,' ' + stosb +.noipappend1: + test byte [IPAppend],02h + jz .noipappend2 + mov si,BOOTIFStr + call strcpy + mov byte [es:di-1],' ' ; Replace null with space +.noipappend2: +%endmacro + +; Unload PXE stack +%define HAVE_UNLOAD_PREP +%macro UNLOAD_PREP 0 + call unload_pxe +%endmacro + +%include "runkernel.inc" + +; +; COMBOOT-loading code +; +%include "comboot.inc" +%include "com32.inc" +%include "cmdline.inc" + +; +; Boot sector loading code +; +%include "bootsect.inc" + +; +; Boot to the local disk by returning the appropriate PXE magic. +; AX contains the appropriate return code. +; +local_boot: + mov si,cs + mov ds,si ; Restore DI + lss esp,[BaseStack] + mov [LocalBootType],ax + call vgaclearmode + mov si,localboot_msg + call writestr + ; Restore the environment we were called with + lss sp,[InitStack] + pop gs + pop fs + pop es + pop ds + popad + mov ax,[cs:LocalBootType] + popfd + retf ; Return to PXE + +; +; abort_check: let the user abort with <ESC> or <Ctrl-C> +; +abort_check: + call pollchar + jz ac_ret1 + pusha + call getchar + cmp al,27 ; <ESC> + je ac_kill + cmp al,3 ; <Ctrl-C> + jne ac_ret2 +ac_kill: mov si,aborted_msg + +; +; abort_load: Called by various routines which wants to print a fatal +; error message and return to the command prompt. Since this +; may happen at just about any stage of the boot process, assume +; our state is messed up, and just reset the segment registers +; and the stack forcibly. +; +; SI = offset (in _text) of error message to print +; +abort_load: + mov ax,cs ; Restore CS = DS = ES + mov ds,ax + mov es,ax + lss esp,[BaseStack] + sti + call cwritestr ; Expects SI -> error msg +al_ok: jmp enter_command ; Return to command prompt +; +; End of abort_check +; +ac_ret2: popa +ac_ret1: ret + + +; +; kaboom: write a message and bail out. Wait for quite a while, +; or a user keypress, then do a hard reboot. +; +kaboom: + mov ax,cs + mov es,ax + mov ds,ax + lss esp,[BaseStack] + sti +.patch: mov si,bailmsg + call writestr ; Returns with AL = 0 +.drain: call pollchar + jz .drained + call getchar + jmp short .drain +.drained: + mov edi,[RebootTime] + mov al,[DHCPMagic] + and al,09h ; Magic+Timeout + cmp al,09h + je .time_set + mov edi,REBOOT_TIME +.time_set: + mov cx,18 +.wait1: push cx + mov ecx,edi +.wait2: mov dx,[BIOS_timer] +.wait3: call pollchar + jnz .keypress + cmp dx,[BIOS_timer] + je .wait3 + loop .wait2,ecx + mov al,'.' + call writechr + pop cx + loop .wait1 +.keypress: + call crlf + mov word [BIOS_magic],0 ; Cold reboot + jmp 0F000h:0FFF0h ; Reset vector address + +; +; memory_scan_for_pxe_struct: +; +; If none of the standard methods find the !PXE structure, look for it +; by scanning memory. +; +; On exit, if found: +; CF = 0, ES:BX -> !PXE structure +; Otherwise CF = 1, all registers saved +; +memory_scan_for_pxe_struct: + push ds + pusha + mov ax,cs + mov ds,ax + mov si,trymempxe_msg + call writestr + mov ax,[BIOS_fbm] ; Starting segment + shl ax,(10-4) ; Kilobytes -> paragraphs +; mov ax,01000h ; Start to look here + dec ax ; To skip inc ax +.mismatch: + inc ax + cmp ax,0A000h ; End of memory + jae .not_found + call writehex4 + mov si,fourbs_msg + call writestr + mov es,ax + mov edx,[es:0] + cmp edx,'!PXE' + jne .mismatch + movzx cx,byte [es:4] ; Length of structure + cmp cl,08h ; Minimum length + jb .mismatch + push ax + xor ax,ax + xor si,si +.checksum: es lodsb + add ah,al + loop .checksum + pop ax + jnz .mismatch ; Checksum must == 0 +.found: mov bp,sp + xor bx,bx + mov [bp+8],bx ; Save BX into stack frame (will be == 0) + mov ax,es + call writehex4 + call crlf + popa + pop ds + clc + ret +.not_found: mov si,notfound_msg + call writestr + popa + pop ds + stc + ret + +; +; memory_scan_for_pxenv_struct: +; +; If none of the standard methods find the PXENV+ structure, look for it +; by scanning memory. +; +; On exit, if found: +; CF = 0, ES:BX -> PXENV+ structure +; Otherwise CF = 1, all registers saved +; +memory_scan_for_pxenv_struct: + pusha + mov si,trymempxenv_msg + call writestr +; mov ax,[BIOS_fbm] ; Starting segment +; shl ax,(10-4) ; Kilobytes -> paragraphs + mov ax,01000h ; Start to look here + dec ax ; To skip inc ax +.mismatch: + inc ax + cmp ax,0A000h ; End of memory + jae .not_found + mov es,ax + mov edx,[es:0] + cmp edx,'PXEN' + jne .mismatch + mov dx,[es:4] + cmp dx,'V+' + jne .mismatch + movzx cx,byte [es:8] ; Length of structure + cmp cl,26h ; Minimum length + jb .mismatch + xor ax,ax + xor si,si +.checksum: es lodsb + add ah,al + loop .checksum + and ah,ah + jnz .mismatch ; Checksum must == 0 +.found: mov bp,sp + mov [bp+8],bx ; Save BX into stack frame + mov ax,bx + call writehex4 + call crlf + clc + ret +.not_found: mov si,notfound_msg + call writestr + popad + stc + ret + +; +; searchdir: +; +; Open a TFTP connection to the server +; +; On entry: +; DS:DI = mangled filename +; If successful: +; ZF clear +; SI = socket pointer +; DX:AX = file length in bytes +; If unsuccessful +; ZF set +; + +searchdir: + push es + mov ax,ds + mov es,ax + mov si,di + push bp + mov bp,sp + + call allocate_socket + jz .error + + mov ax,PKT_RETRY ; Retry counter + mov word [PktTimeout],PKT_TIMEOUT ; Initial timeout + +.sendreq: push ax ; [bp-2] - Retry counter + push si ; [bp-4] - File name + + mov di,packet_buf + mov [pxe_udp_write_pkt.buffer],di + + mov ax,TFTP_RRQ ; TFTP opcode + stosw + + lodsd ; EAX <- server override (if any) + and eax,eax + jnz .noprefix ; No prefix, and we have the server + + push si ; Add common prefix + mov si,PathPrefix + call strcpy + dec di + pop si + + mov eax,[ServerIP] ; Get default server + +.noprefix: + call strcpy ; Filename + + mov [bx+tftp_remoteip],eax + + push bx ; [bp-6] - TFTP block + mov bx,[bx] + push bx ; [bp-8] - TID (local port no) + + mov [pxe_udp_write_pkt.status],byte 0 + mov [pxe_udp_write_pkt.sip],eax + ; Now figure out the gateway + xor eax,[MyIP] + and eax,[Netmask] + jz .nogwneeded + mov eax,[Gateway] +.nogwneeded: + mov [pxe_udp_write_pkt.gip],eax + mov [pxe_udp_write_pkt.lport],bx + mov ax,[ServerPort] + mov [pxe_udp_write_pkt.rport],ax + mov si,tftp_tail + mov cx,tftp_tail_len + rep movsb + sub di,packet_buf ; Get packet size + mov [pxe_udp_write_pkt.buffersize],di + + mov di,pxe_udp_write_pkt + mov bx,PXENV_UDP_WRITE + call pxenv + jc .failure + cmp word [pxe_udp_write_pkt.status],byte 0 + jne .failure + + ; + ; Danger, Will Robinson! We need to support timeout + ; and retry lest we just lost a packet... + ; + + ; Packet transmitted OK, now we need to receive +.getpacket: push word [PktTimeout] ; [bp-10] + push word [BIOS_timer] ; [bp-12] + +.pkt_loop: mov bx,[bp-8] ; TID + mov di,packet_buf + mov word [pxe_udp_read_pkt.status],0 + mov [pxe_udp_read_pkt.buffer],di + mov [pxe_udp_read_pkt.buffer+2],ds + mov word [pxe_udp_read_pkt.buffersize],packet_buf_size + mov eax,[MyIP] + mov [pxe_udp_read_pkt.dip],eax + mov [pxe_udp_read_pkt.lport],bx + mov di,pxe_udp_read_pkt + mov bx,PXENV_UDP_READ + call pxenv + and ax,ax + jz .got_packet ; Wait for packet +.no_packet: + mov dx,[BIOS_timer] + cmp dx,[bp-12] + je .pkt_loop + mov [bp-12],dx + dec word [bp-10] ; Timeout + jnz .pkt_loop + pop ax ; Adjust stack + pop ax + shl word [PktTimeout],1 ; Exponential backoff + jmp .failure + +.got_packet: + mov si,[bp-6] ; TFTP pointer + mov bx,[bp-8] ; TID + + mov eax,[si+tftp_remoteip] + cmp [pxe_udp_read_pkt.sip],eax ; This is technically not to the TFTP spec? + jne .no_packet + + ; Got packet - reset timeout + mov word [PktTimeout],PKT_TIMEOUT + + pop ax ; Adjust stack + pop ax + + mov ax,[pxe_udp_read_pkt.rport] + mov [si+tftp_remoteport],ax + + ; filesize <- -1 == unknown + mov dword [si+tftp_filesize], -1 + ; Default blksize unless blksize option negotiated + mov word [si+tftp_blksize], TFTP_BLOCKSIZE + + mov cx,[pxe_udp_read_pkt.buffersize] + sub cx,2 ; CX <- bytes after opcode + jb .failure ; Garbled reply + + mov si,packet_buf + lodsw + + cmp ax, TFTP_ERROR + je .bailnow ; ERROR reply: don't try again + + cmp ax, TFTP_OACK + jne .no_tsize + + ; Now we need to parse the OACK packet to get the transfer + ; size. SI -> first byte of options; CX -> byte count +.parse_oack: + jcxz .no_tsize ; No options acked +.get_opt_name: + mov di,si + mov bx,si +.opt_name_loop: lodsb + and al,al + jz .got_opt_name + or al,20h ; Convert to lowercase + stosb + loop .opt_name_loop + ; We ran out, and no final null + jmp .err_reply +.got_opt_name: ; si -> option value + dec cx ; bytes left in pkt + jz .err_reply ; Option w/o value + + ; Parse option pointed to by bx; guaranteed to be + ; null-terminated. + push cx + push si + mov si,bx ; -> option name + mov bx,tftp_opt_table + mov cx,tftp_opts +.opt_loop: + push cx + push si + mov di,[bx] ; Option pointer + mov cx,[bx+2] ; Option len + repe cmpsb + pop si + pop cx + je .get_value ; OK, known option + add bx,6 + loop .opt_loop + + pop si + pop cx + jmp .err_reply ; Non-negotiated option returned + +.get_value: pop si ; si -> option value + pop cx ; cx -> bytes left in pkt + mov bx,[bx+4] ; Pointer to data target + add bx,[bp-6] ; TFTP socket pointer + xor eax,eax + xor edx,edx +.value_loop: lodsb + and al,al + jz .got_value + sub al,'0' + cmp al, 9 + ja .err_reply ; Not a decimal digit + imul edx,10 + add edx,eax + mov [bx],edx + loop .value_loop + ; Ran out before final null, accept anyway + jmp short .done_pkt + +.got_value: + dec cx + jnz .get_opt_name ; Not end of packet + + ; ZF == 1 + + ; Success, done! +.done_pkt: + pop si ; Junk + pop si ; We want the packet ptr in SI + + mov eax,[si+tftp_filesize] + cmp eax,-1 + jz .no_tsize + mov edx,eax + shr edx,16 ; DX:AX == EAX + + and eax,eax ; Set ZF depending on file size + pop bp ; Junk + pop bp ; Junk (retry counter) + jz .error_si ; ZF = 1 need to free the socket + pop bp + pop es + ret + +.no_tsize: +.err_reply: ; Option negotiation error. Send ERROR reply. + ; ServerIP and gateway are already programmed in + mov si,[bp-6] + mov ax,[si+tftp_remoteport] + mov word [pxe_udp_write_pkt.rport],ax + mov word [pxe_udp_write_pkt.buffer],tftp_opt_err + mov word [pxe_udp_write_pkt.buffersize],tftp_opt_err_len + mov di,pxe_udp_write_pkt + mov bx,PXENV_UDP_WRITE + call pxenv + + ; Write an error message and explode + mov si,err_oldtftp + call writestr + jmp kaboom + +.bailnow: mov word [bp-2],1 ; Immediate error - no retry + +.failure: pop bx ; Junk + pop bx + pop si + pop ax + dec ax ; Retry counter + jnz .sendreq ; Try again + +.error: mov si,bx ; Socket pointer +.error_si: ; Socket pointer already in SI + call free_socket ; ZF <- 1, SI <- 0 + pop bp + pop es + ret + +; +; allocate_socket: Allocate a local UDP port structure +; +; If successful: +; ZF set +; BX = socket pointer +; If unsuccessful: +; ZF clear +; +allocate_socket: + push cx + mov bx,Files + mov cx,MAX_OPEN +.check: cmp word [bx], byte 0 + je .found + add bx,open_file_t_size + loop .check + xor cx,cx ; ZF = 1 + pop cx + ret + ; Allocate a socket number. Socket numbers are made + ; guaranteed unique by including the socket slot number + ; (inverted, because we use the loop counter cx); add a + ; counter value to keep the numbers from being likely to + ; get immediately reused. + ; + ; The NextSocket variable also contains the top two bits + ; set. This generates a value in the range 49152 to + ; 57343. +.found: + dec cx + push ax + mov ax,[NextSocket] + inc ax + and ax,((1 << (13-MAX_OPEN_LG2))-1) | 0xC000 + mov [NextSocket],ax + shl cx,13-MAX_OPEN_LG2 + add cx,ax ; ZF = 0 + xchg ch,cl ; Convert to network byte order + mov [bx],cx ; Socket in use + pop ax + pop cx + ret + +; +; Free socket: socket in SI; return SI = 0, ZF = 1 for convenience +; +free_socket: + push es + pusha + xor ax,ax + mov es,ax + mov di,si + mov cx,tftp_pktbuf >> 1 ; tftp_pktbuf is not cleared + rep stosw + popa + pop es + xor si,si + ret + +; +; parse_dotquad: +; Read a dot-quad pathname in DS:SI and output an IP +; address in EAX, with SI pointing to the first +; nonmatching character. +; +; Return CF=1 on error. +; +parse_dotquad: + push cx + mov cx,4 + xor eax,eax +.parseloop: + mov ch,ah + mov ah,al + lodsb + sub al,'0' + jb .notnumeric + cmp al,9 + ja .notnumeric + aad ; AL += 10 * AH; AH = 0; + xchg ah,ch + jmp .parseloop +.notnumeric: + cmp al,'.'-'0' + pushf + mov al,ah + mov ah,ch + xor ch,ch + ror eax,8 + popf + jne .error + loop .parseloop + jmp .done +.error: + loop .realerror ; If CX := 1 then we're done + clc + jmp .done +.realerror: + stc +.done: + dec si ; CF unchanged! + pop cx + ret +; +; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed +; to by ES:DI; ends on encountering any whitespace. +; +; This verifies that a filename is < FILENAME_MAX characters +; and doesn't contain whitespace, and zero-pads the output buffer, +; so "repe cmpsb" can do a compare. +; +; The first four bytes of the manged name is the IP address of +; the download host. +; +mangle_name: + push si + mov eax,[ServerIP] + cmp byte [si],0 + je .noip ; Null filename?!?! + cmp word [si],'::' ; Leading ::? + je .gotprefix + +.more: + inc si + cmp byte [si],0 + je .noip + cmp word [si],'::' + jne .more + + ; We have a :: prefix of some sort, it could be either + ; a DNS name or a dot-quad IP address. Try the dot-quad + ; first... +.here: + pop si + push si + call parse_dotquad + jc .notdq + cmp word [si],'::' + je .gotprefix +.notdq: + pop si + push si + call dns_resolv + cmp word [si],'::' + jne .noip + and eax,eax + jnz .gotprefix + +.noip: + pop si + xor eax,eax + jmp .prefix_done + +.gotprefix: + pop cx ; Adjust stack + inc si ; Skip double colon + inc si + +.prefix_done: + stosd ; Save IP address prefix + mov cx,FILENAME_MAX-5 + +.mn_loop: + lodsb + cmp al,' ' ; If control or space, end + jna .mn_end + stosb + loop .mn_loop +.mn_end: + inc cx ; At least one null byte + xor ax,ax ; Zero-fill name + rep stosb ; Doesn't do anything if CX=0 + ret ; Done + +; +; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled +; filename to the conventional representation. This is needed +; for the BOOT_IMAGE= parameter for the kernel. +; NOTE: A 13-byte buffer is mandatory, even if the string is +; known to be shorter. +; +; DS:SI -> input mangled file name +; ES:DI -> output buffer +; +; On return, DI points to the first byte after the output name, +; which is set to a null byte. +; +unmangle_name: + push eax + lodsd + and eax,eax + jz .noip + call gendotquad + mov ax,'::' + stosw +.noip: + call strcpy + dec di ; Point to final null byte + pop eax + ret + +; +; pxenv +; +; This is the main PXENV+/!PXE entry point, using the PXENV+ +; calling convention. This is a separate local routine so +; we can hook special things from it if necessary. +; + +pxenv: +.jump: call 0:pxe_thunk ; Default to calling the thunk + cld ; Make sure DF <- 0 + ret + +; Must be after function def due to NASM bug +PXENVEntry equ pxenv.jump+1 + +; +; pxe_thunk +; +; Convert from the PXENV+ calling convention (BX, ES, DI) to the !PXE +; calling convention (using the stack.) +; +; This is called as a far routine so that we can just stick it into +; the PXENVEntry variable. +; +pxe_thunk: push es + push di + push bx +.jump: call 0:0 + add sp,byte 6 + cmp ax,byte 1 + cmc ; Set CF unless ax == 0 + retf + +; Must be after function def due to NASM bug +PXEEntry equ pxe_thunk.jump+1 + +; +; getfssec: Get multiple clusters from a file, given the starting cluster. +; +; In this case, get multiple blocks from a specific TCP connection. +; +; On entry: +; ES:BX -> Buffer +; SI -> TFTP socket pointer +; CX -> 512-byte block count; 0FFFFh = until end of file +; On exit: +; SI -> TFTP socket pointer (or 0 on EOF) +; CF = 1 -> Hit EOF +; +getfssec: push si + push fs + mov di,bx + mov bx,si + mov ax,pktbuf_seg + mov fs,ax + + movzx ecx,cx + shl ecx,TFTP_BLOCKSIZE_LG2 ; Convert to bytes + jz .hit_eof ; Nothing to do? + +.need_more: + push ecx + + movzx eax,word [bx+tftp_bytesleft] + cmp ecx,eax + jna .ok_size + mov ecx,eax + jcxz .need_packet ; No bytes available? +.ok_size: + + mov ax,cx ; EAX<31:16> == ECX<31:16> == 0 + mov si,[bx+tftp_dataptr] + sub [bx+tftp_bytesleft],cx + fs rep movsb ; Copy from packet buffer + mov [bx+tftp_dataptr],si + + pop ecx + sub ecx,eax + jnz .need_more + + +.hit_eof: + pop fs + pop si + + ; Is there anything left of this? + mov eax,[si+tftp_filesize] + sub eax,[si+tftp_filepos] + jnz .bytes_left ; CF <- 0 + + cmp [si+tftp_bytesleft],ax + jnz .bytes_left ; CF <- 0 + + ; The socket is closed and the buffer drained + ; Close socket structure and re-init for next user + call free_socket + stc +.bytes_left: + ret + +; +; No data in buffer, check to see if we can get a packet... +; +.need_packet: + pop ecx + mov eax,[bx+tftp_filesize] + cmp eax,[bx+tftp_filepos] + je .hit_eof ; Already EOF'd; socket already closed + + pushad + push es + mov si,bx + call get_packet + pop es + popad + + jmp .need_more + +; +; Get a fresh packet; expects fs -> pktbuf_seg and ds:si -> socket structure +; +get_packet: + mov ax,ds + mov es,ax + +.packet_loop: + ; Start by ACKing the previous packet; this should cause the + ; next packet to be sent. + mov cx,PKT_RETRY + mov word [PktTimeout],PKT_TIMEOUT + +.send_ack: push cx ; <D> Retry count + + mov ax,[si+tftp_lastpkt] + call ack_packet ; Send ACK + + ; We used to test the error code here, but sometimes + ; PXE would return negative status even though we really + ; did send the ACK. Now, just treat a failed send as + ; a normally lost packet, and let it time out in due + ; course of events. + +.send_ok: ; Now wait for packet. + mov dx,[BIOS_timer] ; Get current time + + mov cx,[PktTimeout] +.wait_data: push cx ; <E> Timeout + push dx ; <F> Old time + + mov bx,[si+tftp_pktbuf] + mov [pxe_udp_read_pkt.buffer],bx + mov [pxe_udp_read_pkt.buffer+2],fs + mov [pxe_udp_read_pkt.buffersize],word PKTBUF_SIZE + mov eax,[si+tftp_remoteip] + mov [pxe_udp_read_pkt.sip],eax + mov eax,[MyIP] + mov [pxe_udp_read_pkt.dip],eax + mov ax,[si+tftp_remoteport] + mov [pxe_udp_read_pkt.rport],ax + mov ax,[si+tftp_localport] + mov [pxe_udp_read_pkt.lport],ax + mov di,pxe_udp_read_pkt + mov bx,PXENV_UDP_READ + push si ; <G> + call pxenv + pop si ; <G> + and ax,ax + jz .recv_ok + + ; No packet, or receive failure + mov dx,[BIOS_timer] + pop ax ; <F> Old time + pop cx ; <E> Timeout + cmp ax,dx ; Same time -> don't advance timeout + je .wait_data ; Same clock tick + loop .wait_data ; Decrease timeout + + pop cx ; <D> Didn't get any, send another ACK + shl word [PktTimeout],1 ; Exponential backoff + loop .send_ack + jmp kaboom ; Forget it... + +.recv_ok: pop dx ; <F> + pop cx ; <E> + + cmp word [pxe_udp_read_pkt.buffersize],byte 4 + jb .wait_data ; Bad size for a DATA packet + + mov bx,[si+tftp_pktbuf] + cmp word [fs:bx],TFTP_DATA ; Not a data packet? + jne .wait_data ; Then wait for something else + + mov ax,[si+tftp_lastpkt] + xchg ah,al ; Host byte order + inc ax ; Which packet are we waiting for? + xchg ah,al ; Network byte order + cmp [fs:bx+2],ax + je .right_packet + + ; Wrong packet, ACK the packet and then try again + ; This is presumably because the ACK got lost, + ; so the server just resent the previous packet + mov ax,[fs:bx+2] + call ack_packet + jmp .send_ok ; Reset timeout + +.right_packet: ; It's the packet we want. We're also EOF if the size < blocksize + + pop cx ; <D> Don't need the retry count anymore + + mov [si+tftp_lastpkt],ax ; Update last packet number + + movzx ecx,word [pxe_udp_read_pkt.buffersize] + sub cx,byte 4 ; Skip TFTP header + + ; If this is a zero-length block, don't mess with the pointers, + ; since we may have just set up the previous block that way + jz .last_block + + ; Set pointer to data block + lea ax,[bx+4] ; Data past TFTP header + mov [si+tftp_dataptr],ax + + add [si+tftp_filepos],ecx + mov [si+tftp_bytesleft],cx + + cmp cx,[si+tftp_blksize] ; Is it a full block? + jb .last_block ; If so, it's not EOF + + ; If we had the exact right number of bytes, always get + ; one more packet to get the (zero-byte) EOF packet and + ; close the socket. + mov eax,[si+tftp_filepos] + cmp [si+tftp_filesize],eax + je .packet_loop + + ret + + +.last_block: ; Last block - ACK packet immediately + mov ax,[fs:bx+2] + call ack_packet + + ; Make sure we know we are at end of file + mov eax,[si+tftp_filepos] + mov [si+tftp_filesize],eax + + ret + +; +; ack_packet: +; +; Send ACK packet. This is a common operation and so is worth canning. +; +; Entry: +; SI = TFTP block +; AX = Packet # to ack (network byte order) +; Exit: +; ZF = 0 -> Error +; All registers preserved +; +; This function uses the pxe_udp_write_pkt but not the packet_buf. +; +ack_packet: + pushad + mov [ack_packet_buf+2],ax ; Packet number to ack + mov ax,[si] + mov [pxe_udp_write_pkt.lport],ax + mov ax,[si+tftp_remoteport] + mov [pxe_udp_write_pkt.rport],ax + mov eax,[si+tftp_remoteip] + mov [pxe_udp_write_pkt.sip],eax + xor eax,[MyIP] + and eax,[Netmask] + jz .nogw + mov eax,[Gateway] +.nogw: + mov [pxe_udp_write_pkt.gip],eax + mov [pxe_udp_write_pkt.buffer],word ack_packet_buf + mov [pxe_udp_write_pkt.buffersize], word 4 + mov di,pxe_udp_write_pkt + mov bx,PXENV_UDP_WRITE + call pxenv + cmp ax,byte 0 ; ZF = 1 if write OK + popad + ret + +; +; unload_pxe: +; +; This function unloads the PXE and UNDI stacks and unclaims +; the memory. +; +unload_pxe: + test byte [KeepPXE],01h ; Should we keep PXE around? + jnz reset_pxe + + push ds + push es + + mov ax,cs + mov ds,ax + mov es,ax + + mov si,new_api_unload + cmp byte [APIVer+1],2 ; Major API version >= 2? + jae .new_api + mov si,old_api_unload +.new_api: + +.call_loop: xor ax,ax + lodsb + and ax,ax + jz .call_done + xchg bx,ax + mov di,pxe_unload_stack_pkt + push di + xor ax,ax + mov cx,pxe_unload_stack_pkt_len >> 1 + rep stosw + pop di + call pxenv + jc .cant_free + mov ax,word [pxe_unload_stack_pkt.status] + cmp ax,PXENV_STATUS_SUCCESS + jne .cant_free + jmp .call_loop + +.call_done: +; +; This isn't necessary anymore; we can use the memory area previously +; used by the PXE stack indefinitely, and the chainload code sets up +; a new stack independently. Leave the source code in here for now, +; but expect to rip it out soonish. +; +%if 0 ; USE_PXE_PROVIDED_STACK + ; We need to switch to our local stack here... + pusha + pushf + push gs + + mov si,sp + mov ax,ss + mov gs,ax + sub ax,[BaseStack+4] ; Are we using the base stack + je .is_base_stack ; (as opposed to the COMBOOT stack)? + + lgs si,[SavedSSSP] ; COMBOOT stack +.is_base_stack: + + mov cx,[InitStack] + mov di,StackBuf + mov [BaseStack],di + mov [BaseStack+4],es + sub cx,si + sub di,cx + mov [SavedSSSP],di ; New SP + mov [SavedSSSP+2],es + gs rep movsb + + and ax,ax ; Remember which stack + jne .combootstack + + ; Update the base stack pointer since it's in use + lss sp,[SavedSSSP] + +.combootstack: + pop gs + popf + popa +%endif + mov bx,0FF00h + + mov dx,[RealBaseMem] + cmp dx,[BIOS_fbm] ; Sanity check + jna .cant_free + inc bx + + ; Check that PXE actually unhooked the INT 1Ah chain + movzx eax,word [4*0x1a] + movzx ecx,word [4*0x1a+2] + shl ecx,4 + add eax,ecx + shr eax,10 + cmp ax,dx ; Not in range + jae .ok + cmp ax,[BIOS_fbm] + jae .cant_free + ; inc bx + +.ok: + mov [BIOS_fbm],dx +.pop_ret: + pop es + pop ds + ret + +.cant_free: + mov si,cant_free_msg + call writestr + push ax + xchg bx,ax + call writehex4 + mov al,'-' + call writechr + pop ax + call writehex4 + mov al,'-' + call writechr + mov eax,[4*0x1a] + call writehex8 + call crlf + jmp .pop_ret + + ; We want to keep PXE around, but still we should reset + ; it to the standard bootup configuration +reset_pxe: + push es + push cs + pop es + mov bx,PXENV_UDP_CLOSE + mov di,pxe_udp_close_pkt + call pxenv + pop es + ret + +; +; gendotquad +; +; Take an IP address (in network byte order) in EAX and +; output a dotted quad string to ES:DI. +; DI points to terminal null at end of string on exit. +; +gendotquad: + push eax + push cx + mov cx,4 +.genchar: + push eax + cmp al,10 ; < 10? + jb .lt10 ; If so, skip first 2 digits + + cmp al,100 ; < 100 + jb .lt100 ; If so, skip first digit + + aam 100 + ; Now AH = 100-digit; AL = remainder + add ah,'0' + mov [es:di],ah + inc di + +.lt100: + aam 10 + ; Now AH = 10-digit; AL = remainder + add ah,'0' + mov [es:di],ah + inc di + +.lt10: + add al,'0' + stosb + mov al,'.' + stosb + pop eax + ror eax,8 ; Move next char into LSB + loop .genchar + dec di + mov [es:di], byte 0 + pop cx + pop eax + ret + +; +; parse_dhcp +; +; Parse a DHCP packet. This includes dealing with "overloaded" +; option fields (see RFC 2132, section 9.3) +; +; This should fill in the following global variables, if the +; information is present: +; +; MyIP - client IP address +; ServerIP - boot server IP address +; Netmask - network mask +; Gateway - default gateway router IP +; BootFile - boot file name +; DNSServers - DNS server IPs +; LocalDomain - Local domain name +; +; This assumes the DHCP packet is in "trackbuf" and the length +; of the packet in in CX on entry. +; + +parse_dhcp: + mov byte [OverLoad],0 ; Assume no overload + mov eax, [trackbuf+bootp.yip] + and eax, eax + jz .noyip + cmp al,224 ; Class D or higher -> bad + jae .noyip + mov [MyIP], eax +.noyip: + mov eax, [trackbuf+bootp.sip] + and eax, eax + jz .nosip + cmp al,224 ; Class D or higher -> bad + jae .nosip + mov [ServerIP], eax +.nosip: + sub cx, bootp.options + jbe .nooptions + mov si, trackbuf+bootp.option_magic + lodsd + cmp eax, BOOTP_OPTION_MAGIC + jne .nooptions + call parse_dhcp_options +.nooptions: + mov si, trackbuf+bootp.bootfile + test byte [OverLoad],1 + jz .nofileoverload + mov cx,128 + call parse_dhcp_options + jmp short .parsed_file +.nofileoverload: + cmp byte [si], 0 + jz .parsed_file ; No bootfile name + mov di,BootFile + mov cx,32 + rep movsd + xor al,al + stosb ; Null-terminate +.parsed_file: + mov si, trackbuf+bootp.sname + test byte [OverLoad],2 + jz .nosnameoverload + mov cx,64 + call parse_dhcp_options +.nosnameoverload: + ret + +; +; Parse a sequence of DHCP options, pointed to by DS:SI; the field +; size is CX -- some DHCP servers leave option fields unterminated +; in violation of the spec. +; +; For parse_some_dhcp_options, DH contains the minimum value for +; the option to recognize -- this is used to restrict parsing to +; PXELINUX-specific options only. +; +parse_dhcp_options: + xor dx,dx + +parse_some_dhcp_options: +.loop: + and cx,cx + jz .done + + lodsb + dec cx + jz .done ; Last byte; must be PAD, END or malformed + cmp al, 0 ; PAD option + je .loop + cmp al,255 ; END option + je .done + + ; Anything else will have a length field + mov dl,al ; DL <- option number + xor ax,ax + lodsb ; AX <- option length + dec cx + sub cx,ax ; Decrement bytes left counter + jb .done ; Malformed option: length > field size + + cmp dl,dh ; Is the option value valid? + jb .opt_done + + cmp dl,1 ; SUBNET MASK option + jne .not_subnet + mov ebx,[si] + mov [Netmask],ebx + jmp .opt_done +.not_subnet: + + cmp dl,3 ; ROUTER option + jne .not_router + mov ebx,[si] + mov [Gateway],ebx + jmp .opt_done +.not_router: + + cmp dl,6 ; DNS SERVERS option + jne .not_dns + pusha + mov cx,ax + shr cx,2 + cmp cl,DNS_MAX_SERVERS + jna .oklen + mov cl,DNS_MAX_SERVERS +.oklen: + mov di,DNSServers + rep movsd + mov [LastDNSServer],di + popa + jmp .opt_done +.not_dns: + + cmp dl,15 ; DNS LOCAL DOMAIN option + jne .not_localdomain + pusha + mov bx,si + add bx,ax + xor ax,ax + xchg [bx],al ; Zero-terminate option + mov di,LocalDomain + call dns_mangle ; Convert to DNS label set + mov [bx],al ; Restore ending byte + popa + jmp .opt_done +.not_localdomain: + + cmp dl,43 ; VENDOR ENCAPSULATED option + jne .not_vendor + pusha + mov dh,208 ; Only recognize PXELINUX options + mov cx,ax ; Length of option = max bytes to parse + call parse_some_dhcp_options ; Parse recursive structure + popa + jmp .opt_done +.not_vendor: + + cmp dl,52 ; OPTION OVERLOAD option + jne .not_overload + mov bl,[si] + mov [OverLoad],bl + jmp .opt_done +.not_overload: + + cmp dl,67 ; BOOTFILE NAME option + jne .not_bootfile + mov di,BootFile + jmp short .copyoption +.done: + ret ; This is here to make short jumps easier +.not_bootfile: + + cmp dl,208 ; PXELINUX MAGIC option + jne .not_pl_magic + cmp al,4 ; Must have length == 4 + jne .opt_done + cmp dword [si], htonl(0xF100747E) ; Magic number + jne .opt_done + or byte [DHCPMagic], byte 1 ; Found magic # + jmp short .opt_done +.not_pl_magic: + + cmp dl,209 ; PXELINUX CONFIGFILE option + jne .not_pl_config + mov di,ConfigName + or byte [DHCPMagic], byte 2 ; Got config file + jmp short .copyoption +.not_pl_config: + + cmp dl,210 ; PXELINUX PATHPREFIX option + jne .not_pl_prefix + mov di,PathPrefix + or byte [DHCPMagic], byte 4 ; Got path prefix + jmp short .copyoption +.not_pl_prefix: + + cmp dl,211 ; PXELINUX REBOOTTIME option + jne .not_pl_timeout + cmp al,4 + jne .opt_done + mov ebx,[si] + xchg bl,bh ; Convert to host byte order + rol ebx,16 + xchg bl,bh + mov [RebootTime],ebx + or byte [DHCPMagic], byte 8 ; Got RebootTime + ; jmp short .opt_done +.not_pl_timeout: + + ; Unknown option. Skip to the next one. +.opt_done: + add si,ax +.opt_done_noskip: + jmp .loop + + ; Common code for copying an option verbatim +.copyoption: + xchg cx,ax + rep movsb + xchg cx,ax ; Now ax == 0 + stosb ; Null-terminate + jmp short .opt_done_noskip + +; +; genipopt +; +; Generate an ip=<client-ip>:<boot-server-ip>:<gw-ip>:<netmask> +; option into IPOption based on a DHCP packet in trackbuf. +; Assumes CS == DS == ES. +; +genipopt: + pushad + mov di,IPOption + mov eax,'ip=' + stosd + dec di + mov eax,[MyIP] + call gendotquad + mov al,':' + stosb + mov eax,[ServerIP] + call gendotquad + mov al,':' + stosb + mov eax,[Gateway] + call gendotquad + mov al,':' + stosb + mov eax,[Netmask] + call gendotquad ; Zero-terminates its output + sub di,IPOption + mov [IPOptionLen],di + popad + ret + +; +; Call the receive loop while idle. This is done mostly so we can respond to +; ARP messages, but perhaps in the future this can be used to do network +; console. +; +; hpa sez: people using automatic control on the serial port get very +; unhappy if we poll for ARP too often (the PXE stack is pretty slow, +; typically.) Therefore, only poll if at least 4 BIOS timer ticks have +; passed since the last poll, and reset this when a character is +; received (RESET_IDLE). +; +reset_idle: + push ax + mov ax,[cs:BIOS_timer] + mov [cs:IdleTimer],ax + pop ax + ret + +check_for_arp: + push ax + mov ax,[cs:BIOS_timer] + sub ax,[cs:IdleTimer] + cmp ax,4 + pop ax + jae .need_poll + ret +.need_poll: pushad + push ds + push es + mov ax,cs + mov ds,ax + mov es,ax + mov di,packet_buf + mov [pxe_udp_read_pkt.status],al ; 0 + mov [pxe_udp_read_pkt.buffer],di + mov [pxe_udp_read_pkt.buffer+2],ds + mov word [pxe_udp_read_pkt.buffersize],packet_buf_size + mov eax,[MyIP] + mov [pxe_udp_read_pkt.dip],eax + mov word [pxe_udp_read_pkt.lport],htons(9) ; discard port + mov di,pxe_udp_read_pkt + mov bx,PXENV_UDP_READ + call pxenv + ; Ignore result... + pop es + pop ds + popad + RESET_IDLE + ret + +; ----------------------------------------------------------------------------- +; Common modules +; ----------------------------------------------------------------------------- + +%include "getc.inc" ; getc et al +%include "conio.inc" ; Console I/O +%include "writestr.inc" ; String output +writestr equ cwritestr +%include "writehex.inc" ; Hexadecimal output +%include "parseconfig.inc" ; High-level config file handling +%include "parsecmd.inc" ; Low-level config file handling +%include "bcopy32.inc" ; 32-bit bcopy +%include "loadhigh.inc" ; Load a file into high memory +%include "font.inc" ; VGA font stuff +%include "graphics.inc" ; VGA graphics +%include "highmem.inc" ; High memory sizing +%include "strcpy.inc" ; strcpy() +%include "rawcon.inc" ; Console I/O w/o using the console functions +%include "dnsresolv.inc" ; DNS resolver + +; ----------------------------------------------------------------------------- +; Begin data section +; ----------------------------------------------------------------------------- + + section .data + +hextbl_lower db '0123456789abcdef' +copyright_str db ' Copyright (C) 1994-', year, ' H. Peter Anvin' + db CR, LF, 0 +boot_prompt db 'boot: ', 0 +wipe_char db BS, ' ', BS, 0 +err_notfound db 'Could not find kernel image: ',0 +err_notkernel db CR, LF, 'Invalid or corrupt kernel image.', CR, LF, 0 +err_noram db 'It appears your computer has less than ' + asciidec dosram_k + db 'K of low ("DOS")' + db CR, LF + db 'RAM. Linux needs at least this amount to boot. If you get' + db CR, LF + db 'this message in error, hold down the Ctrl key while' + db CR, LF + db 'booting, and I will take your word for it.', CR, LF, 0 +err_badcfg db 'Unknown keyword in config file.', CR, LF, 0 +err_noparm db 'Missing parameter in config file.', CR, LF, 0 +err_noinitrd db CR, LF, 'Could not find ramdisk image: ', 0 +err_nohighmem db 'Not enough memory to load specified kernel.', CR, LF, 0 +err_highload db CR, LF, 'Kernel transfer failure.', CR, LF, 0 +err_oldkernel db 'Cannot load a ramdisk with an old kernel image.' + db CR, LF, 0 +err_notdos db ': attempted DOS system call', CR, LF, 0 +err_comlarge db 'COMBOOT image too large.', CR, LF, 0 +err_bssimage db 'BSS images not supported.', CR, LF, 0 +err_a20 db CR, LF, 'A20 gate not responding!', CR, LF, 0 +err_bootfailed db CR, LF, 'Boot failed: press a key to retry, or wait for reset...', CR, LF, 0 +bailmsg equ err_bootfailed +err_nopxe db "No !PXE or PXENV+ API found; we're dead...", CR, LF, 0 +err_pxefailed db 'PXE API call failed, error ', 0 +err_udpinit db 'Failed to initialize UDP stack', CR, LF, 0 +err_oldtftp db 'TFTP server does not support the tsize option', CR, LF, 0 +found_pxenv db 'Found PXENV+ structure', CR, LF, 0 +using_pxenv_msg db 'Old PXE API detected, using PXENV+ structure', CR, LF, 0 +apiver_str db 'PXE API version is ',0 +pxeentry_msg db 'PXE entry point found (we hope) at ', 0 +pxenventry_msg db 'PXENV entry point found (we hope) at ', 0 +trymempxe_msg db 'Scanning memory for !PXE structure... ', 0 +trymempxenv_msg db 'Scanning memory for PXENV+ structure... ', 0 +undi_data_msg db 'UNDI data segment at: ',0 +undi_data_len_msg db 'UNDI data segment size: ',0 +undi_code_msg db 'UNDI code segment at: ',0 +undi_code_len_msg db 'UNDI code segment size: ',0 +cant_free_msg db 'Failed to free base memory, error ', 0 +notfound_msg db 'not found', CR, LF, 0 +myipaddr_msg db 'My IP address seems to be ',0 +tftpprefix_msg db 'TFTP prefix: ', 0 +localboot_msg db 'Booting from local disk...', CR, LF, 0 +cmdline_msg db 'Command line: ', CR, LF, 0 +ready_msg db 'Ready.', CR, LF, 0 +trying_msg db 'Trying to load: ', 0 +crlfloading_msg db CR, LF ; Fall through +loading_msg db 'Loading ', 0 +dotdot_msg db '.' +dot_msg db '.', 0 +fourbs_msg db BS, BS, BS, BS, 0 +aborted_msg db ' aborted.' ; Fall through to crlf_msg! +crlf_msg db CR, LF +null_msg db 0 +crff_msg db CR, FF, 0 +default_str db 'default', 0 +default_len equ ($-default_str) +syslinux_banner db CR, LF, 'PXELINUX ', version_str, ' ', date, ' ', 0 +cfgprefix db 'pxelinux.cfg/' ; No final null! +cfgprefix_len equ ($-cfgprefix) + +; +; Command line options we'd like to take a look at +; +; mem= and vga= are handled as normal 32-bit integer values +initrd_cmd db 'initrd=' +initrd_cmd_len equ $-initrd_cmd + +; This one we make ourselves +bootif_str db 'BOOTIF=' +bootif_str_len equ $-bootif_str +; +; Config file keyword table +; +%include "keywords.inc" + +; +; Extensions to search for (in *forward* order). +; (.bs and .bss are disabled for PXELINUX, since they are not supported) +; + align 4, db 0 +exten_table: db '.cbt' ; COMBOOT (specific) + db '.0', 0, 0 ; PXE bootstrap program + db '.com' ; COMBOOT (same as DOS) + db '.c32' ; COM32 +exten_table_end: + dd 0, 0 ; Need 8 null bytes here + +; +; PXE unload sequences +; +new_api_unload: + db PXENV_UDP_CLOSE + db PXENV_UNDI_SHUTDOWN + db PXENV_UNLOAD_STACK + db PXENV_STOP_UNDI + db 0 +old_api_unload: + db PXENV_UDP_CLOSE + db PXENV_UNDI_SHUTDOWN + db PXENV_UNLOAD_STACK + db PXENV_UNDI_CLEANUP + db 0 + +; +; PXE query packets partially filled in +; +pxe_bootp_query_pkt_2: +.status: dw 0 ; Status +.packettype: dw 2 ; DHCPACK packet +.buffersize: dw trackbufsize ; Packet size +.buffer: dw trackbuf, 0 ; seg:off of buffer +.bufferlimit: dw trackbufsize ; Unused + +pxe_bootp_query_pkt_3: +.status: dw 0 ; Status +.packettype: dw 3 ; Boot server packet +.buffersize: dw trackbufsize ; Packet size +.buffer: dw trackbuf, 0 ; seg:off of buffer +.bufferlimit: dw trackbufsize ; Unused + +pxe_bootp_size_query_pkt: +.status: dw 0 ; Status +.packettype: dw 2 ; DHCPACK packet +.buffersize: dw 0 ; Packet size +.buffer: dw 0, 0 ; seg:off of buffer +.bufferlimit: dw 0 ; Unused + +pxe_udp_open_pkt: +.status: dw 0 ; Status +.sip: dd 0 ; Source (our) IP + +pxe_udp_close_pkt: +.status: dw 0 ; Status + +pxe_udp_write_pkt: +.status: dw 0 ; Status +.sip: dd 0 ; Server IP +.gip: dd 0 ; Gateway IP +.lport: dw 0 ; Local port +.rport: dw 0 ; Remote port +.buffersize: dw 0 ; Size of packet +.buffer: dw 0, 0 ; seg:off of buffer + +pxe_udp_read_pkt: +.status: dw 0 ; Status +.sip: dd 0 ; Source IP +.dip: dd 0 ; Destination (our) IP +.rport: dw 0 ; Remote port +.lport: dw 0 ; Local port +.buffersize: dw 0 ; Max packet size +.buffer: dw 0, 0 ; seg:off of buffer + +; +; Misc initialized (data) variables +; + alignb 4, db 0 +BaseStack dd StackBuf ; SS:ESP of base stack +NextSocket dw 49152 ; Counter for allocating socket numbers +KeepPXE db 0 ; Should PXE be kept around? + +; +; TFTP commands +; +tftp_tail db 'octet', 0 ; Octet mode +tsize_str db 'tsize' ,0 ; Request size +tsize_len equ ($-tsize_str) + db '0', 0 +blksize_str db 'blksize', 0 ; Request large blocks +blksize_len equ ($-blksize_str) + asciidec TFTP_LARGEBLK + db 0 +tftp_tail_len equ ($-tftp_tail) + + alignb 2, db 0 +; +; Options negotiation parsing table (string pointer, string len, offset +; into socket structure) +; +tftp_opt_table: + dw tsize_str, tsize_len, tftp_filesize + dw blksize_str, blksize_len, tftp_blksize +tftp_opts equ ($-tftp_opt_table)/6 + +; +; Error packet to return on options negotiation error +; +tftp_opt_err dw TFTP_ERROR ; ERROR packet + dw TFTP_EOPTNEG ; ERROR 8: bad options + db 'tsize option required', 0 ; Error message +tftp_opt_err_len equ ($-tftp_opt_err) + + alignb 4, db 0 +ack_packet_buf: dw TFTP_ACK, 0 ; TFTP ACK packet + +; +; IP information (initialized to "unknown" values) +MyIP dd 0 ; My IP address +ServerIP dd 0 ; IP address of boot server +Netmask dd 0 ; Netmask of this subnet +Gateway dd 0 ; Default router +ServerPort dw TFTP_PORT ; TFTP server port + +; +; Variables that are uninitialized in SYSLINUX but initialized here +; + alignb 4, db 0 +BufSafe dw trackbufsize/TFTP_BLOCKSIZE ; Clusters we can load into trackbuf +BufSafeSec dw trackbufsize/512 ; = how many sectors? +BufSafeBytes dw trackbufsize ; = how many bytes? +EndOfGetCBuf dw getcbuf+trackbufsize ; = getcbuf+BufSafeBytes +%ifndef DEPEND +%if ( trackbufsize % TFTP_BLOCKSIZE ) != 0 +%error trackbufsize must be a multiple of TFTP_BLOCKSIZE +%endif +%endif +IPAppend db 0 ; Default IPAPPEND option +DHCPMagic db 0 ; DHCP site-specific option info diff --git a/syslinux/pxelinux.doc b/syslinux/pxelinux.doc new file mode 100644 index 0000000..7e01626 --- /dev/null +++ b/syslinux/pxelinux.doc @@ -0,0 +1,374 @@ + PXELINUX + + A bootloader for Linux using the PXE network booting protocol + + Copyright (C) 1994-2004 H. Peter Anvin + +This program is provided under the terms of the GNU General Public +License, version 2 or, at your option, any later version. There is no +warranty, neither expressed nor implied, to the function of this +program. Please see the included file COPYING for details. + +---------------------------------------------------------------------- + +PXELINUX is a SYSLINUX derivative, for booting Linux off a network +server, using a network ROM conforming to the Intel PXE (Pre-Execution +Environment) specification. PXELINUX is *not* a program that is +intended to be flashed or burned into a PROM on the network card; if +you want that, check out NILO (http://www.nilo.org/). NILO can also +be used to create a PXE-compliant boot PROM for most network cards +which have drivers for Linux or FreeBSD. + + + ++++ HOW TO CONFIGURE PXELINUX ++++ + +PXELINUX operates in many ways like SYSLINUX. If you are not familiar +with SYSLINUX, read syslinux.doc first, since this documentation only +explains the differences. + +On the TFTP server, create the directory "/tftpboot", and copy the +following files to it: + + pxelinux.0 - from the SYSLINUX distribution + + any kernel or initrd images you want to boot + +Finally, create the directory "/tftpboot/pxelinux.cfg". The +configuration file (equivalent of syslinux.cfg -- see syslinux.doc for +the options here) will live in this directory. Because more than one +system may be booted from the same server, the configuration file name +depends on the IP address of the booting machine. PXELINUX will +search for its config file on the boot server in the following way: + + First, it will search for the config file using the hardware type + (using its ARP type code) and address, all in lower case hexadecimal + with dash separators; for example, for an Ethernet (ARP type 1) + with address 88:99:AA:BB:CC:DD it would search for the filename + 01-88-99-aa-bb-cc-dd. + + Next, it will search for the config file using its own IP address + in upper case hexadecimal, e.g. 192.0.2.91 -> C000025B + (you can use the included progam "gethostip" to compute the + hexadecimal IP address for any host.) + + If that file is not found, it will remove one hex digit and try + again. Ultimately, it will try looking for a file named "default" + (in lower case). + + As an example, if the boot file name is /mybootdir/pxelinux.0, the + Ethernet MAC address is 88:99:AA:BB:CC:DD and the IP address + 192.0.2.91, it will try: + + /mybootdir/pxelinux.cfg/01-88-99-aa-bb-cc-dd + /mybootdir/pxelinux.cfg/C000025B + /mybootdir/pxelinux.cfg/C000025 + /mybootdir/pxelinux.cfg/C00002 + /mybootdir/pxelinux.cfg/C0000 + /mybootdir/pxelinux.cfg/C000 + /mybootdir/pxelinux.cfg/C00 + /mybootdir/pxelinux.cfg/C0 + /mybootdir/pxelinux.cfg/C + /mybootdir/pxelinux.cfg/default + + ... in that order. + +Note that all filename references are relative to the directory +pxelinux.0 lives in. PXELINUX generally requires that filenames +(including any relative path) are 127 characters or shorter in length. + +PXELINUX does not support MTFTP, and I have no immediate plans of +doing so. It is of course possible to use MTFTP for the initial boot, +if you have such a setup. MTFTP server setup is beyond the scope of +this document. + + + ++++ SETTING UP THE TFTP SERVER ++++ + +PXELINUX currently requires that the boot server has a TFTP server +which supports the "tsize" TFTP option (RFC 1784/RFC 2349). The +"tftp-hpa" TFTP server, which support options, is available at: + + http://www.kernel.org/pub/software/network/tftp/ + ftp://www.kernel.org/pub/software/network/tftp/ + +... and on any kernel.org mirror (see http://www.kernel.org/mirrors/). + +Another TFTP server which supports this is atftp by Jean-Pierre +Lefebvre: + + ftp://ftp.mamalinux.com/pub/atftp/ + +If your boot server is running Windows (and you can't fix that), try +tftpd32 by Philippe Jounin (you need version 2.11 or later; previous +versions had a bug which made it incompatible with PXELINUX): + + http://tftpd32.jounin.net/ + + + ++++ SETTING UP THE DHCP SERVER ++++ + +The PXE protocol uses a very complex set of extensions to DHCP or +BOOTP. However, most PXE implementations -- this includes all Intel +ones version 0.99n and later -- seem to be able to boot in a +"conventional" DHCP/TFTP configuration. Assuming you don't have to +support any very old or otherwise severely broken clients, this is +probably the best configuration unless you already have a PXE boot +server on your network. + +A sample DHCP setup, using the "conventional TFTP" configuration, +would look something like the following, using ISC dhcp 2.0 dhcpd.conf +syntax: + + allow booting; + allow bootp; + + # Standard configuration directives... + + option domain-name "<domain name>"; + option subnet-mask <subnet mask>; + option broadcast-address <broadcast address>; + option domain-name-servers <dns servers>; + option routers <default router>; + + # Group the PXE bootable hosts together + group { + # PXE-specific configuration directives... + next-server <TFTP server address>; + filename "/tftpboot/pxelinux.0"; + + # You need an entry like this for every host + # unless you're using dynamic addresses + host <hostname> { + hardware ethernet <ethernet address>; + fixed-address <hostname>; + } + } + +Note that if your particular TFTP daemon runs under chroot (tftp-hpa +will do this if you specify the -s (secure) option; this is highly +recommended), you almost certainly should not include the /tftpboot +prefix in the filename statement. + +If this does not work for your configuration, you probably should set +up a "PXE boot server" on port 4011 of your TFTP server; a free PXE +boot server is available at: + + http://www.kano.org.uk/projects/pxe/ + +With such a boot server defined, your DHCP configuration should look +the same except for an "option dhcp-class-identifier" ("option +vendor-class-identifier" if you are using DHCP 3.0): + + allow booting; + allow bootp; + + # Standard configuration directives... + + option domain-name "<domain name>"; + option subnet-mask <subnet mask>; + option broadcast-address <broadcast address>; + option domain-name-servers <dns servers>; + option routers <default router>; + + # Group the PXE bootable hosts together + group { + # PXE-specific configuration directives... + option dhcp-class-identifier "PXEClient"; + next-server <pxe boot server address>; + + # You need an entry like this for every host + # unless you're using dynamic addresses + host <hostname> { + hardware ethernet <ethernet address>; + fixed-address <hostname>; + } + } + +Here, the boot file name is obtained from the PXE server. + +If the "conventional TFTP" configuration doesn't work on your clients, +and setting up a PXE boot server is not an option, you can attempt the +following configuration. It has been known to boot some +configurations correctly; however, there are no guarantees: + + allow booting; + allow bootp; + + # Standard configuration directives... + + option domain-name "<domain name>"; + option subnet-mask <subnet mask>; + option broadcast-address <broadcast address>; + option domain-name-servers <dns servers>; + option routers <default router>; + + # Group the PXE bootable hosts together + group { + # PXE-specific configuration directives... + option dhcp-class-identifier "PXEClient"; + option vendor-encapsulated-options 09:0f:80:00:0c:4e:65:74:77:6f:72:6b:20:62:6f:6f:74:0a:07:00:50:72:6f:6d:70:74:06:01:02:08:03:80:00:00:47:04:80:00:00:00:ff; + next-server <TFTP server>; + filename "/tftpboot/pxelinux.0"; + + # You need an entry like this for every host + # unless you're using dynamic addresses + host <hostname> { + hardware ethernet <ethernet address>; + fixed-address <hostname>; + } + } + +Note that this *will not* boot some clients that *will* boot with the +"conventional TFTP" configuration; Intel Boot Client 3.0 and later are +known to fall into this category. + + + ++++ SPECIAL DHCP OPTIONS ++++ + +PXELINUX (starting with version 1.62) supports the following +nonstandard DHCP options, which depending on your DHCP server you may +be able to use to customize the specific behaviour of PXELINUX: + +Option 208 pxelinux.magic + - Must be set to F1:00:74:7E (241.0.116.126) for PXELINUX to + recognize any special DHCP options whatsoever. + +Option 209 pxelinux.configfile + - Specifies the PXELINUX configuration file name. + +Option 210 pxelinux.pathprefix + - Specifies the PXELINUX common path prefix, instead of + deriving it from the boot file name. This almost certainly + needs to end in whatever character the TFTP server OS uses + as a pathname separator, e.g. slash (/) for Unix. + +Option 211 pxelinux.reboottime + - Specifies, in seconds, the time to wait before reboot in the + event of TFTP failure. 0 means wait "forever" (in reality, + it waits approximately 136 years.) + +ISC dhcp 3.0 supports a rather nice syntax for specifying custom +options; you can use the following syntax in dhcpd.conf if you are +running this version of dhcpd: + + option space pxelinux; + option pxelinux.magic code 208 = string; + option pxelinux.configfile code 209 = text; + option pxelinux.pathprefix code 210 = text; + option pxelinux.reboottime code 211 = unsigned integer 32; + + NOTE: In earlier versions of PXELINUX, this would only work as a + "site-option-space". Since PXELINUX 2.07, this will work both as a + "site-option-space" (unencapsulated) and as a "vendor-option-space" + (type 43 encapsulated.) This may avoid messing with the + dhcp-parameter-request-list, as detailed below. + +Then, inside your PXELINUX-booting group or class (whereever you have +the PXELINUX-related options, such as the filename option), you can +add, for example: + + # Always include the following lines for all PXELINUX clients + site-option-space "pxelinux"; + option pxelinux.magic f1:00:74:7e; + if exists dhcp-parameter-request-list { + # Always send the PXELINUX options (specified in hexadecimal) + option dhcp-parameter-request-list = concat(option dhcp-parameter-request-list,d0,d1,d2,d3); + } + # These lines should be customized to your setup + option pxelinux.configfile "configs/common"; + option pxelinux.pathprefix "/tftpboot/pxelinux/files/"; + option pxelinux.reboottime 30; + filename "/tftpboot/pxelinux/pxelinux.bin"; + +Note that the configfile is relative to the pathprefix: this will look +for a config file called /tftpboot/pxelinux/files/configs/common on +the TFTP server. + +The "option dhcp-parameter-request-list" statement forces the DHCP +server to send the PXELINUX-specific options, even though they are not +explicitly requested. Since the DHCP request is done before PXELINUX +is loaded, the PXE client won't know to request them. + +Using ISC dhcp 3.0 you can create a lot of these strings on the fly. +For example, to use the hexadecimal form of the hardware address as +the configuration file name, you could do something like: + + site-option-space "pxelinux"; + option pxelinux.magic f1:00:74:7e; + if exists dhcp-parameter-request-list { + # Always send the PXELINUX options (specified in hexadecimal) + option dhcp-parameter-request-list = concat(option dhcp-parameter-request-list,d0,d1,d2,d3); + } + option pxelinux.configfile = + concat("pxelinux.cfg/", binary-to-ascii(16, 8, ":", hardware)); + filename "/tftpboot/pxelinux.bin"; + +If you used this from a client whose Ethernet address was +58:FA:84:CF:55:0E, this would look for a configuration file named +"/tftpboot/pxelinux.cfg/1:58:fa:84:cf:55:e". + + + ++++ ALTERNATE TFTP SERVERS ++++ + +PXELINUX supports the following special pathname conventions: + +::filename + + Suppresses the common filename prefix, i.e. passes the string + "filename" unmodified to the server. + +IP address::filename (e.g. 192.0.2.1::filename) + + Suppresses the common filename prefix, *and* sends a request + to an alternate TFTP server. Instead of an IP address, a + DNS name can be used. It will be assumed to be fully + qualified if it contains dots; otherwise the local domain as + reported by the DHCP server (option 15) will be added. + +:: was chosen because it is unlikely to conflict with operating system +usage. However, if you happen to have an environment for which the +special treatment of :: is a problem, please contact the SYSLINUX +mailing list. + + + ++++ SOME NOTES ++++ + +If the boot fails, PXELINUX (unlike SYSLINUX) will not wait forever; +rather, if it has not received any input for approximately five +minutes after displaying an error message, it will reset the machine. +This allows an unattended machine to recover in case it had bad enough +luck of trying to boot at the same time the TFTP server goes down. + +Lots of PXE stacks, especially old ones, have various problems of +varying degrees of severity. Please see: + + http://syslinux.zytor.com/hardware.php + +... for a list of currently known hardware problems, with workarounds +if known. + + + ++++ KEEPING THE PXE STACK AROUND ++++ + +Normally, PXELINUX will unload the PXE and UNDI stacks before invoking +the kernel. In special circumstances (for example, when using MEMDISK +to boot an operating system with an UNDI network driver) it might be +desirable to keep the PXE stack in memory. If the option "keeppxe" +is given on the kernel command line, PXELINUX will keep the PXE and +UNDI stacks in memory. (If you don't know what this means, you +probably don't need it.) + + + ++++ CURRENTLY KNOWN PROBLEMS ++++ + +The following problems are known with PXELINUX, so far: + ++ Requires a TFTP server which supports the "tsize" option. ++ The error recovery routine doesn't work quite right. For right now, + it just does a hard reset - seems good enough. ++ We should probably call the UDP receive function in the keyboard + entry loop, so that we answer ARP requests. ++ Boot sectors/disk images are not supported yet. + +If you have additional problems, please contact the SYSLINUX mailing +list (see syslinux.doc for the address.) diff --git a/syslinux/rawcon.inc b/syslinux/rawcon.inc new file mode 100644 index 0000000..9f02e4f --- /dev/null +++ b/syslinux/rawcon.inc @@ -0,0 +1,72 @@ +; +; writechr: Write a single character in AL to the console without +; mangling any registers. This does raw console writes, +; since some PXE BIOSes seem to interfere regular console I/O. +; +%if IS_ISOLINUX +writechr_full: +%else +writechr: +%endif + push ds + push cs + pop ds + call write_serial ; write to serial port if needed + pushfd + test byte [DisplayCon],01h ; Write to screen? + jz .nothing + + pushad + mov bh,[BIOS_page] + push ax + mov ah,03h ; Read cursor position + int 10h + pop ax + cmp al,8 + je .bs + cmp al,13 + je .cr + cmp al,10 + je .lf + push dx + mov bh,[BIOS_page] + mov bl,07h ; White on black + mov cx,1 ; One only + mov ah,09h ; Write char and attribute + int 10h + pop dx + inc dl + cmp dl,[VidCols] + jna .curxyok + xor dl,dl +.lf: inc dh + cmp dh,[VidRows] + ja .scroll +.curxyok: mov bh,[BIOS_page] + mov ah,02h ; Set cursor position + int 10h +.ret: popad +.nothing: + popfd + pop ds + ret +.scroll: dec dh + mov bh,[BIOS_page] + mov ah,02h + int 10h + mov ax,0601h ; Scroll up one line + mov bh,[ScrollAttribute] + xor cx,cx + mov dx,[ScreenSize] ; The whole screen + int 10h + jmp short .ret +.cr: xor dl,dl + jmp short .curxyok +.bs: sub dl,1 + jnc .curxyok + mov dl,[VidCols] + sub dh,1 + jnc .curxyok + xor dh,dh + jmp short .curxyok + diff --git a/syslinux/regdump.inc b/syslinux/regdump.inc new file mode 100644 index 0000000..8125281 --- /dev/null +++ b/syslinux/regdump.inc @@ -0,0 +1,111 @@ +;; $Id: regdump.inc,v 1.2 2004/12/14 22:46:25 hpa Exp $ +;; ----------------------------------------------------------------------- +;; +;; Copyright 2003 H. Peter Anvin - All Rights Reserved +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +;; Boston MA 02111-1307, USA; either version 2 of the License, or +;; (at your option) any later version; incorporated herein by reference. +;; +;; ----------------------------------------------------------------------- + +;; +;; regdump.inc +;; +;; Dump as much as possible of the register state; for debugging +;; + +disk_dumpregs: + mov ah,02h + call dumpregs + int 13h + ret + +dumpregs: + push gs + push fs + push es + push ds + push ss + push cs + pushad + pushfd + + push cs + pop ds + + mov bp,sp + mov di,regnames + + mov cx,9 ; 9 32-bit registers +.reg8: + mov si,[di] + inc di + inc di + call cwritestr + mov eax,[bp] + add bp,4 + call writehex8 + loop .reg8 + + mov cx,7 ; 6 16-bit registers +.reg4: + mov si,[di] + inc di + inc di + call cwritestr + mov eax,[bp] + inc bp + inc bp + call writehex4 + loop .reg4 + + call crlf + + popfd + popad + add sp,4 ; Skip CS, SS + pop ds + pop es + pop fs + pop gs + ret + +regnames: + dw .eflags + dw .edi + dw .esi + dw .ebp + dw .esp + dw .ebx + dw .edx + dw .ecx + dw .eax + dw .cs + dw .ss + dw .ds + dw .es + dw .fs + dw .gs + dw .ip + +.eflags db 'EFL: ', 0 +.edi db 13,10,'EDI: ', 0 +.esi db ' ESI: ', 0 +.ebp db ' EBP: ', 0 +.esp db ' ESP: ', 0 +.ebx db 13,10,'EBX: ', 0 +.edx db ' EDX: ', 0 +.ecx db ' ECX: ', 0 +.eax db ' EAX: ', 0 +.cs db 13,10,'CS: ',0 +.ss db ' SS: ',0 +.ds db ' DS: ',0 +.es db ' ES: ',0 +.fs db ' FS: ',0 +.gs db ' GS: ',0 +.ip db ' IP: ',0 + + diff --git a/syslinux/rllpack.inc b/syslinux/rllpack.inc new file mode 100644 index 0000000..f2599df --- /dev/null +++ b/syslinux/rllpack.inc @@ -0,0 +1,133 @@ +; -*- fundamental -*- +; ----------------------------------------------------------------------- +; +; Copyright 2004 H. Peter Anvin - All Rights Reserved +; +; This program is free software; you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +; Boston MA 02111-1307, USA; either version 2 of the License, or +; (at your option) any later version; incorporated herein by reference. +; +; ----------------------------------------------------------------------- +; $Id: rllpack.inc,v 1.2 2004/12/17 07:52:54 hpa Exp $ + +; +; rllpack.inc +; +; Very simple RLL compressor/decompressor, used to pack binary structures +; together. +; +; Format of leading byte +; 1-128 = x verbatim bytes follow +; 129-255 = (x-126) times subsequent byte +; 0 = end of data +; + + section .text + +; +; rllpack: +; Pack CX bytes from DS:SI into ES:DI +; Returns updated SI, DI and CX = number of bytes output +; +rllpack: + push ax + push bx + push cx + push bp + push di +.startseq: + xor ax,ax ; Zero byte + xor bx,bx ; Run length zero + mov bp,di ; Pointer to header byte + stosb ; Store header byte (might be zero) + jcxz .done_null +.stdbyte: + lodsb + stosb + dec cx + cmp ah,al + je .same +.diff: + mov ah,al + xor bx,bx +.plainbyte: + inc bx + inc byte [es:bp] + jcxz .done + jns .stdbyte + jmp .startseq +.same: + cmp bl,2 + jb .plainbyte + ; 3 bytes or more in a row, time to convert sequence + sub byte [es:bp],bl + jnz .normal + dec di ; We killed a whole stretch, remove start byte +.normal: + inc bx + sub di,bx + mov bp,di + mov al,bl + add al,126 + stosb + mov al,ah + stosb +.getrun: + jcxz .done + cmp bl,255-126 + jae .startseq + lodsb + cmp al,ah + jne .nomatch + inc bx + inc byte [es:bp] + dec cx + jmp .getrun +.nomatch: + dec si + jmp .startseq +.done: + xor al,al + stosb +.done_null: + pop dx + sub dx,di + neg dx + pop bp + pop cx + pop bx + pop ax + ret +; +; rllunpack: +; Unpack bytes from DS:SI into ES:DI +; On return SI, DI are updated and CX contains number of bytes output +; +rllunpack: + push ax + push di + xor cx,cx +.header: + lodsb + and al,al + jz .done + cmp al,129 + jae .isrun + ; Not a run + mov cl,al + rep movsb + jmp .header +.isrun: + sub al,126 + mov cl,al + lodsb + rep stosb + jmp .header +.done: + pop cx + sub cx,di + neg cx + pop ax + ret diff --git a/syslinux/runkernel.inc b/syslinux/runkernel.inc new file mode 100644 index 0000000..ed22936 --- /dev/null +++ b/syslinux/runkernel.inc @@ -0,0 +1,635 @@ +;; $Id: runkernel.inc,v 1.20 2005/05/08 21:47:03 hpa Exp $ +;; ----------------------------------------------------------------------- +;; +;; Copyright 1994-2005 H. Peter Anvin - All Rights Reserved +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +;; Boston MA 02111-1307, USA; either version 2 of the License, or +;; (at your option) any later version; incorporated herein by reference. +;; +;; ----------------------------------------------------------------------- + +;; +;; runkernel.inc +;; +;; Common code for running a Linux kernel +;; + +; +; Hook macros, that may or may not be defined +; +%ifndef HAVE_SPECIAL_APPEND +%macro SPECIAL_APPEND 0 +%endmacro +%endif + +%ifndef HAVE_UNLOAD_PREP +%macro UNLOAD_PREP 0 +%endmacro +%endif + +; +; A Linux kernel consists of three parts: boot sector, setup code, and +; kernel code. The boot sector is never executed when using an external +; booting utility, but it contains some status bytes that are necessary. +; +; First check that our kernel is at least 1K and less than 8M (if it is +; more than 8M, we need to change the logic for loading it anyway...) +; +; We used to require the kernel to be 64K or larger, but it has gotten +; popular to use the Linux kernel format for other things, which may +; not be so large. +; +is_linux_kernel: + cmp dx,80h ; 8 megs + ja kernel_corrupt + and dx,dx + jnz kernel_sane + cmp ax,1024 ; Bootsect + 1 setup sect + jb kernel_corrupt +kernel_sane: push ax + push dx + push si + mov si,loading_msg + call cwritestr +; +; Now start transferring the kernel +; + push word real_mode_seg + pop es + + movzx eax,ax ; Fix this by using a 32-bit + shl edx,16 ; register for the kernel size + or eax,edx + mov [KernelSize],eax + add eax,SECTOR_SIZE-1 + shr eax,SECTOR_SHIFT + mov [KernelSects],eax ; Total sectors in kernel + +; +; Now, if we transfer these straight, we'll hit 64K boundaries. Hence we +; have to see if we're loading more than 64K, and if so, load it step by +; step. +; + +; +; Start by loading the bootsector/setup code, to see if we need to +; do something funky. It should fit in the first 32K (loading 64K won't +; work since we might have funny stuff up near the end of memory). +; If we have larger than 32K clusters, yes, we're hosed. +; + call abort_check ; Check for abort key + mov ecx,8000h >> SECTOR_SHIFT ; Half a moby (32K) + cmp ecx,[KernelSects] + jna .normalkernel + mov ecx,[KernelSects] +.normalkernel: + sub [KernelSects],ecx + xor bx,bx + pop si ; Cluster pointer on stack + call getfssec + cmp word [es:bs_bootsign],0AA55h + jne kernel_corrupt ; Boot sec signature missing + +; +; Save the cluster pointer for later... +; + push si +; +; Get the BIOS' idea of what the size of high memory is. +; + call highmemsize +; +; Construct the command line (append options have already been copied) +; +construct_cmdline: + mov di,[CmdLinePtr] + mov si,boot_image ; BOOT_IMAGE= + mov cx,boot_image_len + rep movsb + mov si,KernelCName ; Unmangled kernel name + mov cx,[KernelCNameLen] + rep movsb + mov al,' ' ; Space + stosb + + SPECIAL_APPEND ; Module-specific hook + + mov si,[CmdOptPtr] ; Options from user input + call strcpy + +; +; Scan through the command line for anything that looks like we might be +; interested in. The original version of this code automatically assumed +; the first option was BOOT_IMAGE=, but that is no longer certain. +; + mov si,cmd_line_here + xor ax,ax + mov [InitRDPtr],ax ; No initrd= option (yet) + push es ; Set DS <- real_mode_seg + pop ds +get_next_opt: lodsb + and al,al + jz cmdline_end + cmp al,' ' + jbe get_next_opt + dec si + mov eax,[si] + cmp eax,'vga=' + je is_vga_cmd + cmp eax,'mem=' + je is_mem_cmd +%if IS_PXELINUX + cmp eax,'keep' ; Is it "keeppxe"? + jne .notkeep + cmp dword [si+3],'ppxe' + jne .notkeep + cmp byte [si+7],' ' ; Must be whitespace or EOS + ja .notkeep + or byte [cs:KeepPXE],1 +.notkeep: +%endif + push es ; Save ES -> real_mode_seg + push cs + pop es ; Set ES <- normal DS + mov di,initrd_cmd + mov cx,initrd_cmd_len + repe cmpsb + jne .not_initrd + + cmp al,' ' + jbe .noramdisk + mov [cs:InitRDPtr],si + jmp .not_initrd +.noramdisk: + xor ax,ax + mov [cs:InitRDPtr],ax +.not_initrd: pop es ; Restore ES -> real_mode_seg +skip_this_opt: lodsb ; Load from command line + cmp al,' ' + ja skip_this_opt + dec si + jmp short get_next_opt +is_vga_cmd: + add si,4 + mov eax,[si-1] + mov bx,-1 + cmp eax,'=nor' ; vga=normal + je vc0 + dec bx ; bx <- -2 + cmp eax,'=ext' ; vga=ext + je vc0 + dec bx ; bx <- -3 + cmp eax,'=ask' ; vga=ask + je vc0 + call parseint ; vga=<number> + jc skip_this_opt ; Not an integer +vc0: mov [bs_vidmode],bx ; Set video mode + jmp short skip_this_opt +is_mem_cmd: + add si,4 + call parseint + jc skip_this_opt ; Not an integer +%if HIGHMEM_SLOP != 0 + sub ebx,HIGHMEM_SLOP +%endif + mov [cs:HighMemSize],ebx + jmp short skip_this_opt +cmdline_end: + push cs ; Restore standard DS + pop ds + sub si,cmd_line_here + mov [CmdLineLen],si ; Length including final null +; +; Now check if we have a large kernel, which needs to be loaded high +; + mov dword [RamdiskMax], HIGHMEM_MAX ; Default initrd limit + cmp dword [es:su_header],HEADER_ID ; New setup code ID + jne old_kernel ; Old kernel, load low + cmp word [es:su_version],0200h ; Setup code version 2.0 + jb old_kernel ; Old kernel, load low + cmp word [es:su_version],0201h ; Version 2.01+? + jb new_kernel ; If 2.00, skip this step + mov word [es:su_heapend],linux_stack ; Set up the heap + or byte [es:su_loadflags],80h ; Let the kernel know we care + cmp word [es:su_version],0203h ; Version 2.03+? + jb new_kernel ; Not 2.03+ + mov eax,[es:su_ramdisk_max] + mov [RamdiskMax],eax ; Set the ramdisk limit + +; +; We definitely have a new-style kernel. Let the kernel know who we are, +; and that we are clueful +; +new_kernel: + mov byte [es:su_loader],my_id ; Show some ID + movzx ax,byte [es:bs_setupsecs] ; Variable # of setup sectors + mov [SetupSecs],ax + xor eax,eax + mov [es:su_ramdisklen],eax ; No initrd loaded yet + +; +; About to load the kernel. This is a modern kernel, so use the boot flags +; we were provided. +; + mov al,[es:su_loadflags] + mov [LoadFlags],al +; +; Load the kernel. We always load it at 100000h even if we're supposed to +; load it "low"; for a "low" load we copy it down to low memory right before +; jumping to it. +; +read_kernel: + mov si,KernelCName ; Print kernel name part of + call cwritestr ; "Loading" message + mov si,dotdot_msg ; Print dots + call cwritestr + + mov eax,[HighMemSize] + sub eax,100000h ; Load address + cmp eax,[KernelSize] + jb no_high_mem ; Not enough high memory +; +; Move the stuff beyond the setup code to high memory at 100000h +; + movzx esi,word [SetupSecs] ; Setup sectors + inc si ; plus 1 boot sector + shl si,9 ; Convert to bytes + mov ecx,8000h ; 32K + sub ecx,esi ; Number of bytes to copy + push ecx + add esi,(real_mode_seg << 4) ; Pointer to source + mov edi,100000h ; Copy to address 100000h + + call bcopy ; Transfer to high memory + + ; On exit EDI -> where to load the rest + + mov si,dot_msg ; Progress report + call cwritestr + call abort_check + + pop ecx ; Number of bytes in the initial portion + pop si ; Restore file handle/cluster pointer + mov eax,[KernelSize] + sub eax,8000h ; Amount of kernel not yet loaded + jbe high_load_done ; Zero left (tiny kernel) + + xor dx,dx ; No padding needed + call load_high ; Copy the file + +high_load_done: + mov [KernelEnd],edi + mov ax,real_mode_seg ; Set to real mode seg + mov es,ax + + mov si,dot_msg + call cwritestr + +; +; Now see if we have an initial RAMdisk; if so, do requisite computation +; We know we have a new kernel; the old_kernel code already will have objected +; if we tried to load initrd using an old kernel +; +load_initrd: + cmp word [InitRDPtr],0 + jz nk_noinitrd + call parse_load_initrd +nk_noinitrd: +; +; Abandon hope, ye that enter here! We do no longer permit aborts. +; + call abort_check ; Last chance!! + + mov si,ready_msg + call cwritestr + + call vgaclearmode ; We can't trust ourselves after this + + UNLOAD_PREP ; Module-specific hook + +; +; Now, if we were supposed to load "low", copy the kernel down to 10000h +; and the real mode stuff to 90000h. We assume that all bzImage kernels are +; capable of starting their setup from a different address. +; + mov ax,real_mode_seg + mov fs,ax + +; +; Copy command line. Unfortunately, the kernel boot protocol requires +; the command line to exist in the 9xxxxh range even if the rest of the +; setup doesn't. +; + cli ; In case of hooked interrupts + test byte [LoadFlags],LOAD_HIGH + jz need_high_cmdline + cmp word [fs:su_version],0202h ; Support new cmdline protocol? + jb need_high_cmdline + ; New cmdline protocol + ; Store 32-bit (flat) pointer to command line + mov dword [fs:su_cmd_line_ptr],(real_mode_seg << 4) + cmd_line_here + jmp short in_proper_place + +need_high_cmdline: +; +; Copy command line up to 90000h +; + mov ax,9000h + mov es,ax + mov si,cmd_line_here + mov di,si + mov [fs:kern_cmd_magic],word CMD_MAGIC ; Store magic + mov [fs:kern_cmd_offset],di ; Store pointer + + mov cx,[CmdLineLen] + cmp cx,255 + jna .len_ok + mov cx,255 ; Protocol < 0x202 has 255 as hard limit +.len_ok: + fs rep movsb + fs stosb ; Final null, note AL == 0 here + + push fs + pop es + + test byte [LoadFlags],LOAD_HIGH + jnz in_proper_place ; If high load, we're done + +; +; Loading low; we can't assume it's safe to run in place. +; +; Copy real_mode stuff up to 90000h +; + mov ax,9000h + mov es,ax + mov cx,[SetupSecs] + inc cx ; Setup + boot sector + shl cx,7 ; Sectors -> dwords + xor si,si + xor di,di + fs rep movsd ; Copy setup + boot sector +; +; Some kernels in the 1.2 ballpark but pre-bzImage have more than 4 +; setup sectors, but the boot protocol had not yet been defined. They +; rely on a signature to figure out if they need to copy stuff from +; the "protected mode" kernel area. Unfortunately, we used that area +; as a transfer buffer, so it's going to find the signature there. +; Hence, zero the low 32K beyond the setup area. +; + mov di,[SetupSecs] + inc di ; Setup + boot sector + mov cx,32768/512 ; Sectors/32K + sub cx,di ; Remaining sectors + shl di,9 ; Sectors -> bytes + shl cx,7 ; Sectors -> dwords + xor eax,eax + rep stosd ; Clear region +; +; Copy the kernel down to the "low" location +; + mov ecx,[KernelSize] + mov esi,100000h + mov edi,10000h + call bcopy + +; +; Now everything is where it needs to be... +; +; When we get here, es points to the final segment, either +; 9000h or real_mode_seg +; +in_proper_place: + +; +; If the default root device is set to FLOPPY (0000h), change to +; /dev/fd0 (0200h) +; + cmp word [es:bs_rootdev],byte 0 + jne root_not_floppy + mov word [es:bs_rootdev],0200h +root_not_floppy: + +; +; Copy the disk table to high memory, then re-initialize the floppy +; controller +; +%if IS_SYSLINUX || IS_MDSLINUX + lgs si,[cs:fdctab] + mov di,linux_fdctab + mov cx,6 ; 12 bytes + gs rep movsw + mov [cs:fdctab],word linux_fdctab ; Save new floppy tab pos + mov [cs:fdctab+2],es +%endif +; +; Linux wants the floppy motor shut off before starting the kernel, +; at least bootsect.S seems to imply so. +; +kill_motor: + xor ax,ax + xor dx,dx + int 13h + +; +; If we're debugging, wait for a keypress so we can read any debug messages +; +%ifdef debug + xor ax,ax + int 16h +%endif +; +; Set up segment registers and the Linux real-mode stack +; Note: es == the real mode segment +; + cli + mov bx,es + mov ds,bx + mov fs,bx + mov gs,bx + mov ss,bx + mov sp,linux_stack +; +; We're done... now RUN THAT KERNEL!!!! +; Setup segment == real mode segment + 020h; we need to jump to offset +; zero in the real mode segment. +; + add bx,020h + push bx + push word 0h + retf + +; +; Load an older kernel. Older kernels always have 4 setup sectors, can't have +; initrd, and are always loaded low. +; +old_kernel: + cmp word [InitRDPtr],0 ; Old kernel can't have initrd + je load_old_kernel + mov si,err_oldkernel + jmp abort_load +load_old_kernel: + mov word [SetupSecs],4 ; Always 4 setup sectors + mov byte [LoadFlags],0 ; Always low + jmp read_kernel + +; +; parse_load_initrd +; +; Parse an initrd= option and load the initrds. Note that we load +; from the high end of memory first, so we parse this option from +; left to right. +; +parse_load_initrd: + push es + push ds + mov ax,real_mode_seg + mov ds,ax + push cs + pop es ; DS == real_mode_seg, ES == CS + + mov si,[cs:InitRDPtr] +.find_end: + lodsb + cmp al,' ' + ja .find_end + ; Now SI points to one character beyond the + ; byte that ended this option. + +.get_chunk: + dec si + + ; DS:SI points to a termination byte + + xor ax,ax + xchg al,[si] ; Zero-terminate + push si ; Save ending byte address + push ax ; Save ending byte + +.find_start: + dec si + cmp si,[cs:InitRDPtr] + je .got_start + cmp byte [si],',' + jne .find_start + + ; It's a comma byte + inc si + +.got_start: + push si + mov di,InitRD ; Target buffer for mangled name + call mangle_name + call loadinitrd + pop si + + pop ax + pop di + mov [di],al ; Restore ending byte + + cmp si,[cs:InitRDPtr] + ja .get_chunk + + pop ds + pop es + ret + +; +; Load RAM disk into high memory +; +; Input: InitRD - set to the mangled name of the initrd +; +loadinitrd: + push ds + push es + mov ax,cs ; CS == DS == ES + mov ds,ax + mov es,ax + mov si,InitRD + mov di,InitRDCName + call unmangle_name ; Create human-readable name + sub di,InitRDCName + mov [InitRDCNameLen],di + mov di,InitRD + call searchdir ; Look for it in directory + jz .notthere + + mov cx,dx + shl ecx,16 + mov cx,ax ; ECX <- ram disk length + + mov ax,real_mode_seg + mov es,ax + + push ecx ; Bytes to load + cmp dword [es:su_ramdisklen],0 + je .nopadding ; Don't pad the last initrd + add ecx,4095 + and cx,0F000h +.nopadding: + add [es:su_ramdisklen],ecx + mov edx,[HighMemSize] ; End of memory + dec edx + mov eax,[RamdiskMax] ; Highest address allowed by kernel + cmp edx,eax + jna .memsize_ok + mov edx,eax ; Adjust to fit inside limit +.memsize_ok: + inc edx + and dx,0F000h ; Round down to 4K boundary + sub edx,ecx ; Subtract size of ramdisk + and dx,0F000h ; Round down to 4K boundary + cmp edx,[KernelEnd] ; Are we hitting the kernel image? + jb no_high_mem + + mov [es:su_ramdiskat],edx ; Load address + mov [RamdiskMax],edx ; Next initrd loaded here + + mov edi,edx ; initrd load address + push si + mov si,crlfloading_msg ; Write "Loading " + call cwritestr + mov si,InitRDCName ; Write ramdisk name + call cwritestr + mov si,dotdot_msg ; Write dots + call cwritestr + pop si + + pop eax ; Bytes to load + mov dx,0FFFh ; Pad to page + call load_high ; Load the file + + pop es + pop ds + jmp crlf ; Print carriage return and return + +.notthere: + mov si,err_noinitrd + call cwritestr + mov si,InitRDCName + call cwritestr + mov si,crlf_msg + jmp abort_load + +no_high_mem: ; Error routine + mov si,err_nohighmem + jmp abort_load + + ret + + section .data +boot_image db 'BOOT_IMAGE=' +boot_image_len equ $-boot_image + + section .bss + alignb 4 +RamdiskMax resd 1 ; Highest address for ramdisk +KernelSize resd 1 ; Size of kernel in bytes +KernelSects resd 1 ; Size of kernel in sectors +KernelEnd resd 1 ; Ending address of the kernel image +CmdLineLen resw 1 ; Length of command line including null +SetupSecs resw 1 ; Number of setup sectors +InitRDPtr resw 1 ; Pointer to initrd= option in command line +LoadFlags resb 1 ; Loadflags from kernel diff --git a/syslinux/sample/Makefile b/syslinux/sample/Makefile new file mode 100644 index 0000000..9947f93 --- /dev/null +++ b/syslinux/sample/Makefile @@ -0,0 +1,84 @@ +#ident "$Id: Makefile,v 1.23 2005/01/03 08:23:16 hpa Exp $" +## ----------------------------------------------------------------------- +## +## Copyright 2001-2004 H. Peter Anvin - All Rights Reserved +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, Inc., 53 Temple Place Ste 330, +## Boston MA 02111-1307, USA; either version 2 of the License, or +## (at your option) any later version; incorporated herein by reference. +## +## ----------------------------------------------------------------------- + +## +## samples for syslinux users +## + +gcc_ok = $(shell if gcc $(1) -c -x c /dev/null -o /dev/null 2>/dev/null; \ + then echo $(1); else echo $(2); fi) + +M32 := $(call gcc_ok,-m32,) $(call gcc_ok,-ffreestanding,) + +CC = gcc $(M32) +LD = ld -m elf_i386 +AR = ar +NASM = nasm +RANLIB = ranlib +CFLAGS = -W -Wall -march=i386 -Os -fomit-frame-pointer -I../com32/include +SFLAGS = -march=i386 +LDFLAGS = -s +OBJCOPY = objcopy +PPMTOLSS16 = ../ppmtolss16 +LIB = liboldcom32.a + +LIBOBJS = conio.o atou.o skipatou.o printf.o c32exit.o + +ARCH := $(shell uname -m) +ifneq (x86_64, $ARCH) +CFLAGS += -m32 +SFLAGS += -m32 +LDFLAGS += -m elf_i386 +endif + +.SUFFIXES: .lss .c .o .elf .c32 + +all: syslogo.lss comecho.com hello.c32 hello2.c32 filetest.c32 c32echo.c32 \ + fd.c32 $(LIB) + +.PRECIOUS: %.o +%.o: %.S + $(CC) $(SFLAGS) -c -o $@ $< + +.PRECIOUS: %.o +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +.PRECIOUS: %.elf +%.elf: c32entry.o %.o $(LIB) + $(LD) $(LDFLAGS) -Ttext 0x101000 -e _start -o $@ $^ + +%.c32: %.elf + $(OBJCOPY) -O binary $< $@ + +%.com: %.asm + $(NASM) -f bin -o $@ -l $*.lst $< + +$(LIB): $(LIBOBJS) + rm -f $@ + $(AR) cq $@ $^ + $(RANLIB) $@ + +syslogo.lss: syslogo.png $(PPMTOLSS16) + pngtopnm syslogo.png | \ + $(PPMTOLSS16) \#000000=0 \#d0d0d0=7 \#f6f6f6=15 \ + > syslogo.lss + +tidy: + rm -f *.o *.a *.lst *.elf + +# Don't specify *.com since mdiskchk.com can't be built using Linux tools +clean: tidy + rm -f *.lss *.o *.c32 comecho.com + +spotless: clean diff --git a/syslinux/sample/README b/syslinux/sample/README new file mode 100644 index 0000000..0a053f5 --- /dev/null +++ b/syslinux/sample/README @@ -0,0 +1,6 @@ +This directory contains files intended to be used as sample code. +This includes COMBOOT, COM32, and MS-DOS programs as well as LSS +icons. + +For developing COM32 programs, you probably want to use the new com32 +toolkit (libcom32 and libutil), available in the com32 directory. diff --git a/syslinux/sample/atou.c b/syslinux/sample/atou.c new file mode 100644 index 0000000..3658599 --- /dev/null +++ b/syslinux/sample/atou.c @@ -0,0 +1,14 @@ +static inline int +isdigit(int ch) +{ + return (ch >= '0') && (ch <= '9'); +} + +unsigned int atou(const char *s) +{ + unsigned int i = 0; + while (isdigit(*s)) + i = i*10 + (*s++ - '0'); + return i; +} + diff --git a/syslinux/sample/c32echo.c b/syslinux/sample/c32echo.c new file mode 100644 index 0000000..9f5096a --- /dev/null +++ b/syslinux/sample/c32echo.c @@ -0,0 +1,49 @@ +#ident "$Id: c32echo.c,v 1.3 2005/01/03 08:23:16 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2002 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * c32echo.c + * + * Simple COM32 program which only prints out its own command line + */ + +#include <com32.h> + +#define NULL ((void *)0) + +static inline void memset(void *buf, int ch, unsigned int len) +{ + asm volatile("cld; rep; stosb" + : "+D" (buf), "+c" (len) : "a" (ch) : "memory"); +} + +int __start(void) +{ + com32sys_t inreg; + const char *p; + + memset(&inreg, 0, sizeof inreg); + inreg.eax.b[1] = 0x02; /* Write Character */ + + for ( p = __com32.cs_cmdline ; *p ; p++ ) { + inreg.edx.b[0] = *p; + __com32.cs_intcall(0x21, &inreg, NULL); + } + + inreg.edx.b[0] = '\r'; + __com32.cs_intcall(0x21, &inreg, NULL); + inreg.edx.b[0] = '\n'; + __com32.cs_intcall(0x21, &inreg, NULL); + + return 0; +} diff --git a/syslinux/sample/c32entry.S b/syslinux/sample/c32entry.S new file mode 100644 index 0000000..d50cd41 --- /dev/null +++ b/syslinux/sample/c32entry.S @@ -0,0 +1,67 @@ +#ident "$Id: c32entry.S,v 1.5 2005/01/03 08:23:16 hpa Exp $" +# ----------------------------------------------------------------------- +# +# Copyright 2003 H. Peter Anvin - All Rights Reserved +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom +# the Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall +# be included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +# ----------------------------------------------------------------------- + +# COM32 start up code - must be linked first in the binary + + + .section ".text","ax" + .globl _start +_start: + # This first instruction acts as COM32 magic number + movl $0x21cd4cff,%eax + + # Upwards string operations + cld + + # Zero the .bss segment + xorl %eax,%eax + movl $__bss_start,%edi # Symbol provided by linker + movl $_end+3,%ecx # Symbol provided by linker + subl %edi,%ecx + shrl $2,%ecx + rep ; stosl + + # Copy COM32 invocation parameters + leal 4(%esp),%esi # Argument list + movl $__com32,%edi + movl $6,%ecx + movl %esp,-4(%edi) # Save the initial stack ptr + cmpl (%esi),%ecx + jbe 1f + movl (%esi),%ecx +1: rep ; movsl + + # Run program; we call this __start rather than main since we + # did not parse the command line or anything like that. + jmp __start + + .section ".bss","aw" + .globl __entry_esp +__entry_esp: .space 4 + .globl __com32 +__com32: .space 4*6 diff --git a/syslinux/sample/c32exit.S b/syslinux/sample/c32exit.S new file mode 100644 index 0000000..5c5ba03 --- /dev/null +++ b/syslinux/sample/c32exit.S @@ -0,0 +1,10 @@ +# $Id# +# +# Implementation of exit() for com32 based on c32entry.S +# + .text + .globl exit +exit: + movl 4(%esp),%eax # Exit code in %eax = return value + movl (__entry_esp),%esp # Return stack pointer to entry value + ret # Return to termination address diff --git a/syslinux/sample/comecho.asm b/syslinux/sample/comecho.asm new file mode 100644 index 0000000..3cdf601 --- /dev/null +++ b/syslinux/sample/comecho.asm @@ -0,0 +1,35 @@ +; +; Simple COMBOOT program that just prints out its own command line. +; This also works in DOS. +; + + org 100h + +_start: + xor cx,cx + mov cl,[80h] ; Command line len + mov si,81h ; Command line + + mov dl,"<" + mov ah,02h + int 21h + +.writechar: + lodsb + mov dl,al + mov ah,02h + int 21h + loop .writechar + + mov dx,end_str + mov ah,09h + int 21h + + ; Exit with near return, INT 20h, or INT 21h AX=4C00h + ret + + +end_str db ">", 0Dh, 0Ah, "$" + + + \ No newline at end of file diff --git a/syslinux/sample/conio.c b/syslinux/sample/conio.c new file mode 100644 index 0000000..df05253 --- /dev/null +++ b/syslinux/sample/conio.c @@ -0,0 +1,61 @@ +#ident "$Id: conio.c,v 1.4 2005/01/03 08:23:16 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2001-2003 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * conio.c + * + * Output to the screen + */ + +#include <com32.h> +#include <stdarg.h> + +#define NULL ((void *)0) + +static inline void memset(void *buf, int ch, unsigned int len) +{ + asm volatile("cld; rep; stosb" + : "+D" (buf), "+c" (len) : "a" (ch) : "memory"); +} + +int putchar(int ch) +{ + com32sys_t regs; + + memset(®s, 0, sizeof regs); + + if ( ch == '\n' ) { + /* \n -> \r\n */ + putchar('\r'); + } + + regs.eax.b[1] = 0x02; + regs.edx.b[0] = ch; + __com32.cs_intcall(0x21, ®s, NULL); + + return ch; +} + +/* Note: doesn't put '\n' like the stdc version does */ +int puts(const char *s) +{ + int count = 0; + + while ( *s ) { + putchar(*s); + count++; + s++; + } + + return count; +} diff --git a/syslinux/sample/fd.c b/syslinux/sample/fd.c new file mode 100644 index 0000000..6081136 --- /dev/null +++ b/syslinux/sample/fd.c @@ -0,0 +1,63 @@ +#ident "$Id: fd.c,v 1.2 2004/12/14 22:46:25 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2003 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * fd.c + * + * Chainload a floppy disk (currently rather braindead.) + */ + +#include <com32.h> +#define NULL ((void *)0) + +int printf(const char *, ...); +unsigned int atou(const char *); + +int __start(void) +{ + int whichfd = atou(__com32.cs_cmdline); + static com32sys_t inreg, outreg; /* In bss, so zeroed automatically */ + int retry; + + for ( retry = 0 ; retry < 6 ; retry++ ) { + printf(">"); + inreg.eax.w[0] = 0x0201; /* Read one sector */ + inreg.ecx.w[0] = 0x0001; /* Cyl 0 sector 1 */ + inreg.edx.b[1] = 0; /* Head 0 */ + inreg.edx.b[0] = whichfd; /* Drive number */ + inreg.es = SEG(__com32.cs_bounce); /* Read into the bounce buffer */ + inreg.ebx.w[0] = OFFS(__com32.cs_bounce); + __com32.cs_intcall(0x13, &inreg, &outreg); + + if ( (outreg.eflags.l & 1) == 0 ) + break; + } + + if ( (outreg.eflags.l & 1) == 0 ) { + printf("!\n"); + inreg.eax.w[0] = 0x000d; + inreg.edx.w[0] = 0; + inreg.edi.l = (uint32_t) __com32.cs_bounce; + inreg.ecx.l = 512; + inreg.ebx.l = whichfd & 0xff; + inreg.esi.l = 0; /* No partitions */ + inreg.ds = 0; /* No partitions */ + __com32.cs_intcall(0x22, &inreg, NULL); + } + + /* If we get here, badness happened */ + return 255; +} + + + diff --git a/syslinux/sample/filetest.c b/syslinux/sample/filetest.c new file mode 100644 index 0000000..ca1d0a6 --- /dev/null +++ b/syslinux/sample/filetest.c @@ -0,0 +1,98 @@ +#include <com32.h> +#include <stdarg.h> + +#define NULL ((void *)0) +int printf(const char *, ...); +int putchar(int); + +static inline void memset(void *buf, int ch, unsigned int len) +{ + asm volatile("cld; rep; stosb" + : "+D" (buf), "+c" (len) : "a" (ch) : "memory"); +} + +static void strcpy(char *dst, const char *src) +{ + while ( *src ) + *dst++ = *src++; + + *dst = '\0'; +} + +static void printregs(const com32sys_t *r) +{ + printf("eflags = %08x ds = %04x es = %04x fs = %04x gs = %04x\n" + "eax = %08x ebx = %08x ecx = %08x edx = %08x\n" + "ebp = %08x esi = %08x edi = %08x esp = %08x\n", + r->eflags.l, r->ds, r->es, r->fs, r->gs, + r->eax.l, r->ebx.l, r->ecx.l, r->edx.l, + r->ebp.l, r->esi.l, r->edi.l, r->_unused.l); +} + +int __start(void) +{ + unsigned int ax,cx,si,t; + com32sys_t inreg,outreg; + char *p; + + /* Test null system call */ + inreg.eflags.l = 0xffffffff; + inreg.eax.l = 0x11110000; + inreg.ecx.l = 0x22222222; + inreg.edx.l = 0x33333333; + inreg.ebx.l = 0x44444444; + inreg.ebp.l = 0x55555555; + inreg.esi.l = 0x66666666; + inreg.edi.l = 0x77777777; + inreg.ds = 0xaaaa; + inreg.es = 0xbbbb; + inreg.fs = 0xcccc; + inreg.gs = 0xdddd; + printregs(&inreg); + __com32.cs_intcall(0x22, &inreg, &outreg); + printregs(&outreg); + printf("----\n"); + + memset(&inreg, 0, sizeof inreg); + memset(&outreg, 0, sizeof outreg); + strcpy(__com32.cs_bounce, "test.txt"); + inreg.eax.w[0] = 0x0006; // Open file + inreg.esi.w[0] = OFFS(__com32.cs_bounce); + inreg.es = SEG(__com32.cs_bounce); + printregs(&inreg); + __com32.cs_intcall(0x22, &inreg, &outreg); + printregs(&outreg); + printf("----\n"); + + si = outreg.esi.w[0]; /* File handle */ + cx = outreg.ecx.w[0]; /* Block size */ + ax = outreg.eax.l; /* File length */ + + while ( si ) { + /* We can only read 64K per call */ + t = ( ax > 65536 ) ? 65536/cx : (ax+cx-1)/cx; + + memset(&inreg, 0, sizeof inreg); + inreg.esi.w[0] = si; + inreg.ecx.w[0] = t; /* Block count */ + inreg.eax.w[0] = 0x0007; // Read file + inreg.ebx.w[0] = OFFS(__com32.cs_bounce); + inreg.es = SEG(__com32.cs_bounce); + printregs(&inreg); + __com32.cs_intcall(0x22, &inreg, &outreg); + printregs(&outreg); + printf("----\n"); + si = outreg.esi.w[0]; + + /* Print the buffer */ + t = (ax < 65536) ? ax : 65536; + p = __com32.cs_bounce; + while ( t ) { + putchar(*p++); + t--; + ax--; + } + } + + return 0; +} diff --git a/syslinux/sample/hello.c b/syslinux/sample/hello.c new file mode 100644 index 0000000..2cf3da4 --- /dev/null +++ b/syslinux/sample/hello.c @@ -0,0 +1,45 @@ +#ident "$Id: hello.c,v 1.6 2005/01/03 08:23:16 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2002 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * hello.c + * + * Simple COM32 image + */ + +#include <com32.h> + +#define NULL ((void *)0) + +static inline void memset(void *buf, int ch, unsigned int len) +{ + asm volatile("cld; rep; stosb" + : "+D" (buf), "+c" (len) : "a" (ch) : "memory"); +} + +int __start(void) +{ + const char *msg = "Hello, World!\r\n"; + com32sys_t inreg; + const char *p; + + memset(&inreg, 0, sizeof inreg); + + for ( p = msg ; *p ; p++ ) { + inreg.edx.b[0] = *p; + inreg.eax.b[1] = 0x02; /* Write Character */ + __com32.cs_intcall(0x21, &inreg, NULL); + } + + return 0; +} diff --git a/syslinux/sample/hello2.c b/syslinux/sample/hello2.c new file mode 100644 index 0000000..eae9a5d --- /dev/null +++ b/syslinux/sample/hello2.c @@ -0,0 +1,61 @@ +#ident "$Id: hello2.c,v 1.4 2004/12/14 22:46:25 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 2002 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * hello2.c + * + * Simple COM32 image + * + * This version shows how to use the bounce buffer for data transfer + * to the BIOS or COMBOOT system calls. + */ + +#include <com32.h> + +#define NULL ((void *)0) + +static inline void memset(void *buf, int ch, unsigned int len) +{ + asm volatile("cld; rep; stosb" + : "+D" (buf), "+c" (len) : "a" (ch) : "memory"); +} + +static void strcpy(char *dst, const char *src) +{ + while ( *src ) + *dst++ = *src++; + + *dst = '\0'; +} + +static void writemsg(const char *msg) +{ + com32sys_t inreg; + + memset(&inreg, 0, sizeof inreg); + + strcpy(__com32.cs_bounce, msg); + inreg.eax.w[0] = 0x0002; /* Write string */ + inreg.ebx.w[0] = OFFS(__com32.cs_bounce); + inreg.es = SEG(__com32.cs_bounce); + __com32.cs_intcall(0x22, &inreg, NULL); +}; + +int __start(void) +{ + writemsg("Hello, World!\r\n" + "cmdline = "); + writemsg(__com32.cs_cmdline); + writemsg("\r\n"); + return 0; +} diff --git a/syslinux/sample/mdiskchk.c b/syslinux/sample/mdiskchk.c new file mode 100644 index 0000000..9045c86 --- /dev/null +++ b/syslinux/sample/mdiskchk.c @@ -0,0 +1,147 @@ +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2003-2004 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ +/* $Id: mdiskchk.c,v 1.7 2004/12/30 21:57:12 hpa Exp $ */ + +/* + * mdiskchk.c + * + * DOS program to check for the existence of a memdisk. + * + * This program can be compiled for DOS with the OpenWatcom compiler + * (http://www.openwatcom.org/): + * + * wcl -3 -osx -mt mdiskchk.c + */ + +#include <stdio.h> +#include <string.h> +#include <i86.h> /* For MK_FP() */ + +typedef unsigned long uint32_t; +typedef unsigned short uint16_t; +typedef unsigned char uint8_t; + +struct memdiskinfo { + uint16_t bytes; /* Bytes from memdisk */ + uint16_t version; /* Memdisk version */ + uint32_t base; /* Base of disk in high memory */ + uint32_t size; /* Size of disk in sectors */ + char far * cmdline; /* Command line */ + void far * oldint13; /* Old INT 13h */ + void far * oldint15; /* Old INT 15h */ + uint16_t olddosmem; + uint8_t bootloaderid; + + uint8_t _pad; + + /* We add our own fields at the end */ + int cylinders; + int heads; + int sectors; +}; + +struct memdiskinfo * query_memdisk(int drive) +{ + static struct memdiskinfo mm; + uint32_t _eax, _ebx, _ecx, _edx; + uint16_t _es, _di; + unsigned char _dl = drive; + uint16_t bytes; + + __asm { + .386 ; + mov eax, 454d0800h ; + mov ecx, 444d0000h ; + mov edx, 53490000h ; + mov dl, _dl ; + mov ebx, 3f4b0000h ; + int 13h ; + mov _eax, eax ; + mov _ecx, ecx ; + mov _edx, edx ; + mov _ebx, ebx ; + mov _es, es ; + mov _di, di ; + } + + if ( _eax >> 16 != 0x4d21 || + _ecx >> 16 != 0x4d45 || + _edx >> 16 != 0x4944 || + _ebx >> 16 != 0x4b53 ) + return NULL; + + memset(&mm, 0, sizeof mm); + + bytes = *(uint16_t far *)MK_FP(_es, _di); + + /* 27 is the most we know how to handle */ + if ( bytes > 27 ) + bytes = 27; + + _fmemcpy((void far *)&mm, (void far *)MK_FP(_es,_di), bytes); + + mm.cylinders = ((_ecx >> 8) & 0xff) + ((_ecx & 0xc0) << 2) + 1; + mm.heads = ((_edx >> 8) & 0xff) + 1; + mm.sectors = (_ecx & 0x3f); + + return &mm; +} + +const char *bootloadername(uint8_t id) +{ + static const struct { + uint8_t id, mask; + const char *name; + } *lp, list[] = + { + { 0x10, 0xf0, "LILO" }, + { 0x20, 0xf0, "LOADLIN" }, + { 0x31, 0xff, "SYSLINUX" }, + { 0x32, 0xff, "PXELINUX" }, + { 0x33, 0xff, "ISOLINUX" }, + { 0x34, 0xff, "EXTLINUX" }, + { 0x30, 0xf0, "SYSLINUX family" }, + { 0x40, 0xf0, "Etherboot" }, + { 0x50, 0xf0, "ELILO" }, + { 0x70, 0xf0, "GrUB" }, + { 0x80, 0xf0, "U-Boot" }, + { 0x00, 0x00, "unknown" } + }; + + for ( lp = list ; ; lp++ ) { + if ( ((id ^ lp->id) & lp->mask) == 0 ) + return lp->name; + } +} + +int main(int argc, char *argv[]) +{ + int d; + int found = 0; + struct memdiskinfo *m; + + for ( d = 0 ; d <= 0xff ; d++ ) { + if ( (m = query_memdisk(d)) != NULL ) { + printf("Drive %02X is MEMDISK %u.%02u:\n" + "\tAddress = 0x%08lx, len = %lu sectors, chs = %u/%u/%u,\n" + "\tloader = 0x%02x (%s),\n" + "\tcmdline = %Fs\n", + d, m->version >> 8, m->version & 0xff, + m->base, m->size, m->cylinders, m->heads, m->sectors, + m->bootloaderid, bootloadername(m->bootloaderid), + m->cmdline); + found++; + } + } + + return found; +} diff --git a/syslinux/sample/mdiskchk.com b/syslinux/sample/mdiskchk.com new file mode 100755 index 0000000000000000000000000000000000000000..07e1471b3ddc3696f865352ef7a5460de88f2c38 GIT binary patch literal 9680 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 FzXMqd$T|Q3 literal 0 HcmV?d00001 diff --git a/syslinux/sample/printf.c b/syslinux/sample/printf.c new file mode 100644 index 0000000..eb16301 --- /dev/null +++ b/syslinux/sample/printf.c @@ -0,0 +1,307 @@ +/* + * Oh, it's a waste of space, but oh-so-yummy for debugging. It's just + * initialization code anyway, so it doesn't take up space when we're + * actually running. This version of printf() does not include 64-bit + * support. "Live with it." + * + * Most of this code was shamelessly snarfed from the Linux kernel, then + * modified. + * + * FIX THIS: Replace printf() implementation with BSD/MIT-licensed one + * from klibc + */ + +#include <stdarg.h> + +int puts(const char *); + +static inline int +isdigit(int ch) +{ + return (ch >= '0') && (ch <= '9'); +} + +unsigned int skip_atou(const char **s); +unsigned int atou(const char *s); + +static int strnlen(const char *s, int maxlen) +{ + const char *es = s; + while ( *es && maxlen ) { + es++; maxlen--; + } + + return (es-s); +} + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SPECIAL 32 /* 0x */ +#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ + +#define do_div(n,base) ({ \ +int __res; \ +__res = ((unsigned long) n) % (unsigned) base; \ +n = ((unsigned long) n) / (unsigned) base; \ +__res; }) + +static char * number(char * str, long num, int base, int size, int precision + ,int type) +{ + char c,sign,tmp[66]; + const char *digits="0123456789abcdefghijklmnopqrstuvwxyz"; + int i; + + if (type & LARGE) + digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + if (type & LEFT) + type &= ~ZEROPAD; + if (base < 2 || base > 36) + return 0; + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) { + if (num < 0) { + sign = '-'; + num = -num; + size--; + } else if (type & PLUS) { + sign = '+'; + size--; + } else if (type & SPACE) { + sign = ' '; + size--; + } + } + if (type & SPECIAL) { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + i = 0; + if (num == 0) + tmp[i++]='0'; + else while (num != 0) + tmp[i++] = digits[do_div(num,base)]; + if (i > precision) + precision = i; + size -= precision; + if (!(type&(ZEROPAD+LEFT))) + while(size-->0) + *str++ = ' '; + if (sign) + *str++ = sign; + if (type & SPECIAL) { + if (base==8) + *str++ = '0'; + else if (base==16) { + *str++ = '0'; + *str++ = digits[33]; + } + } + if (!(type & LEFT)) + while (size-- > 0) + *str++ = c; + while (i < precision--) + *str++ = '0'; + while (i-- > 0) + *str++ = tmp[i]; + while (size-- > 0) + *str++ = ' '; + return str; +} + +/* Forward decl. needed for IP address printing stuff... */ +int sprintf(char * buf, const char *fmt, ...); + +int vsprintf(char *buf, const char *fmt, va_list args) +{ + int len; + unsigned long num; + int i, base; + char * str; + const char *s; + + int flags; /* flags to number() */ + + int field_width; /* width of output field */ + int precision; /* min. # of digits for integers; max + number of chars for from string */ + int qualifier; /* 'h', 'l', or 'L' for integer fields */ + + for (str=buf ; *fmt ; ++fmt) { + if (*fmt != '%') { + *str++ = *fmt; + continue; + } + + /* process flags */ + flags = 0; + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': flags |= LEFT; goto repeat; + case '+': flags |= PLUS; goto repeat; + case ' ': flags |= SPACE; goto repeat; + case '#': flags |= SPECIAL; goto repeat; + case '0': flags |= ZEROPAD; goto repeat; + } + + /* get field width */ + field_width = -1; + if (isdigit(*fmt)) + field_width = skip_atou(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt == '.') { + ++fmt; + if (isdigit(*fmt)) + precision = skip_atou(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { + qualifier = *fmt; + ++fmt; + } + + /* default base */ + base = 10; + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + *str++ = ' '; + *str++ = (unsigned char) va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + continue; + + case 's': + s = va_arg(args, char *); + len = strnlen(s, precision); + + if (!(flags & LEFT)) + while (len < field_width--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = *s++; + while (len < field_width--) + *str++ = ' '; + continue; + + case 'p': + if (field_width == -1) { + field_width = 2*sizeof(void *); + flags |= ZEROPAD; + } + str = number(str, + (unsigned long) va_arg(args, void *), 16, + field_width, precision, flags); + continue; + + + case 'n': + if (qualifier == 'l') { + long * ip = va_arg(args, long *); + *ip = (str - buf); + } else { + int * ip = va_arg(args, int *); + *ip = (str - buf); + } + continue; + + case '%': + *str++ = '%'; + continue; + + /* integer number formats - set up the flags and "break" */ + case 'o': + base = 8; + break; + + case 'X': + flags |= LARGE; + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + break; + + default: + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + continue; + } + if (qualifier == 'l') + num = va_arg(args, unsigned long); + else if (qualifier == 'h') { + num = (unsigned short) va_arg(args, int); + if (flags & SIGN) + num = (short) num; + } else if (flags & SIGN) + num = va_arg(args, int); + else + num = va_arg(args, unsigned int); + str = number(str, num, base, field_width, precision, flags); + } + *str = '\0'; + return str-buf; +} + +int sprintf(char * buf, const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i=vsprintf(buf,fmt,args); + va_end(args); + return i; +} + +int printf(const char *fmt, ...) +{ + char printf_buf[1024]; + va_list args; + int printed; + + va_start(args, fmt); + printed = vsprintf(printf_buf, fmt, args); + va_end(args); + + puts(printf_buf); + + return printed; +} + diff --git a/syslinux/sample/sample.msg b/syslinux/sample/sample.msg new file mode 100644 index 0000000..155e5cd --- /dev/null +++ b/syslinux/sample/sample.msg @@ -0,0 +1,13 @@ + $Id: sample.msg,v 1.2 2001/04/10 00:27:27 hpa Exp $ +Note that <Ctrl-P>...<Ctrl-W> can be used to delimit something +that is effectively a comment. +This message is displayed before the image. +syslogo.lss +This message is displayed after the image. + +Please note colors do not work quite as expected in graphics mode! + +04 RED 07 02 GREEN 07 01 BLUE 07 +47 RED 07 27 GREEN 07 17 BLUE 07 + + diff --git a/syslinux/sample/skipatou.c b/syslinux/sample/skipatou.c new file mode 100644 index 0000000..9888153 --- /dev/null +++ b/syslinux/sample/skipatou.c @@ -0,0 +1,14 @@ +static inline int +isdigit(int ch) +{ + return (ch >= '0') && (ch <= '9'); +} + +unsigned int skip_atou(const char **s) +{ + int i=0; + + while (isdigit(**s)) + i = i*10 + *((*s)++) - '0'; + return i; +} diff --git a/syslinux/sample/syslogo.png b/syslinux/sample/syslogo.png new file mode 100644 index 0000000000000000000000000000000000000000..45b4b5ec89b22e9d0ac066b75b31b98a1119cf69 GIT binary patch literal 19847 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 literal 0 HcmV?d00001 diff --git a/syslinux/sha1pass b/syslinux/sha1pass new file mode 100755 index 0000000..76193f1 --- /dev/null +++ b/syslinux/sha1pass @@ -0,0 +1,32 @@ +#!/usr/bin/perl + +use bytes; +use Digest::SHA1; +use MIME::Base64; + +sub random_bytes($) { + my($n) = @_; + my($v, $i); + + if ( open(RANDOM, '<', '/dev/random') || + open(RANDOM, '<', '/dev/urandom') ) { + read(RANDOM, $v, $n); + } else { + # No real RNG available... + srand($$ ^ time); + $v = ''; + for ( $i = 0 ; $i < $n ; $i++ ) { + $v .= ord(int(rand() * 256)); + } + } + + return $v; +} + + +($pass, $salt) = @ARGV; + +$salt = $salt || MIME::Base64::encode(random_bytes(6), ''); +$pass = Digest::SHA1::sha1_base64($salt, $pass); + +print '$4$', $salt, '$', $pass, "\$\n"; diff --git a/syslinux/strcpy.inc b/syslinux/strcpy.inc new file mode 100644 index 0000000..5068a8e --- /dev/null +++ b/syslinux/strcpy.inc @@ -0,0 +1,14 @@ +; +; strcpy: Copy DS:SI -> ES:DI up to and including a null byte; +; on exit SI and DI point to the byte *after* the null byte +; + section .text + +strcpy: push ax +.loop: lodsb + stosb + and al,al + jnz .loop + pop ax + ret + diff --git a/syslinux/sys2ansi.pl b/syslinux/sys2ansi.pl new file mode 100755 index 0000000..f555cc5 --- /dev/null +++ b/syslinux/sys2ansi.pl @@ -0,0 +1,54 @@ +#!/usr/bin/perl +# $Id: sys2ansi.pl,v 1.8 2003/07/01 00:49:31 hpa Exp $ +# +# Perl script to convert a Syslinux-format screen to PC-ANSI +# to display in a color xterm or on the Linux console +# + +@ansicol = (0,4,2,6,1,5,3,7); + +$getting_file = 0; +$enable = 1; + +while ( read(STDIN, $ch, 1) > 0 ) { + if ( $ch eq "\x1A" ) { # <SUB> <Ctrl-Z> EOF + last; + } elsif ( $ch eq "\x0C" ) { # <FF> <Ctrl-L> Clear screen + print "\x1b[2J" if ( $enable && !$getting_file ); + } elsif ( $ch eq "\x0F" ) { # <SI> <Ctrl-O> Attribute change + if ( !$getting_file ) { + if ( read(STDIN, $attr, 2) == 2 ) { + $attr = hex $attr; + if ( $enable ) { + print "\x1b[0;"; + if ( $attr & 0x80 ) { + print "5;"; + $attr &= ~0x80; + } + if ( $attr & 0x08 ) { + print "1;"; + $attr &= ~0x08; + } + printf "%d;%dm", + $ansicol[$attr >> 4] + 40, $ansicol[$attr & 7] + 30; + } + } + } + } elsif ( $ch eq "\x18" ) { # <CAN> <Ctrl-X> Display image + # We can't display an image; pretend to be a text screen + # Ignore all input until end of line + $getting_file = 1; + } elsif ( (ord($ch) & ~07) == 0x10 ) { # Mode controls + $enable = (ord($ch) & 0x01); # Emulate the text screen + } elsif ( $ch eq "\x0D" ) { # <CR> <Ctrl-M> Carriage return + # Ignore + } elsif ( $ch eq "\x0A" ) { # <LF> <Ctrl-J> Line feed + if ( $getting_file ) { + $getting_file = 0; + } else { + print $ch if ( $enable ); + } + } else { + print $ch if ( $enable && !$getting_file ); + } +} diff --git a/syslinux/syslinux.doc b/syslinux/syslinux.doc new file mode 100644 index 0000000..bd9f76a --- /dev/null +++ b/syslinux/syslinux.doc @@ -0,0 +1,683 @@ + SYSLINUX + + A suite of bootloaders for Linux + + Copyright (C) 1994-2004 H. Peter Anvin + +This program is provided under the terms of the GNU General Public +License, version 2 or, at your option, any later version. There is no +warranty, neither expressed nor implied, to the function of this +program. Please see the included file COPYING for details. + +---------------------------------------------------------------------- + + SYSLINUX now has a home page at http://syslinux.zytor.com/ + +---------------------------------------------------------------------- + +The SYSLINUX suite contains the following boot loaders +("derivatives"), for their respective boot media: + + SYSLINUX - MS-DOS/Windows FAT filesystem + PXELINUX - PXE network booting + ISOLINUX - ISO9660 CD-ROM + EXTLINUX - Linux ext2/ext3 filesystem + +For historical reasons, some of the sections in this document applies +to the FAT loader only; see pxelinux.doc, isolinux.doc and +extlinux.doc for what differs in these versions. + +Help with cleaning up the docs would be greatly appreciated. + + + ++++ CREATING A BOOTABLE LINUX FLOPPY +++ + +In order to create a bootable Linux floppy using SYSLINUX, prepare a +normal MS-DOS formatted floppy. Copy one or more Linux kernel files to +it, then execute the DOS command: + + syslinux [-s] a: + +(or whichever drive letter is appropriate; the [] meaning -s is optional) + +Use "syslinux.com" (in the dos subdirectory of the distribution) for +plain DOS (MS-DOS, DR-DOS, PC-DOS, FreeDOS...) or Win9x/ME. + +Use "syslinux.exe" (in the win32 subdirectory of the distribution) for +WinNT/2000/XP. + +Under Linux, execute the command: + + syslinux [-s] [-o offset] /dev/fd0 + +(or, again, whichever device is the correct one.) + +This will alter the boot sector on the disk and copy a file named +LDLINUX.SYS into its root directory. + +The -s option, if given, will install a "safe, slow and stupid" +version of SYSLINUX. This version may work on some very buggy BIOSes +on which SYSLINUX would otherwise fail. If you find a machine on +which the -s option is required to make it boot reliably, please send +as much info about your machine as you can, and include the failure +mode. + +The -o option is used with a disk image file and specifies the byte +offset of the filesystem image in the file. + +On boot time, by default, the kernel will be loaded from the image named +LINUX on the boot floppy. This default can be changed, see the section +on the SYSLINUX config file. + +If the Shift or Alt keys are held down during boot, or the Caps or Scroll +locks are set, SYSLINUX will display a LILO-style "boot:" prompt. The +user can then type a kernel file name followed by any kernel parameters. +The SYSLINUX loader does not need to know about the kernel file in +advance; all that is required is that it is a file located in the root +directory on the disk. + +There are two versions of the Linux installer; one in the "mtools" +directory which requires no special privilege (other than write +permission to the device where you are installing) but requires the +mtools program suite to be available, and one in the "unix" directory +which requires root privilege. + + + ++++ CONFIGURATION FILE ++++ + +All the configurable defaults in SYSLINUX can be changed by putting a +file called SYSLINUX.CFG in the root directory of the boot floppy. This +is a text file in either UNIX or DOS format, containing one or more of +the following items (case is insensitive for keywords; upper case is used +here to indicate that a word should be typed verbatim): + +All options here applies to PXELINUX, ISOLINUX and EXTLINUX as well as +SYSLINUX unless otherwise noted. See the respective .doc files. + +# comment + A comment line. The whitespace after the hash mark is mandatory. + +DEFAULT kernel options... + Sets the default command line. If SYSLINUX boots automatically, + it will act just as if the entries after DEFAULT had been typed + in at the "boot:" prompt. + + If no configuration file is present, or no DEFAULT entry is + present in the config file, the default is "linux auto". + + NOTE: Earlier versions of SYSLINUX used to automatically + append the string "auto" to whatever the user specified using + the DEFAULT command. As of version 1.54, this is no longer + true, as it caused problems when using a shell as a substitute + for "init." You may want to include this option manually. + +APPEND options... + Add one or more options to the kernel command line. These are + added both for automatic and manual boots. The options are + added at the very beginning of the kernel command line, + usually permitting explicitly entered kernel options to override + them. This is the equivalent of the LILO "append" option. + +IPAPPEND flag_val [PXELINUX only] + The IPAPPEND option is available only on PXELINUX. The + flag_val is an OR of the following options: + + 1: indicates that an option of the following format + should be generated and added to the kernel command line: + + ip=<client-ip>:<boot-server-ip>:<gw-ip>:<netmask> + + ... based on the input from the DHCP/BOOTP or PXE boot server. + + THE USE OF THIS OPTION IS NOT RECOMMENDED. If you have to use + it, it is probably an indication that your network configuration + is broken. Using just "ip=dhcp" on the kernel command line + is a preferrable option, or, better yet, run dhcpcd/dhclient, + from an initrd if necessary. + + 2: indicates that an option of the following format + should be generated and added to the kernel command line: + + BOOTIF=<hardware-address-of-boot-interface> + + ... in dash-separated hexadecimal with leading hardware type + (same as for the configuration file; see pxelinux.doc.) + + This allows an initrd program to determine from which + interface the system booted. + +LABEL label + KERNEL image + APPEND options... + IPAPPEND flag_val [PXELINUX only] + Indicates that if "label" is entered as the kernel to boot, + SYSLINUX should instead boot "image", and the specified APPEND + and IPAPPEND options should be used instead of the ones + specified in the global section of the file (before the first + LABEL command.) The default for "image" is the same as + "label", and if no APPEND is given the default is to use the + global entry (if any). + + Starting with version 2.20, LABEL statements are compressed + internally, therefore the maximum number of LABEL statements + depends on their complexity. Typical is around 600. SYSLINUX + will print an error message if the internal memory for labels + is overrun. + + Note that LILO uses the syntax: + image = mykernel + label = mylabel + append = "myoptions" + + ... whereas SYSLINUX uses the syntax: + label mylabel + kernel mykernel + append myoptions + + Notes: Labels are mangled as if they were filenames, and must be + unique after mangling. For example, two labels + "v2.1.30" and "v2.1.31" will not be distinguishable + under SYSLINUX, since both mangle to the same DOS filename. + + The "kernel" doesn't have to be a Linux kernel; it can + be a boot sector or a COMBOOT file (see below.) + + APPEND - + Append nothing. APPEND with a single hyphen as argument in a + LABEL section can be used to override a global APPEND. + + LOCALBOOT type [ISOLINUX, PXELINUX] + On PXELINUX, specifying "LOCALBOOT 0" instead of a "KERNEL" + option means invoking this particular label will cause a local + disk boot instead of booting a kernel. + + The argument 0 means perform a normal boot. The argument 4 + will perform a local boot with the Universal Network Driver + Interface (UNDI) driver still resident in memory. Finally, + the argument 5 will perform a local boot with the entire PXE + stack, including the UNDI driver, still resident in memory. + All other values are undefined. If you don't know what the + UNDI or PXE stacks are, don't worry -- you don't want them, + just specify 0. + + On ISOLINUX, the "type" specifies the local drive number to + boot from; 0x00 is the primary floppy drive and 0x80 is the + primary hard drive. The special value -1 causes ISOLINUX to + report failure to the BIOS, which, on recent BIOSes, should + mean that the next boot device in the boot sequence should be + activated. + +IMPLICIT flag_val + If flag_val is 0, do not load a kernel image unless it has been + explicitly named in a LABEL statement. The default is 1. + +ALLOWOPTIONS flag_val + If flag_val is 0, the user is not allowed to specify any + arguments on the kernel command line. The only options + recognized are those specified in an APPEND statement. The + default is 1. + +TIMEOUT timeout + Indicates how long to wait at the boot: prompt until booting + automatically, in units of 1/10 s. The timeout is cancelled as + soon as the user types anything on the keyboard, the assumption + being that the user will complete the command line already + begun. A timeout of zero will disable the timeout completely, + this is also the default. + + NOTE: The maximum possible timeout value is 35996; corresponding to + just below one hour. + +ONTIMEOUT kernel options... + Sets the command line invoked on a timeout. Normally this is + the same thing as invoked by "DEFAULT". If this is specified, + then "DEFAULT" is used only if the user presses <Enter> to + boot. + +ONERROR kernel options... + If a kernel image is not found (either due to it not existing, + or because IMPLICIT is set), run the specified command. The + faulty command line is appended to the specified options, so + if the ONERROR directive reads as: + + ONERROR xyzzy plugh + + ... and the command line as entered by the user is: + + foo bar baz + + ... SYSLINUX will execute the following as if entered by the + user: + + xyzzy plugh foo bar baz + +SERIAL port [[baudrate] flowcontrol] + Enables a serial port to act as the console. "port" is a + number (0 = /dev/ttyS0 = COM1, etc.) or an I/O port address + (e.g. 0x3F8); if "baudrate" is omitted, the baud rate defaults + to 9600 bps. The serial parameters are hardcoded to be 8 + bits, no parity, 1 stop bit. + + "flowcontrol" is a combination of the following bits: + 0x001 - Assert DTR + 0x002 - Assert RTS + 0x010 - Wait for CTS assertion + 0x020 - Wait for DSR assertion + 0x040 - Wait for RI assertion + 0x080 - Wait for DCD assertion + 0x100 - Ignore input unless CTS asserted + 0x200 - Ignore input unless DSR asserted + 0x400 - Ignore input unless RI asserted + 0x800 - Ignore input unless DCD asserted + + All other bits are reserved. + + Typical values are: + + 0 - No flow control (default) + 0x303 - Null modem cable detect + 0x013 - RTS/CTS flow control + 0x813 - RTS/CTS flow control, modem input + 0x023 - DTR/DSR flow control + 0x083 - DTR/DCD flow control + + For the SERIAL directive to be guaranteed to work properly, it + should be the first directive in the configuration file. + + NOTE: "port" values from 0 to 3 means the first four serial + ports detected by the BIOS. They may or may not correspond to + the legacy port values 0x3F8, 0x2F8, 0x3E8, 0x2E8. + +CONSOLE flag_val + If flag_val is 0, disable output to the normal video console. + If flag_val is 1, enable output to the video console (this is + the default.) + + Some BIOSes try to forward this to the serial console and + sometimes make a total mess thereof, so this option lets you + disable the video console on these systems. + +FONT filename + Load a font in .psf format before displaying any output + (except the copyright line, which is output as ldlinux.sys + itself is loaded.) SYSLINUX only loads the font onto the + video card; if the .psf file contains a Unicode table it is + ignored. This only works on EGA and VGA cards; hopefully it + should do nothing on others. + +KBDMAP keymap + Install a simple keyboard map. The keyboard remapper used is + *very* simplistic (it simply remaps the keycodes received from + the BIOS, which means that only the key combinations relevant + in the default layout -- usually U.S. English -- can be + mapped) but should at least help people with AZERTY keyboard + layout and the locations of = and , (two special characters + used heavily on the Linux kernel command line.) + + The included program keytab-lilo.pl from the LILO distribution + can be used to create such keymaps. The file keytab-lilo.doc + contains the documentation for this program. + +DISPLAY filename + Displays the indicated file on the screen at boot time (before + the boot: prompt, if displayed). Please see the section below + on DISPLAY files. + + NOTE: If the file is missing, this option is simply ignored. + +SAY message + Prints the message on the screen. + +PROMPT flag_val + If flag_val is 0, display the boot: prompt only if the Shift or Alt + key is pressed, or Caps Lock or Scroll lock is set (this is the + default). If flag_val is 1, always display the boot: prompt. + +NOESCAPE flag_val + If flag_val is set to 1, ignore the Shift/Alt/Caps Lock/Scroll + Lock escapes. Use this (together with PROMPT 0) to force the + default boot alternative. + +F1 filename +F2 filename + ...etc... +F9 filename +F0 filename + Displays the indicated file on the screen when a function key is + pressed at the boot: prompt. This can be used to implement + pre-boot online help (presumably for the kernel command line + options.) Note that F10 MUST be entered in the config file as + "F0", not "F10", and that there is currently no way to bind + file names to F11 and F12. Please see the section below on + DISPLAY files. + + When using the serial console, press <Ctrl-F><digit> to get to + the help screens, e.g. <Ctrl-F><2> to get to the F2 screen, + and <Ctrl-F><0> for the F10 one. + +Blank lines are ignored. + +Note that the configuration file is not completely decoded. Syntax +different from the one described above may still work correctly in this +version of SYSLINUX, but may break in a future one. + + + ++++ DISPLAY FILE FORMAT ++++ + +DISPLAY and function-key help files are text files in either DOS or UNIX +format (with or without <CR>). In addition, the following special codes +are interpreted: + +<FF> <FF> = <Ctrl-L> = ASCII 12 + Clear the screen, home the cursor. Note that the screen is + filled with the current display color. + +<SI><bg><fg> <SI> = <Ctrl-O> = ASCII 15 + Set the display colors to the specified background and + foreground colors, where <bg> and <fg> are hex digits, + corresponding to the standard PC display attributes: + + 0 = black 8 = dark grey + 1 = dark blue 9 = bright blue + 2 = dark green a = bright green + 3 = dark cyan b = bright cyan + 4 = dark red c = bright red + 5 = dark purple d = bright purple + 6 = brown e = yellow + 7 = light grey f = white + + Picking a bright color (8-f) for the background results in the + corresponding dark color (0-7), with the foreground flashing. + + Colors are not visible over the serial console. + +<CAN>filename<newline> <CAN> = <Ctrl-X> = ASCII 24 + If a VGA display is present, enter graphics mode and display + the graphic included in the specified file. The file format + is an ad hoc format called LSS16; the included Perl program + "ppmtolss16" can be used to produce these images. This Perl + program also includes the file format specification. + + The image is displayed in 640x480 16-color mode. Once in + graphics mode, the display attributes (set by <SI> code + sequences) work slightly differently: the background color is + ignored, and the foreground colors are the 16 colors specified + in the image file. For that reason, ppmtolss16 allows you to + specify that certain colors should be assigned to specific + color indicies. + + Color indicies 0 and 7, in particular, should be chosen with + care: 0 is the background color, and 7 is the color used for + the text printed by SYSLINUX itself. + +<EM> <EM> = <Ctrl-Y> = ASCII 25 + If we are currently in graphics mode, return to text mode. + +<DLE>..<ETB> <Ctrl-P>..<Ctrl-W> = ASCII 16-23 + These codes can be used to select which modes to print a + certain part of the message file in. Each of these control + characters select a specific set of modes (text screen, + graphics screen, serial port) for which the output is actually + displayed: + + Character Text Graph Serial + ------------------------------------------------------ + <DLE> = <Ctrl-P> = ASCII 16 No No No + <DC1> = <Ctrl-Q> = ASCII 17 Yes No No + <DC2> = <Ctrl-R> = ASCII 18 No Yes No + <DC3> = <Ctrl-S> = ASCII 19 Yes Yes No + <DC4> = <Ctrl-T> = ASCII 20 No No Yes + <NAK> = <Ctrl-U> = ASCII 21 Yes No Yes + <SYN> = <Ctrl-V> = ASCII 22 No Yes Yes + <ETB> = <Ctrl-W> = ASCII 23 Yes Yes Yes + + For example: + + <DC1>Text mode<DC2>Graphics mode<DC4>Serial port<ETB> + + ... will actually print out which mode the console is in! + +<SUB> <SUB> = <Ctrl-Z> = ASCII 26 + End of file (DOS convention). + + + ++++ COMMAND LINE KEYSTROKES ++++ + +The command line prompt supports the following keystrokes: + +<Enter> boot specified command line +<BackSpace> erase one character +<Ctrl-U> erase the whole line +<Ctrl-V> display the current SYSLINUX version +<Ctrl-W> erase one word +<Ctrl-X> force text mode +<F1>..<F10> help screens (if configured) +<Ctrl-F><digit> equivalent to F1..F10 +<Ctrl-C> interrupt boot in progress +<Esc> interrupt boot in progress + + + ++++ COMBOOT IMAGES AND OTHER OPERATING SYSTEMS ++++ + +This version of SYSLINUX supports chain loading of other operating +systems (such as MS-DOS and its derivatives, including Windows 95/98), +as well as COMBOOT-style standalone executables (a subset of DOS .COM +files; see separate section below.) + +Chain loading requires the boot sector of the foreign operating system +to be stored in a file in the root directory of the filesystem. +Because neither Linux kernels, boot sector images, nor COMBOOT files +have reliable magic numbers, SYSLINUX will look at the file extension. +The following extensions are recognized (case insensitive): + + none or other Linux kernel image + .0 PXE bootstrap program (NBP) [PXELINUX only] + .bin "CD boot sector" [ISOLINUX only] + .bs Boot sector [SYSLINUX only] + .bss Boot sector, DOS superblock will be patched in [SYSLINUX only] + .c32 COM32 image (32-bit COMBOOT) + .cbt COMBOOT image (not runnable from DOS) + .com COMBOOT image (runnable from DOS) + .img Disk image [ISOLINUX only] + +For filenames given on the command line, SYSLINUX will search for the +file by adding extensions in the order listed above if the plain +filename is not found. Filenames in KERNEL statements must be fully +qualified. + + + ++++ BOOTING DOS (OR OTHER SIMILAR OPERATING SYSTEMS) ++++ + +This section applies to SYSLINUX only, not to PXELINUX or ISOLINUX. +See isolinux.doc for an equivalent procedure for ISOLINUX. + +This is the recommended procedure for creating a SYSLINUX disk that +can boot either DOS or Linux. This example assumes the drive is A: in +DOS and /dev/fd0 in Linux; for other drives, substitute the +appropriate drive designator. + + ---- Linux procedure ---- + +1. Make a DOS bootable disk. This can be done either by specifying + the /s option when formatting the disk in DOS, or by running the + DOS command SYS (this can be done under DOSEMU if DOSEMU has + direct device access to the relevant drive): + + format a: /s + or + sys a: + +2. Boot Linux. Copy the DOS boot sector from the disk into a file: + + dd if=/dev/fd0 of=dos.bss bs=512 count=1 + +3. Run SYSLINUX on the disk: + + syslinux /dev/fd0 + +4. Mount the disk and copy the DOS boot sector file to it. The file + *must* have extension .bss: + + mount -t msdos /dev/fd0 /mnt + cp dos.bss /mnt + +5. Copy the Linux kernel image(s), initrd(s), etc to the disk, and + create/edit syslinux.cfg and help files if desired: + + cp vmlinux /mnt + cp initrd.gz /mnt + +6. Unmount the disk (if applicable.) + + umount /mnt + + ---- DOS/Windows procedure ---- + +To make this installation in DOS only, you need the utility copybs.com +(included with SYSLINUX) as well as the syslinux.com installer. If +you are on an WinNT-based system (WinNT, Win2k, WinXP or later), use +syslinux.exe instead. + +1. Make a DOS bootable disk. This can be done either by specifying + the /s option when formatting the disk in DOS, or by running the + DOS command SYS: + + format a: /s + or + sys a: + +2. Copy the DOS boot sector from the disk into a file. The file + *must* have extension .bss: + + copybs a: a:dos.bss + +3. Run SYSLINUX on the disk: + + syslinux a: + +4. Copy the Linux kernel image(s), initrd(s), etc to the disk, and + create/edit syslinux.cfg and help files if desired: + + copy vmlinux a: + copy initrd.gz a: + + + ++++ COMBOOT EXECUTABLES ++++ + +SYSLINUX supports simple standalone programs, using a file format +similar to DOS ".com" files. A 32-bit version, called COM32, is also +provided. A simple API provides access to a limited set of filesystem +and console functions. + +See the file comboot.doc for more information on COMBOOT and COM32 +programs. + + + ++++ NOVICE PROTECTION ++++ + +SYSLINUX will attempt to detect booting on a machine with too little +memory, which means the Linux boot sequence cannot complete. If so, a +message is displayed and the boot sequence aborted. Holding down the +Ctrl key while booting disables this feature. + +Any file that SYSLINUX uses can be marked hidden, system or readonly +if so is convenient; SYSLINUX ignores all file attributes. The +SYSLINUX installed automatically sets the readonly/hidden/system +attributes on LDLINUX.SYS. + + + ++++ NOTES ON BOOTABLE CD-ROMS ++++ + +SYSLINUX can be used to create bootdisk images for El +Torito-compatible bootable CD-ROMs. However, it appears that many +BIOSes are very buggy when it comes to booting CD-ROMs. Some users +have reported that the following steps are helpful in making a CD-ROM +that is bootable on the largest possible number of machines: + + a) Use the -s (safe, slow and stupid) option to SYSLINUX; + b) Put the boot image as close to the beginning of the + ISO 9660 filesystem as possible. + +A CD-ROM is so much faster than a floppy that the -s option shouldn't +matter from a speed perspective. + +Of course, you probably want to use ISOLINUX instead. See isolinux.doc. + + + ++++ BOOTING FROM A FAT FILESYSTEM PARTITION ON A HARD DISK ++++ + +SYSLINUX can boot from a FAT filesystem partition on a hard disk +(including FAT32). The installation procedure is identical to the +procedure for installing it on a floppy, and should work under either +DOS or Linux. To boot from a partition, SYSLINUX needs to be launched +from a Master Boot Record or another boot loader, just like DOS itself +would. + +Under DOS, you can install a standard simple MBR on the primary hard +disk by running the command: + + FDISK /MBR + +Then use the FDISK command to mark the appropriate partition active. + +A simple MBR, roughly on par with the one installed by DOS (but +unencumbered), is included in the SYSLINUX distribution. To install +it under Linux, simply type: + + cat mbr.bin > /dev/XXX + +... where /dev/XXX is the device you wish to install it on. + +Under DOS or Win32, you can install the SYSLINUX MBR with the -m +option to the SYSLINUX installer, and use the -a option to mark the +current partition active: + + syslinux -ma c: + +Note that this will also install SYSLINUX on the specified partition. + + + ++++ HARDWARE INFORMATION +++ + +I have started to maintain a web page of hardware with known +problems. There are, unfortunately, lots of broken hardware out +there; especially early PXE stacks (for PXELINUX) have lots of +problems. + +A list of problems, and workarounds (if known), is maintained at: + + http://syslinux.zytor.com/hardware.php + + + ++++ BOOT LOADER IDS USED ++++ + +The Linux boot protocol supports a "boot loader ID", a single byte +where the upper nybble specifies a boot loader family (3 = SYSLINUX) +and the lower nybble is version or, in the case of SYSLINUX, media: + + 0x31 = SYSLINUX + 0x32 = PXELINUX + 0x33 = ISOLINUX + 0x34 = EXTLINUX + + + ++++ BUG REPORTS ++++ + +I would appreciate hearing of any problems you have with SYSLINUX. I +would also like to hear from you if you have successfully used SYSLINUX, +*especially* if you are using it for a distribution. + +If you are reporting problems, please include all possible information +about your system and your BIOS; the vast majority of all problems +reported turn out to be BIOS or hardware bugs, and I need as much +information as possible in order to diagnose the problems. + +There is a mailing list for discussion among SYSLINUX users and for +announcements of new and test versions. To join, or to browse the +archive, go to: + + http://www.zytor.com/mailman/listinfo/syslinux + +Please DO NOT send HTML messages or attachments to the mailing list +(including multipart/alternative or similar.) All such messages will +be bounced. diff --git a/syslinux/syslinux.h b/syslinux/syslinux.h new file mode 100644 index 0000000..58c2e32 --- /dev/null +++ b/syslinux/syslinux.h @@ -0,0 +1,44 @@ +#ident "$Id: syslinux.h,v 1.9 2004/12/22 17:53:54 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 1998-2004 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#ifndef SYSLINUX_H +#define SYSLINUX_H + +#include <inttypes.h> + +/* The standard boot sector and ldlinux image */ +extern unsigned char syslinux_bootsect[]; +extern unsigned int syslinux_bootsect_len; +extern int syslinux_bootsect_mtime; + +extern unsigned char syslinux_ldlinux[]; +extern unsigned int syslinux_ldlinux_len; +extern int syslinux_ldlinux_mtime; + +extern unsigned char syslinux_mbr[]; +extern unsigned int syslinux_mbr_len; +extern int syslinux_mbr_mtime; + +/* This switches the boot sector to "stupid mode" */ +void syslinux_make_stupid(void); + +/* This takes a boot sector and merges in the syslinux fields */ +void syslinux_make_bootsect(void *); + +/* Check to see that what we got was indeed an MS-DOS boot sector/superblock */ +const char *syslinux_check_bootsect(const void *bs); + +/* This patches the boot sector and ldlinux.sys based on a sector map */ +int syslinux_patch(const uint32_t *sectors, int nsectors); + +#endif diff --git a/syslinux/syslinux.spec b/syslinux/syslinux.spec new file mode 100644 index 0000000..f4406ca --- /dev/null +++ b/syslinux/syslinux.spec @@ -0,0 +1,203 @@ +# -*- rpm -*- +%define RPMVERSION 3.08 +%define VERSION 3.08 +Summary: Kernel loader which uses a FAT or iso9660 filesystem or a PXE network +Name: syslinux +Version: %{RPMVERSION} +Release: 1 +License: GPL +Group: Applications/System +Source0: ftp://ftp.kernel.org/pub/linux/utils/boot/syslinux/%{name}-%{VERSION}.tar.gz +ExclusiveArch: i386 x86_64 +Packager: H. Peter Anvin <hpa@zytor.com> +Buildroot: %{_tmppath}/%{name}-%{VERSION}-root +BuildPrereq: nasm >= 0.98.38, perl +Autoreq: 0 +%ifarch i386 +Requires: mtools, libc.so.6 +%endif +%ifarch x86_64 +Requires: mtools, libc.so.6()(64bit) +%endif + +# NOTE: extlinux belongs in /sbin, not in /usr/sbin, since it is typically +# a system bootloader, and may be necessary for system recovery. +%define _sbindir /sbin + +%package devel +Summary: Development environment for SYSLINUX add-on modules +Group: Development/Libraries + +%description +SYSLINUX is a suite of bootloaders, currently supporting DOS FAT +filesystems, Linux ext2/ext3 filesystems (EXTLINUX), PXE network boots +(PXELINUX), or ISO 9660 CD-ROMs (ISOLINUX). It also includes a tool, +MEMDISK, which loads legacy operating systems from these media. + +%description devel +The SYSLINUX boot loader contains an API, called COM32, for writing +sophisticated add-on modules. This package contains the libraries +necessary to compile such modules. + +%prep +%setup -q -n syslinux-%{VERSION} + +%build +make clean +make installer +make -C sample tidy + +%install +rm -rf %{buildroot} +mkdir -p %{buildroot}%{_bindir} +mkdir -p %{buildroot}%{_sbindir} +mkdir -p %{buildroot}%{_libdir}/syslinux +mkdir -p %{buildroot}%{_includedir} +make install-all \ + INSTALLROOT=%{buildroot} BINDIR=%{_bindir} SBINDIR=%{_sbindir} \ + LIBDIR=%{_libdir} INCDIR=%{_includedir} +make -C sample tidy +cp mkdiskimage sys2ansi.pl keytab-lilo.pl %{buildroot}%{_libdir}/syslinux + +%clean +rm -rf %{buildroot} + +%files +%defattr(-,root,root) +%doc NEWS README* *.doc memdisk/*.doc COPYING +%doc sample +%{_bindir}/syslinux +%{_sbindir}/extlinux +%{_bindir}/ppmtolss16 +%{_bindir}/lss16toppm +%{_bindir}/gethostip +%{_libdir}/syslinux/*.com +%{_libdir}/syslinux/*.exe +%{_libdir}/syslinux/*.c32 +%{_libdir}/syslinux/*.bin +%{_libdir}/syslinux/*.0 +%{_libdir}/syslinux/memdisk +%{_libdir}/syslinux/*.pl +%{_libdir}/syslinux/mkdiskimage + +%files devel +%{_libdir}/syslinux/com32 + +%post + +%postun + +%changelog +* Thu Dec 30 2004 H. Peter Anvin <hpa@zytor.com> +- libsyslinux dropped in syslinux 3.00. +- Additional documentation. +- Add extlinux. + +* Tue Dec 14 2004 H. Peter Anvin <hpa@zytor.com> +- Add a devel package for the com32 library added in 2.12. + +* Wed Apr 16 2003 H. Peter Anvin <hpa@zytor.com> 2.04-1 +- 2.04 release +- Add support for libsyslinux.so* +- Templatize for inclusion in CVS tree + +* Thu Apr 10 2003 H. Peter Anvin <hpa@zytor.com> +- 2.03 release +- Add support for libsyslinux.a +- Add keytab-lilo.pl to the /usr/lib/syslinux directory +- Modernize syntax +- Support building on x86-64 + +* Thu Feb 13 2003 H. Peter Anvin <hpa@zytor.com> +- 2.02 release; no longer setuid + +* Thu Jan 30 2003 H. Peter Anvin <hpa@zytor.com> +- Prepare for 2.01 release; make /usr/bin/syslinux setuid root + +* Fri Oct 25 2002 H. Peter Anvin <hpa@zytor.com> +- Upgrade to 2.00. + +* Tue Aug 27 2002 H. Peter Anvin <hpa@zytor.com> +- Upgrade to 1.76. + +* Fri Jun 14 2002 H. Peter Anvin <hpa@zytor.com> +- Upgrade to 1.75. + +* Sat Jun 1 2002 H. Peter Anvin <hpa@zytor.com> +- Upgrade to 1.74. + +* Sun May 26 2002 H. Peter Anvin <hpa@zytor.com> +- Upgrade to 1.73. + +* Tue Apr 23 2002 H. Peter Anvin <hpa@zytor.com> +- Upgrade to 1.72. + +* Wed Apr 17 2002 H. Peter Anvin <hpa@zytor.com> +- Upgrade to 1.71. +- Update the title. + +* Wed Apr 17 2002 H. Peter Anvin <hpa@zytor.com> +- Upgrade to 1.70. + +* Sat Feb 3 2002 H. Peter Anvin <hpa@zytor.com> +- Upgrade to 1.67. + +* Tue Jan 1 2002 H. Peter Anvin <hpa@zytor.com> +- Upgrade to 1.66. + +* Sat Dec 15 2001 H. Peter Anvin <hpa@zytor.com> +- Upgrade to 1.65; make appropriate changes. + +* Sat Aug 24 2001 H. Peter Anvin <hpa@zytor.com> +- Upgrade to 1.64. + +* Mon Aug 6 2001 H. Peter Anvin <hpa@zytor.com> +- Upgrade to 1.63. +- Use make install since the stock SYSLINUX distribution now supports + INSTALLROOT. + +* Sat Apr 24 2001 H. Peter Anvin <hpa@zytor.com> +- Upgrade to 1.62. + +* Sat Apr 14 2001 H. Peter Anvin <hpa@zytor.com> +- Fix missing %files; correct modes. + +* Fri Apr 13 2001 H. Peter Anvin <hpa@zytor.com> +- Upgrade to 1.61 +- Install auxilliary programs in /usr/lib/syslinux + +* Sat Feb 10 2001 Matt Wilson <msw@redhat.com> +- 1.52 + +* Wed Jan 24 2001 Matt Wilson <msw@redhat.com> +- 1.51pre7 + +* Mon Jan 22 2001 Matt Wilson <msw@redhat.com> +- 1.51pre5 + +* Fri Jan 19 2001 Matt Wilson <msw@redhat.com> +- 1.51pre3, with e820 detection + +* Tue Dec 12 2000 Than Ngo <than@redhat.com> +- rebuilt with fixed fileutils + +* Thu Nov 9 2000 Than Ngo <than@redhat.com> +- update to 1.49 +- update ftp site +- clean up specfile +- add some useful documents + +* Tue Jul 18 2000 Nalin Dahyabhai <nalin@redhat.com> +- add %%defattr (release 4) + +* Wed Jul 12 2000 Prospector <bugzilla@redhat.com> +- automatic rebuild + +* Thu Jul 06 2000 Trond Eivind Glomsrød <teg@redhat.com> +- use %%{_tmppath} +- change application group (Applications/Internet doesn't seem + right to me) +- added BuildRequires + +* Tue Apr 04 2000 Erik Troan <ewt@redhat.com> +- initial packaging diff --git a/syslinux/syslxmod.c b/syslinux/syslxmod.c new file mode 100644 index 0000000..d598f8e --- /dev/null +++ b/syslinux/syslxmod.c @@ -0,0 +1,284 @@ +#ident "$Id: syslxmod.c,v 1.11 2004/12/22 07:17:31 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 1998-2004 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * syslxmod.c - Code to provide a SYSLINUX code set to an installer. + */ + +#define _XOPEN_SOURCE 500 /* Required on glibc 2.x */ +#define _BSD_SOURCE +#include <stdio.h> +#include <inttypes.h> +#include <string.h> +#include <stddef.h> + +#include "syslinux.h" + +#define LDLINUX_MAGIC 0x3eb202fe + +enum bs_offsets { + bsJump = 0x00, + bsOemName = 0x03, + bsBytesPerSec = 0x0b, + bsSecPerClust = 0x0d, + bsResSectors = 0x0e, + bsFATs = 0x10, + bsRootDirEnts = 0x11, + bsSectors = 0x13, + bsMedia = 0x15, + bsFATsecs = 0x16, + bsSecPerTrack = 0x18, + bsHeads = 0x1a, + bsHiddenSecs = 0x1c, + bsHugeSectors = 0x20, + + /* FAT12/16 only */ + bs16DriveNumber = 0x24, + bs16Reserved1 = 0x25, + bs16BootSignature = 0x26, + bs16VolumeID = 0x27, + bs16VolumeLabel = 0x2b, + bs16FileSysType = 0x36, + bs16Code = 0x3e, + + /* FAT32 only */ + bs32FATSz32 = 36, + bs32ExtFlags = 40, + bs32FSVer = 42, + bs32RootClus = 44, + bs32FSInfo = 48, + bs32BkBootSec = 50, + bs32Reserved = 52, + bs32DriveNumber = 64, + bs32Reserved1 = 65, + bs32BootSignature = 66, + bs32VolumeID = 67, + bs32VolumeLabel = 71, + bs32FileSysType = 82, + bs32Code = 90, + + bsSignature = 0x1fe +}; + +#define bsHead bsJump +#define bsHeadLen (bsOemName-bsHead) +#define bsCode bs32Code /* The common safe choice */ +#define bsCodeLen (bsSignature-bs32Code) + +/* + * Access functions for littleendian numbers, possibly misaligned. + */ +static inline uint8_t get_8(const unsigned char *p) +{ + return *(const uint8_t *)p; +} + +static inline uint16_t get_16(const unsigned char *p) +{ +#if defined(__i386__) || defined(__x86_64__) + /* Littleendian and unaligned-capable */ + return *(const uint16_t *)p; +#else + return (uint16_t)p[0] + ((uint16_t)p[1] << 8); +#endif +} + +static inline uint32_t get_32(const unsigned char *p) +{ +#if defined(__i386__) || defined(__x86_64__) + /* Littleendian and unaligned-capable */ + return *(const uint32_t *)p; +#else + return (uint32_t)p[0] + ((uint32_t)p[1] << 8) + + ((uint32_t)p[2] << 16) + ((uint32_t)p[3] << 24); +#endif +} + +static inline void set_16(unsigned char *p, uint16_t v) +{ +#if defined(__i386__) || defined(__x86_64__) + /* Littleendian and unaligned-capable */ + *(uint16_t *)p = v; +#else + p[0] = (v & 0xff); + p[1] = ((v >> 8) & 0xff); +#endif +} + +static inline void set_32(unsigned char *p, uint32_t v) +{ +#if defined(__i386__) || defined(__x86_64__) + /* Littleendian and unaligned-capable */ + *(uint32_t *)p = v; +#else + p[0] = (v & 0xff); + p[1] = ((v >> 8) & 0xff); + p[2] = ((v >> 16) & 0xff); + p[3] = ((v >> 24) & 0xff); +#endif +} + +/* Patch the code so that we're running in stupid mode */ +void syslinux_make_stupid(void) +{ + /* Access only one sector at a time */ + set_16(syslinux_bootsect+0x1FC, 1); +} + +void syslinux_make_bootsect(void *bs) +{ + unsigned char *bootsect = bs; + + memcpy(bootsect+bsHead, syslinux_bootsect+bsHead, bsHeadLen); + memcpy(bootsect+bsCode, syslinux_bootsect+bsCode, bsCodeLen); +} + +/* + * Check to see that what we got was indeed an MS-DOS boot sector/superblock; + * Return NULL if OK and otherwise an error message; + */ +const char *syslinux_check_bootsect(const void *bs) +{ + int veryold; + int sectorsize; + long long sectors, fatsectors, dsectors; + long long clusters; + int rootdirents, clustersize; + const unsigned char *sectbuf = bs; + + veryold = 0; + + /* Must be 0xF0 or 0xF8..0xFF */ + if ( get_8(sectbuf+bsMedia) != 0xF0 && + get_8(sectbuf+bsMedia) < 0xF8 ) + goto invalid; + + sectorsize = get_16(sectbuf+bsBytesPerSec); + if ( sectorsize == 512 ) + ; /* ok */ + else if ( sectorsize == 1024 || sectorsize == 2048 || sectorsize == 4096 ) + return "only 512-byte sectors are supported"; + else + goto invalid; + + clustersize = get_8(sectbuf+bsSecPerClust); + if ( clustersize == 0 || (clustersize & (clustersize-1)) ) + goto invalid; /* Must be nonzero and a power of 2 */ + + sectors = get_16(sectbuf+bsSectors); + sectors = sectors ? sectors : get_32(sectbuf+bsHugeSectors); + + dsectors = sectors - get_16(sectbuf+bsResSectors); + + fatsectors = get_16(sectbuf+bsFATsecs); + fatsectors = fatsectors ? fatsectors : get_32(sectbuf+bs32FATSz32); + fatsectors *= get_8(sectbuf+bsFATs); + dsectors -= fatsectors; + + rootdirents = get_16(sectbuf+bsRootDirEnts); + dsectors -= (rootdirents+sectorsize/32-1)/sectorsize; + + if ( dsectors < 0 || fatsectors == 0 ) + goto invalid; + + clusters = dsectors/clustersize; + + if ( clusters < 0xFFF5 ) { + /* FAT12 or FAT16 */ + + if ( !get_16(sectbuf+bsFATsecs) ) + goto invalid; + + if ( get_8(sectbuf+bs16BootSignature) == 0x29 ) { + if ( !memcmp(sectbuf+bs16FileSysType, "FAT12 ", 8) ) { + if ( clusters >= 0xFF5 ) + return "more than 4084 clusters but claims FAT12"; + } else if ( !memcmp(sectbuf+bs16FileSysType, "FAT16 ", 8) ) { + if ( clusters < 0xFF5 ) + return "less than 4084 clusters but claims FAT16"; + } else if ( memcmp(sectbuf+bs16FileSysType, "FAT ", 8) ) { + static char fserr[] = "filesystem type \"????????\" not supported"; + memcpy(fserr+17, sectbuf+bs16FileSysType, 8); + return fserr; + } + } + } else if ( clusters < 0x0FFFFFF5 ) { + /* FAT32 */ + /* Moving the FileSysType and BootSignature was a lovely stroke of M$ idiocy */ + if ( get_8(sectbuf+bs32BootSignature) != 0x29 || + memcmp(sectbuf+bs32FileSysType, "FAT32 ", 8) ) + goto invalid; + } else { + goto invalid; + } + + return NULL; + + invalid: + return "this doesn't look like a valid FAT filesystem"; +} + +/* + * This patches the boot sector and the first sector of ldlinux.sys + * based on an ldlinux.sys sector map passed in. Typically this is + * handled by writing ldlinux.sys, mapping it, and then overwrite it + * with the patched version. If this isn't safe to do because of + * an OS which does block reallocation, then overwrite it with + * direct access since the location is known. + * + * Return 0 if successful, otherwise -1. + */ +int syslinux_patch(const uint32_t *sectors, int nsectors) +{ + unsigned char *patcharea, *p; + int nsect = (syslinux_ldlinux_len+511) >> 9; + uint32_t csum; + int i, dw; + + if ( nsectors < nsect ) + return -1; + + /* First sector need pointer in boot sector */ + set_32(syslinux_bootsect+0x1F8, *sectors++); + nsect--; + + /* Search for LDLINUX_MAGIC to find the patch area */ + for ( p = syslinux_ldlinux ; get_32(p) != LDLINUX_MAGIC ; p += 4 ); + patcharea = p+8; + + /* Set up the totals */ + dw = syslinux_ldlinux_len >> 2; /* COMPLETE dwords! */ + set_16(patcharea, dw); + set_16(patcharea+2, nsect); /* Does not include the first sector! */ + + /* Set the sector pointers */ + p = patcharea+8; + + memset(p, 0, 64*4); + while ( nsect-- ) { + set_32(p, *sectors++); + p += 4; + } + + /* Now produce a checksum */ + set_32(patcharea+4, 0); + + csum = LDLINUX_MAGIC; + for ( i = 0, p = syslinux_ldlinux ; i < dw ; i++, p += 4 ) + csum -= get_32(p); /* Negative checksum */ + + set_32(patcharea+4, csum); + + return 0; +} + diff --git a/syslinux/tracers.inc b/syslinux/tracers.inc new file mode 100644 index 0000000..5728292 --- /dev/null +++ b/syslinux/tracers.inc @@ -0,0 +1,41 @@ +;; $Id: tracers.inc,v 1.6 2005/01/12 00:35:13 hpa Exp $ +;; ----------------------------------------------------------------------- +;; +;; Copyright 1994-2002 H. Peter Anvin - All Rights Reserved +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +;; Boston MA 02111-1307, USA; either version 2 of the License, or +;; (at your option) any later version; incorporated herein by reference. +;; +;; ----------------------------------------------------------------------- + +;; +;; tracers.inc +;; +;; Debugging tracers +;; + +%ifndef _TRACERS_INC +%define _TRACERS_INC + +; Note: The Makefile builds one version with DEBUG_MESSAGES automatically. +; %define DEBUG_TRACERS 1 ; Uncomment to get debugging tracers +; %define DEBUG_MESSAGES ; Uncomment to get debugging messages + +%ifdef DEBUG_TRACERS + +%macro TRACER 1 + call debug_tracer + db %1 +%endmacro + +%else ; DEBUG_TRACERS + +%macro TRACER 1 +%endmacro + +%endif ; DEBUG_TRACERS + +%endif ; _TRACERS_INC diff --git a/syslinux/ui.inc b/syslinux/ui.inc new file mode 100644 index 0000000..5309faa --- /dev/null +++ b/syslinux/ui.inc @@ -0,0 +1,495 @@ +;; $Id: ui.inc,v 1.20 2005/04/08 16:33:32 hpa Exp $ +;; ----------------------------------------------------------------------- +;; +;; Copyright 1994-2002 H. Peter Anvin - All Rights Reserved +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +;; Boston MA 02111-1307, USA; either version 2 of the License, or +;; (at your option) any later version; incorporated herein by reference. +;; +;; ----------------------------------------------------------------------- + +; +; This file should be entered with the config file open (for getc) +; + call parse_config ; Parse configuration file +no_config_file: +; +; Check whether or not we are supposed to display the boot prompt. +; +check_for_key: + cmp word [ForcePrompt],byte 0 ; Force prompt? + jnz enter_command + test byte [KbdFlags],5Bh ; Caps, Scroll, Shift, Alt + jz auto_boot ; If neither, default boot + +enter_command: + mov si,boot_prompt + call cwritestr + + mov byte [FuncFlag],0 ; <Ctrl-F> not pressed + mov di,command_line +; +; get the very first character -- we can either time +; out, or receive a character press at this time. Some dorky BIOSes stuff +; a return in the buffer on bootup, so wipe the keyboard buffer first. +; +clear_buffer: mov ah,11h ; Check for pending char + int 16h + jz get_char_time + mov ah,10h ; Get char + int 16h + jmp short clear_buffer +get_char_time: + call vgashowcursor + RESET_IDLE + mov cx,[KbdTimeOut] + and cx,cx + jz get_char ; Timeout == 0 -> no timeout + inc cx ; The first loop will happen + ; immediately as we don't + ; know the appropriate DX value +time_loop: push cx +tick_loop: push dx + call pollchar + jnz get_char_pop + mov dx,[BIOS_timer] ; Get time "of day" + pop ax + cmp dx,ax ; Has the timer advanced? + je tick_loop + pop cx + DO_IDLE + loop time_loop ; If so, decrement counter + + ; Timeout!!!! + call vgahidecursor + mov si,Ontimeout ; Copy ontimeout command + mov cx,[OntimeoutLen] ; if we have one... + rep movsb +.stddefault: + jmp command_done + +get_char_pop: pop eax ; Clear stack +get_char: + call vgashowcursor + call getchar + call vgahidecursor + and al,al + jz func_key + +got_ascii: cmp al,7Fh ; <DEL> == <BS> + je backspace + cmp al,' ' ; ASCII? + jb not_ascii + ja enter_char + cmp di,command_line ; Space must not be first + je short get_char +enter_char: test byte [FuncFlag],1 + jz .not_ctrl_f + mov byte [FuncFlag],0 + cmp al,'0' + jb .not_ctrl_f + je ctrl_f_0 + cmp al,'9' + jbe ctrl_f +.not_ctrl_f: cmp di,max_cmd_len+command_line ; Check there's space + jnb short get_char + stosb ; Save it + call writechr ; Echo to screen + jmp short get_char +not_ascii: mov byte [FuncFlag],0 + cmp al,0Dh ; Enter + je command_done + cmp al,'F' & 1Fh ; <Ctrl-F> + je set_func_flag + cmp al,'U' & 1Fh ; <Ctrl-U> + je kill_command ; Kill input line + cmp al,'V' & 1Fh ; <Ctrl-V> + je print_version + cmp al,'X' & 1Fh ; <Ctrl-X> + je force_text_mode + cmp al,08h ; Backspace + jne get_char +backspace: cmp di,command_line ; Make sure there is anything + je get_char ; to erase + dec di ; Unstore one character + mov si,wipe_char ; and erase it from the screen + call cwritestr + jmp short get_char_2 + +kill_command: + call crlf + jmp enter_command + +force_text_mode: + call vgaclearmode + jmp enter_command + +set_func_flag: + mov byte [FuncFlag],1 +get_char_2: + jmp short get_char + +ctrl_f_0: add al,10 ; <Ctrl-F>0 == F10 +ctrl_f: sub al,'1' + xor ah,ah + jmp short show_help + +func_key: + ; AL = 0 if we get here + xchg al,ah + cmp al,68 ; F10 + ja short get_char_2 + sub al,59 ; F1 + jb short get_char_2 +show_help: ; AX = func key # (0 = F1, 9 = F10) + push di ; Save end-of-cmdline pointer + shl ax,FILENAME_MAX_LG2 ; Convert to pointer + add ax,FKeyName + xchg di,ax + cmp byte [di+NULLOFFSET],NULLFILE + je short fk_nofile ; Undefined F-key + call searchdir + jz short fk_nofile ; File not found + push si + call crlf + pop si + call get_msg_file + jmp short fk_wrcmd + +print_version: + push di ; Command line write pointer + mov si,syslinux_banner + call cwritestr + mov si,copyright_str + call cwritestr + + ; ... fall through ... + + ; Write the boot prompt and command line again and + ; wait for input. Note that this expects the cursor + ; to already have been CRLF'd, and that the old value + ; of DI (the command line write pointer) is on the stack. +fk_wrcmd: + mov si,boot_prompt + call cwritestr + pop di ; Command line write pointer + push di + mov byte [di],0 ; Null-terminate command line + mov si,command_line + call cwritestr ; Write command line so far +fk_nofile: pop di + jmp short get_char_2 +auto_boot: + mov si,default_cmd + mov di,command_line + mov cx,(max_cmd_len+4) >> 2 + rep movsd + jmp short load_kernel +command_done: + call crlf + cmp di,command_line ; Did we just hit return? + je auto_boot + xor al,al ; Store a final null + stosb + +load_kernel: ; Load the kernel now +; +; First we need to mangle the kernel name the way DOS would... +; + mov si,command_line + mov di,KernelName + push si + push di + call mangle_name + pop di + pop si +; +; Fast-forward to first option (we start over from the beginning, since +; mangle_name doesn't necessarily return a consistent ending state.) +; +clin_non_wsp: lodsb + cmp al,' ' + ja clin_non_wsp +clin_is_wsp: and al,al + jz clin_opt_ptr + lodsb + cmp al,' ' + jbe clin_is_wsp +clin_opt_ptr: dec si ; Point to first nonblank + mov [CmdOptPtr],si ; Save ptr to first option +; +; If "allowoptions 0", put a null character here in order to ignore any +; user-specified options. +; + mov ax,[AllowOptions] + and ax,ax + jnz clin_opt_ok + mov [si],al +clin_opt_ok: + +; +; Now check if it is a "virtual kernel" +; +vk_check: + xor si,si ; Beginning of vk_seg +.scan: + cmp si,[VKernelBytes] + jae .not_vk + + push ds + push word vk_seg + pop ds + + mov di,VKernelBuf + call rllunpack + pop ds + ; SI updated on return + + sub di,cx ; Return to beginning of buf + push si + mov si,KernelName + mov cx,FILENAME_MAX + es repe cmpsb + pop si + je .found + jmp .scan + +; +; We *are* using a "virtual kernel" +; +.found: + push es + push word real_mode_seg + pop es + mov di,cmd_line_here + mov si,VKernelBuf+vk_append + mov cx,[VKernelBuf+vk_appendlen] + rep movsb + mov [CmdLinePtr],di ; Where to add rest of cmd + pop es + mov di,KernelName + push di + mov si,VKernelBuf+vk_rname + mov cx,FILENAME_MAX ; We need ECX == CX later + rep movsb + pop di +%if IS_PXELINUX + mov al,[VKernelBuf+vk_ipappend] + mov [IPAppend],al +%endif + xor bx,bx ; Try only one version + +%if IS_PXELINUX || IS_ISOLINUX + ; Is this a "localboot" pseudo-kernel? +%if IS_PXELINUX + cmp byte [VKernelBuf+vk_rname+4], 0 +%else + cmp byte [VKernelBuf+vk_rname], 0 +%endif + jne get_kernel ; No, it's real, go get it + + mov ax, [VKernelBuf+vk_rname+1] + jmp local_boot +%else + jmp get_kernel +%endif + +.not_vk: + +; +; Not a "virtual kernel" - check that's OK and construct the command line +; + cmp word [AllowImplicit],byte 0 + je bad_implicit + push es + push si + push di + mov di,real_mode_seg + mov es,di + mov si,AppendBuf + mov di,cmd_line_here + mov cx,[AppendLen] + rep movsb + mov [CmdLinePtr],di + pop di + pop si + pop es +; +; Find the kernel on disk +; +get_kernel: mov byte [KernelName+FILENAME_MAX],0 ; Zero-terminate filename/extension +%if IS_SYSLINUX || IS_MDSLINUX ; SYSLINUX has to deal with DOS mangled names... + mov eax,[KernelName+8] ; Save initial extension + mov [exten_table_end],eax ; Last case == initial ext. +%else + mov di,KernelName+4*IS_PXELINUX + xor al,al + mov cx,FILENAME_MAX-5 ; Need 4 chars + null + repne scasb ; Scan for final null + jne .no_skip + dec di ; Point to final null +.no_skip: mov [KernelExtPtr],di +%endif + mov bx,exten_table +.search_loop: push bx + mov di,KernelName ; Search on disk + call searchdir + pop bx + jnz kernel_good + mov eax,[bx] ; Try a different extension +%if IS_SYSLINUX || IS_MDSLINUX + mov [KernelName+8],eax +%else + mov si,[KernelExtPtr] + mov [si],eax + mov byte [si+4],0 +%endif + add bx,byte 4 + cmp bx,exten_table_end + jna .search_loop ; allow == case (final case) + ; Fall into bad_kernel +; +; bad_kernel: Kernel image not found +; bad_implicit: The user entered a nonvirtual kernel name, with "implicit 0" +; +bad_implicit: +bad_kernel: + mov cx,[OnerrorLen] + and cx,cx + jnz on_error +.really: + mov si,KernelName + mov di,KernelCName + push di + call unmangle_name ; Get human form + mov si,err_notfound ; Complain about missing kernel + call cwritestr + pop si ; KernelCName + call cwritestr + mov si,crlf_msg + jmp abort_load ; Ask user for clue + +; +; on_error: bad kernel, but we have onerror set +; +on_error: + mov si,Onerror + mov di,command_line + push si ; <A> + push di ; <B> + push cx ; <C> + push cx ; <D> + push di ; <E> + repe cmpsb + pop di ; <E> di == command_line + pop bx ; <D> bx == [OnerrorLen] + je bad_kernel.really ; Onerror matches command_line already + neg bx ; bx == -[OnerrorLen] + lea cx,[max_cmd_len+bx] + ; CX == max_cmd_len-[OnerrorLen] + mov di,command_line+max_cmd_len-1 + mov byte [di+1],0 ; Enforce null-termination + lea si,[di+bx] + std + rep movsb ; Make space in command_line + cld + pop cx ; <C> cx == [OnerrorLen] + pop di ; <B> di == command_line + pop si ; <A> si == Onerror + rep movsb + jmp load_kernel + +; +; kernel_corrupt: Called if the kernel file does not seem healthy +; +kernel_corrupt: mov si,err_notkernel + jmp abort_load +; +; This is it! We have a name (and location on the disk)... let's load +; that sucker!! First we have to decide what kind of file this is; base +; that decision on the file extension. The following extensions are +; recognized; case insensitive: +; +; .com - COMBOOT image +; .cbt - COMBOOT image +; .c32 - COM32 image +; .bs - Boot sector +; .0 - PXE bootstrap program (PXELINUX only) +; .bin - Boot sector +; .bss - Boot sector, but transfer over DOS superblock (SYSLINUX only) +; .img - Floppy image (ISOLINUX only) +; +; Anything else is assumed to be a Linux kernel. +; +kernel_good: + pusha + mov si,KernelName + mov di,KernelCName + call unmangle_name + sub di,KernelCName + mov [KernelCNameLen],di + popa + +%if IS_SYSLINUX || IS_MDSLINUX + mov ecx,[KernelName+7] + mov cl,'.' +%else + push di + push ax + mov di,KernelName+4*IS_PXELINUX + xor al,al + mov cx,FILENAME_MAX + repne scasb + jne .one_step + dec di +.one_step: mov ecx,[di-4] ; 4 bytes before end + pop ax + pop di +%endif + +; +; At this point, DX:AX contains the size of the kernel, and SI contains +; the file handle/cluster pointer. +; + or ecx,20202000h ; Force lower case + + cmp ecx,'.com' + je is_comboot_image + cmp ecx,'.cbt' + je is_comboot_image + cmp ecx,'.c32' + je is_com32_image +%if IS_ISOLINUX + cmp ecx,'.img' + je is_disk_image +%endif + cmp ecx,'.bss' + je is_bss_sector + cmp ecx,'.bin' + je is_bootsector +%if IS_SYSLINUX || IS_MDSLINUX + cmp ecx,'.bs ' + je is_bootsector + cmp ecx,'.0 ' + je is_bootsector +%else + shr ecx,8 + cmp ecx,'.bs' + je is_bootsector + shr ecx,8 + cmp cx,'.0' + je is_bootsector +%endif + ; Otherwise Linux kernel + + section .bss + alignb 2 +KernelExtPtr resw 1 ; During search, final null pointer +CmdOptPtr resw 1 ; Pointer to first option on cmd line +KbdFlags resb 1 ; Check for keyboard escapes +FuncFlag resb 1 ; Escape sequences received from keyboard + + section .text diff --git a/syslinux/unix/Makefile b/syslinux/unix/Makefile new file mode 100644 index 0000000..39b25c0 --- /dev/null +++ b/syslinux/unix/Makefile @@ -0,0 +1,43 @@ +CC = gcc +OPTFLAGS = -g -Os +INCLUDES = -I. -I.. -I../libfat +CFLAGS = -W -Wall -D_FILE_OFFSET_BITS=64 $(OPTFLAGS) $(INCLUDES) +LDFLAGS = -s + +SRCS = syslinux.c ../syslxmod.c ../bootsect_bin.c ../ldlinux_bin.c $(wildcard ../libfat/*.c) +OBJS = $(patsubst %.c,%.o,$(notdir $(SRCS))) + +.SUFFIXES: .c .o .i .s .S + +VPATH = .:..:../libfat + +all: installer + +tidy: + -rm -f *.o *.i *.s *.a .*.d + +clean: tidy + -rm -f syslinux syslinux-nomtools + +spotless: clean + -rm -f *~ + +installer: syslinux syslinux-nomtools + +syslinux: $(OBJS) + $(CC) $(LDFLAGS) -o $@ $^ + +syslinux-nomtools: syslinux + ln -f $< $@ + +%.o: %.c + $(CC) -Wp,-MT,$@,-MMD,.$@.d $(CFLAGS) -c -o $@ $< +%.i: %.c + $(CC) $(CFLAGS) -E -o $@ $< +%.s: %.c + $(CC) $(CFLAGS) -S -o $@ $< + +-include .*.d + + + diff --git a/syslinux/unix/syslinux.c b/syslinux/unix/syslinux.c new file mode 100644 index 0000000..8211c0b --- /dev/null +++ b/syslinux/unix/syslinux.c @@ -0,0 +1,505 @@ +#ident "$Id: syslinux.c,v 1.7 2005/01/04 03:27:43 hpa Exp $" +/* ----------------------------------------------------------------------- * + * + * Copyright 1998-2005 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * syslinux.c - Linux installer program for SYSLINUX + * + * This program ought to be portable. I hope so, at least. + * + * This is an alternate version of the installer which doesn't require + * mtools, but requires root privilege. + */ + +/* + * If DO_DIRECT_MOUNT is 0, call mount(8) + * If DO_DIRECT_MOUNT is 1, call mount(2) + */ +#ifdef __KLIBC__ +# define DO_DIRECT_MOUNT 1 +#else +# define DO_DIRECT_MOUNT 0 /* glibc has broken losetup ioctls */ +#endif + +#define _GNU_SOURCE +#define _XOPEN_SOURCE 500 /* For pread() pwrite() */ +#define _FILE_OFFSET_BITS 64 +#include <alloca.h> +#include <errno.h> +#include <fcntl.h> +#include <paths.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <inttypes.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/mount.h> + +#include "syslinux.h" +#include "libfat.h" + +#if DO_DIRECT_MOUNT + +# include <linux/loop.h> + +#else + +# include <paths.h> +# ifndef _PATH_MOUNT +# define _PATH_MOUNT "/bin/mount" +# endif +# ifndef _PATH_UMOUNT +# define _PATH_UMOUNT "/bin/umount" +# endif + +#endif + +const char *program; /* Name of program */ +const char *device; /* Device to install to */ +pid_t mypid; +char *mntpath = NULL; /* Path on which to mount */ +off_t filesystem_offset = 0; /* Filesystem offset */ +#if DO_DIRECT_MOUNT +int loop_fd = -1; /* Loop device */ +#endif + +void __attribute__((noreturn)) usage(void) +{ + fprintf(stderr, "Usage: %s [-sf] [-o offset] device\n", program); + exit(1); +} + +void __attribute__((noreturn)) die(const char *msg) +{ + fprintf(stderr, "%s: %s\n", program, msg); + +#if DO_DIRECT_MOUNT + if ( loop_fd != -1 ) { + ioctl(loop_fd, LOOP_CLR_FD, 0); /* Free loop device */ + close(loop_fd); + loop_fd = -1; + } +#endif + + if ( mntpath ) + unlink(mntpath); + + exit(1); +} + +/* + * read/write wrapper functions + */ +ssize_t xpread(int fd, void *buf, size_t count, off_t offset) +{ + char *bufp = (char *)buf; + ssize_t rv; + ssize_t done = 0; + + while ( count ) { + rv = pread(fd, bufp, count, offset); + if ( rv == 0 ) { + die("short read"); + } else if ( rv == -1 ) { + if ( errno == EINTR ) { + continue; + } else { + die(strerror(errno)); + } + } else { + bufp += rv; + offset += rv; + done += rv; + count -= rv; + } + } + + return done; +} + +ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset) +{ + const char *bufp = (const char *)buf; + ssize_t rv; + ssize_t done = 0; + + while ( count ) { + rv = pwrite(fd, bufp, count, offset); + if ( rv == 0 ) { + die("short write"); + } else if ( rv == -1 ) { + if ( errno == EINTR ) { + continue; + } else { + die(strerror(errno)); + } + } else { + bufp += rv; + offset += rv; + done += rv; + count -= rv; + } + } + + return done; +} + +/* + * Version of the read function suitable for libfat + */ +int libfat_xpread(intptr_t pp, void *buf, size_t secsize, libfat_sector_t sector) +{ + off_t offset = (off_t)sector * secsize + filesystem_offset; + return xpread(pp, buf, secsize, offset); +} + +int main(int argc, char *argv[]) +{ + static unsigned char sectbuf[512]; + unsigned char *dp; + const unsigned char *cdp; + int dev_fd, fd; + struct stat st; + int nb, left; + int err = 0; + pid_t f, w; + int status; + char mntname[64], devfdname[64]; + char *ldlinux_name, **argp, *opt; + int force = 0; /* -f (force) option */ + struct libfat_filesystem *fs; + struct libfat_direntry dentry; + libfat_sector_t s, *secp, sectors[65]; /* 65 is maximum possible */ + int32_t ldlinux_cluster; + int nsectors; + const char *errmsg; + + (void)argc; /* Unused */ + + program = argv[0]; + mypid = getpid(); + + device = NULL; + + umask(077); + + for ( argp = argv+1 ; *argp ; argp++ ) { + if ( **argp == '-' ) { + opt = *argp + 1; + if ( !*opt ) + usage(); + + while ( *opt ) { + if ( *opt == 's' ) { + syslinux_make_stupid(); /* Use "safe, slow and stupid" code */ + } else if ( *opt == 'f' ) { + force = 1; /* Force install */ + } else if ( *opt == 'o' && argp[1] ) { + filesystem_offset = (off_t)strtoull(*++argp, NULL, 0); /* Byte offset */ + } else { + usage(); + } + opt++; + } + } else { + if ( device ) + usage(); + device = *argp; + } + } + + if ( !device ) + usage(); + + /* + * First make sure we can open the device at all, and that we have + * read/write permission. + */ + dev_fd = open(device, O_RDWR); + if ( dev_fd < 0 || fstat(dev_fd, &st) < 0 ) { + perror(device); + exit(1); + } + + if ( !force && !S_ISBLK(st.st_mode) && !S_ISREG(st.st_mode) ) { + die("not a block device or regular file (use -f to override)"); + } + + if ( !force && filesystem_offset && !S_ISREG(st.st_mode) ) { + die("not a regular file and an offset specified (use -f to override)"); + } + + xpread(dev_fd, sectbuf, 512, filesystem_offset); + fsync(dev_fd); + + /* + * Check to see that what we got was indeed an MS-DOS boot sector/superblock + */ + if( (errmsg = syslinux_check_bootsect(sectbuf)) ) { + fprintf(stderr, "%s: %s\n", device, errmsg); + exit(1); + } + + /* + * Now mount the device. + */ + if ( geteuid() ) { + die("This program needs root privilege"); + } else { + int i = 0; + struct stat dst; + int rv; + + /* We're root or at least setuid. + Make a temp dir and pass all the gunky options to mount. */ + + if ( chdir("/tmp") ) { + perror(program); + exit(1); + } + +#define TMP_MODE (S_IXUSR|S_IWUSR|S_IXGRP|S_IWGRP|S_IWOTH|S_IXOTH|S_ISVTX) + + if ( stat(".", &dst) || !S_ISDIR(dst.st_mode) || + (dst.st_mode & TMP_MODE) != TMP_MODE ) { + die("possibly unsafe /tmp permissions"); + } + + for ( i = 0 ; ; i++ ) { + snprintf(mntname, sizeof mntname, "syslinux.mnt.%lu.%d", + (unsigned long)mypid, i); + + if ( lstat(mntname, &dst) != -1 || errno != ENOENT ) + continue; + + rv = mkdir(mntname, 0000); + + if ( rv == -1 ) { + if ( errno == EEXIST || errno == EINTR ) + continue; + perror(program); + exit(1); + } + + if ( lstat(mntname, &dst) || dst.st_mode != (S_IFDIR|0000) || + dst.st_uid != 0 ) { + die("someone is trying to symlink race us!"); + } + break; /* OK, got something... */ + } + + mntpath = mntname; + +#if DO_DIRECT_MOUNT + if ( S_ISREG(st.st_mode) ) { + /* It's file, need to mount it loopback */ + unsigned int n = 0; + struct loop_info64 loopinfo; + + for ( n = 0 ; loop_fd < 0 ; n++ ) { + snprintf(devfdname, sizeof devfdname, "/dev/loop%u", n); + loop_fd = open(devfdname, O_RDWR); + if ( loop_fd < 0 && errno == ENOENT ) { + die("no available loopback device!"); + } + if ( ioctl(loop_fd, LOOP_SET_FD, (void *)dev_fd) ) { + close(loop_fd); loop_fd = -1; + if ( errno != EBUSY ) + die("cannot set up loopback device"); + else + continue; + } + + if ( ioctl(loop_fd, LOOP_GET_STATUS64, &loopinfo) || + (loopinfo.lo_offset = filesystem_offset, + ioctl(loop_fd, LOOP_SET_STATUS64, &loopinfo)) ) + die("cannot set up loopback device"); + } + } else { + snprintf(devfdname, sizeof devfdname, "/proc/%lu/fd/%d", + (unsigned long)mypid, dev_fd); + } + + if ( mount(devfdname, mntpath, "msdos", + MS_NOEXEC|MS_NOSUID, "umask=077,quiet") ) + die("could not mount filesystem"); + +#else + + snprintf(devfdname, sizeof devfdname, "/proc/%lu/fd/%d", + (unsigned long)mypid, dev_fd); + + f = fork(); + if ( f < 0 ) { + perror(program); + rmdir(mntpath); + exit(1); + } else if ( f == 0 ) { + char mnt_opts[128]; + if ( S_ISREG(st.st_mode) ) { + snprintf(mnt_opts, sizeof mnt_opts, "rw,nodev,noexec,loop,offset=%llu,umask=077,quiet", + (unsigned long long)filesystem_offset); + } else { + snprintf(mnt_opts, sizeof mnt_opts, "rw,nodev,noexec,umask=077,quiet"); + } + execl(_PATH_MOUNT, _PATH_MOUNT, "-t", "msdos", "-o", mnt_opts,\ + devfdname, mntpath, NULL); + _exit(255); /* execl failed */ + } + + w = waitpid(f, &status, 0); + if ( w != f || status ) { + rmdir(mntpath); + exit(1); /* Mount failed */ + } + +#endif + } + + ldlinux_name = alloca(strlen(mntpath)+13); + if ( !ldlinux_name ) { + perror(program); + err = 1; + goto umount; + } + sprintf(ldlinux_name, "%s/ldlinux.sys", mntpath); + + unlink(ldlinux_name); + fd = open(ldlinux_name, O_WRONLY|O_CREAT|O_TRUNC, 0444); + if ( fd < 0 ) { + perror(device); + err = 1; + goto umount; + } + + cdp = syslinux_ldlinux; + left = syslinux_ldlinux_len; + while ( left ) { + nb = write(fd, cdp, left); + if ( nb == -1 && errno == EINTR ) + continue; + else if ( nb <= 0 ) { + perror(device); + err = 1; + goto umount; + } + + dp += nb; + left -= nb; + } + + /* + * I don't understand why I need this. Does the DOS filesystems + * not honour the mode passed to open()? + */ + fchmod(fd, 0400); + + close(fd); + + sync(); + +umount: +#if DO_DIRECT_MOUNT + + if ( umount2(mntpath, 0) ) + die("could not umount path"); + + if ( loop_fd != -1 ) { + ioctl(loop_fd, LOOP_CLR_FD, 0); /* Free loop device */ + close(loop_fd); + loop_fd = -1; + } + +#else + + f = fork(); + if ( f < 0 ) { + perror("fork"); + exit(1); + } else if ( f == 0 ) { + execl(_PATH_UMOUNT, _PATH_UMOUNT, mntpath, NULL); + } + + w = waitpid(f, &status, 0); + if ( w != f || status ) { + exit(1); + } + +#endif + + sync(); + rmdir(mntpath); + + if ( err ) + exit(err); + + /* + * Now, use libfat to create a block map. This probably + * should be changed to use ioctl(...,FIBMAP,...) since + * this is supposed to be a simple, privileged version + * of the installer. + */ + fs = libfat_open(libfat_xpread, dev_fd); + ldlinux_cluster = libfat_searchdir(fs, 0, "LDLINUX SYS", &dentry); + secp = sectors; + nsectors = 0; + s = libfat_clustertosector(fs, ldlinux_cluster); + while ( s && nsectors < 65 ) { + *secp++ = s; + nsectors++; + s = libfat_nextsector(fs, s); + } + libfat_close(fs); + + /* + * Patch ldlinux.sys and the boot sector + */ + syslinux_patch(sectors, nsectors); + + /* + * Write the now-patched first sector of ldlinux.sys + */ + xpwrite(dev_fd, syslinux_ldlinux, 512, filesystem_offset + ((off_t)sectors[0] << 9)); + + /* + * Patch the root directory to set attributes to + * HIDDEN|SYSTEM|READONLY + */ + { + const unsigned char attrib = 0x07; + xpwrite(dev_fd, &attrib, 1, ((off_t)dentry.sector << 9)+dentry.offset+11); + } + + /* + * To finish up, write the boot sector + */ + + /* Read the superblock again since it might have changed while mounted */ + xpread(dev_fd, sectbuf, 512, filesystem_offset); + + /* Copy the syslinux code into the boot sector */ + syslinux_make_bootsect(sectbuf); + + /* Write new boot sector */ + xpwrite(dev_fd, sectbuf, 512, filesystem_offset); + + close(dev_fd); + sync(); + + /* Done! */ + + return 0; +} + diff --git a/syslinux/version b/syslinux/version new file mode 100644 index 0000000..6fe94f3 --- /dev/null +++ b/syslinux/version @@ -0,0 +1 @@ +3.08 diff --git a/syslinux/version.gen b/syslinux/version.gen new file mode 100644 index 0000000..31640a2 --- /dev/null +++ b/syslinux/version.gen @@ -0,0 +1,3 @@ +%define VERSION "3.08" +%define VER_MAJOR 3 +%define VER_MINOR 8 diff --git a/syslinux/version.h b/syslinux/version.h new file mode 100644 index 0000000..5e2c61b --- /dev/null +++ b/syslinux/version.h @@ -0,0 +1,3 @@ +#define VERSION "3.08" +#define VER_MAJOR 3 +#define VER_MINOR 8 diff --git a/syslinux/version.pl b/syslinux/version.pl new file mode 100755 index 0000000..4440369 --- /dev/null +++ b/syslinux/version.pl @@ -0,0 +1,26 @@ +#!/usr/bin/perl +# +# Read the "version" file and produce some macro declarations +# + +use Fcntl; + +($vfile, $vout, $def) = @ARGV; +sysopen(VERSION, $vfile, O_RDONLY) or die "$0: Cannot open $vfile\n"; +$version = <VERSION>; +chomp $version; +close(VERSION); + +unless ( $version =~ /^([0-9]+)\.([0-9]+)$/ ) { + die "$0: Cannot parse version format\n"; +} +$vma = $1+0; $vmi = $2+0; + +sysopen(VI, $vout, O_WRONLY|O_CREAT|O_TRUNC) + or die "$0: Cannot create $vout: $!\n"; +print VI "$def VERSION \"$version\"\n"; +print VI "$def VER_MAJOR $vma\n"; +print VI "$def VER_MINOR $vmi\n"; +close(VI); + + diff --git a/syslinux/win32/Makefile b/syslinux/win32/Makefile new file mode 100644 index 0000000..10e9d6f --- /dev/null +++ b/syslinux/win32/Makefile @@ -0,0 +1,86 @@ +## $Id: Makefile,v 1.12 2004/12/22 17:53:54 hpa Exp $ +## ----------------------------------------------------------------------- +## +## Copyright 1998-2004 H. Peter Anvin - All Rights Reserved +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, Inc., 53 Temple Place Ste 330, +## Boston MA 02111-1307, USA; either version 2 of the License, or +## (at your option) any later version; incorporated herein by reference. +## +## ----------------------------------------------------------------------- + +# +# Makefile for SYSLINUX Win32 +# +# This is separated out mostly so we can have a different set of Makefile +# variables. +# + +OSTYPE = $(shell uname -msr) +ifeq ($(findstring CYGWIN,$(OSTYPE)),CYGWIN) +CC = gcc +AR = ar +RANLIB = ranlib +CFLAGS = -mno-cygwin -W -Wall -Os -fomit-frame-pointer -D_FILE_OFFSET_BITS=64 +PIC = +LDFLAGS = -mno-cygwin -Os -s +else +ifeq ($(findstring MINGW32,$(OSTYPE)),MINGW32) +CC = gcc +AR = ar +RANLIB = ranlib +else +CC = mingw-gcc +AR = mingw-ar +RANLIB = mingw-ranlib +endif + +CFLAGS = -W -Wall -Wno-sign-compare -Os -fomit-frame-pointer -D_FILE_OFFSET_BITS=64 +PIC = +LDFLAGS = -Os -s +endif +CFLAGS += -I. -I.. -I../libfat + +CC_IS_GOOD := $(shell $(CC) $(CFLAGS) $(LDFLAGS) -o hello.exe hello.c >/dev/null 2>&1 ; echo $$?) + +.SUFFIXES: .c .o .i .s .S + +SRCS = syslinux.c ../syslxmod.c ../bootsect_bin.c ../ldlinux_bin.c \ + ../mbr_bin.c $(wildcard ../libfat/*.c) +OBJS = $(patsubst %.c,%.o,$(notdir $(SRCS))) + +VPATH = .:..:../libfat + +TARGETS = syslinux.exe + +ifeq ($(CC_IS_GOOD),0) +all: $(TARGETS) +else +all: + rm -f $(TARGETS) +endif + +tidy: + -rm -f *.o *.i *.s *.a .*.d *_bin.c + +clean: tidy + +spotless: clean + -rm -f *~ $(TARGETS) + +installer: + +syslinux.exe: $(OBJS) + $(CC) $(LDFLAGS) -o $@ $^ + + +%.o: %.c + $(CC) -Wp,-MT,$@,-MMD,.$@.d $(CFLAGS) -c -o $@ $< +%.i: %.c + $(CC) $(CFLAGS) -E -o $@ $< +%.s: %.c + $(CC) $(CFLAGS) -S -o $@ $< + +-include .*.d diff --git a/syslinux/win32/hello.c b/syslinux/win32/hello.c new file mode 100644 index 0000000..b1f7594 --- /dev/null +++ b/syslinux/win32/hello.c @@ -0,0 +1,13 @@ +/* + * Test program for C compiler; if this doesn't compile, the + * C compiler is seriously broken. + */ + +#include <stdlib.h> +#include <stdio.h> + +int main(void) +{ + printf("Hello, World!\n"); + return 0; +} diff --git a/syslinux/win32/hello.exe b/syslinux/win32/hello.exe new file mode 100755 index 0000000000000000000000000000000000000000..c3ed662b6995019888811b68793168e6de5cb21c GIT binary patch literal 10752 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 X*a-ixf7@EOKiXpCq<vccoaKK2Djz0j literal 0 HcmV?d00001 diff --git a/syslinux/win32/syslinux.c b/syslinux/win32/syslinux.c new file mode 100644 index 0000000..283861b --- /dev/null +++ b/syslinux/win32/syslinux.c @@ -0,0 +1,483 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2003 Lars Munch Christensen - All Rights Reserved + * Copyright 1998-2004 H. Peter Anvin - All Rights Reserved + * + * Based on the Linux installer program for SYSLINUX by H. Peter Anvin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * syslinux-mingw.c - Win2k/WinXP installer program for SYSLINUX + */ + +#include <windows.h> +#include <stdio.h> +#include <ctype.h> + +#include "syslinux.h" +#include "libfat.h" + +#ifdef __GNUC__ +# define noreturn void __attribute__((noreturn)) +#else +# define noreturn void +#endif + +void error(char* msg); + +/* Begin stuff for MBR code */ + +#include <winioctl.h> + +#define SECTOR_SIZE 512 +#define PART_TABLE 0x1be +#define PART_SIZE 0x10 +#define PART_COUNT 4 +#define PART_ACTIVE 0x80 + +// The following struct should be in the ntddstor.h file, but I didn't have it. +// TODO: Make this a conditional compilation +typedef struct _STORAGE_DEVICE_NUMBER { + DEVICE_TYPE DeviceType; + ULONG DeviceNumber; + ULONG PartitionNumber; +} STORAGE_DEVICE_NUMBER, *PSTORAGE_DEVICE_NUMBER; + +BOOL GetStorageDeviceNumberByHandle( HANDLE handle, const STORAGE_DEVICE_NUMBER *sdn ) { + BOOL result = FALSE; + DWORD count; + + if ( DeviceIoControl( handle, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, + 0, (LPVOID)sdn, sizeof( *sdn ), &count, NULL ) ) { + result = TRUE; + } + else { + error("GetDriveNumber: DeviceIoControl failed"); + } + + return( result ); +} + +int GetBytesPerSector( HANDLE drive ) { + int result = 0; + DISK_GEOMETRY g; + DWORD count; + + if ( DeviceIoControl( drive, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, + &g, sizeof( g ), &count, NULL ) ) { + result = g.BytesPerSector; + } + + return( result ); +} + +BOOL FixMBR(int driveNum, int partitionNum, int write_mbr, int set_active) { + BOOL result = TRUE; + HANDLE drive; + + char driveName[128]; + + sprintf( driveName, "\\\\.\\PHYSICALDRIVE%d", driveNum ); + + drive = CreateFile( driveName, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_WRITE | FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + 0, + NULL ); + + if( drive == INVALID_HANDLE_VALUE ) { + error("Accessing physical drive"); + result = FALSE; + } + + if( result ) { + unsigned char sector[SECTOR_SIZE]; + DWORD howMany; + + if( GetBytesPerSector( drive ) != SECTOR_SIZE ) { + fprintf(stderr, "Error: Sector size of this drive is %d; must be %d\n", + GetBytesPerSector( drive ), SECTOR_SIZE ); + result = FALSE; + } + + if ( result ) { + if ( ReadFile( drive, sector, sizeof( sector ), &howMany, NULL ) == 0 ) { + error("Reading raw drive"); + result = FALSE; + } else if ( howMany != sizeof( sector ) ) { + fprintf(stderr, "Error: ReadFile on drive only got %d of %d bytes\n", + (int)howMany, sizeof( sector ) ); + result = FALSE; + } + } + + // Copy over the MBR code if specified (-m) + if ( write_mbr ) { + if ( result ) { + if ( syslinux_mbr_len >= PART_TABLE ) { + fprintf(stderr, "Error: MBR will not fit; not writing\n" ); + result = FALSE; + } else { + memcpy( sector, syslinux_mbr, syslinux_mbr_len ); + } + } + } + + // Check that our partition is active if specified (-a) + if ( set_active ) { + if ( sector[ PART_TABLE + ( PART_SIZE * ( partitionNum - 1 ) ) ] != 0x80 ) { + int p; + for ( p = 0; p < PART_COUNT; p++ ) + sector[ PART_TABLE + ( PART_SIZE * p ) ] = ( p == partitionNum - 1 ? 0x80 : 0 ); + } + } + + if ( result ) { + SetFilePointer( drive, 0, NULL, FILE_BEGIN ); + + if ( WriteFile( drive, sector, sizeof( sector ), &howMany, NULL ) == 0 ) { + error("Writing MBR"); + result = FALSE; + } else if ( howMany != sizeof( sector ) ) { + fprintf(stderr, "Error: WriteFile on drive only wrote %d of %d bytes\n", + (int)howMany, sizeof( sector ) ); + result = FALSE; + } + } + + if( !CloseHandle( drive ) ) { + error("CloseFile on drive"); + result = FALSE; + } + } + + return( result ); +} + +/* End stuff for MBR code */ + +const char *program; /* Name of program */ +const char *drive; /* Drive to install to */ + +/* + * Check Windows version. + * + * On Windows Me/98/95 you cannot open a directory, physical disk, or + * volume using CreateFile. + */ +int checkver(void) +{ + OSVERSIONINFO osvi; + + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&osvi); + + return (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) && + ((osvi.dwMajorVersion > 4) || + ((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion == 0))); +} + +/* + * Windows error function + */ +void error(char* msg) +{ + LPVOID lpMsgBuf; + + /* Format the Windows error message */ + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, 0, NULL ); + + /* Print it */ + fprintf(stderr, "%s: %s", msg, (char*) lpMsgBuf); + + /* Free the buffer */ + LocalFree(lpMsgBuf); +} + +/* + * Wrapper for ReadFile suitable for libfat + */ +int libfat_readfile(intptr_t pp, void *buf, size_t secsize, libfat_sector_t sector) +{ + uint64_t offset = (uint64_t)sector * secsize; + LONG loword = (LONG)offset; + LONG hiword = (LONG)(offset >> 32); + LONG hiwordx = hiword; + DWORD bytes_read; + + if ( SetFilePointer((HANDLE)pp, loword, &hiwordx, FILE_BEGIN) != loword || + hiword != hiwordx || + !ReadFile((HANDLE)pp, buf, secsize, &bytes_read, NULL) || + bytes_read != secsize ) { + fprintf(stderr, "Cannot read sector %u\n", sector); + exit(1); + } + + return secsize; +} + +noreturn usage(void) +{ + fprintf(stderr, "Usage: syslinux.exe [-sfma] <drive>: [bootsecfile]\n"); + exit(1); +} + +int main(int argc, char *argv[]) +{ + HANDLE f_handle, d_handle; + DWORD bytes_read; + DWORD bytes_written; + DWORD drives; + UINT drive_type; + + static unsigned char sectbuf[512]; + char **argp, *opt; + static char drive_name[] = "\\\\.\\?:"; + static char drive_root[] = "?:\\"; + static char ldlinux_name[] = "?:\\ldlinux.sys" ; + const char *errmsg; + struct libfat_filesystem *fs; + libfat_sector_t s, *secp, sectors[65]; /* 65 is maximum possible */ + uint32_t ldlinux_cluster; + int nsectors; + const char *bootsecfile = NULL; + + int force = 0; /* -f (force) option */ + int mbr = 0; /* -m (MBR) option */ + int setactive = 0; /* -a (set partition active) */ + + (void)argc; + + if (!checkver()) { + fprintf(stderr, "You need to be running at least Windows NT; use syslinux.com instead.\n"); + exit(1); + } + + program = argv[0]; + drive = NULL; + + for ( argp = argv+1 ; *argp ; argp++ ) { + if ( **argp == '-' ) { + opt = *argp + 1; + if ( !*opt ) + usage(); + + while ( *opt ) { + switch ( *opt ) { + case 's': /* Use "safe, slow and stupid" code */ + syslinux_make_stupid(); + break; + case 'f': /* Force install */ + force = 1; + break; + case 'm': /* Install MBR */ + mbr = 1; + break; + case 'a': /* Mark this partition active */ + setactive = 1; + break; + default: + usage(); + break; + } + opt++; + } + } else { + if ( bootsecfile ) + usage(); + else if ( drive ) + bootsecfile = *argp; + else + drive = *argp; + } + } + + if ( !drive || !isalpha(drive[0]) || drive[1] != ':' || drive[2] ) + usage(); + + /* Test if drive exists */ + drives = GetLogicalDrives(); + if(!(drives & ( 1 << (tolower(drive[0]) - 'a')))) { + fprintf(stderr, "No such drive %c:\n", drive[0]); + exit(1); + } + + /* Determines the drive type */ + drive_name[4] = drive[0]; + ldlinux_name[0] = drive[0]; + drive_root[0] = drive[0]; + drive_type = GetDriveType(drive_root); + + /* Test for removeable media */ + if ((drive_type == DRIVE_FIXED) && (force == 0)) { + fprintf(stderr, "Not a removable drive (use -f to override) \n"); + exit(1); + } + + /* Test for unsupported media */ + if ((drive_type != DRIVE_FIXED) && (drive_type != DRIVE_REMOVABLE)) { + fprintf(stderr, "Unsupported media\n"); + exit(1); + } + + /* + * First open the drive + */ + d_handle = CreateFile(drive_name, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL ); + + if (d_handle == INVALID_HANDLE_VALUE) { + error("Could not open drive"); + exit(1); + } + + /* + * Make sure we can read the boot sector + */ + if ( !ReadFile(d_handle, sectbuf, 512, &bytes_read, NULL) ) { + error("Reading boot sector"); + exit(1); + } + if (bytes_read != 512) { + fprintf(stderr, "Could not read the whole boot sector\n"); + exit(1); + } + + /* Check to see that what we got was indeed an MS-DOS boot sector/superblock */ + if( (errmsg = syslinux_check_bootsect(sectbuf)) ) { + fprintf(stderr, "%s\n", errmsg); + exit(1); + } + + /* Change to normal attributes to enable deletion */ + /* Just ignore error if the file do not exists */ + SetFileAttributes(ldlinux_name, FILE_ATTRIBUTE_NORMAL); + + /* Delete the file */ + /* Just ignore error if the file do not exists */ + DeleteFile(ldlinux_name); + + /* Create ldlinux.sys file */ + f_handle = CreateFile(ldlinux_name, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, CREATE_ALWAYS, + FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM | + FILE_ATTRIBUTE_HIDDEN, + NULL ); + + if (f_handle == INVALID_HANDLE_VALUE) { + error("Unable to create ldlinux.sys"); + exit(1); + } + + /* Write ldlinux.sys file */ + if (!WriteFile(f_handle, syslinux_ldlinux, syslinux_ldlinux_len, &bytes_written, NULL)) { + error("Could not write ldlinux.sys"); + exit(1); + } + + if (bytes_written != syslinux_ldlinux_len) { + fprintf(stderr, "Could not write whole ldlinux.sys\n"); + exit(1); + } + + /* Now flush the media */ + if(!FlushFileBuffers(f_handle)) { + error("FlushFileBuffers failed"); + exit(1); + } + + /* Map the file (is there a better way to do this?) */ + fs = libfat_open(libfat_readfile, (intptr_t)d_handle); + ldlinux_cluster = libfat_searchdir(fs, 0, "LDLINUX SYS", NULL); + secp = sectors; + nsectors = 0; + s = libfat_clustertosector(fs, ldlinux_cluster); + while ( s && nsectors < 65 ) { + *secp++ = s; + nsectors++; + s = libfat_nextsector(fs, s); + } + libfat_close(fs); + + /* + * Patch ldlinux.sys and the boot sector + */ + syslinux_patch(sectors, nsectors); + + /* + * Rewrite the file + */ + if ( SetFilePointer(f_handle, 0, NULL, FILE_BEGIN) != 0 || + !WriteFile(f_handle, syslinux_ldlinux, syslinux_ldlinux_len, &bytes_written, NULL) || + bytes_written != syslinux_ldlinux_len ) { + error("Could not write ldlinux.sys"); + exit(1); + } + + /* If desired, fix the MBR */ + if( mbr || setactive ) { + STORAGE_DEVICE_NUMBER sdn; + if( GetStorageDeviceNumberByHandle( d_handle, &sdn ) ) { + if( !FixMBR(sdn.DeviceNumber, sdn.PartitionNumber, mbr, setactive) ) { + fprintf(stderr, "Did not successfully update the MBR; continuing...\n"); + } + } else { + fprintf(stderr, "Could not find device number for updating MBR; continuing...\n"); + } + } + + /* Close file */ + CloseHandle(f_handle); + + /* Make the syslinux boot sector */ + syslinux_make_bootsect(sectbuf); + + /* Write the syslinux boot sector into the boot sector */ + if ( bootsecfile ) { + f_handle = CreateFile(bootsecfile, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, CREATE_ALWAYS, + FILE_ATTRIBUTE_ARCHIVE, + NULL ); + if (f_handle == INVALID_HANDLE_VALUE) { + error("Unable to create bootsector file"); + exit(1); + } + if (!WriteFile(f_handle, sectbuf, 512, &bytes_written, NULL)) { + error("Could not write boot sector file"); + exit(1); + } + CloseHandle(f_handle); + } else { + SetFilePointer(d_handle, 0, NULL, FILE_BEGIN); + WriteFile( d_handle, sectbuf, 512, &bytes_written, NULL ) ; + } + + if(bytes_written != 512) { + fprintf(stderr, "Could not write the whole boot sector\n"); + exit(1); + } + + /* Close file */ + CloseHandle(d_handle); + + /* Done! */ + return 0; +} diff --git a/syslinux/win32/syslinux.exe b/syslinux/win32/syslinux.exe new file mode 100755 index 0000000000000000000000000000000000000000..fadbdeca79dfa2b47ff00d5a528876f46e489fab GIT binary patch literal 29696 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 QpK`dA52BW(|Bue&FNx%VCjbBd literal 0 HcmV?d00001 diff --git a/syslinux/writehex.inc b/syslinux/writehex.inc new file mode 100644 index 0000000..d83db19 --- /dev/null +++ b/syslinux/writehex.inc @@ -0,0 +1,55 @@ +;; $Id: writehex.inc,v 1.3 2005/01/18 13:13:50 hpa Exp $ +;; ----------------------------------------------------------------------- +;; +;; Copyright 1994-2002 H. Peter Anvin - All Rights Reserved +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +;; Boston MA 02111-1307, USA; either version 2 of the License, or +;; (at your option) any later version; incorporated herein by reference. +;; +;; ----------------------------------------------------------------------- + +;; +;; writehex.inc +;; +;; Write hexadecimal numbers to the console +;; + + section .text +; +; writehex[248]: Write a hex number in (AL, AX, EAX) to the console +; +writehex2: + pushfd + pushad + rol eax,24 + mov cx,2 + jmp short writehex_common +writehex4: + pushfd + pushad + rol eax,16 + mov cx,4 + jmp short writehex_common +writehex8: + pushfd + pushad + mov cx,8 +writehex_common: +.loop: rol eax,4 + push eax + and al,0Fh + cmp al,10 + jae .high +.low: add al,'0' + jmp short .ischar +.high: add al,'A'-10 +.ischar: call writechr + pop eax + loop .loop + popad + popfd + ret + diff --git a/syslinux/writestr.inc b/syslinux/writestr.inc new file mode 100644 index 0000000..228ac72 --- /dev/null +++ b/syslinux/writestr.inc @@ -0,0 +1,48 @@ +;; $Id: writestr.inc,v 1.5 2005/01/18 13:13:50 hpa Exp $ +;; ----------------------------------------------------------------------- +;; +;; Copyright 1994-2002 H. Peter Anvin - All Rights Reserved +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +;; Boston MA 02111-1307, USA; either version 2 of the License, or +;; (at your option) any later version; incorporated herein by reference. +;; +;; ----------------------------------------------------------------------- + +;; +;; writestr.inc +;; +;; Code to write a simple string. +;; + + section .text +; +; crlf: Print a newline +; +crlf: push ax + mov al,CR + call writechr + mov al,LF + call writechr + pop ax + ret + +; +; cwritestr: write a null-terminated string to the console, saving +; registers on entry. +; +; Note: writestr and cwritestr are distinct in SYSLINUX (only) +; +cwritestr: + pushfd + pushad +.top: lodsb + and al,al + jz .end + call writechr + jmp short .top +.end: popad + popfd + ret -- 2.47.0