home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-03-27 | 53.7 KB | 1,830 lines |
- Newsgroups: comp.sources.misc
- From: jpeg-info@uunet.uu.net (Independent JPEG Group)
- Subject: v29i012: jpeg - JPEG image compression, Part12/18
- Message-ID: <1992Mar25.145246.512@sparky.imd.sterling.com>
- X-Md4-Signature: 0d9a9e7a1e09e2d4f2267531baf9d1bb
- Date: Wed, 25 Mar 1992 14:52:46 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: jpeg-info@uunet.uu.net (Independent JPEG Group)
- Posting-number: Volume 29, Issue 12
- Archive-name: jpeg/part12
- Environment: UNIX, VMS, MS-DOS, Mac, Amiga, Cray
-
- #! /bin/sh
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # The tool that generated this appeared in the comp.sources.unix newsgroup;
- # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
- # Contents: ansi2knr.c jmemansi.c jmemdos.c jversion.h jwrjfif.c
- # Wrapped by kent@sparky on Mon Mar 23 16:02:50 1992
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- echo If this archive is complete, you will see the following message:
- echo ' "shar: End of archive 12 (of 18)."'
- if test -f 'ansi2knr.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'ansi2knr.c'\"
- else
- echo shar: Extracting \"'ansi2knr.c'\" \(16258 characters\)
- sed "s/^X//" >'ansi2knr.c' <<'END_OF_FILE'
- X/*
- X * Received from Peter Deutsch (ghost@aladdin.com)
- X * Fri, 26 Apr 91 10:10:10 PDT
- X * Small portability improvements by Tom Lane
- X */
- X
- X/* Copyright (C) 1989, 1991 Aladdin Enterprises. All rights reserved.
- X Distributed by Free Software Foundation, Inc.
- X
- XThis file is part of Ghostscript.
- X
- XGhostscript is distributed in the hope that it will be useful, but
- XWITHOUT ANY WARRANTY. No author or distributor accepts responsibility
- Xto anyone for the consequences of using it or for whether it serves any
- Xparticular purpose or works at all, unless he says so in writing. Refer
- Xto the Ghostscript General Public License for full details.
- X
- XEveryone is granted permission to copy, modify and redistribute
- XGhostscript, but only under the conditions described in the Ghostscript
- XGeneral Public License. A copy of this license is supposed to have been
- Xgiven to you along with Ghostscript so you can know your rights and
- Xresponsibilities. It should be in a file named COPYING. Among other
- Xthings, the copyright notice and this notice must be preserved on all
- Xcopies. */
- X
- X/*
- X---------- Here is the GhostScript file COPYING, referred to above ----------
- X----- These terms do NOT apply to the JPEG software itself; see README ------
- X
- X GHOSTSCRIPT GENERAL PUBLIC LICENSE
- X (Clarified 11 Feb 1988)
- X
- X Copyright (C) 1988 Richard M. Stallman
- X Everyone is permitted to copy and distribute verbatim copies of this
- X license, but changing it is not allowed. You can also use this wording
- X to make the terms for other programs.
- X
- X The license agreements of most software companies keep you at the
- Xmercy of those companies. By contrast, our general public license is
- Xintended to give everyone the right to share Ghostscript. To make sure
- Xthat you get the rights we want you to have, we need to make
- Xrestrictions that forbid anyone to deny you these rights or to ask you
- Xto surrender the rights. Hence this license agreement.
- X
- X Specifically, we want to make sure that you have the right to give
- Xaway copies of Ghostscript, that you receive source code or else can get
- Xit if you want it, that you can change Ghostscript or use pieces of it
- Xin new free programs, and that you know you can do these things.
- X
- X To make sure that everyone has such rights, we have to forbid you to
- Xdeprive anyone else of these rights. For example, if you distribute
- Xcopies of Ghostscript, you must give the recipients all the rights that
- Xyou have. You must make sure that they, too, receive or can get the
- Xsource code. And you must tell them their rights.
- X
- X Also, for our own protection, we must make certain that everyone finds
- Xout that there is no warranty for Ghostscript. If Ghostscript is
- Xmodified by someone else and passed on, we want its recipients to know
- Xthat what they have is not what we distributed, so that any problems
- Xintroduced by others will not reflect on our reputation.
- X
- X Therefore we (Richard M. Stallman and the Free Software Foundation,
- XInc.) make the following terms which say what you must do to be allowed
- Xto distribute or change Ghostscript.
- X
- X
- X COPYING POLICIES
- X
- X 1. You may copy and distribute verbatim copies of Ghostscript source
- Xcode as you receive it, in any medium, provided that you conspicuously
- Xand appropriately publish on each copy a valid copyright and license
- Xnotice "Copyright (C) 1989 Aladdin Enterprises. All rights reserved.
- XDistributed by Free Software Foundation, Inc." (or with whatever year is
- Xappropriate); keep intact the notices on all files that refer to this
- XLicense Agreement and to the absence of any warranty; and give any other
- Xrecipients of the Ghostscript program a copy of this License Agreement
- Xalong with the program. You may charge a distribution fee for the
- Xphysical act of transferring a copy.
- X
- X 2. You may modify your copy or copies of Ghostscript or any portion of
- Xit, and copy and distribute such modifications under the terms of
- XParagraph 1 above, provided that you also do the following:
- X
- X a) cause the modified files to carry prominent notices stating
- X that you changed the files and the date of any change; and
- X
- X b) cause the whole of any work that you distribute or publish,
- X that in whole or in part contains or is a derivative of Ghostscript
- X or any part thereof, to be licensed at no charge to all third
- X parties on terms identical to those contained in this License
- X Agreement (except that you may choose to grant more extensive
- X warranty protection to some or all third parties, at your option).
- X
- X c) You may charge a distribution fee for the physical act of
- X transferring a copy, and you may at your option offer warranty
- X protection in exchange for a fee.
- X
- XMere aggregation of another unrelated program with this program (or its
- Xderivative) on a volume of a storage or distribution medium does not bring
- Xthe other program under the scope of these terms.
- X
- X 3. You may copy and distribute Ghostscript (or a portion or derivative
- Xof it, under Paragraph 2) in object code or executable form under the
- Xterms of Paragraphs 1 and 2 above provided that you also do one of the
- Xfollowing:
- X
- X a) accompany it with the complete corresponding machine-readable
- X source code, which must be distributed under the terms of
- X Paragraphs 1 and 2 above; or,
- X
- X b) accompany it with a written offer, valid for at least three
- X years, to give any third party free (except for a nominal
- X shipping charge) a complete machine-readable copy of the
- X corresponding source code, to be distributed under the terms of
- X Paragraphs 1 and 2 above; or,
- X
- X c) accompany it with the information you received as to where the
- X corresponding source code may be obtained. (This alternative is
- X allowed only for noncommercial distribution and only if you
- X received the program in object code or executable form alone.)
- X
- XFor an executable file, complete source code means all the source code for
- Xall modules it contains; but, as a special exception, it need not include
- Xsource code for modules which are standard libraries that accompany the
- Xoperating system on which the executable file runs.
- X
- X 4. You may not copy, sublicense, distribute or transfer Ghostscript
- Xexcept as expressly provided under this License Agreement. Any attempt
- Xotherwise to copy, sublicense, distribute or transfer Ghostscript is
- Xvoid and your rights to use the program under this License agreement
- Xshall be automatically terminated. However, parties who have received
- Xcomputer software programs from you with this License Agreement will not
- Xhave their licenses terminated so long as such parties remain in full
- Xcompliance.
- X
- X 5. If you wish to incorporate parts of Ghostscript into other free
- Xprograms whose distribution conditions are different, write to the Free
- XSoftware Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not
- Xyet worked out a simple rule that can be stated here, but we will often
- Xpermit this. We will be guided by the two goals of preserving the free
- Xstatus of all derivatives of our free software and of promoting the
- Xsharing and reuse of software.
- X
- XYour comments and suggestions about our licensing policies and our
- Xsoftware are welcome! Please contact the Free Software Foundation,
- XInc., 675 Mass Ave, Cambridge, MA 02139, or call (617) 876-3296.
- X
- X NO WARRANTY
- X
- X BECAUSE GHOSTSCRIPT IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
- XNO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT
- XWHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC, RICHARD
- XM. STALLMAN, ALADDIN ENTERPRISES, L. PETER DEUTSCH, AND/OR OTHER PARTIES
- XPROVIDE GHOSTSCRIPT "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
- XEXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- XWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
- XENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF GHOSTSCRIPT IS WITH
- XYOU. SHOULD GHOSTSCRIPT PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
- XNECESSARY SERVICING, REPAIR OR CORRECTION.
- X
- X IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
- XSTALLMAN, THE FREE SOFTWARE FOUNDATION, INC., L. PETER DEUTSCH, ALADDIN
- XENTERPRISES, AND/OR ANY OTHER PARTY WHO MAY MODIFY AND REDISTRIBUTE
- XGHOSTSCRIPT AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING
- XANY LOST PROFITS, LOST MONIES, OR OTHER SPECIAL, INCIDENTAL OR
- XCONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
- X(INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
- XINACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR A FAILURE OF THE
- XPROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) GHOSTSCRIPT, EVEN IF YOU
- XHAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM
- XBY ANY OTHER PARTY.
- X-------------------- End of file COPYING ------------------------------
- X*/
- X
- X
- X/* ansi2knr.c */
- X/* Convert ANSI function declarations to K&R syntax */
- X
- X#include <stdio.h>
- X#include <ctype.h>
- X
- X#ifdef BSD
- X#include <strings.h>
- X#define strchr index
- X#else
- X#ifdef VMS
- X extern char *strcat(), *strchr(), *strcpy(), *strupr();
- X extern int strcmp(), strlen(), strncmp();
- X#else
- X#include <string.h>
- X#endif
- X#endif
- X
- X#ifdef MSDOS
- X#include <malloc.h>
- X#else
- X#ifdef VMS
- X extern char *malloc();
- X extern void free();
- X#else
- X extern char *malloc();
- X extern int free();
- X#endif
- X#endif
- X
- X/* Usage:
- X ansi2knr input_file output_file
- X * If no output_file is supplied, output goes to stdout.
- X * There are no error messages.
- X *
- X * ansi2knr recognizes functions by seeing a non-keyword identifier
- X * at the left margin, followed by a left parenthesis,
- X * with a right parenthesis as the last character on the line.
- X * It will recognize a multi-line header if the last character
- X * on each line but the last is a left parenthesis or comma.
- X * These algorithms ignore whitespace and comments, except that
- X * the function name must be the first thing on the line.
- X * The following constructs will confuse it:
- X - Any other construct that starts at the left margin and
- X follows the above syntax (such as a macro or function call).
- X - Macros that tinker with the syntax of the function header.
- X */
- X
- X/* Scanning macros */
- X#define isidchar(ch) (isalnum(ch) || (ch) == '_')
- X#define isidfirstchar(ch) (isalpha(ch) || (ch) == '_')
- X
- Xint
- Xmain(argc, argv)
- X int argc;
- X char *argv[];
- X{ FILE *in, *out;
- X#define bufsize 500 /* arbitrary size */
- X char buf[bufsize+1];
- X char *line;
- X switch ( argc )
- X {
- X default:
- X printf("Usage: ansi2knr input_file [output_file]\n");
- X exit(0);
- X case 2:
- X out = stdout; break;
- X case 3:
- X out = fopen(argv[2], "w");
- X if ( out == NULL )
- X { fprintf(stderr, "Cannot open %s\n", argv[2]);
- X exit(1);
- X }
- X }
- X in = fopen(argv[1], "r");
- X if ( in == NULL )
- X { fprintf(stderr, "Cannot open %s\n", argv[1]);
- X exit(1);
- X }
- X fprintf(out, "#line 1 \"%s\"\n", argv[1]);
- X line = buf;
- X while ( fgets(line, (unsigned)(buf + bufsize - line), in) != NULL )
- X { switch ( test1(buf) )
- X {
- X case 1: /* a function */
- X convert1(buf, out);
- X break;
- X case -1: /* maybe the start of a function */
- X line = buf + strlen(buf);
- X continue;
- X default: /* not a function */
- X fputs(buf, out);
- X break;
- X }
- X line = buf;
- X }
- X if ( line != buf ) fputs(buf, out);
- X fclose(out);
- X fclose(in);
- X return 0;
- X}
- X
- X/* Skip over space and comments, in either direction. */
- Xchar *
- Xskipspace(p, dir)
- X register char *p;
- X register int dir; /* 1 for forward, -1 for backward */
- X{ for ( ; ; )
- X { while ( isspace(*p) ) p += dir;
- X if ( !(*p == '/' && p[dir] == '*') ) break;
- X p += dir; p += dir;
- X while ( !(*p == '*' && p[dir] == '/') )
- X { if ( *p == 0 ) return p; /* multi-line comment?? */
- X p += dir;
- X }
- X p += dir; p += dir;
- X }
- X return p;
- X}
- X
- X/*
- X * Write blanks over part of a string.
- X */
- Xint
- Xwriteblanks(start, end)
- X char *start;
- X char *end;
- X{ char *p;
- X for ( p = start; p < end; p++ ) *p = ' ';
- X return 0;
- X}
- X
- X/*
- X * Test whether the string in buf is a function definition.
- X * The string may contain and/or end with a newline.
- X * Return as follows:
- X * 0 - definitely not a function definition;
- X * 1 - definitely a function definition;
- X * -1 - may be the beginning of a function definition,
- X * append another line and look again.
- X */
- Xint
- Xtest1(buf)
- X char *buf;
- X{ register char *p = buf;
- X char *bend;
- X char *endfn;
- X int contin;
- X if ( !isidfirstchar(*p) )
- X return 0; /* no name at left margin */
- X bend = skipspace(buf + strlen(buf) - 1, -1);
- X switch ( *bend )
- X {
- X case ')': contin = 1; break;
- X case '(':
- X case ',': contin = -1; break;
- X default: return 0; /* not a function */
- X }
- X while ( isidchar(*p) ) p++;
- X endfn = p;
- X p = skipspace(p, 1);
- X if ( *p++ != '(' )
- X return 0; /* not a function */
- X p = skipspace(p, 1);
- X if ( *p == ')' )
- X return 0; /* no parameters */
- X /* Check that the apparent function name isn't a keyword. */
- X /* We only need to check for keywords that could be followed */
- X /* by a left parenthesis (which, unfortunately, is most of them). */
- X { static char *words[] =
- X { "asm", "auto", "case", "char", "const", "double",
- X "extern", "float", "for", "if", "int", "long",
- X "register", "return", "short", "signed", "sizeof",
- X "static", "switch", "typedef", "unsigned",
- X "void", "volatile", "while", 0
- X };
- X char **key = words;
- X char *kp;
- X int len = endfn - buf;
- X while ( (kp = *key) != 0 )
- X { if ( strlen(kp) == len && !strncmp(kp, buf, len) )
- X return 0; /* name is a keyword */
- X key++;
- X }
- X }
- X return contin;
- X}
- X
- Xint
- Xconvert1(buf, out)
- X char *buf;
- X FILE *out;
- X{ char *endfn = strchr(buf, '(') + 1;
- X register char *p;
- X char **breaks;
- X unsigned num_breaks = 2; /* for testing */
- X char **btop;
- X char **bp;
- X char **ap;
- Xtop: p = endfn;
- X breaks = (char **)malloc(sizeof(char *) * num_breaks * 2);
- X if ( breaks == 0 )
- X { /* Couldn't allocate break table, give up */
- X fprintf(stderr, "Unable to allocate break table!\n");
- X fputs(buf, out);
- X return -1;
- X }
- X btop = breaks + num_breaks * 2 - 2;
- X bp = breaks;
- X /* Parse the argument list */
- X do
- X { int level = 0;
- X char *end = NULL;
- X if ( bp >= btop )
- X { /* Filled up break table. */
- X /* Allocate a bigger one and start over. */
- X free((char *)breaks);
- X num_breaks <<= 1;
- X goto top;
- X }
- X *bp++ = p;
- X /* Find the end of the argument */
- X for ( ; end == NULL; p++ )
- X { switch(*p)
- X {
- X case ',': if ( !level ) end = p; break;
- X case '(': level++; break;
- X case ')': if ( --level < 0 ) end = p; break;
- X case '/': p = skipspace(p, 1) - 1; break;
- X default: ;
- X }
- X }
- X p--; /* back up over terminator */
- X /* Find the name being declared. */
- X /* This is complicated because of procedure and */
- X /* array modifiers. */
- X for ( ; ; )
- X { p = skipspace(p - 1, -1);
- X switch ( *p )
- X {
- X case ']': /* skip array dimension(s) */
- X case ')': /* skip procedure args OR name */
- X { int level = 1;
- X while ( level )
- X switch ( *--p )
- X {
- X case ']': case ')': level++; break;
- X case '[': case '(': level--; break;
- X case '/': p = skipspace(p, -1) + 1; break;
- X default: ;
- X }
- X }
- X if ( *p == '(' && *skipspace(p + 1, 1) == '*' )
- X { /* We found the name being declared */
- X while ( !isidfirstchar(*p) )
- X p = skipspace(p, 1) + 1;
- X goto found;
- X }
- X break;
- X default: goto found;
- X }
- X }
- Xfound: if ( *p == '.' && p[-1] == '.' && p[-2] == '.' )
- X { p++;
- X if ( bp == breaks + 1 ) /* sole argument */
- X writeblanks(breaks[0], p);
- X else
- X writeblanks(bp[-1] - 1, p);
- X bp--;
- X }
- X else
- X { while ( isidchar(*p) ) p--;
- X *bp++ = p+1;
- X }
- X p = end;
- X }
- X while ( *p++ == ',' );
- X *bp = p;
- X /* Make a special check for 'void' arglist */
- X if ( bp == breaks+2 )
- X { p = skipspace(breaks[0], 1);
- X if ( !strncmp(p, "void", 4) )
- X { p = skipspace(p+4, 1);
- X if ( p == breaks[2] - 1 )
- X { bp = breaks; /* yup, pretend arglist is empty */
- X writeblanks(breaks[0], p + 1);
- X }
- X }
- X }
- X /* Put out the function name */
- X p = buf;
- X while ( p != endfn ) putc(*p, out), p++;
- X /* Put out the declaration */
- X for ( ap = breaks+1; ap < bp; ap += 2 )
- X { p = *ap;
- X while ( isidchar(*p) ) putc(*p, out), p++;
- X if ( ap < bp - 1 ) fputs(", ", out);
- X }
- X fputs(") ", out);
- X /* Put out the argument declarations */
- X for ( ap = breaks+2; ap <= bp; ap += 2 ) (*ap)[-1] = ';';
- X fputs(breaks[0], out);
- X free((char *)breaks);
- X return 0;
- X}
- END_OF_FILE
- if test 16258 -ne `wc -c <'ansi2knr.c'`; then
- echo shar: \"'ansi2knr.c'\" unpacked with wrong size!
- fi
- # end of 'ansi2knr.c'
- fi
- if test -f 'jmemansi.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'jmemansi.c'\"
- else
- echo shar: Extracting \"'jmemansi.c'\" \(4303 characters\)
- sed "s/^X//" >'jmemansi.c' <<'END_OF_FILE'
- X/*
- X * jmemansi.c (jmemsys.c)
- X *
- X * Copyright (C) 1992, Thomas G. Lane.
- X * This file is part of the Independent JPEG Group's software.
- X * For conditions of distribution and use, see the accompanying README file.
- X *
- X * This file provides a simple generic implementation of the system-
- X * dependent portion of the JPEG memory manager. This implementation
- X * assumes that you have the ANSI-standard library routine tmpfile().
- X * Also, the problem of determining the amount of memory available
- X * is shoved onto the user.
- X */
- X
- X#include "jinclude.h"
- X#include "jmemsys.h"
- X
- X#ifdef INCLUDES_ARE_ANSI
- X#include <stdlib.h> /* to declare malloc(), free() */
- X#else
- Xextern void * malloc PP((size_t size));
- Xextern void free PP((void *ptr));
- X#endif
- X
- X#ifndef SEEK_SET /* pre-ANSI systems may not define this; */
- X#define SEEK_SET 0 /* if not, assume 0 is correct */
- X#endif
- X
- X
- Xstatic external_methods_ptr methods; /* saved for access to error_exit */
- X
- Xstatic long total_used; /* total memory requested so far */
- X
- X
- X/*
- X * Memory allocation and freeing are controlled by the regular library
- X * routines malloc() and free().
- X */
- X
- XGLOBAL void *
- Xjget_small (size_t sizeofobject)
- X{
- X total_used += sizeofobject;
- X return (void *) malloc(sizeofobject);
- X}
- X
- XGLOBAL void
- Xjfree_small (void * object)
- X{
- X free(object);
- X}
- X
- X/*
- X * We assume NEED_FAR_POINTERS is not defined and so the separate entry points
- X * jget_large, jfree_large are not needed.
- X */
- X
- X
- X/*
- X * This routine computes the total memory space available for allocation.
- X * It's impossible to do this in a portable way; our current solution is
- X * to make the user tell us (with a default value set at compile time).
- X * If you can actually get the available space, it's a good idea to subtract
- X * a slop factor of 5% or so.
- X */
- X
- X#ifndef DEFAULT_MAX_MEM /* so can override from makefile */
- X#define DEFAULT_MAX_MEM 1000000L /* default: one megabyte */
- X#endif
- X
- XGLOBAL long
- Xjmem_available (long min_bytes_needed, long max_bytes_needed)
- X{
- X return methods->max_memory_to_use - total_used;
- X}
- X
- X
- X/*
- X * Backing store (temporary file) management.
- X * Backing store objects are only used when the value returned by
- X * jmem_available is less than the total space needed. You can dispense
- X * with these routines if you have plenty of virtual memory; see jmemnobs.c.
- X */
- X
- X
- XMETHODDEF void
- Xread_backing_store (backing_store_ptr info, void FAR * buffer_address,
- X long file_offset, long byte_count)
- X{
- X if (fseek(info->temp_file, file_offset, SEEK_SET))
- X ERREXIT(methods, "fseek failed on temporary file");
- X if (JFREAD(info->temp_file, buffer_address, byte_count)
- X != (size_t) byte_count)
- X ERREXIT(methods, "fread failed on temporary file");
- X}
- X
- X
- XMETHODDEF void
- Xwrite_backing_store (backing_store_ptr info, void FAR * buffer_address,
- X long file_offset, long byte_count)
- X{
- X if (fseek(info->temp_file, file_offset, SEEK_SET))
- X ERREXIT(methods, "fseek failed on temporary file");
- X if (JFWRITE(info->temp_file, buffer_address, byte_count)
- X != (size_t) byte_count)
- X ERREXIT(methods, "fwrite failed on temporary file --- out of disk space?");
- X}
- X
- X
- XMETHODDEF void
- Xclose_backing_store (backing_store_ptr info)
- X{
- X fclose(info->temp_file);
- X /* Since this implementation uses tmpfile() to create the file,
- X * no explicit file deletion is needed.
- X */
- X}
- X
- X
- X/*
- X * Initial opening of a backing-store object.
- X *
- X * This version uses tmpfile(), which constructs a suitable file name
- X * behind the scenes. We don't have to use temp_name[] at all;
- X * indeed, we can't even find out the actual name of the temp file.
- X */
- X
- XGLOBAL void
- Xjopen_backing_store (backing_store_ptr info, long total_bytes_needed)
- X{
- X if ((info->temp_file = tmpfile()) == NULL)
- X ERREXIT(methods, "Failed to create temporary file");
- X info->read_backing_store = read_backing_store;
- X info->write_backing_store = write_backing_store;
- X info->close_backing_store = close_backing_store;
- X}
- X
- X
- X/*
- X * These routines take care of any system-dependent initialization and
- X * cleanup required. Keep in mind that jmem_term may be called more than
- X * once.
- X */
- X
- XGLOBAL void
- Xjmem_init (external_methods_ptr emethods)
- X{
- X methods = emethods; /* save struct addr for error exit access */
- X emethods->max_memory_to_use = DEFAULT_MAX_MEM;
- X total_used = 0;
- X}
- X
- XGLOBAL void
- Xjmem_term (void)
- X{
- X /* no work */
- X}
- END_OF_FILE
- if test 4303 -ne `wc -c <'jmemansi.c'`; then
- echo shar: \"'jmemansi.c'\" unpacked with wrong size!
- fi
- # end of 'jmemansi.c'
- fi
- if test -f 'jmemdos.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'jmemdos.c'\"
- else
- echo shar: Extracting \"'jmemdos.c'\" \(17266 characters\)
- sed "s/^X//" >'jmemdos.c' <<'END_OF_FILE'
- X/*
- X * jmemdos.c (jmemsys.c)
- X *
- X * Copyright (C) 1992, Thomas G. Lane.
- X * This file is part of the Independent JPEG Group's software.
- X * For conditions of distribution and use, see the accompanying README file.
- X *
- X * This file provides an MS-DOS-compatible implementation of the system-
- X * dependent portion of the JPEG memory manager. Temporary data can be
- X * stored in extended or expanded memory as well as in regular DOS files.
- X *
- X * If you use this file, you must be sure that NEED_FAR_POINTERS is defined
- X * if you compile in a small-data memory model; it should NOT be defined if
- X * you use a large-data memory model. This file is not recommended if you
- X * are using a flat-memory-space 386 environment such as DJGCC or Watcom C.
- X *
- X * Based on code contributed by Ge' Weijers.
- X */
- X
- X/*
- X * If you have both extended and expanded memory, you may want to change the
- X * order in which they are tried in jopen_backing_store. On a 286 machine
- X * expanded memory is usually faster, since extended memory access involves
- X * an expensive protected-mode-and-back switch. On 386 and better, extended
- X * memory is usually faster. As distributed, the code tries extended memory
- X * first (what? not everyone has a 386? :-).
- X *
- X * You can disable use of extended/expanded memory entirely by altering these
- X * definitions or overriding them from the Makefile (eg, -DEMS_SUPPORTED=0).
- X */
- X
- X#ifndef XMS_SUPPORTED
- X#define XMS_SUPPORTED 1
- X#endif
- X#ifndef EMS_SUPPORTED
- X#define EMS_SUPPORTED 1
- X#endif
- X
- X
- X#include "jinclude.h"
- X#include "jmemsys.h"
- X
- X#ifdef INCLUDES_ARE_ANSI
- X#include <stdlib.h> /* to declare malloc(), free() */
- X#else
- Xextern void * malloc PP((size_t size));
- Xextern void free PP((void *ptr));
- X#endif
- X
- X#ifdef NEED_FAR_POINTERS
- X
- X#ifdef __TURBOC__
- X/* These definitions work for Borland C (Turbo C) */
- X#include <alloc.h> /* need farmalloc(), farfree() */
- X#define far_malloc(x) farmalloc(x)
- X#define far_free(x) farfree(x)
- X#else
- X/* These definitions work for Microsoft C and compatible compilers */
- X#include <malloc.h> /* need _fmalloc(), _ffree() */
- X#define far_malloc(x) _fmalloc(x)
- X#define far_free(x) _ffree(x)
- X#endif
- X
- X#endif
- X
- X#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */
- X#define READ_BINARY "r"
- X#else
- X#define READ_BINARY "rb"
- X#endif
- X
- X
- X/*
- X * Declarations for assembly-language support routines (see jmemdosa.asm).
- X *
- X * The functions are declared "far" as are all pointer arguments;
- X * this ensures the assembly source code will work regardless of the
- X * compiler memory model. We assume "short" is 16 bits, "long" is 32.
- X */
- X
- Xtypedef void far * XMSDRIVER; /* actually a pointer to code */
- Xtypedef struct { /* registers for calling XMS driver */
- X unsigned short ax, dx, bx;
- X void far * ds_si;
- X } XMScontext;
- Xtypedef struct { /* registers for calling EMS driver */
- X unsigned short ax, dx, bx;
- X void far * ds_si;
- X } EMScontext;
- X
- XEXTERN short far jdos_open PP((short far * handle, char far * filename));
- XEXTERN short far jdos_close PP((short handle));
- XEXTERN short far jdos_seek PP((short handle, long offset));
- XEXTERN short far jdos_read PP((short handle, void far * buffer,
- X unsigned short count));
- XEXTERN short far jdos_write PP((short handle, void far * buffer,
- X unsigned short count));
- XEXTERN void far jxms_getdriver PP((XMSDRIVER far *));
- XEXTERN void far jxms_calldriver PP((XMSDRIVER, XMScontext far *));
- XEXTERN short far jems_available PP((void));
- XEXTERN void far jems_calldriver PP((EMScontext far *));
- X
- X
- Xstatic external_methods_ptr methods; /* saved for access to error_exit */
- X
- Xstatic long total_used; /* total FAR memory requested so far */
- X
- X
- X/*
- X * Selection of a file name for a temporary file.
- X * This is highly system-dependent, and you may want to customize it.
- X */
- X
- Xstatic int next_file_num; /* to distinguish among several temp files */
- X
- XLOCAL void
- Xselect_file_name (char * fname)
- X{
- X const char * env;
- X char * ptr;
- X FILE * tfile;
- X
- X /* Keep generating file names till we find one that's not in use */
- X for (;;) {
- X /* Get temp directory name from environment TMP or TEMP variable;
- X * if none, use "."
- X */
- X if ((env = (const char *) getenv("TMP")) == NULL)
- X if ((env = (const char *) getenv("TEMP")) == NULL)
- X env = ".";
- X if (*env == '\0') /* null string means "." */
- X env = ".";
- X ptr = fname; /* copy name to fname */
- X while (*env != '\0')
- X *ptr++ = *env++;
- X if (ptr[-1] != '\\' && ptr[-1] != '/')
- X *ptr++ = '\\'; /* append backslash if not in env variable */
- X /* Append a suitable file name */
- X next_file_num++; /* advance counter */
- X sprintf(ptr, "JPG%03d.TMP", next_file_num);
- X /* Probe to see if file name is already in use */
- X if ((tfile = fopen(fname, READ_BINARY)) == NULL)
- X break;
- X fclose(tfile); /* oops, it's there; close tfile & try again */
- X }
- X}
- X
- X
- X/*
- X * Near-memory allocation and freeing are controlled by the regular library
- X * routines malloc() and free().
- X */
- X
- XGLOBAL void *
- Xjget_small (size_t sizeofobject)
- X{
- X /* near data space is NOT counted in total_used */
- X#ifndef NEED_FAR_POINTERS
- X total_used += sizeofobject;
- X#endif
- X return (void *) malloc(sizeofobject);
- X}
- X
- XGLOBAL void
- Xjfree_small (void * object)
- X{
- X free(object);
- X}
- X
- X
- X/*
- X * Far-memory allocation and freeing
- X */
- X
- X#ifdef NEED_FAR_POINTERS
- X
- XGLOBAL void FAR *
- Xjget_large (size_t sizeofobject)
- X{
- X total_used += sizeofobject;
- X return (void FAR *) far_malloc(sizeofobject);
- X}
- X
- XGLOBAL void
- Xjfree_large (void FAR * object)
- X{
- X far_free(object);
- X}
- X
- X#endif
- X
- X
- X/*
- X * This routine computes the total memory space available for allocation.
- X * It's impossible to do this in a portable way; our current solution is
- X * to make the user tell us (with a default value set at compile time).
- X * If you can actually get the available space, it's a good idea to subtract
- X * a slop factor of 5% or so.
- X */
- X
- X#ifndef DEFAULT_MAX_MEM /* so can override from makefile */
- X#define DEFAULT_MAX_MEM 300000L /* for total usage about 450K */
- X#endif
- X
- XGLOBAL long
- Xjmem_available (long min_bytes_needed, long max_bytes_needed)
- X{
- X return methods->max_memory_to_use - total_used;
- X}
- X
- X
- X/*
- X * Backing store (temporary file) management.
- X * Backing store objects are only used when the value returned by
- X * jmem_available is less than the total space needed. You can dispense
- X * with these routines if you have plenty of virtual memory; see jmemnobs.c.
- X */
- X
- X/*
- X * For MS-DOS we support three types of backing storage:
- X * 1. Conventional DOS files. We access these by direct DOS calls rather
- X * than via the stdio package. This provides a bit better performance,
- X * but the real reason is that the buffers to be read or written are FAR.
- X * The stdio library for small-data memory models can't cope with that.
- X * 2. Extended memory, accessed per the XMS V2.0 specification.
- X * 3. Expanded memory, accessed per the LIM/EMS 4.0 specification.
- X * You'll need copies of those specs to make sense of the related code.
- X * The specs are available by Internet FTP from SIMTEL20 and its various
- X * mirror sites; see microsoft/xms20.arc and info/limems41.zip.
- X */
- X
- X
- X/*
- X * Access methods for a DOS file.
- X */
- X
- X
- XMETHODDEF void
- Xread_file_store (backing_store_ptr info, void FAR * buffer_address,
- X long file_offset, long byte_count)
- X{
- X if (jdos_seek(info->handle.file_handle, file_offset))
- X ERREXIT(methods, "seek failed on temporary file");
- X /* Since MAX_ALLOC_CHUNK is less than 64K, byte_count will be too. */
- X if (byte_count > 65535L) /* safety check */
- X ERREXIT(methods, "MAX_ALLOC_CHUNK should be less than 64K");
- X if (jdos_read(info->handle.file_handle, buffer_address,
- X (unsigned short) byte_count))
- X ERREXIT(methods, "read failed on temporary file");
- X}
- X
- X
- XMETHODDEF void
- Xwrite_file_store (backing_store_ptr info, void FAR * buffer_address,
- X long file_offset, long byte_count)
- X{
- X if (jdos_seek(info->handle.file_handle, file_offset))
- X ERREXIT(methods, "seek failed on temporary file");
- X /* Since MAX_ALLOC_CHUNK is less than 64K, byte_count will be too. */
- X if (byte_count > 65535L) /* safety check */
- X ERREXIT(methods, "MAX_ALLOC_CHUNK should be less than 64K");
- X if (jdos_write(info->handle.file_handle, buffer_address,
- X (unsigned short) byte_count))
- X ERREXIT(methods, "write failed on temporary file --- out of disk space?");
- X}
- X
- X
- XMETHODDEF void
- Xclose_file_store (backing_store_ptr info)
- X{
- X jdos_close(info->handle.file_handle); /* close the file */
- X remove(info->temp_name); /* delete the file */
- X/* If your system doesn't have remove(), try unlink() instead.
- X * remove() is the ANSI-standard name for this function, but
- X * unlink() was more common in pre-ANSI systems.
- X */
- X TRACEMS1(methods, 1, "Closed DOS file %d", info->handle.file_handle);
- X}
- X
- X
- XLOCAL boolean
- Xopen_file_store (backing_store_ptr info, long total_bytes_needed)
- X{
- X short handle;
- X char tracemsg[TEMP_NAME_LENGTH+40];
- X
- X select_file_name(info->temp_name);
- X if (jdos_open((short far *) & handle, (char far *) info->temp_name))
- X return FALSE;
- X info->handle.file_handle = handle;
- X info->read_backing_store = read_file_store;
- X info->write_backing_store = write_file_store;
- X info->close_backing_store = close_file_store;
- X /* hack to get around TRACEMS' inability to handle string parameters */
- X sprintf(tracemsg, "Opened DOS file %d %s", handle, info->temp_name);
- X TRACEMS(methods, 1, tracemsg);
- X return TRUE; /* succeeded */
- X}
- X
- X
- X/*
- X * Access methods for extended memory.
- X */
- X
- X#if XMS_SUPPORTED
- X
- Xstatic XMSDRIVER xms_driver; /* saved address of XMS driver */
- X
- Xtypedef union { /* either long offset or real-mode pointer */
- X long offset;
- X void far * ptr;
- X } XMSPTR;
- X
- Xtypedef struct { /* XMS move specification structure */
- X long length;
- X XMSH src_handle;
- X XMSPTR src;
- X XMSH dst_handle;
- X XMSPTR dst;
- X } XMSspec;
- X
- X#define ODD(X) (((X) & 1L) != 0)
- X
- X
- XMETHODDEF void
- Xread_xms_store (backing_store_ptr info, void FAR * buffer_address,
- X long file_offset, long byte_count)
- X{
- X XMScontext ctx;
- X XMSspec spec;
- X char endbuffer[2];
- X
- X /* The XMS driver can't cope with an odd length, so handle the last byte
- X * specially if byte_count is odd. We don't expect this to be common.
- X */
- X
- X spec.length = byte_count & (~ 1L);
- X spec.src_handle = info->handle.xms_handle;
- X spec.src.offset = file_offset;
- X spec.dst_handle = 0;
- X spec.dst.ptr = buffer_address;
- X
- X ctx.ds_si = (void far *) & spec;
- X ctx.ax = 0x0b00; /* EMB move */
- X jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
- X if (ctx.ax != 1)
- X ERREXIT(methods, "read from extended memory failed");
- X
- X if (ODD(byte_count)) {
- X read_xms_store(info, (void FAR *) endbuffer,
- X file_offset + byte_count - 1L, 2L);
- X ((char FAR *) buffer_address)[byte_count - 1L] = endbuffer[0];
- X }
- X}
- X
- X
- XMETHODDEF void
- Xwrite_xms_store (backing_store_ptr info, void FAR * buffer_address,
- X long file_offset, long byte_count)
- X{
- X XMScontext ctx;
- X XMSspec spec;
- X char endbuffer[2];
- X
- X /* The XMS driver can't cope with an odd length, so handle the last byte
- X * specially if byte_count is odd. We don't expect this to be common.
- X */
- X
- X spec.length = byte_count & (~ 1L);
- X spec.src_handle = 0;
- X spec.src.ptr = buffer_address;
- X spec.dst_handle = info->handle.xms_handle;
- X spec.dst.offset = file_offset;
- X
- X ctx.ds_si = (void far *) & spec;
- X ctx.ax = 0x0b00; /* EMB move */
- X jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
- X if (ctx.ax != 1)
- X ERREXIT(methods, "write to extended memory failed");
- X
- X if (ODD(byte_count)) {
- X read_xms_store(info, (void FAR *) endbuffer,
- X file_offset + byte_count - 1L, 2L);
- X endbuffer[0] = ((char FAR *) buffer_address)[byte_count - 1L];
- X write_xms_store(info, (void FAR *) endbuffer,
- X file_offset + byte_count - 1L, 2L);
- X }
- X}
- X
- X
- XMETHODDEF void
- Xclose_xms_store (backing_store_ptr info)
- X{
- X XMScontext ctx;
- X
- X ctx.dx = info->handle.xms_handle;
- X ctx.ax = 0x0a00;
- X jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
- X TRACEMS1(methods, 1, "Freed XMS handle %u", info->handle.xms_handle);
- X /* we ignore any error return from the driver */
- X}
- X
- X
- XLOCAL boolean
- Xopen_xms_store (backing_store_ptr info, long total_bytes_needed)
- X{
- X XMScontext ctx;
- X
- X /* Get address of XMS driver */
- X jxms_getdriver((XMSDRIVER far *) & xms_driver);
- X if (xms_driver == NULL)
- X return FALSE; /* no driver to be had */
- X
- X /* Get version number, must be >= 2.00 */
- X ctx.ax = 0x0000;
- X jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
- X if (ctx.ax < (unsigned short) 0x0200)
- X return FALSE;
- X
- X /* Try to get space (expressed in kilobytes) */
- X ctx.dx = (unsigned short) ((total_bytes_needed + 1023L) >> 10);
- X ctx.ax = 0x0900;
- X jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
- X if (ctx.ax != 1)
- X return FALSE;
- X
- X /* Succeeded, save the handle and away we go */
- X info->handle.xms_handle = ctx.dx;
- X info->read_backing_store = read_xms_store;
- X info->write_backing_store = write_xms_store;
- X info->close_backing_store = close_xms_store;
- X TRACEMS1(methods, 1, "Obtained XMS handle %u", ctx.dx);
- X return TRUE; /* succeeded */
- X}
- X
- X#endif /* XMS_SUPPORTED */
- X
- X
- X/*
- X * Access methods for expanded memory.
- X */
- X
- X#if EMS_SUPPORTED
- X
- Xtypedef union { /* either offset/page or real-mode pointer */
- X struct { unsigned short offset, page; } ems;
- X void far * ptr;
- X } EMSPTR;
- X
- Xtypedef struct { /* EMS move specification structure */
- X long length;
- X char src_type; /* 1 = EMS, 0 = conventional memory */
- X EMSH src_handle; /* use 0 if conventional memory */
- X EMSPTR src;
- X char dst_type;
- X EMSH dst_handle;
- X EMSPTR dst;
- X } EMSspec;
- X
- X#define EMSPAGESIZE 16384L /* gospel, see the EMS specs */
- X
- X#define HIBYTE(W) (((W) >> 8) & 0xFF)
- X#define LOBYTE(W) ((W) & 0xFF)
- X
- X
- XMETHODDEF void
- Xread_ems_store (backing_store_ptr info, void FAR * buffer_address,
- X long file_offset, long byte_count)
- X{
- X EMScontext ctx;
- X EMSspec spec;
- X
- X spec.length = byte_count;
- X spec.src_type = 1;
- X spec.src_handle = info->handle.ems_handle;
- X spec.src.ems.page = (unsigned short) (file_offset / EMSPAGESIZE);
- X spec.src.ems.offset = (unsigned short) (file_offset % EMSPAGESIZE);
- X spec.dst_type = 0;
- X spec.dst_handle = 0;
- X spec.dst.ptr = buffer_address;
- X
- X ctx.ds_si = (void far *) & spec;
- X ctx.ax = 0x5700; /* move memory region */
- X jems_calldriver((EMScontext far *) & ctx);
- X if (HIBYTE(ctx.ax) != 0)
- X ERREXIT(methods, "read from expanded memory failed");
- X}
- X
- X
- XMETHODDEF void
- Xwrite_ems_store (backing_store_ptr info, void FAR * buffer_address,
- X long file_offset, long byte_count)
- X{
- X EMScontext ctx;
- X EMSspec spec;
- X
- X spec.length = byte_count;
- X spec.src_type = 0;
- X spec.src_handle = 0;
- X spec.src.ptr = buffer_address;
- X spec.dst_type = 1;
- X spec.dst_handle = info->handle.ems_handle;
- X spec.dst.ems.page = (unsigned short) (file_offset / EMSPAGESIZE);
- X spec.dst.ems.offset = (unsigned short) (file_offset % EMSPAGESIZE);
- X
- X ctx.ds_si = (void far *) & spec;
- X ctx.ax = 0x5700; /* move memory region */
- X jems_calldriver((EMScontext far *) & ctx);
- X if (HIBYTE(ctx.ax) != 0)
- X ERREXIT(methods, "write to expanded memory failed");
- X}
- X
- X
- XMETHODDEF void
- Xclose_ems_store (backing_store_ptr info)
- X{
- X EMScontext ctx;
- X
- X ctx.ax = 0x4500;
- X ctx.dx = info->handle.ems_handle;
- X jems_calldriver((EMScontext far *) & ctx);
- X TRACEMS1(methods, 1, "Freed EMS handle %u", info->handle.ems_handle);
- X /* we ignore any error return from the driver */
- X}
- X
- X
- XLOCAL boolean
- Xopen_ems_store (backing_store_ptr info, long total_bytes_needed)
- X{
- X EMScontext ctx;
- X
- X /* Is EMS driver there? */
- X if (! jems_available())
- X return FALSE;
- X
- X /* Get status, make sure EMS is OK */
- X ctx.ax = 0x4000;
- X jems_calldriver((EMScontext far *) & ctx);
- X if (HIBYTE(ctx.ax) != 0)
- X return FALSE;
- X
- X /* Get version, must be >= 4.0 */
- X ctx.ax = 0x4600;
- X jems_calldriver((EMScontext far *) & ctx);
- X if (HIBYTE(ctx.ax) != 0 || LOBYTE(ctx.ax) < 0x40)
- X return FALSE;
- X
- X /* Try to allocate requested space */
- X ctx.ax = 0x4300;
- X ctx.bx = (unsigned short) ((total_bytes_needed + EMSPAGESIZE-1L) / EMSPAGESIZE);
- X jems_calldriver((EMScontext far *) & ctx);
- X if (HIBYTE(ctx.ax) != 0)
- X return FALSE;
- X
- X /* Succeeded, save the handle and away we go */
- X info->handle.ems_handle = ctx.dx;
- X info->read_backing_store = read_ems_store;
- X info->write_backing_store = write_ems_store;
- X info->close_backing_store = close_ems_store;
- X TRACEMS1(methods, 1, "Obtained EMS handle %u", ctx.dx);
- X return TRUE; /* succeeded */
- X}
- X
- X#endif /* EMS_SUPPORTED */
- X
- X
- X/*
- X * Initial opening of a backing-store object.
- X */
- X
- XGLOBAL void
- Xjopen_backing_store (backing_store_ptr info, long total_bytes_needed)
- X{
- X /* Try extended memory, then expanded memory, then regular file. */
- X#if XMS_SUPPORTED
- X if (open_xms_store(info, total_bytes_needed))
- X return;
- X#endif
- X#if EMS_SUPPORTED
- X if (open_ems_store(info, total_bytes_needed))
- X return;
- X#endif
- X if (open_file_store(info, total_bytes_needed))
- X return;
- X ERREXIT(methods, "Failed to create temporary file");
- X}
- X
- X
- X/*
- X * These routines take care of any system-dependent initialization and
- X * cleanup required. Keep in mind that jmem_term may be called more than
- X * once.
- X */
- X
- XGLOBAL void
- Xjmem_init (external_methods_ptr emethods)
- X{
- X methods = emethods; /* save struct addr for error exit access */
- X emethods->max_memory_to_use = DEFAULT_MAX_MEM;
- X total_used = 0;
- X next_file_num = 0;
- X}
- X
- XGLOBAL void
- Xjmem_term (void)
- X{
- X /* no work */
- X}
- END_OF_FILE
- if test 17266 -ne `wc -c <'jmemdos.c'`; then
- echo shar: \"'jmemdos.c'\" unpacked with wrong size!
- fi
- # end of 'jmemdos.c'
- fi
- if test -f 'jversion.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'jversion.h'\"
- else
- echo shar: Extracting \"'jversion.h'\" \(358 characters\)
- sed "s/^X//" >'jversion.h' <<'END_OF_FILE'
- X/*
- X * jversion.h
- X *
- X * Copyright (C) 1991, 1992, Thomas G. Lane.
- X * This file is part of the Independent JPEG Group's software.
- X * For conditions of distribution and use, see the accompanying README file.
- X *
- X * This file contains software version identification.
- X */
- X
- X
- X#define JVERSION "3 17-Mar-92"
- X
- X#define JCOPYRIGHT "Copyright (C) 1992, Thomas G. Lane"
- END_OF_FILE
- if test 358 -ne `wc -c <'jversion.h'`; then
- echo shar: \"'jversion.h'\" unpacked with wrong size!
- fi
- # end of 'jversion.h'
- fi
- if test -f 'jwrjfif.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'jwrjfif.c'\"
- else
- echo shar: Extracting \"'jwrjfif.c'\" \(11708 characters\)
- sed "s/^X//" >'jwrjfif.c' <<'END_OF_FILE'
- X/*
- X * jwrjfif.c
- X *
- X * Copyright (C) 1991, 1992, Thomas G. Lane.
- X * This file is part of the Independent JPEG Group's software.
- X * For conditions of distribution and use, see the accompanying README file.
- X *
- X * This file contains routines to write standard JPEG file headers/markers.
- X * The file format created is a raw JPEG data stream with (optionally) an
- X * APP0 marker per the JFIF spec. This will handle baseline and
- X * JFIF-convention JPEG files, although there is currently no provision
- X * for inserting a thumbnail image in the JFIF header.
- X *
- X * These routines may need modification for non-Unix environments or
- X * specialized applications. As they stand, they assume output to
- X * an ordinary stdio stream. However, the changes to write to something
- X * else are localized in the macros appearing just below.
- X *
- X * These routines are invoked via the methods write_file_header,
- X * write_scan_header, write_jpeg_data, write_scan_trailer, and
- X * write_file_trailer.
- X */
- X
- X#include "jinclude.h"
- X
- X#ifdef JFIF_SUPPORTED
- X
- X
- X/*
- X * To output to something other than a stdio stream, you'd need to redefine
- X * these macros.
- X */
- X
- X/* Write a single byte */
- X#define emit_byte(cinfo,x) putc((x), cinfo->output_file)
- X
- X/* Write some bytes from a (char *) buffer */
- X#define WRITE_BYTES(cinfo,dataptr,datacount) \
- X { if (JFWRITE(cinfo->output_file, dataptr, datacount) \
- X != (size_t) (datacount)) \
- X ERREXIT(cinfo->emethods, "Output file write error"); }
- X
- X/* Clean up and verify successful output */
- X#define CHECK_OUTPUT(cinfo) \
- X { fflush(cinfo->output_file); \
- X if (ferror(cinfo->output_file)) \
- X ERREXIT(cinfo->emethods, "Output file write error"); }
- X
- X
- X/* End of stdio-specific code. */
- X
- X
- Xtypedef enum { /* JPEG marker codes */
- X M_SOF0 = 0xc0,
- X M_SOF1 = 0xc1,
- X M_SOF2 = 0xc2,
- X M_SOF3 = 0xc3,
- X
- X M_SOF5 = 0xc5,
- X M_SOF6 = 0xc6,
- X M_SOF7 = 0xc7,
- X
- X M_JPG = 0xc8,
- X M_SOF9 = 0xc9,
- X M_SOF10 = 0xca,
- X M_SOF11 = 0xcb,
- X
- X M_SOF13 = 0xcd,
- X M_SOF14 = 0xce,
- X M_SOF15 = 0xcf,
- X
- X M_DHT = 0xc4,
- X
- X M_DAC = 0xcc,
- X
- X M_RST0 = 0xd0,
- X M_RST1 = 0xd1,
- X M_RST2 = 0xd2,
- X M_RST3 = 0xd3,
- X M_RST4 = 0xd4,
- X M_RST5 = 0xd5,
- X M_RST6 = 0xd6,
- X M_RST7 = 0xd7,
- X
- X M_SOI = 0xd8,
- X M_EOI = 0xd9,
- X M_SOS = 0xda,
- X M_DQT = 0xdb,
- X M_DNL = 0xdc,
- X M_DRI = 0xdd,
- X M_DHP = 0xde,
- X M_EXP = 0xdf,
- X
- X M_APP0 = 0xe0,
- X M_APP15 = 0xef,
- X
- X M_JPG0 = 0xf0,
- X M_JPG13 = 0xfd,
- X M_COM = 0xfe,
- X
- X M_TEM = 0x01,
- X
- X M_ERROR = 0x100
- X} JPEG_MARKER;
- X
- X
- XLOCAL void
- Xemit_marker (compress_info_ptr cinfo, JPEG_MARKER mark)
- X/* Emit a marker code */
- X{
- X emit_byte(cinfo, 0xFF);
- X emit_byte(cinfo, mark);
- X}
- X
- X
- XLOCAL void
- Xemit_2bytes (compress_info_ptr cinfo, int value)
- X/* Emit a 2-byte integer; these are always MSB first in JPEG files */
- X{
- X emit_byte(cinfo, (value >> 8) & 0xFF);
- X emit_byte(cinfo, value & 0xFF);
- X}
- X
- X
- XLOCAL int
- Xemit_dqt (compress_info_ptr cinfo, int index)
- X/* Emit a DQT marker */
- X/* Returns the precision used (0 = 8bits, 1 = 16bits) for baseline checking */
- X{
- X QUANT_TBL_PTR data = cinfo->quant_tbl_ptrs[index];
- X int prec = 0;
- X int i;
- X
- X for (i = 0; i < DCTSIZE2; i++) {
- X if (data[i] > 255)
- X prec = 1;
- X }
- X
- X emit_marker(cinfo, M_DQT);
- X
- X emit_2bytes(cinfo, prec ? DCTSIZE2*2 + 1 + 2 : DCTSIZE2 + 1 + 2);
- X
- X emit_byte(cinfo, index + (prec<<4));
- X
- X for (i = 0; i < DCTSIZE2; i++) {
- X if (prec)
- X emit_byte(cinfo, data[i] >> 8);
- X emit_byte(cinfo, data[i] & 0xFF);
- X }
- X
- X return prec;
- X}
- X
- X
- XLOCAL void
- Xemit_dht (compress_info_ptr cinfo, int index, boolean is_ac)
- X/* Emit a DHT marker */
- X{
- X HUFF_TBL * htbl;
- X int length, i;
- X
- X if (is_ac) {
- X htbl = cinfo->ac_huff_tbl_ptrs[index];
- X index += 0x10; /* output index has AC bit set */
- X } else {
- X htbl = cinfo->dc_huff_tbl_ptrs[index];
- X }
- X
- X if (htbl == NULL)
- X ERREXIT1(cinfo->emethods, "Huffman table 0x%02x was not defined", index);
- X
- X if (! htbl->sent_table) {
- X emit_marker(cinfo, M_DHT);
- X
- X length = 0;
- X for (i = 1; i <= 16; i++)
- X length += htbl->bits[i];
- X
- X emit_2bytes(cinfo, length + 2 + 1 + 16);
- X emit_byte(cinfo, index);
- X
- X for (i = 1; i <= 16; i++)
- X emit_byte(cinfo, htbl->bits[i]);
- X
- X for (i = 0; i < length; i++)
- X emit_byte(cinfo, htbl->huffval[i]);
- X
- X htbl->sent_table = TRUE;
- X }
- X}
- X
- X
- XLOCAL void
- Xemit_dac (compress_info_ptr cinfo)
- X/* Emit a DAC marker */
- X/* Since the useful info is so small, we want to emit all the tables in */
- X/* one DAC marker. Therefore this routine does its own scan of the table. */
- X{
- X char dc_in_use[NUM_ARITH_TBLS];
- X char ac_in_use[NUM_ARITH_TBLS];
- X int length, i;
- X
- X for (i = 0; i < NUM_ARITH_TBLS; i++)
- X dc_in_use[i] = ac_in_use[i] = 0;
- X
- X for (i = 0; i < cinfo->num_components; i++) {
- X dc_in_use[cinfo->comp_info[i].dc_tbl_no] = 1;
- X ac_in_use[cinfo->comp_info[i].ac_tbl_no] = 1;
- X }
- X
- X length = 0;
- X for (i = 0; i < NUM_ARITH_TBLS; i++)
- X length += dc_in_use[i] + ac_in_use[i];
- X
- X emit_marker(cinfo, M_DAC);
- X
- X emit_2bytes(cinfo, length*2 + 2);
- X
- X for (i = 0; i < NUM_ARITH_TBLS; i++) {
- X if (dc_in_use[i]) {
- X emit_byte(cinfo, i);
- X emit_byte(cinfo, cinfo->arith_dc_L[i] + (cinfo->arith_dc_U[i]<<4));
- X }
- X if (ac_in_use[i]) {
- X emit_byte(cinfo, i + 0x10);
- X emit_byte(cinfo, cinfo->arith_ac_K[i]);
- X }
- X }
- X}
- X
- X
- XLOCAL void
- Xemit_dri (compress_info_ptr cinfo)
- X/* Emit a DRI marker */
- X{
- X emit_marker(cinfo, M_DRI);
- X
- X emit_2bytes(cinfo, 4); /* fixed length */
- X
- X emit_2bytes(cinfo, (int) cinfo->restart_interval);
- X}
- X
- X
- XLOCAL void
- Xemit_sof (compress_info_ptr cinfo, JPEG_MARKER code)
- X/* Emit a SOF marker */
- X{
- X int i;
- X
- X emit_marker(cinfo, code);
- X
- X emit_2bytes(cinfo, 3 * cinfo->num_components + 2 + 5 + 1); /* length */
- X
- X if (cinfo->image_height > 65535L || cinfo->image_width > 65535L)
- X ERREXIT(cinfo->emethods, "Maximum image dimension for JFIF is 65535 pixels");
- X
- X emit_byte(cinfo, cinfo->data_precision);
- X emit_2bytes(cinfo, (int) cinfo->image_height);
- X emit_2bytes(cinfo, (int) cinfo->image_width);
- X
- X emit_byte(cinfo, cinfo->num_components);
- X
- X for (i = 0; i < cinfo->num_components; i++) {
- X emit_byte(cinfo, cinfo->comp_info[i].component_id);
- X emit_byte(cinfo, (cinfo->comp_info[i].h_samp_factor << 4)
- X + cinfo->comp_info[i].v_samp_factor);
- X emit_byte(cinfo, cinfo->comp_info[i].quant_tbl_no);
- X }
- X}
- X
- X
- XLOCAL void
- Xemit_sos (compress_info_ptr cinfo)
- X/* Emit a SOS marker */
- X{
- X int i;
- X
- X emit_marker(cinfo, M_SOS);
- X
- X emit_2bytes(cinfo, 2 * cinfo->comps_in_scan + 2 + 1 + 3); /* length */
- X
- X emit_byte(cinfo, cinfo->comps_in_scan);
- X
- X for (i = 0; i < cinfo->comps_in_scan; i++) {
- X emit_byte(cinfo, cinfo->cur_comp_info[i]->component_id);
- X emit_byte(cinfo, (cinfo->cur_comp_info[i]->dc_tbl_no << 4)
- X + cinfo->cur_comp_info[i]->ac_tbl_no);
- X }
- X
- X emit_byte(cinfo, 0); /* Spectral selection start */
- X emit_byte(cinfo, DCTSIZE2-1); /* Spectral selection end */
- X emit_byte(cinfo, 0); /* Successive approximation */
- X}
- X
- X
- XLOCAL void
- Xemit_jfif_app0 (compress_info_ptr cinfo)
- X/* Emit a JFIF-compliant APP0 marker */
- X{
- X /*
- X * Length of APP0 block (2 bytes)
- X * Block ID (4 bytes - ASCII "JFIF")
- X * Zero byte (1 byte to terminate the ID string)
- X * Version Major, Minor (2 bytes - 0x01, 0x01)
- X * Units (1 byte - 0x00 = none, 0x01 = inch, 0x02 = cm)
- X * Xdpu (2 bytes - dots per unit horizontal)
- X * Ydpu (2 bytes - dots per unit vertical)
- X * Thumbnail X size (1 byte)
- X * Thumbnail Y size (1 byte)
- X */
- X
- X emit_marker(cinfo, M_APP0);
- X
- X emit_2bytes(cinfo, 2 + 4 + 1 + 2 + 1 + 2 + 2 + 1 + 1); /* length */
- X
- X emit_byte(cinfo, 'J'); /* Identifier */
- X emit_byte(cinfo, 'F');
- X emit_byte(cinfo, 'I');
- X emit_byte(cinfo, 'F');
- X emit_byte(cinfo, 0);
- X emit_byte(cinfo, 1); /* Major version */
- X emit_byte(cinfo, 1); /* Minor version */
- X emit_byte(cinfo, cinfo->density_unit); /* Pixel size information */
- X emit_2bytes(cinfo, (int) cinfo->X_density);
- X emit_2bytes(cinfo, (int) cinfo->Y_density);
- X emit_byte(cinfo, 0); /* No thumbnail image */
- X emit_byte(cinfo, 0);
- X}
- X
- X
- X/*
- X * Write the file header.
- X */
- X
- X
- XMETHODDEF void
- Xwrite_file_header (compress_info_ptr cinfo)
- X{
- X char qt_in_use[NUM_QUANT_TBLS];
- X int i, prec;
- X boolean is_baseline;
- X
- X emit_marker(cinfo, M_SOI); /* first the SOI */
- X
- X if (cinfo->write_JFIF_header) /* next an optional JFIF APP0 */
- X emit_jfif_app0(cinfo);
- X
- X /* Emit DQT for each quantization table. */
- X /* Note that doing it here means we can't adjust the QTs on-the-fly. */
- X /* If we did want to do that, we'd have a problem with checking precision */
- X /* for the is_baseline determination. */
- X
- X for (i = 0; i < NUM_QUANT_TBLS; i++)
- X qt_in_use[i] = 0;
- X
- X for (i = 0; i < cinfo->num_components; i++)
- X qt_in_use[cinfo->comp_info[i].quant_tbl_no] = 1;
- X
- X prec = 0;
- X for (i = 0; i < NUM_QUANT_TBLS; i++) {
- X if (qt_in_use[i])
- X prec += emit_dqt(cinfo, i);
- X }
- X /* now prec is nonzero iff there are any 16-bit quant tables. */
- X
- X if (cinfo->restart_interval)
- X emit_dri(cinfo);
- X
- X /* Check for a non-baseline specification. */
- X /* Note we assume that Huffman table numbers won't be changed later. */
- X is_baseline = TRUE;
- X if (cinfo->arith_code || (cinfo->data_precision != 8))
- X is_baseline = FALSE;
- X for (i = 0; i < cinfo->num_components; i++) {
- X if (cinfo->comp_info[i].dc_tbl_no > 1 || cinfo->comp_info[i].ac_tbl_no > 1)
- X is_baseline = FALSE;
- X }
- X if (prec && is_baseline) {
- X is_baseline = FALSE;
- X /* If it's baseline except for quantizer size, warn the user */
- X TRACEMS(cinfo->emethods, 0,
- X "Caution: quantization tables are too coarse for baseline JPEG");
- X }
- X
- X
- X /* Emit the proper SOF marker */
- X if (cinfo->arith_code)
- X emit_sof(cinfo, M_SOF9); /* SOF code for arithmetic coding */
- X else if (is_baseline)
- X emit_sof(cinfo, M_SOF0); /* SOF code for baseline implementation */
- X else
- X emit_sof(cinfo, M_SOF1); /* SOF code for non-baseline Huffman file */
- X}
- X
- X
- X/*
- X * Write the start of a scan (everything through the SOS marker).
- X */
- X
- XMETHODDEF void
- Xwrite_scan_header (compress_info_ptr cinfo)
- X{
- X int i;
- X
- X if (cinfo->arith_code) {
- X /* Emit arith conditioning info. We will have some duplication
- X * if the file has multiple scans, but it's so small it's hardly
- X * worth worrying about.
- X */
- X emit_dac(cinfo);
- X } else {
- X /* Emit Huffman tables. Note that emit_dht takes care of
- X * suppressing duplicate tables.
- X */
- X for (i = 0; i < cinfo->comps_in_scan; i++) {
- X emit_dht(cinfo, cinfo->cur_comp_info[i]->dc_tbl_no, FALSE);
- X emit_dht(cinfo, cinfo->cur_comp_info[i]->ac_tbl_no, TRUE);
- X }
- X }
- X
- X emit_sos(cinfo);
- X}
- X
- X
- X/*
- X * Write some bytes of compressed data within a scan.
- X */
- X
- XMETHODDEF void
- Xwrite_jpeg_data (compress_info_ptr cinfo, char *dataptr, int datacount)
- X{
- X WRITE_BYTES(cinfo, dataptr, datacount);
- X}
- X
- X
- X/*
- X * Finish up after a compressed scan (series of write_jpeg_data calls).
- X */
- X
- XMETHODDEF void
- Xwrite_scan_trailer (compress_info_ptr cinfo)
- X{
- X /* no work needed in this format */
- X}
- X
- X
- X/*
- X * Finish up at the end of the file.
- X */
- X
- XMETHODDEF void
- Xwrite_file_trailer (compress_info_ptr cinfo)
- X{
- X emit_marker(cinfo, M_EOI);
- X /* Make sure we wrote the output file OK */
- X CHECK_OUTPUT(cinfo);
- X}
- X
- X
- X/*
- X * The method selection routine for standard JPEG header writing.
- X * This should be called from c_ui_method_selection if appropriate.
- X */
- X
- XGLOBAL void
- Xjselwjfif (compress_info_ptr cinfo)
- X{
- X cinfo->methods->write_file_header = write_file_header;
- X cinfo->methods->write_scan_header = write_scan_header;
- X cinfo->methods->write_jpeg_data = write_jpeg_data;
- X cinfo->methods->write_scan_trailer = write_scan_trailer;
- X cinfo->methods->write_file_trailer = write_file_trailer;
- X}
- X
- X#endif /* JFIF_SUPPORTED */
- END_OF_FILE
- if test 11708 -ne `wc -c <'jwrjfif.c'`; then
- echo shar: \"'jwrjfif.c'\" unpacked with wrong size!
- fi
- # end of 'jwrjfif.c'
- fi
- echo shar: End of archive 12 \(of 18\).
- cp /dev/null ark12isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 18 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still must unpack the following archives:
- echo " " ${MISSING}
- fi
- exit 0
- exit 0 # Just in case...
-