diff --git a/tools/dos-ani/Makefile b/tools/dos-ani/Makefile new file mode 100755 index 000000000..79089c29a --- /dev/null +++ b/tools/dos-ani/Makefile @@ -0,0 +1,34 @@ +######################################################################## +# This is a GNU makefile - tested on CYGWIN and Linux +# +# You may need to compile or install libpng and/or zlib before +# compiling this. +# + +TARGET = undani +# These flags are needed to get it to compile with libpngX.dll on CYGWIN +CYGWINFLAGS = -DPNG_USE_DLL +#CYGWINFLAGS = +PNGFLAGS = -I. + +CC = gcc +CFLAGS = -W -Wall -O0 # -g +LIBS = -L/usr/local/lib -lpng -lm +LDFLAGS= + +BINS = $(TARGET) $(TARGET).exe +SRCS = undani.c lzhuf.c +OBJS = undani.o lzhuf.o + +.SUFFIXES: .c .o + +.c.o: + $(CC) -c $(CFLAGS) -o $@ $*.c $(PNGFLAGS) $(CYGWINFLAGS) + +all: $(TARGET) + +$(TARGET): $(OBJS) + $(CC) -o $(TARGET) $(OBJS) $(LIBS) $(LDFLAGS) + +clean: + rm -f $(BINS) *.o diff --git a/tools/dos-ani/config.h b/tools/dos-ani/config.h new file mode 100755 index 000000000..0a70fe8f0 --- /dev/null +++ b/tools/dos-ani/config.h @@ -0,0 +1,15 @@ +/* Dummy compile-time configuration options + * Only used when compiling in MS VC++ using UQM's getopt.c + */ + +#ifndef _CONFIG_H +#define _CONFIG_H + +/* Define if words are stored with the most significant byte first */ +#undef WORDS_BIGENDIAN + +/* Defined if your system has getopt.h */ +#undef HAVE_GETOPT_H + +#endif /* _CONFIG_H */ + diff --git a/tools/dos-ani/lzhuf.c b/tools/dos-ani/lzhuf.c new file mode 100755 index 000000000..7f09c2e0d --- /dev/null +++ b/tools/dos-ani/lzhuf.c @@ -0,0 +1,682 @@ +/************************************************************************** + lzhuf.c + written by Haruyasu Yoshizaki 1988/11/20 + some minor changes 1989/04/06 + comments translated by Haruhiko Okumura 1989/04/07 + getbit and getbyte modified 1990/03/23 by Paul Edwards + so that they would work on machines where integers are + not necessarily 16 bits (although ANSI guarantees a + minimum of 16). This program has compiled and run with + no errors under Turbo C 2.0, Power C, and SAS/C 4.5 + (running on an IBM mainframe under MVS/XA 2.2). Could + people please use YYYY/MM/DD date format so that everyone + in the world can know what format the date is in? + external storage of filesize changed 1990/04/18 by Paul Edwards to + Intel's "little endian" rather than a machine-dependant style so + that files produced on one machine with lzhuf can be decoded on + any other. "little endian" style was chosen since lzhuf + originated on PC's, and therefore they should dictate the + standard. + initialization of something predicting spaces changed 1990/04/22 by + Paul Edwards so that when the compressed file is taken somewhere + else, it will decode properly, without changing ascii spaces to + ebcdic spaces. This was done by changing the ' ' (space literal) + to 0x20 (which is the far most likely character to occur, if you + don't know what environment it will be running on. +***************************************************************************** + This code was found at http://www.cs.umu.se/~isak/Snippets + with the following Copyright notice. A lot information in the notice + is quite outdated by today (at least FidoNet is pretty dead). +***************************************************************************** +Welcome to SNIPPETS! + + All the code I put into SNIPPETS for distribution is Public Domain or free +to the best that I can determine. What this means is that: + +1. I know or can contact the original author(s) to verify the presumed + copyright ownership, and + +2. The work bears an explicit Public Domain notice, or + +3. The work is copyrighted but includes a free use license, or + +4. The work was published without a copyright notice prior to the effective + date of the new copyright law. + + This has been occasionally annoying when I've had to pass up some useful +piece of code because it's questionable whether anyone can use it without +incurring liability (distributing someone else's property makes me an +accessory, doncha know). + + Since SNIPPETS includes both public domain and free code, be sure to +carefully read each header for any free license restrictions which may +apply. + +Distribution: + + Starting with the December 1992 version, SNIPPETS is distributed in two +files: + +SNIPmmyy.LZH is the full SNIPPETS collection. +SNPDmmyy.LZH contains only the files changes since the last release. + + SNIPPETS is distributed through the FidoNet Programmer's Distribution +Network (PDN - see the file PDN.LST for a list of PDN sites and further +information. The SNIPPETS files are also available from my "home" BBS, Comm +Port One, (713) 980-9671, FidoNet address 1:106/2000 using the "magic" F'req +names of "SNIPPETS" and "SNIPDIFF". Various Internet mirror sites also carry +SNIPPETS, but I'm not sure which ones have it an any given time. One place to +try is oak.oakland.edu in /pub/msdos/c. + + ...Bob Stout +------------------------------- Enjoy! ----------------------------------- +***************************************************************************** + + made into lib-like reentrant by Alex Volkov 20050208 + +*****************************************************************************/ +#include +#include +#include +#include +#include "lzhuf.h" + +static size_t h_read(lzhuf_session_t* sess, void* buf, size_t size, size_t count) +{ + if (!sess->read) + return 0; + return sess->read(buf, size, count, sess->infile); +} + +static size_t h_write(lzhuf_session_t* sess, const void* buf, size_t size, size_t count) +{ + if (!sess->write) + return 0; + return sess->write(buf, size, count, sess->outfile); +} + +static int h_putc(lzhuf_session_t* sess, unsigned char c) +{ + return h_write(sess, &c, sizeof(c), 1) == 1 ? c : EOF; +} + +static int h_getc(lzhuf_session_t* sess) +{ + unsigned char c; + return h_read(sess, &c, sizeof(c), 1) == 1 ? c : EOF; +} + +static int h_seek(lzhuf_session_t* sess, lzhuf_handle_t h, long ofs, int origin) +{ + if (!sess->seek) + return -1; + return sess->seek(h, ofs, origin); +} + +static long h_tell(lzhuf_session_t* sess, lzhuf_handle_t h) +{ + if (!sess->tell) + return -1; + return sess->tell(h); +} + +static void InitTree(lzhuf_session_t* sess) /* initialize trees */ +{ + int i; + + for (i = LZHUF_N + 1; i <= LZHUF_N + 256; i++) + sess->rson[i] = LZHUF_NIL; /* root */ + for (i = 0; i < LZHUF_N; i++) + sess->dad[i] = LZHUF_NIL; /* node */ +} + +static void InsertNode(lzhuf_session_t* sess, int r) /* insert to tree */ +{ + int i, p, cmp; + unsigned char *key; + unsigned c; + + cmp = 1; + key = &sess->text_buf[r]; + p = LZHUF_N + 1 + key[0]; + sess->rson[r] = sess->lson[r] = LZHUF_NIL; + sess->match_length = 0; + for ( ; ; ) { + if (cmp >= 0) { + if (sess->rson[p] != LZHUF_NIL) + p = sess->rson[p]; + else { + sess->rson[p] = r; + sess->dad[r] = p; + return; + } + } else { + if (sess->lson[p] != LZHUF_NIL) + p = sess->lson[p]; + else { + sess->lson[p] = r; + sess->dad[r] = p; + return; + } + } + for (i = 1; i < LZHUF_F; i++) + if ((cmp = key[i] - sess->text_buf[p + i]) != 0) + break; + if (i > LZHUF_THRESHOLD) { + if (i > sess->match_length) { + sess->match_position = ((r - p) & (LZHUF_N - 1)) - 1; + if ((sess->match_length = i) >= LZHUF_F) + break; + } + if (i == sess->match_length) { + if ((c = ((r - p) & (LZHUF_N-1)) - 1) < (unsigned)sess->match_position) { + sess->match_position = c; + } + } + } + } + sess->dad[r] = sess->dad[p]; + sess->lson[r] = sess->lson[p]; + sess->rson[r] = sess->rson[p]; + sess->dad[sess->lson[p]] = r; + sess->dad[sess->rson[p]] = r; + if (sess->rson[sess->dad[p]] == p) + sess->rson[sess->dad[p]] = r; + else + sess->lson[sess->dad[p]] = r; + sess->dad[p] = LZHUF_NIL; /* remove p */ +} + +static void DeleteNode(lzhuf_session_t* sess, int p) /* remove from tree */ +{ + int q; + + if (sess->dad[p] == LZHUF_NIL) + return; /* not registered */ + if (sess->rson[p] == LZHUF_NIL) + q = sess->lson[p]; + else + if (sess->lson[p] == LZHUF_NIL) + q = sess->rson[p]; + else { + q = sess->lson[p]; + if (sess->rson[q] != LZHUF_NIL) { + do { + q = sess->rson[q]; + } while (sess->rson[q] != LZHUF_NIL); + sess->rson[sess->dad[q]] = sess->lson[q]; + sess->dad[sess->lson[q]] = sess->dad[q]; + sess->lson[q] = sess->lson[p]; + sess->dad[sess->lson[p]] = q; + } + sess->rson[q] = sess->rson[p]; + sess->dad[sess->rson[p]] = q; + } + sess->dad[q] = sess->dad[p]; + if (sess->rson[sess->dad[p]] == p) + sess->rson[sess->dad[p]] = q; + else + sess->lson[sess->dad[p]] = q; + sess->dad[p] = LZHUF_NIL; +} + + +/* table for encoding and decoding the upper 6 bits of position */ + +/* for encoding */ +static const unsigned char p_len[64] = { + 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 +}; + +static const unsigned char p_code[64] = { + 0x00, 0x20, 0x30, 0x40, 0x50, 0x58, 0x60, 0x68, + 0x70, 0x78, 0x80, 0x88, 0x90, 0x94, 0x98, 0x9C, + 0xA0, 0xA4, 0xA8, 0xAC, 0xB0, 0xB4, 0xB8, 0xBC, + 0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE, + 0xD0, 0xD2, 0xD4, 0xD6, 0xD8, 0xDA, 0xDC, 0xDE, + 0xE0, 0xE2, 0xE4, 0xE6, 0xE8, 0xEA, 0xEC, 0xEE, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF +}; + +/* for decoding */ +static const unsigned char d_code[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, + 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, + 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, + 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, + 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, + 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, + 0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B, + 0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F, + 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, + 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27, + 0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B, + 0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, +}; + +static const unsigned char d_len[256] = { + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, +}; + + +static int GetBit(lzhuf_session_t* sess) /* get one bit */ +{ + unsigned i; + + while (sess->getlen <= 8) { + if ((int)(i = h_getc(sess)) < 0) + i = 0; + sess->getbuf |= i << (8 - sess->getlen); + sess->getlen += 8; + } + i = sess->getbuf; + sess->getbuf <<= 1; + sess->getlen--; + return (int)((i & 0x8000) >> 15); +} + +static int GetByte(lzhuf_session_t* sess) /* get one byte */ +{ + unsigned i; + + while (sess->getlen <= 8) { + if ((int)(i = h_getc(sess)) < 0) + i = 0; + sess->getbuf |= i << (8 - sess->getlen); + sess->getlen += 8; + } + i = sess->getbuf; + sess->getbuf <<= 8; + sess->getlen -= 8; + return (int)((i & 0xff00) >> 8); +} + +static int Putcode(lzhuf_session_t* sess, int l, unsigned c) /* output c bits of code */ +{ + sess->putbuf |= c >> sess->putlen; + if ((sess->putlen += l) >= 8) { + if (h_putc(sess, (unsigned char)(sess->putbuf >> 8)) == EOF) + return -1; + if ((sess->putlen -= 8) >= 8) { + if (h_putc(sess, (unsigned char)sess->putbuf) == EOF) + return -1; + sess->codesize += 2; + sess->putlen -= 8; + sess->putbuf = c << (l - sess->putlen); + } else { + sess->putbuf <<= 8; + sess->codesize++; + } + } + return 0; +} + + +/* initialization of tree */ + +static void StartHuff(lzhuf_session_t* sess) +{ + int i, j; + + for (i = 0; i < LZHUF_N_CHAR; i++) { + sess->freq[i] = 1; + sess->son[i] = i + LZHUF_T; + sess->prnt[i + LZHUF_T] = i; + } + i = 0; j = LZHUF_N_CHAR; + while (j <= LZHUF_R) { + sess->freq[j] = sess->freq[i] + sess->freq[i + 1]; + sess->son[j] = i; + sess->prnt[i] = sess->prnt[i + 1] = j; + i += 2; j++; + } + sess->freq[LZHUF_T] = 0xffff; + sess->prnt[LZHUF_R] = 0; +} + + +/* reconstruction of tree */ + +static void reconst(lzhuf_session_t* sess) +{ + int i, j, k; + unsigned f, l; + + /* collect leaf nodes in the first half of the table */ + /* and replace the freq by (freq + 1) / 2. */ + j = 0; + for (i = 0; i < LZHUF_T; i++) { + if (sess->son[i] >= LZHUF_T) { + sess->freq[j] = (sess->freq[i] + 1) / 2; + sess->son[j] = sess->son[i]; + j++; + } + } + /* begin constructing tree by connecting sons */ + for (i = 0, j = LZHUF_N_CHAR; j < LZHUF_T; i += 2, j++) { + k = i + 1; + f = sess->freq[j] = sess->freq[i] + sess->freq[k]; + for (k = j - 1; f < sess->freq[k]; k--) + ; + k++; + l = j - k; + memmove(sess->freq + k + 1, sess->freq + k, l * sizeof(sess->freq[0])); + sess->freq[k] = f; + memmove(sess->son + k + 1, sess->son + k, l * sizeof(sess->son[0])); + sess->son[k] = i; + } + /* connect prnt */ + for (i = 0; i < LZHUF_T; i++) { + if ((k = sess->son[i]) >= LZHUF_T) { + sess->prnt[k] = i; + } else { + sess->prnt[k] = sess->prnt[k + 1] = i; + } + } +} + + +/* increment frequency of given code by one, and update tree */ + +static void update(lzhuf_session_t* sess, int c) +{ + int i, j, k, l; + + if (sess->freq[LZHUF_R] == LZHUF_MAX_FREQ) { + reconst(sess); + } + c = sess->prnt[c + LZHUF_T]; + do { + k = ++sess->freq[c]; + + /* if the order is disturbed, exchange nodes */ + if ((unsigned)k > sess->freq[l = c + 1]) { + while ((unsigned)k > sess->freq[++l]) + ; + l--; + sess->freq[c] = sess->freq[l]; + sess->freq[l] = k; + + i = sess->son[c]; + sess->prnt[i] = l; + if (i < LZHUF_T) + sess->prnt[i + 1] = l; + + j = sess->son[l]; + sess->son[l] = i; + + sess->prnt[j] = c; + if (j < LZHUF_T) + sess->prnt[j + 1] = c; + sess->son[c] = j; + + c = l; + } + } while ((c = sess->prnt[c]) != 0); /* repeat up to root */ +} + + +static void EncodeChar(lzhuf_session_t* sess, unsigned c) +{ + unsigned i; + int j, k; + + i = 0; + j = 0; + k = sess->prnt[c + LZHUF_T]; + + /* travel from leaf to root */ + do { + i >>= 1; + + /* if node's address is odd-numbered, choose bigger brother node */ + if (k & 1) + i += 0x8000; + + j++; + } while ((k = sess->prnt[k]) != LZHUF_R); + Putcode(sess, j, (i & 0xffff)); + update(sess, c); +} + +static void EncodePosition(lzhuf_session_t* sess, unsigned c) +{ + unsigned i; + + /* output upper 6 bits by table lookup */ + i = c >> 6; + Putcode(sess, p_len[i], (unsigned)p_code[i] << 8); + + /* output lower 6 bits verbatim */ + Putcode(sess, 6, (c & 0x3f) << 10); +} + +static int EncodeEnd(lzhuf_session_t* sess) +{ + if (sess->putlen) { + if (h_putc(sess, (unsigned char)(sess->putbuf >> 8)) == EOF) + return -1; + sess->codesize++; + } + return 0; +} + +static int DecodeChar(lzhuf_session_t* sess) +{ + unsigned c; + + c = sess->son[LZHUF_R]; + + /* travel from root to leaf, */ + /* choosing the smaller child node (son[]) if the read bit is 0, */ + /* the bigger (son[]+1} if 1 */ + while (c < LZHUF_T) { + c += GetBit(sess); + c = sess->son[c]; + } + c -= LZHUF_T; + update(sess, c); + return (int)c; +} + +static int DecodePosition(lzhuf_session_t* sess) +{ + unsigned i, j, c; + + /* recover upper 6 bits from table */ + i = GetByte(sess); + c = (unsigned)d_code[i] << 6; + j = d_len[i]; + + /* read lower 6 bits verbatim */ + j -= 2; + while (j--) { + i = (i << 1) + GetBit(sess); + } + return (int)(c | (i & 0x3f)); +} + +/* compression */ + +int lzhuf_encode(lzhuf_session_t* sess) /* compression */ +{ + int i, c, len, r, s, last_match_length; + unsigned long int textsize = 0; + int ret; + + h_seek(sess, sess->infile, 0L, SEEK_END); + textsize = h_tell(sess, sess->infile); + + if (h_putc(sess, (unsigned char)((textsize & 0xff))) == EOF || + h_putc(sess, (unsigned char)((textsize & 0xff00) >> 8)) == EOF || + h_putc(sess, (unsigned char)((textsize & 0xff0000L) >> 16)) == EOF || + h_putc(sess, (unsigned char)((textsize & 0xff000000L) >> 24)) == EOF) + return -1; + if (textsize == 0) + return 0; + h_seek(sess, sess->infile, 0L, SEEK_SET); + textsize = 0; /* rewind and re-read */ + StartHuff(sess); + InitTree(sess); + s = 0; + r = LZHUF_N - LZHUF_F; + for (i = s; i < r; i++) + sess->text_buf[i] = 0x20; + for (len = 0; len < LZHUF_F && (c = h_getc(sess)) != EOF; len++) + sess->text_buf[r + len] = (unsigned char)c; + textsize = len; + for (i = 1; i <= LZHUF_F; i++) + InsertNode(sess, r - i); + InsertNode(sess, r); + do { + if (sess->match_length > len) + sess->match_length = len; + if (sess->match_length <= LZHUF_THRESHOLD) { + sess->match_length = 1; + EncodeChar(sess, sess->text_buf[r]); + } else { + EncodeChar(sess, 255 - LZHUF_THRESHOLD + sess->match_length); + EncodePosition(sess, sess->match_position); + } + last_match_length = sess->match_length; + for (i = 0; i < last_match_length && (c = h_getc(sess)) != EOF; i++) { + DeleteNode(sess, s); + sess->text_buf[s] = (unsigned char)c; + if (s < LZHUF_F - 1) + sess->text_buf[s + LZHUF_N] = (unsigned char)c; + s = (s + 1) & (LZHUF_N - 1); + r = (r + 1) & (LZHUF_N - 1); + InsertNode(sess, r); + } + textsize += i; + while (i++ < last_match_length) { + DeleteNode(sess, s); + s = (s + 1) & (LZHUF_N - 1); + r = (r + 1) & (LZHUF_N - 1); + if (--len) + InsertNode(sess, r); + } + } while (len > 0); + + ret = EncodeEnd(sess); + + return ret; +} + +int lzhuf_decode(lzhuf_session_t* sess) /* recover */ +{ + int i, j, k, r, c; + unsigned long int count; + unsigned long int textsize = 0; + + if (EOF == (c = h_getc(sess))) + return -1; + textsize = c; + if (EOF == (c = h_getc(sess))) + return -1; + textsize |= (c << 8); + if (EOF == (c = h_getc(sess))) + return -1; + textsize |= (c << 16); + if (EOF == (c = h_getc(sess))) + return -1; + textsize |= (c << 24); + if (textsize == 0) + return 0; + StartHuff(sess); + for (i = 0; i < LZHUF_N - LZHUF_F; i++) + sess->text_buf[i] = 0x20; + r = LZHUF_N - LZHUF_F; + for (count = 0; count < textsize; ) { + c = DecodeChar(sess); + if (c < 256) { + if (h_putc(sess, (unsigned char)c) == EOF) + return -1; + sess->text_buf[r++] = (unsigned char)c; + r &= (LZHUF_N - 1); + count++; + } else { + i = (r - DecodePosition(sess) - 1) & (LZHUF_N - 1); + j = c - 255 + LZHUF_THRESHOLD; + for (k = 0; k < j; k++) { + c = sess->text_buf[(i + k) & (LZHUF_N - 1)]; + if (h_putc(sess, (unsigned char)c) == EOF) + return -1; + sess->text_buf[r++] = (unsigned char)c; + r &= (LZHUF_N - 1); + count++; + } + } + } + return 0; +} + +void lzhuf_startSession(lzhuf_session_t* sess) +{ + memset(sess, 0, sizeof(*sess)); +} + +void lzhuf_endSession(lzhuf_session_t* sess) +{ + // do nothing + (void)sess; +} diff --git a/tools/dos-ani/lzhuf.h b/tools/dos-ani/lzhuf.h new file mode 100755 index 000000000..e07a4aa1b --- /dev/null +++ b/tools/dos-ani/lzhuf.h @@ -0,0 +1,72 @@ +/************************************************************** + lzhuf.h + + Lib-like reentrant definition of lzhuf.c + Please see lzhuf.c for authorship info +**************************************************************/ + +#ifndef LZHUF_H_INCL_ +#define LZHUF_H_INCL_ + +/********** LZSS compression **********/ + +#define LZHUF_N 4096 /* buffer size */ +#define LZHUF_F 60 /* lookahead buffer size */ +#define LZHUF_THRESHOLD 2 +#define LZHUF_NIL LZHUF_N /* leaf of tree */ + +/* Huffman coding */ + +#define LZHUF_N_CHAR (256 - LZHUF_THRESHOLD + LZHUF_F) + /* kinds of characters (character code = 0..LZHUF_N_CHAR-1) */ +#define LZHUF_T (LZHUF_N_CHAR * 2 - 1) /* size of table */ +#define LZHUF_R (LZHUF_T - 1) /* position of root */ +#define LZHUF_MAX_FREQ 0x8000 /* updates tree when the */ + + +typedef void* lzhuf_handle_t; + +typedef struct +{ + unsigned long int codesize; + unsigned char text_buf[LZHUF_N + LZHUF_F - 1]; + int match_position; + int match_length; + int lson[LZHUF_N + 1]; + int rson[LZHUF_N + 257]; + int dad[LZHUF_N + 1]; + + unsigned freq[LZHUF_T + 1]; /* frequency table */ + + int prnt[LZHUF_T + LZHUF_N_CHAR]; /* pointers to parent nodes, except for the */ + /* elements [LZHUF_T..LZHUF_T + LZHUF_N_CHAR - 1] which are used to get */ + /* the positions of leaves corresponding to the codes. */ + + int son[LZHUF_T]; /* pointers to child nodes (son[], son[] + 1) */ + + unsigned getbuf; + unsigned char getlen; + + unsigned putbuf; + unsigned char putlen; + + /* user-settable data */ + void* userdata; + + lzhuf_handle_t infile; + lzhuf_handle_t outfile; + + size_t (* read)(void*, size_t, size_t, lzhuf_handle_t); + size_t (* write)(const void*, size_t, size_t, lzhuf_handle_t); + int (* seek)(lzhuf_handle_t, long, int); + long (* tell)(lzhuf_handle_t); + +} lzhuf_session_t; + +void lzhuf_startSession(lzhuf_session_t *); +void lzhuf_endSession(lzhuf_session_t *); +int lzhuf_encode(lzhuf_session_t *); /* compression */ +int lzhuf_decode(lzhuf_session_t *); /* recover */ + + +#endif /* LZHUF_H_INCL_ */ diff --git a/tools/dos-ani/undani.c b/tools/dos-ani/undani.c new file mode 100755 index 000000000..c7644a50e --- /dev/null +++ b/tools/dos-ani/undani.c @@ -0,0 +1,1368 @@ +/* + * DOS SC2 .ani file extractor + * By Alex Volkov (codepro@usa.net), 20050207 + + * -- Largely adapted from 'unani' by Serge van den Boom (svdb@stack.nl) + * -- Yet more stuff borrowed from FSCP by Mudry (mudronyl@dragon.klte.hu) + * -- Utilizes LZSS algorithm; + * code found at http://www.cs.umu.se/~isak/Snippets + * + * The GPL applies (to this file). + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(WIN32) && defined(_MSC_VER) +# include +# include +# define makedir(d) _mkdir(d) +# define inline __inline +#else +# include +# define makedir(d) mkdir(d, 0777) +#endif +#if defined(__GNUC__) +# include +# define inline __inline__ +#endif +#include +#include "lzhuf.h" + +#define countof(a) ( sizeof(a)/sizeof(*a) ) +#ifndef offsetof +# define offsetof(s,m) ( (size_t)(&((s*)0)->m) ) +#endif + +#if defined(_MSC_VER) +# define PACKED +# pragma pack(push, 1) +#elif defined(__GNUC__) +# define PACKED __attribute__((packed)) +#endif + +typedef struct +{ + uint32_t PACKED magic; // Always ffff + uint32_t PACKED z; // Always zero + uint16_t PACKED ofs; // Offset of data + uint16_t PACKED recs_and_flags; // bits 0..11: number of records; bits 12..15: flags +} header_t; + +#define HEADER_START sizeof(uint32_t) + +typedef struct +{ + int16_t x; + int16_t y; +} hotspot_t; + +typedef struct +{ + uint16_t w; + uint16_t h; +} bounds_t; + +typedef struct +{ + hotspot_t PACKED hotspot; + uint16_t PACKED zb; // Always zero + uint16_t PACKED zc; // Always zero + bounds_t PACKED bounds; + uint16_t PACKED flags; // Flags + uint16_t PACKED xsize8; // Width of 8bit image in bytes + uint32_t PACKED size8; // Size of 8bit image in bytes + uint16_t PACKED zj; // Always zero + uint16_t PACKED mflags; // Mask flags + uint16_t PACKED xsize1; // Width of 1bit image in bytes + uint16_t PACKED size1; // Size of 1bit image in bytes + uint16_t PACKED zn; // Always zero + uint16_t PACKED zo; // Always zero + uint16_t PACKED index; // frame index, only lower 12 bits used +} frame_desc_t; + +#define FTYPE_SHIFT 12 +#define FINDEX_MASK ((1 << FTYPE_SHIFT) - 1) +#define FTYPE_MASK (0xffff & ~FINDEX_MASK) + +#define TYPE_GET(f) (((f) & FTYPE_MASK) >> FTYPE_SHIFT) +#define INDEX_GET(f) ((f) & FINDEX_MASK) + +#define GFX_DATA_CHILD (1 << 8) +#define GFX_DATA_FLAG2 (1 << 9) +#define GFX_DATA_COMPRESSED (1 << 10) + +typedef struct +{ + frame_desc_t* desc; + uint32_t csize8; + uint8_t* data8; + uint32_t csize1; + uint8_t* data1; + int malloced; + int sx0, sx1; + int sy0, sy1; +} frame_info_t; + +typedef struct +{ + int32_t num_frames; + uint32_t data_ofs; + uint32_t flags; + frame_info_t* frames; +} index_header_t; + + +#define GFX_HAS_MASKS (1 << 0) +#define GFX_HAS_IMAGES (1 << 1) +#define GFX_HAS_COMPRESSED (1 << 2) + +#define PAL_COLORS 0x100 + +#if defined(_MSC_VER) +# pragma pack(pop) +#endif + +struct options +{ + char *infile; + char *outdir; + char *prefix; + int makeani; + int list; + int print; + int crop; + int verbose; + int plut; + int num_palettefiles; + char **palettefiles; +}; + +png_color palette[PAL_COLORS]; + +int verbose_level = 0; +void verbose(int level, const char* fmt, ...); + +index_header_t* readIndex(uint8_t *buf); +void freeIndex(index_header_t *); +void printIndex(const index_header_t* h, const uint8_t *buf, FILE *out); +void generateAni(const index_header_t* h, const char *prefix, int plut, FILE *out); +int findTransparentColour(const char *name, const frame_info_t* f); +void writeFiles(const index_header_t* h, const char *path, const char *prefix); +void parse_arguments(int argc, char *argv[], struct options *opts); +void listFrames(const index_header_t* h, FILE *out); +int loadPalette(const char *filename); +int decompressFrames(const index_header_t *); +int cropFrames(const index_header_t *); + +inline uint16_t get_16_le(uint16_t* val); +inline uint32_t get_32_le(uint32_t* val); + +int main(int argc, char *argv[]) +{ + FILE* in; + size_t inlen; + uint8_t *buf; + index_header_t *h; + struct options opts; + char *prefix; + + parse_arguments(argc, argv, &opts); + verbose_level = opts.verbose; + + in = fopen(opts.infile, "rb"); + if (!in) + { + verbose(1, "Error: Could not open file %s: %s\n", + opts.infile, strerror(errno)); + return EXIT_FAILURE; + } + + fseek(in, 0, SEEK_END); + inlen = ftell(in); + fseek(in, 0, SEEK_SET); + + buf = malloc(inlen); + if (!buf) + { + verbose(1, "Out of memory reading file\n"); + return EXIT_FAILURE; + } + if (inlen != fread(buf, 1, inlen, in)) + { + verbose(1, "Cannot read file '%s'\n", opts.infile); + return EXIT_FAILURE; + } + fclose(in); + + { + int i; + + memset(palette, 0, sizeof (palette)); + for (i = 0; i < opts.num_palettefiles; i++) + loadPalette(opts.palettefiles[i]); + } + + h = readIndex(buf); + if (opts.print) + printIndex(h, buf, stdout); + + if (opts.list) + listFrames(h, stdout); + + if (opts.prefix == NULL) + { + char *start, *end; + + start = strrchr(opts.infile, '/'); + if (start == NULL) { + start = opts.infile; + } else + start++; + end = strrchr(start, '.'); + if (end == NULL) + end = start + strlen(start); + prefix = alloca(end - start + 1); + memcpy(prefix, start, end - start); + prefix[end - start] = '\0'; + } else + prefix = opts.prefix; + + if (opts.makeani || (!opts.print && !opts.list)) + { + if (decompressFrames(h) != 0) + { + verbose(1, "Cannot decompress frames\n"); + return EXIT_FAILURE; + } + + if (opts.crop && cropFrames(h) != 0) + { + verbose(1, "Cannot crop frames\n"); + return EXIT_FAILURE; + } + } + + if (opts.makeani) + generateAni(h, prefix, opts.plut, stdout); + + if (!opts.print && !opts.list && !opts.makeani) + { + size_t len; + + len = strlen(opts.outdir); + if (opts.outdir[len - 1] == '/') + opts.outdir[len - 1] = '\0'; + + writeFiles(h, opts.outdir, prefix); + } + + freeIndex(h); + free(buf); + + return EXIT_SUCCESS; +} + +void verbose(int level, const char* fmt, ...) +{ + va_list args; + + if (verbose_level < level) + return; + + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); +} + +void usage() +{ + fprintf(stderr, + "undani -a [-m ] [-r] \n" + "undani -p \n" + "undani [-c ] [-r] [-o ] [-n ] \n" + "Options:\n" + "\t-a output .ani file\n" + "\t-p print header and frame info\n" + "\t-c load palette in dos format (multiple -c allowed)\n" + "\t-o stuff pngs into \n" + "\t-n name pngs ..png\n" + "\t-r crop the images removing edge rows and columns consisting\n" + "\t entirely of transparent color (affects hotspots with -a)\n" + "\t-v increase verbosity level (use more than once)\n" + ); +} + +void parse_arguments(int argc, char *argv[], struct options *opts) +{ + char ch; + + memset(opts, 0, sizeof (struct options)); + opts->plut = -1; + + while (-1 != (ch = getopt(argc, argv, "ac:h?ln:o:m:prv"))) + { + switch (ch) + { + case 'a': + opts->makeani = 1; + break; + case 'c': + opts->palettefiles = realloc(opts->palettefiles, + (opts->num_palettefiles + 1) * sizeof (char *)); + opts->palettefiles[opts->num_palettefiles] = optarg; + opts->num_palettefiles++; + break; + case 'l': + opts->list = 1; + break; + case 'o': + opts->outdir = optarg; + break; + case 'm': + opts->plut = atoi(optarg); + break; + case 'n': + opts->prefix = optarg; + break; + case 'p': + opts->print = 1; + break; + case 'r': + opts->crop = 1; + break; + case 'v': + opts->verbose++; + break; + case '?': + case 'h': + default: + usage(); + exit(EXIT_FAILURE); + } + } + argc -= optind; + argv += optind; + if (argc != 1) + { + usage(); + exit(EXIT_FAILURE); + } + opts->infile = argv[0]; + if (opts->outdir == NULL) + opts->outdir = "."; +} + +index_header_t* readIndex(uint8_t *buf) +{ + index_header_t *h; + const uint8_t *bufptr; + int i; + header_t* fh = (header_t*) buf; + uint32_t cofs; + uint32_t csize; + + h = malloc(sizeof (index_header_t)); + + // convert all from little endian + fh->magic = get_32_le(&fh->magic); + fh->z = get_32_le(&fh->z); + fh->ofs = get_16_le(&fh->ofs); + fh->recs_and_flags = get_16_le(&fh->recs_and_flags); + + if (fh->magic != 0xffffffff || fh->z != 0x00000000) + { + verbose(1, "File is not a valid dos .ani file.\n"); + exit(EXIT_FAILURE); + } + + h->num_frames = INDEX_GET(fh->recs_and_flags) + 1; + h->flags = TYPE_GET(fh->recs_and_flags); + h->data_ofs = HEADER_START + fh->ofs; + + bufptr = buf + sizeof(*fh); + h->frames = malloc(h->num_frames * sizeof (frame_info_t)); + if (!h->frames) + { + verbose(1, "Out of memory parsing frame descriptors\n"); + exit(EXIT_FAILURE); + } + memset(h->frames, 0, h->num_frames * sizeof (frame_info_t)); + + for (i = 0; i < h->num_frames; i++, bufptr += sizeof(frame_desc_t)) + { + frame_desc_t* desc = (frame_desc_t*) bufptr; + + // convert all from little endian + desc->hotspot.x = get_16_le(&desc->hotspot.x); + desc->hotspot.y = get_16_le(&desc->hotspot.y); + desc->bounds.w = get_16_le(&desc->bounds.w); + desc->bounds.h = get_16_le(&desc->bounds.h); + desc->flags = get_16_le(&desc->flags); + desc->xsize8 = get_16_le(&desc->xsize8); + desc->size8 = get_32_le(&desc->size8); + desc->mflags = get_16_le(&desc->mflags); + desc->xsize1 = get_16_le(&desc->xsize1); + desc->size1 = get_16_le(&desc->size1); + desc->index = get_16_le(&desc->index); + + if (desc->zb != 0 || desc->zc != 0 || desc->zj != 0 || desc->zn != 0 || desc->zo != 0) + { + verbose(1, "Error: one of zero fields is not zero in frame index %d\n", i); + exit(EXIT_FAILURE); + } + + h->frames[i].desc = desc; + } + + // read or compute offsets and sizes + cofs = h->data_ofs; + if (h->flags & GFX_HAS_MASKS) + { // all 1bit masks have to be processed first + for (i = 0; i < h->num_frames; ++i, cofs += csize) + { + frame_info_t* info = h->frames + i; + + if (info->desc->mflags & GFX_DATA_COMPRESSED) + { // compressed data + uint16_t* psize = (uint16_t*) (buf + cofs); + + csize = get_16_le(psize); + + info->data1 = buf + cofs + sizeof(*psize); + info->csize1 = csize - sizeof(*psize); + } + else + { // uncompressed data + info->data1 = buf + cofs; + info->csize1 = csize = info->desc->size1; + } + } + } + if (h->flags & GFX_HAS_IMAGES) + { // then all 8bit images + for (i = 0; i < h->num_frames; ++i, cofs += csize) + { + frame_info_t* info = h->frames + i; + + if (info->desc->flags & GFX_DATA_COMPRESSED) + { // compressed data + uint16_t* psize = (uint16_t*) (buf + cofs); + + csize = get_16_le(psize); + + info->data8 = buf + cofs + sizeof(*psize); + info->csize8 = csize - sizeof(*psize); + } + else + { // uncompressed data + info->data8 = buf + cofs; + info->csize8 = csize = info->desc->size8; + } + } + } + + return h; +} + +void freeFrame(frame_info_t* f) +{ + if ((f->malloced & 1) && f->data1) + free(f->data1); + if ((f->malloced & 2) && f->data8) + free(f->data8); +} + +void freeIndex(index_header_t* h) +{ + int i; + + if (!h) + return; + if (h->frames) + { + for (i = 0; i < h->num_frames; ++i) + freeFrame(h->frames + i); + + free(h->frames); + } + free(h); +} + +void printIndex(const index_header_t *h, const uint8_t *buf, FILE *out) +{ + fprintf(out, "0x%08x Number of frames: %d\n", + offsetof(header_t, recs_and_flags), + h->num_frames); + + fprintf(out, "0x%08x Flags: 0x%02x - %s%s%s\n", + offsetof(header_t, recs_and_flags), + h->flags, + (h->flags & GFX_HAS_COMPRESSED) ? + "HAS_COMPRESSED " : "", + (h->flags & GFX_HAS_MASKS) ? + "HAS_MASKS " : "", + (h->flags & GFX_HAS_IMAGES) ? + "HAS_IMAGES " : ""); + fprintf(out, "0x%08x frame info:\n", sizeof(header_t)); + { + int i; + + for (i = 0; i < h->num_frames; i++) + { + frame_desc_t* desc = h->frames[i].desc; + + fprintf(out, "0x%08x Frame %d:\n", (uint8_t*)desc - buf, + INDEX_GET(desc->index)); + + fprintf(out, "0x%08x Hotspot: (%d, %d)\n", (uint8_t*)&desc->hotspot - buf, + (int)desc->hotspot.x, (int)desc->hotspot.y); + fprintf(out, "0x%08x Size: %dx%d\n", (uint8_t*)&desc->bounds - buf, + (int)desc->bounds.w, (int)desc->bounds.h); + + fprintf(out, "0x%08x Flags: 0x%02x - %s%s%s\n", + (uint8_t*)&desc->flags - buf, + desc->flags, + (desc->flags & GFX_DATA_COMPRESSED) ? + "DATA_COMPRESSED " : "", + (desc->flags & GFX_DATA_FLAG2) ? + "DATA_FLAG2 " : "", + (desc->flags & GFX_DATA_CHILD) ? + "DATA_CHILD" : ""); + } + } +} + +void listFrames(const index_header_t* h, FILE *out) +{ + int i; + + for (i = 0; i < h->num_frames; i++) + { + frame_desc_t* desc = h->frames[i].desc; + + fprintf(out, "0x%04x %dx%d image, %s%s%s\n", + (int)INDEX_GET(desc->index), + (int)desc->bounds.w, (int)desc->bounds.h, + (desc->flags & GFX_DATA_COMPRESSED) ? + "DATA_COMPRESSED " : "", + (desc->flags & GFX_DATA_FLAG2) ? + "DATA_FLAG2 " : "", + (desc->flags & GFX_DATA_CHILD) ? + "DATA_CHILD" : ""); + } +} + +void generateAni(const index_header_t *h, const char *prefix, int plut, FILE *out) +{ + int i; + int transparentPixel = -1; + + for (i = 0; i < h->num_frames; i++) + { + frame_info_t* info = h->frames + i; + frame_desc_t* desc = info->desc; + int actplut; + + if ((h->flags & GFX_HAS_IMAGES) && (h->flags & GFX_HAS_MASKS)) + { + char tempbuf[sizeof("frame -2147483648")]; + sprintf(tempbuf, "frame %d", i); + transparentPixel = findTransparentColour(tempbuf, info); + actplut = plut; + } + else if (h->flags & GFX_HAS_MASKS) + { + transparentPixel = 0; // masks always have index 0 transparent + actplut = -1; // no colormap for masks + } + + fprintf(out, "%s.%d.%s %d %d %d %d\n", + prefix, (int)INDEX_GET(desc->index), + "png", transparentPixel, actplut, + (int)desc->hotspot.x - info->sx0, + (int)desc->hotspot.y - info->sy0); + } +} + +void writeFile(const char *file, const uint8_t *data, size_t len) +{ + FILE* f; + + // check if all the path components exist + { + const char *ptr; + char path[512]; + + ptr = file; + if (ptr[0] == '/') + ptr++; + while (1) { + ptr = strchr(ptr, '/'); + if (ptr == NULL) + break; + ptr++; + memcpy(path, file, ptr - file); + path[ptr - file] = '\0'; + if (makedir(path) == -1) + { + if (errno == EEXIST) + continue; + verbose(1, "Error: Could not make directory %s: %s\n", + path, strerror(errno)); + exit(EXIT_FAILURE); + } + } + } + + f = fopen(file, "wb"); + if (!f) + { + perror("Could not open file for writing"); + exit(EXIT_FAILURE); + } + while (len > 0) + { + size_t written; + written = fwrite(data, 1, len, f); + if (!written) + { + if (errno != EINTR) + { + perror("write failed"); + exit(1); + } + } + len -= written; + data += written; + } + fclose(f); +} + +// If there are no transparent pixels, returns -1 +// Otherwise, returns an index in the palette that is never used so can be +// used for transparancy. If all palette entries are used, a warning is +// printed and 0 is used. +int findTransparentColour(const char *name, const frame_info_t* f) +{ + const uint8_t *src1, *src8; + uint8_t mask; + int y, x, i; + int paletteUsed[PAL_COLORS]; + int haveTransparent; + + if (!f->data1) + return -1; // transparency is not used in this image + + memset(paletteUsed, 0, sizeof (paletteUsed)); + haveTransparent = 0; + + for (y = 0; y < (int)f->desc->bounds.h; ++y) + { + src1 = f->data1 + f->desc->xsize1 * y; + src8 = f->data8 + f->desc->xsize8 * y; + + for (x = 0, mask = 0x80; x < (int)f->desc->bounds.w; ++x, ++src8, mask >>= 1) + { + if (!mask) + { // next mask byte + mask = 0x80; + ++src1; + } + + if (*src1 & mask) + { // opaque pixel + paletteUsed[*src8] = 1; + } + else + { // transparent pixel + haveTransparent = 1; + } + } + } + + if (!haveTransparent) + return -1; + + for (i = 0; i < PAL_COLORS; i++) + { + if (!paletteUsed[i]) + return i; + } + verbose(2, "WARNING: Could not find an unused palette entry to use" + " for transparency for %s\n", name); + return -1; +} + +void writePaletted(const char *filename, const frame_info_t* f) +{ + frame_desc_t* desc = f->desc; + uint32_t bufsize; + uint8_t *buf; + const uint8_t *src8, *src1; + uint8_t mask; + uint8_t *dst; + uint8_t **lines; + int transparentPixel; + int x, y; + + transparentPixel = findTransparentColour(filename, f); + bufsize = desc->bounds.w * desc->bounds.h * sizeof(uint8_t); + buf = alloca(bufsize); + if (!buf) + { + verbose(1, "Out of stack while writing image\n"); + exit(EXIT_FAILURE); + } + memset(buf, 0, bufsize); + + lines = alloca(desc->bounds.h * sizeof(uint8_t *)); + + for (y = 0; y < (int)desc->bounds.h; ++y) + { + src1 = f->data1 + desc->xsize1 * y; + src8 = f->data8 + desc->xsize8 * y; + dst = buf + desc->bounds.w * y; + lines[y] = dst + f->sx0; + + for (x = 0, mask = 0x80; x < (int)desc->bounds.w; ++x, ++src8, ++dst, mask >>= 1) + { + if (!mask) + { // next mask byte + mask = 0x80; + ++src1; + } + + if (transparentPixel >= 0 && f->data1 && !(*src1 & mask)) + *dst = transparentPixel; + else + *dst = *src8; + } + } + + { + FILE *file; + png_structp png_ptr; + png_infop info_ptr; + png_color_8 sig_bit; + + png_ptr = png_create_write_struct + (PNG_LIBPNG_VER_STRING, (png_voidp) NULL /* user_error_ptr */, + NULL /* user_error_fn */, NULL /* user_warning_fn */); + if (!png_ptr) + { + verbose(1, "png_create_write_struct failed.\n"); + exit(EXIT_FAILURE); + } + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_write_struct(&png_ptr, (png_infopp) NULL); + verbose(1, "png_create_info_struct failed.\n"); + exit(EXIT_FAILURE); + } + if (setjmp(png_jmpbuf(png_ptr))) + { + verbose(1, "png error.\n"); + png_destroy_write_struct(&png_ptr, &info_ptr); + exit(EXIT_FAILURE); + } + + file = fopen(filename, "wb"); + if (!file) + { + verbose(1, "Could not open file '%s': %s\n", + filename, strerror(errno)); + png_destroy_write_struct(&png_ptr, &info_ptr); + exit(EXIT_FAILURE); + } + png_init_io(png_ptr, file); + png_set_IHDR(png_ptr, info_ptr, + desc->bounds.w - f->sx0 - f->sx1, + desc->bounds.h - f->sy0 - f->sy1, + 8 /* bit_depth per channel */, PNG_COLOR_TYPE_PALETTE, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + sig_bit.red = 8; + sig_bit.green = 8; + sig_bit.blue = 8; + png_set_sBIT(png_ptr, info_ptr, &sig_bit); + png_set_PLTE(png_ptr, info_ptr, palette, PAL_COLORS); + if (transparentPixel >= 0) + { // generate transparency chunk + // for indexed PNGs, tRNS chunk contains an array of + // alpha values corresponding to palette entries + png_byte trans[PAL_COLORS]; + // set all palette alpha values to 0xff initially + memset(trans, 0xff, PAL_COLORS * sizeof (png_byte)); + trans[transparentPixel] = 0; // the only one + // only need to write out upto and including transparentPixel + png_set_tRNS(png_ptr, info_ptr, trans, transparentPixel + 1, NULL); + } + png_write_info(png_ptr, info_ptr); + png_write_image(png_ptr, lines + f->sy0); + png_write_end(png_ptr, info_ptr); + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(file); + } +} + +#if 0 +// this version writes out 1bit PNGs +void writeBitmapMask(const char *filename, const frame_info_t* f) +{ + uint8_t **lines; + int y; + + lines = alloca(f->desc->bounds.h * sizeof (uint8_t *)); + + for (y = 0; y < (int)f->desc->bounds.h; ++y) + lines[y] = f->data1 + f->desc->xsize1 * y; + + { + FILE *file; + png_structp png_ptr; + png_infop info_ptr; + + png_ptr = png_create_write_struct + (PNG_LIBPNG_VER_STRING, (png_voidp) NULL /* user_error_ptr */, + NULL /* user_error_fn */, NULL /* user_warning_fn */); + if (!png_ptr) + { + verbose(1, "png_create_write_struct failed.\n"); + exit(EXIT_FAILURE); + } + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_write_struct(&png_ptr, (png_infopp) NULL); + verbose(1, "png_create_info_struct failed.\n"); + exit(EXIT_FAILURE); + } + if (setjmp(png_jmpbuf(png_ptr))) + { + verbose(1, "png error.\n"); + png_destroy_write_struct(&png_ptr, &info_ptr); + exit(EXIT_FAILURE); + } + + file = fopen(filename, "wb"); + if (!file) + { + verbose(1, "Could not open file '%s': %s\n", + filename, strerror(errno)); + png_destroy_write_struct(&png_ptr, &info_ptr); + exit(EXIT_FAILURE); + } + png_init_io(png_ptr, file); + png_set_IHDR(png_ptr, info_ptr, f->desc->bounds.w, f->desc->bounds.h, + 1 /* bit_depth per channel */, PNG_COLOR_TYPE_GRAY, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + png_write_info(png_ptr, info_ptr); + png_write_image(png_ptr, (png_byte **) lines); + png_write_end(png_ptr, info_ptr); + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(file); + } +} +#else +// this version writes out 8bit PNGs with 2-color pal +void writeBitmapMask(const char *filename, const frame_info_t* f) +{ + frame_desc_t* desc = f->desc; + uint32_t bufsize; + uint8_t *buf; + const uint8_t *src1; + uint8_t mask; + uint8_t *dst; + uint8_t **lines; + int x, y; + + bufsize = desc->bounds.w * desc->bounds.h * sizeof(uint8_t); + buf = alloca(bufsize); + if (!buf) + { + verbose(1, "Out of stack while writing image\n"); + exit(EXIT_FAILURE); + } + memset(buf, 0, bufsize); + + lines = alloca(desc->bounds.h * sizeof(uint8_t *)); + + for (y = 0; y < (int)desc->bounds.h; ++y) + { + src1 = f->data1 + desc->xsize1 * y; + dst = buf + desc->bounds.w * y; + lines[y] = dst + f->sx0; + + for (x = 0, mask = 0x80; x < (int)desc->bounds.w; ++x, ++dst, mask >>= 1) + { + if (!mask) + { // next mask byte + mask = 0x80; + ++src1; + } + + *dst = (*src1 & mask) ? 1 : 0; + } + } + + { + FILE *file; + png_structp png_ptr; + png_infop info_ptr; + png_color_8 sig_bit; + png_color bmppal[2] = {{0x00, 0x00, 0x00}, {0xff, 0xff, 0xff}}; + png_byte trans[2] = {0x00, 0xff}; + + png_ptr = png_create_write_struct + (PNG_LIBPNG_VER_STRING, (png_voidp) NULL /* user_error_ptr */, + NULL /* user_error_fn */, NULL /* user_warning_fn */); + if (!png_ptr) + { + verbose(1, "png_create_write_struct failed.\n"); + exit(EXIT_FAILURE); + } + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_write_struct(&png_ptr, (png_infopp) NULL); + verbose(1, "png_create_info_struct failed.\n"); + exit(EXIT_FAILURE); + } + if (setjmp(png_jmpbuf(png_ptr))) + { + verbose(1, "png error.\n"); + png_destroy_write_struct(&png_ptr, &info_ptr); + exit(EXIT_FAILURE); + } + + file = fopen(filename, "wb"); + if (!file) + { + verbose(1, "Could not open file '%s': %s\n", + filename, strerror(errno)); + png_destroy_write_struct(&png_ptr, &info_ptr); + exit(EXIT_FAILURE); + } + png_init_io(png_ptr, file); + png_set_IHDR(png_ptr, info_ptr, + desc->bounds.w - f->sx0 - f->sx1, + desc->bounds.h - f->sy0 - f->sy1, + 8 /* bit_depth per channel */, PNG_COLOR_TYPE_PALETTE, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + sig_bit.red = 8; + sig_bit.green = 8; + sig_bit.blue = 8; + png_set_sBIT(png_ptr, info_ptr, &sig_bit); + png_set_PLTE(png_ptr, info_ptr, bmppal, 2); + // generate transparency chunk + // only need to write out upto and including transparent index + png_set_tRNS(png_ptr, info_ptr, trans, 1, NULL); + png_write_info(png_ptr, info_ptr); + png_write_image(png_ptr, lines + f->sy0); + png_write_end(png_ptr, info_ptr); + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(file); + } +} +#endif // 0 or 1 + +void writeFiles(const index_header_t *h, const char *path, const char *prefix) +{ + int i; + char filename[512]; + + for (i = 0; i < h->num_frames; i++) + { + frame_desc_t* desc = h->frames[i].desc; + + sprintf(filename, "%s/%s.%d.", + path, prefix, (int)INDEX_GET(desc->index)); + if (desc->flags & GFX_DATA_FLAG2) + { + verbose(2, "Do not know the meaning of DATA_FLAG2, image index %d\n", i); + } + else if (h->flags & GFX_HAS_IMAGES) + { + strcat(filename, "png"); + writePaletted(filename, h->frames + i); + } + else if (h->flags & GFX_HAS_MASKS) + { + strcat(filename, "png"); + writeBitmapMask(filename, h->frames + i); + } + else + { + verbose(2, "Huh? Nothing in the frame pack? (Flags=%0x02x)\n", h->flags); + return; + } + } +} + +typedef struct +{ + uint8_t* buf; + long len; + long ptr; +} decomp_handle_t; + +size_t decRead(void* buf, size_t size, size_t count, lzhuf_handle_t h) +{ + decomp_handle_t* p = (decomp_handle_t*)h; + long cb; + size_t crec; + + cb = count * size; + if (cb > p->len - p->ptr) + cb = p->len - p->ptr; + crec = cb / size; + cb = crec * size; + if (!cb) + return 0; + + memcpy(buf, p->buf + p->ptr, cb); + p->ptr += cb; + + return crec; +} + +size_t decWrite(const void* buf, size_t size, size_t count, lzhuf_handle_t h) +{ + decomp_handle_t* p = (decomp_handle_t*)h; + long cb; + size_t crec; + + cb = count * size; + if (cb > p->len - p->ptr) + cb = p->len - p->ptr; + crec = cb / size; + cb = crec * size; + if (!cb) + return 0; + + memcpy(p->buf + p->ptr, buf, cb); + p->ptr += cb; + + return crec; +} + +int decSeek(lzhuf_handle_t h, long ofs, int origin) +{ + decomp_handle_t* p = (decomp_handle_t*)h; + long newptr; + + switch (origin) + { + case SEEK_SET: + newptr = ofs; + break; + case SEEK_CUR: + newptr = p->ptr + ofs; + break; + case SEEK_END: + newptr = p->len + ofs; + break; + } + if (newptr < 0 || newptr > p->len) + return EOF; + p->ptr = newptr; + return 0; +} + +long decTell(lzhuf_handle_t h) +{ + decomp_handle_t* p = (decomp_handle_t*)h; + return p->ptr; +} + +int decompressData(uint8_t* src, uint32_t srclen, uint8_t* dst, uint32_t dstlen) +{ + lzhuf_session_t sess; + decomp_handle_t readh = {src, srclen, 0}; + decomp_handle_t writeh = {dst, dstlen, 0}; + int ret; + + lzhuf_startSession(&sess); + sess.infile = &readh; + sess.outfile = &writeh; + sess.read = decRead; + sess.write = decWrite; + sess.seek = decSeek; + sess.tell = decTell; + ret = lzhuf_decode(&sess); + lzhuf_endSession(&sess); + + if (ret != 0) + return EXIT_FAILURE; + + return writeh.ptr; +} + +inline uint32_t getLzDecompressedSize(void* lzdata) +{ + return get_32_le((uint32_t*)lzdata); +} + +int decompressFrames(const index_header_t* h) +{ +#define DEC_REASONABLE_SIZE 0x100000 + int i; + + for (i = 0; i < h->num_frames; i++) + { + frame_info_t* info = h->frames + i; + frame_desc_t* desc = info->desc; + + if ((desc->mflags & GFX_DATA_COMPRESSED) && info->csize1 != 0 && info->data1 != 0) + { + int declen; + uint32_t buflen = desc->size1; + uint8_t* buf = 0; + uint32_t lzlen = getLzDecompressedSize(info->data1); + + if (buflen != lzlen) + verbose(2, "WARNING: decompressed size in LZ data does not match the descriptor, frame index %d\n", i); + if (buflen < lzlen) + buflen = lzlen; + if (buflen > DEC_REASONABLE_SIZE) + buflen = DEC_REASONABLE_SIZE; + buf = malloc(buflen); + if (!buf) + { + verbose(1, "Out of memory decompressing mask bitmap, frame index %d\n", i); + return EXIT_FAILURE; + } + + declen = decompressData(info->data1, info->csize1, buf, buflen); + if (declen <= 0) + { + verbose(1, "Decompression of mask bitmap failed, frame index %d\n", i); + free(buf); + return EXIT_FAILURE; + } + if (declen != (int)desc->size1) + verbose(2, "WARNING: Decompressed mask bitmap data length does not match the descriptor, frame index %d\n", i); + + info->malloced |= 1; + info->data1 = realloc(buf, declen); + info->csize1 = declen; + } + + if ((desc->flags & GFX_DATA_COMPRESSED) && info->csize8 != 0 && info->data8 != 0) + { + int declen; + uint32_t buflen = desc->size8; + uint8_t* buf = 0; + uint32_t lzlen = getLzDecompressedSize(info->data8); + + if (buflen != lzlen) + verbose(2, "WARNING: decompressed size in LZ data does not match the descriptor, frame index %d\n", i); + if (buflen < lzlen) + buflen = lzlen; + if (buflen > DEC_REASONABLE_SIZE) + buflen = DEC_REASONABLE_SIZE; + buf = malloc(buflen); + if (!buf) + { + verbose(1, "Out of memory decompressing image, frame index %d\n", i); + return EXIT_FAILURE; + } + + declen = decompressData(h->frames[i].data8, h->frames[i].csize8, buf, buflen); + if (declen <= 0) + { + verbose(1, "Decompression of image failed, frame index %d\n", i); + free(buf); + return EXIT_FAILURE; + } + if (declen != (int)desc->size8) + verbose(2, "WARNING: Decompressed image data length does not match the descriptor, frame index %d\n", i); + + info->malloced |= 2; + info->data8 = realloc(buf, declen); + info->csize8 = declen; + } + } + + return 0; +} + +int cropFrame(frame_info_t* f) +{ + frame_desc_t* desc = f->desc; + const uint8_t *src1; + uint8_t mask; + int y, x; + int mcx0, mcx1, mcy0, mcy1; + int cx0, cx1; + int sawOpaqueX, sawOpaqueY; + + if (!f->data1) + return 0; // cannot crop - transparency is not used in this image + + mcx0 = mcx1 = desc->bounds.w; + mcy0 = mcy1 = 0; + + sawOpaqueY = 0; + + for (y = 0; y < (int)f->desc->bounds.h; ++y) + { + src1 = f->data1 + f->desc->xsize1 * y; + + sawOpaqueX = 0; + cx0 = cx1 = 0; + + for (x = 0, mask = 0x80; x < (int)f->desc->bounds.w; ++x, mask >>= 1) + { + if (!mask) + { // next mask byte + mask = 0x80; + ++src1; + } + + if (*src1 & mask) + { // opaque pixel + sawOpaqueX = 1; + cx1 = 0; + } + else + { // transparent pixel + if (sawOpaqueX) + cx1++; + else + cx0++; + } + } + + if (cx0 < mcx0) + mcx0 = cx0; + if (cx1 < mcx1 && cx0 < desc->bounds.w) + mcx1 = cx1; + + if (sawOpaqueX) + { + sawOpaqueY = 1; + mcy1 = 0; + } + else + mcy1++; + + if (!sawOpaqueY) + mcy0++; + } + + if (mcy0 == desc->bounds.h) + { // no opaque pixels!? + verbose(2, "WARNING: Completely empty image detected\n"); + // generate a 1x1 image + mcx0 = 0; + mcx1 = desc->bounds.w - 1; + mcy0 = 0; + mcy1 = desc->bounds.h - 1; + } + + f->sx0 = mcx0; + f->sx1 = mcx1; + f->sy0 = mcy0; + f->sy1 = mcy1; + + return (mcx0 + mcx1 + mcy0 + mcy1 != 0); +} + +int cropFrames(const index_header_t* h) +{ + int i; + + if (!(h->flags & GFX_HAS_MASKS)) + return 0; // cannot crop w/o masks + + for (i = 0; i < h->num_frames; i++) + { + frame_info_t* info = h->frames + i; + //frame_desc_t* desc = info->desc; + int cropped; + + //if ((h->flags & GFX_HAS_IMAGES) && !(desc->flags & GFX_DATA_MASK)) + // continue; + + cropped = cropFrame(info); + if (cropped) + verbose(2, "Frame %02d cropped x0=%d x1=%d y0=%d y1=%d\n", + i, info->sx0, info->sx1, info->sy0, info->sy1); + } + + return 0; +} + +int loadPalette(const char *filename) +{ + FILE* in; + size_t inlen; + uint8_t *buf, *clr; + int i; + + in = fopen(filename, "rb"); + if (!in) + { + verbose(1, "Error: Could not open file %s: %s\n", filename, + strerror(errno)); + return EXIT_FAILURE; + } + + fseek(in, 0, SEEK_END); + inlen = ftell(in); + fseek(in, 0, SEEK_SET); + + buf = malloc(inlen); + if (!buf) + { + verbose(1, "Out of memory reading file\n"); + fclose(in); + return EXIT_FAILURE; + } + if (inlen != fread(buf, 1, inlen, in)) + { + verbose(1, "Cannot read file '%s'\n", filename); + fclose(in); + return EXIT_FAILURE; + } + fclose(in); + + verbose(2, "%s contains %d palette entries\n", + filename, (int)buf[1] - buf[0] + 1); + + for (i = buf[0], clr = buf + 2; i <= (int)buf[1]; ++i, clr += 3) + { + palette[i].red = clr[0] << 2; + palette[i].green = clr[1] << 2; + palette[i].blue = clr[2] << 2; + } + + free(buf); + + return 0; +} + +inline uint16_t get_16_le(uint16_t* val) +{ + return (uint16_t)(((uint8_t*)val)[1]) << 8 | ((uint8_t*)val)[0]; +} + +inline uint32_t get_32_le(uint32_t* val) +{ + return (uint32_t)(((uint16_t*)val)[1]) << 16 | ((uint16_t*)val)[0]; +} diff --git a/tools/dos-ani/undani.dsp b/tools/dos-ani/undani.dsp new file mode 100755 index 000000000..983c05ac3 --- /dev/null +++ b/tools/dos-ani/undani.dsp @@ -0,0 +1,114 @@ +# Microsoft Developer Studio Project File - Name="undani" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=undani - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "undani.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "undani.mak" CFG="undani - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "undani - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "undani - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=xicl6.exe +RSC=rc.exe + +!IF "$(CFG)" == "undani - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\src\getopt" /I "." /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "PNG_USE_DLL" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=xilink6.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib advapi32.lib shell32.lib libpng10.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "undani - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MD /W3 /Gm /GX /ZI /Od /I "..\..\src\getopt" /I "." /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "PNG_USE_DLL" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=xilink6.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib advapi32.lib shell32.lib libpng10.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "undani - Win32 Release" +# Name "undani - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\config.h +# End Source File +# Begin Source File + +SOURCE=..\..\src\getopt\getopt.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\getopt\getopt.h +# End Source File +# Begin Source File + +SOURCE=.\lzhuf.c +# End Source File +# Begin Source File + +SOURCE=.\lzhuf.h +# End Source File +# Begin Source File + +SOURCE=.\undani.c +# End Source File +# End Group +# End Target +# End Project diff --git a/tools/dos-ani/undani.dsw b/tools/dos-ani/undani.dsw new file mode 100755 index 000000000..10210acc9 --- /dev/null +++ b/tools/dos-ani/undani.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "undani"=.\undani.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### +