17dd7cddfSDavid du Colombier /*
27dd7cddfSDavid du Colombier * jmemmac.c
37dd7cddfSDavid du Colombier *
4*593dc095SDavid du Colombier * Copyright (C) 1992-1997, Thomas G. Lane.
57dd7cddfSDavid du Colombier * This file is part of the Independent JPEG Group's software.
67dd7cddfSDavid du Colombier * For conditions of distribution and use, see the accompanying README file.
77dd7cddfSDavid du Colombier *
87dd7cddfSDavid du Colombier * jmemmac.c provides an Apple Macintosh implementation of the system-
97dd7cddfSDavid du Colombier * dependent portion of the JPEG memory manager.
107dd7cddfSDavid du Colombier *
11*593dc095SDavid du Colombier * If you use jmemmac.c, then you must define USE_MAC_MEMMGR in the
12*593dc095SDavid du Colombier * JPEG_INTERNALS part of jconfig.h.
13*593dc095SDavid du Colombier *
147dd7cddfSDavid du Colombier * jmemmac.c uses the Macintosh toolbox routines NewPtr and DisposePtr
157dd7cddfSDavid du Colombier * instead of malloc and free. It accurately determines the amount of
167dd7cddfSDavid du Colombier * memory available by using CompactMem. Notice that if left to its
177dd7cddfSDavid du Colombier * own devices, this code can chew up all available space in the
187dd7cddfSDavid du Colombier * application's zone, with the exception of the rather small "slop"
197dd7cddfSDavid du Colombier * factor computed in jpeg_mem_available(). The application can ensure
207dd7cddfSDavid du Colombier * that more space is left over by reducing max_memory_to_use.
217dd7cddfSDavid du Colombier *
22*593dc095SDavid du Colombier * Large images are swapped to disk using temporary files and System 7.0+'s
23*593dc095SDavid du Colombier * temporary folder functionality.
247dd7cddfSDavid du Colombier *
25*593dc095SDavid du Colombier * Note that jmemmac.c depends on two features of MacOS that were first
26*593dc095SDavid du Colombier * introduced in System 7: FindFolder and the FSSpec-based calls.
27*593dc095SDavid du Colombier * If your application uses jmemmac.c and is run under System 6 or earlier,
28*593dc095SDavid du Colombier * and the jpeg library decides it needs a temporary file, it will abort,
29*593dc095SDavid du Colombier * printing error messages about requiring System 7. (If no temporary files
30*593dc095SDavid du Colombier * are created, it will run fine.)
31*593dc095SDavid du Colombier *
32*593dc095SDavid du Colombier * If you want to use jmemmac.c in an application that might be used with
33*593dc095SDavid du Colombier * System 6 or earlier, then you should remove dependencies on FindFolder
34*593dc095SDavid du Colombier * and the FSSpec calls. You will need to replace FindFolder with some
35*593dc095SDavid du Colombier * other mechanism for finding a place to put temporary files, and you
36*593dc095SDavid du Colombier * should replace the FSSpec calls with their HFS equivalents:
37*593dc095SDavid du Colombier *
38*593dc095SDavid du Colombier * FSpDelete -> HDelete
39*593dc095SDavid du Colombier * FSpGetFInfo -> HGetFInfo
40*593dc095SDavid du Colombier * FSpCreate -> HCreate
41*593dc095SDavid du Colombier * FSpOpenDF -> HOpen *** Note: not HOpenDF ***
42*593dc095SDavid du Colombier * FSMakeFSSpec -> (fill in spec by hand.)
43*593dc095SDavid du Colombier *
44*593dc095SDavid du Colombier * (Use HOpen instead of HOpenDF. HOpen is just a glue-interface to PBHOpen,
45*593dc095SDavid du Colombier * which is on all HFS macs. HOpenDF is a System 7 addition which avoids the
46*593dc095SDavid du Colombier * ages-old problem of names starting with a period.)
47*593dc095SDavid du Colombier *
48*593dc095SDavid du Colombier * Contributed by Sam Bushell (jsam@iagu.on.net) and
49*593dc095SDavid du Colombier * Dan Gildor (gyld@in-touch.com).
507dd7cddfSDavid du Colombier */
517dd7cddfSDavid du Colombier
527dd7cddfSDavid du Colombier #define JPEG_INTERNALS
537dd7cddfSDavid du Colombier #include "jinclude.h"
547dd7cddfSDavid du Colombier #include "jpeglib.h"
557dd7cddfSDavid du Colombier #include "jmemsys.h" /* import the system-dependent declarations */
567dd7cddfSDavid du Colombier
57*593dc095SDavid du Colombier #ifndef USE_MAC_MEMMGR /* make sure user got configuration right */
58*593dc095SDavid du Colombier You forgot to define USE_MAC_MEMMGR in jconfig.h. /* deliberate syntax error */
597dd7cddfSDavid du Colombier #endif
607dd7cddfSDavid du Colombier
61*593dc095SDavid du Colombier #include <Memory.h> /* we use the MacOS memory manager */
62*593dc095SDavid du Colombier #include <Files.h> /* we use the MacOS File stuff */
63*593dc095SDavid du Colombier #include <Folders.h> /* we use the MacOS HFS stuff */
64*593dc095SDavid du Colombier #include <Script.h> /* for smSystemScript */
65*593dc095SDavid du Colombier #include <Gestalt.h> /* we use Gestalt to test for specific functionality */
66*593dc095SDavid du Colombier
67*593dc095SDavid du Colombier #ifndef TEMP_FILE_NAME /* can override from jconfig.h or Makefile */
68*593dc095SDavid du Colombier #define TEMP_FILE_NAME "JPG%03d.TMP"
69*593dc095SDavid du Colombier #endif
70*593dc095SDavid du Colombier
71*593dc095SDavid du Colombier static int next_file_num; /* to distinguish among several temp files */
72*593dc095SDavid du Colombier
737dd7cddfSDavid du Colombier
747dd7cddfSDavid du Colombier /*
757dd7cddfSDavid du Colombier * Memory allocation and freeing are controlled by the MacOS library
767dd7cddfSDavid du Colombier * routines NewPtr() and DisposePtr(), which allocate fixed-address
777dd7cddfSDavid du Colombier * storage. Unfortunately, the IJG library isn't smart enough to cope
787dd7cddfSDavid du Colombier * with relocatable storage.
797dd7cddfSDavid du Colombier */
807dd7cddfSDavid du Colombier
817dd7cddfSDavid du Colombier GLOBAL(void *)
jpeg_get_small(j_common_ptr cinfo,size_t sizeofobject)827dd7cddfSDavid du Colombier jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
837dd7cddfSDavid du Colombier {
847dd7cddfSDavid du Colombier return (void *) NewPtr(sizeofobject);
857dd7cddfSDavid du Colombier }
867dd7cddfSDavid du Colombier
877dd7cddfSDavid du Colombier GLOBAL(void)
jpeg_free_small(j_common_ptr cinfo,void * object,size_t sizeofobject)887dd7cddfSDavid du Colombier jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
897dd7cddfSDavid du Colombier {
907dd7cddfSDavid du Colombier DisposePtr((Ptr) object);
917dd7cddfSDavid du Colombier }
927dd7cddfSDavid du Colombier
937dd7cddfSDavid du Colombier
947dd7cddfSDavid du Colombier /*
957dd7cddfSDavid du Colombier * "Large" objects are treated the same as "small" ones.
967dd7cddfSDavid du Colombier * NB: we include FAR keywords in the routine declarations simply for
977dd7cddfSDavid du Colombier * consistency with the rest of the IJG code; FAR should expand to empty
987dd7cddfSDavid du Colombier * on rational architectures like the Mac.
997dd7cddfSDavid du Colombier */
1007dd7cddfSDavid du Colombier
1017dd7cddfSDavid du Colombier GLOBAL(void FAR *)
jpeg_get_large(j_common_ptr cinfo,size_t sizeofobject)1027dd7cddfSDavid du Colombier jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
1037dd7cddfSDavid du Colombier {
1047dd7cddfSDavid du Colombier return (void FAR *) NewPtr(sizeofobject);
1057dd7cddfSDavid du Colombier }
1067dd7cddfSDavid du Colombier
1077dd7cddfSDavid du Colombier GLOBAL(void)
jpeg_free_large(j_common_ptr cinfo,void FAR * object,size_t sizeofobject)1087dd7cddfSDavid du Colombier jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
1097dd7cddfSDavid du Colombier {
1107dd7cddfSDavid du Colombier DisposePtr((Ptr) object);
1117dd7cddfSDavid du Colombier }
1127dd7cddfSDavid du Colombier
1137dd7cddfSDavid du Colombier
1147dd7cddfSDavid du Colombier /*
1157dd7cddfSDavid du Colombier * This routine computes the total memory space available for allocation.
1167dd7cddfSDavid du Colombier */
1177dd7cddfSDavid du Colombier
1187dd7cddfSDavid du Colombier GLOBAL(long)
jpeg_mem_available(j_common_ptr cinfo,long min_bytes_needed,long max_bytes_needed,long already_allocated)1197dd7cddfSDavid du Colombier jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
1207dd7cddfSDavid du Colombier long max_bytes_needed, long already_allocated)
1217dd7cddfSDavid du Colombier {
1227dd7cddfSDavid du Colombier long limit = cinfo->mem->max_memory_to_use - already_allocated;
1237dd7cddfSDavid du Colombier long slop, mem;
1247dd7cddfSDavid du Colombier
1257dd7cddfSDavid du Colombier /* Don't ask for more than what application has told us we may use */
1267dd7cddfSDavid du Colombier if (max_bytes_needed > limit && limit > 0)
1277dd7cddfSDavid du Colombier max_bytes_needed = limit;
1287dd7cddfSDavid du Colombier /* Find whether there's a big enough free block in the heap.
1297dd7cddfSDavid du Colombier * CompactMem tries to create a contiguous block of the requested size,
1307dd7cddfSDavid du Colombier * and then returns the size of the largest free block (which could be
1317dd7cddfSDavid du Colombier * much more or much less than we asked for).
1327dd7cddfSDavid du Colombier * We add some slop to ensure we don't use up all available memory.
1337dd7cddfSDavid du Colombier */
1347dd7cddfSDavid du Colombier slop = max_bytes_needed / 16 + 32768L;
1357dd7cddfSDavid du Colombier mem = CompactMem(max_bytes_needed + slop) - slop;
1367dd7cddfSDavid du Colombier if (mem < 0)
1377dd7cddfSDavid du Colombier mem = 0; /* sigh, couldn't even get the slop */
1387dd7cddfSDavid du Colombier /* Don't take more than the application says we can have */
1397dd7cddfSDavid du Colombier if (mem > limit && limit > 0)
1407dd7cddfSDavid du Colombier mem = limit;
1417dd7cddfSDavid du Colombier return mem;
1427dd7cddfSDavid du Colombier }
1437dd7cddfSDavid du Colombier
1447dd7cddfSDavid du Colombier
1457dd7cddfSDavid du Colombier /*
1467dd7cddfSDavid du Colombier * Backing store (temporary file) management.
1477dd7cddfSDavid du Colombier * Backing store objects are only used when the value returned by
1487dd7cddfSDavid du Colombier * jpeg_mem_available is less than the total space needed. You can dispense
1497dd7cddfSDavid du Colombier * with these routines if you have plenty of virtual memory; see jmemnobs.c.
1507dd7cddfSDavid du Colombier */
1517dd7cddfSDavid du Colombier
1527dd7cddfSDavid du Colombier
1537dd7cddfSDavid du Colombier METHODDEF(void)
read_backing_store(j_common_ptr cinfo,backing_store_ptr info,void FAR * buffer_address,long file_offset,long byte_count)1547dd7cddfSDavid du Colombier read_backing_store (j_common_ptr cinfo, backing_store_ptr info,
1557dd7cddfSDavid du Colombier void FAR * buffer_address,
1567dd7cddfSDavid du Colombier long file_offset, long byte_count)
1577dd7cddfSDavid du Colombier {
158*593dc095SDavid du Colombier long bytes = byte_count;
159*593dc095SDavid du Colombier long retVal;
160*593dc095SDavid du Colombier
161*593dc095SDavid du Colombier if ( SetFPos ( info->temp_file, fsFromStart, file_offset ) != noErr )
1627dd7cddfSDavid du Colombier ERREXIT(cinfo, JERR_TFILE_SEEK);
163*593dc095SDavid du Colombier
164*593dc095SDavid du Colombier retVal = FSRead ( info->temp_file, &bytes,
165*593dc095SDavid du Colombier (unsigned char *) buffer_address );
166*593dc095SDavid du Colombier if ( retVal != noErr || bytes != byte_count )
1677dd7cddfSDavid du Colombier ERREXIT(cinfo, JERR_TFILE_READ);
1687dd7cddfSDavid du Colombier }
1697dd7cddfSDavid du Colombier
1707dd7cddfSDavid du Colombier
1717dd7cddfSDavid du Colombier METHODDEF(void)
write_backing_store(j_common_ptr cinfo,backing_store_ptr info,void FAR * buffer_address,long file_offset,long byte_count)1727dd7cddfSDavid du Colombier write_backing_store (j_common_ptr cinfo, backing_store_ptr info,
1737dd7cddfSDavid du Colombier void FAR * buffer_address,
1747dd7cddfSDavid du Colombier long file_offset, long byte_count)
1757dd7cddfSDavid du Colombier {
176*593dc095SDavid du Colombier long bytes = byte_count;
177*593dc095SDavid du Colombier long retVal;
178*593dc095SDavid du Colombier
179*593dc095SDavid du Colombier if ( SetFPos ( info->temp_file, fsFromStart, file_offset ) != noErr )
1807dd7cddfSDavid du Colombier ERREXIT(cinfo, JERR_TFILE_SEEK);
181*593dc095SDavid du Colombier
182*593dc095SDavid du Colombier retVal = FSWrite ( info->temp_file, &bytes,
183*593dc095SDavid du Colombier (unsigned char *) buffer_address );
184*593dc095SDavid du Colombier if ( retVal != noErr || bytes != byte_count )
1857dd7cddfSDavid du Colombier ERREXIT(cinfo, JERR_TFILE_WRITE);
1867dd7cddfSDavid du Colombier }
1877dd7cddfSDavid du Colombier
1887dd7cddfSDavid du Colombier
1897dd7cddfSDavid du Colombier METHODDEF(void)
close_backing_store(j_common_ptr cinfo,backing_store_ptr info)1907dd7cddfSDavid du Colombier close_backing_store (j_common_ptr cinfo, backing_store_ptr info)
1917dd7cddfSDavid du Colombier {
192*593dc095SDavid du Colombier FSClose ( info->temp_file );
193*593dc095SDavid du Colombier FSpDelete ( &(info->tempSpec) );
1947dd7cddfSDavid du Colombier }
1957dd7cddfSDavid du Colombier
1967dd7cddfSDavid du Colombier
1977dd7cddfSDavid du Colombier /*
1987dd7cddfSDavid du Colombier * Initial opening of a backing-store object.
1997dd7cddfSDavid du Colombier *
200*593dc095SDavid du Colombier * This version uses FindFolder to find the Temporary Items folder,
201*593dc095SDavid du Colombier * and puts the temporary file in there.
2027dd7cddfSDavid du Colombier */
2037dd7cddfSDavid du Colombier
2047dd7cddfSDavid du Colombier GLOBAL(void)
jpeg_open_backing_store(j_common_ptr cinfo,backing_store_ptr info,long total_bytes_needed)2057dd7cddfSDavid du Colombier jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,
2067dd7cddfSDavid du Colombier long total_bytes_needed)
2077dd7cddfSDavid du Colombier {
208*593dc095SDavid du Colombier short tmpRef, vRefNum;
209*593dc095SDavid du Colombier long dirID;
210*593dc095SDavid du Colombier FInfo finderInfo;
211*593dc095SDavid du Colombier FSSpec theSpec;
212*593dc095SDavid du Colombier Str255 fName;
213*593dc095SDavid du Colombier OSErr osErr;
214*593dc095SDavid du Colombier long gestaltResponse = 0;
215*593dc095SDavid du Colombier
216*593dc095SDavid du Colombier /* Check that FSSpec calls are available. */
217*593dc095SDavid du Colombier osErr = Gestalt( gestaltFSAttr, &gestaltResponse );
218*593dc095SDavid du Colombier if ( ( osErr != noErr )
219*593dc095SDavid du Colombier || !( gestaltResponse & (1<<gestaltHasFSSpecCalls) ) )
220*593dc095SDavid du Colombier ERREXITS(cinfo, JERR_TFILE_CREATE, "- System 7.0 or later required");
221*593dc095SDavid du Colombier /* TO DO: add a proper error message to jerror.h. */
222*593dc095SDavid du Colombier
223*593dc095SDavid du Colombier /* Check that FindFolder is available. */
224*593dc095SDavid du Colombier osErr = Gestalt( gestaltFindFolderAttr, &gestaltResponse );
225*593dc095SDavid du Colombier if ( ( osErr != noErr )
226*593dc095SDavid du Colombier || !( gestaltResponse & (1<<gestaltFindFolderPresent) ) )
227*593dc095SDavid du Colombier ERREXITS(cinfo, JERR_TFILE_CREATE, "- System 7.0 or later required.");
228*593dc095SDavid du Colombier /* TO DO: add a proper error message to jerror.h. */
229*593dc095SDavid du Colombier
230*593dc095SDavid du Colombier osErr = FindFolder ( kOnSystemDisk, kTemporaryFolderType, kCreateFolder,
231*593dc095SDavid du Colombier &vRefNum, &dirID );
232*593dc095SDavid du Colombier if ( osErr != noErr )
233*593dc095SDavid du Colombier ERREXITS(cinfo, JERR_TFILE_CREATE, "- temporary items folder unavailable");
234*593dc095SDavid du Colombier /* TO DO: Try putting the temp files somewhere else. */
235*593dc095SDavid du Colombier
236*593dc095SDavid du Colombier /* Keep generating file names till we find one that's not in use */
237*593dc095SDavid du Colombier for (;;) {
238*593dc095SDavid du Colombier next_file_num++; /* advance counter */
239*593dc095SDavid du Colombier
240*593dc095SDavid du Colombier sprintf(info->temp_name, TEMP_FILE_NAME, next_file_num);
241*593dc095SDavid du Colombier strcpy ( (Ptr)fName+1, info->temp_name );
242*593dc095SDavid du Colombier *fName = strlen (info->temp_name);
243*593dc095SDavid du Colombier osErr = FSMakeFSSpec ( vRefNum, dirID, fName, &theSpec );
244*593dc095SDavid du Colombier
245*593dc095SDavid du Colombier if ( (osErr = FSpGetFInfo ( &theSpec, &finderInfo ) ) != noErr )
246*593dc095SDavid du Colombier break;
247*593dc095SDavid du Colombier }
248*593dc095SDavid du Colombier
249*593dc095SDavid du Colombier osErr = FSpCreate ( &theSpec, '????', '????', smSystemScript );
250*593dc095SDavid du Colombier if ( osErr != noErr )
251*593dc095SDavid du Colombier ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name);
252*593dc095SDavid du Colombier
253*593dc095SDavid du Colombier osErr = FSpOpenDF ( &theSpec, fsRdWrPerm, &(info->temp_file) );
254*593dc095SDavid du Colombier if ( osErr != noErr )
255*593dc095SDavid du Colombier ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name);
256*593dc095SDavid du Colombier
257*593dc095SDavid du Colombier info->tempSpec = theSpec;
258*593dc095SDavid du Colombier
2597dd7cddfSDavid du Colombier info->read_backing_store = read_backing_store;
2607dd7cddfSDavid du Colombier info->write_backing_store = write_backing_store;
2617dd7cddfSDavid du Colombier info->close_backing_store = close_backing_store;
262*593dc095SDavid du Colombier TRACEMSS(cinfo, 1, JTRC_TFILE_OPEN, info->temp_name);
2637dd7cddfSDavid du Colombier }
2647dd7cddfSDavid du Colombier
2657dd7cddfSDavid du Colombier
2667dd7cddfSDavid du Colombier /*
2677dd7cddfSDavid du Colombier * These routines take care of any system-dependent initialization and
2687dd7cddfSDavid du Colombier * cleanup required.
2697dd7cddfSDavid du Colombier */
2707dd7cddfSDavid du Colombier
2717dd7cddfSDavid du Colombier GLOBAL(long)
jpeg_mem_init(j_common_ptr cinfo)2727dd7cddfSDavid du Colombier jpeg_mem_init (j_common_ptr cinfo)
2737dd7cddfSDavid du Colombier {
274*593dc095SDavid du Colombier next_file_num = 0;
275*593dc095SDavid du Colombier
2767dd7cddfSDavid du Colombier /* max_memory_to_use will be initialized to FreeMem()'s result;
2777dd7cddfSDavid du Colombier * the calling application might later reduce it, for example
2787dd7cddfSDavid du Colombier * to leave room to invoke multiple JPEG objects.
2797dd7cddfSDavid du Colombier * Note that FreeMem returns the total number of free bytes;
2807dd7cddfSDavid du Colombier * it may not be possible to allocate a single block of this size.
2817dd7cddfSDavid du Colombier */
2827dd7cddfSDavid du Colombier return FreeMem();
2837dd7cddfSDavid du Colombier }
2847dd7cddfSDavid du Colombier
2857dd7cddfSDavid du Colombier GLOBAL(void)
jpeg_mem_term(j_common_ptr cinfo)2867dd7cddfSDavid du Colombier jpeg_mem_term (j_common_ptr cinfo)
2877dd7cddfSDavid du Colombier {
2887dd7cddfSDavid du Colombier /* no work */
2897dd7cddfSDavid du Colombier }
290