Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / lib / DtHelp / il / ilefs.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: ilefs.c /main/3 1995/10/23 15:47:01 rswiston $ */
24 /**---------------------------------------------------------------------
25 ***     
26 ***    (c)Copyright 1992 Hewlett-Packard Co.
27 ***    
28 ***                             RESTRICTED RIGHTS LEGEND
29 ***    Use, duplication, or disclosure by the U.S. Government is subject to
30 ***    restrictions as set forth in sub-paragraph (c)(1)(ii) of the Rights in
31 ***    Technical Data and Computer Software clause in DFARS 252.227-7013.
32 ***                             Hewlett-Packard Company
33 ***                             3000 Hanover Street
34 ***                             Palo Alto, CA 94304 U.S.A.
35 ***    Rights for non-DOD U.S. Government Departments and Agencies are as set
36 ***    forth in FAR 52.227-19(c)(1,2).
37 ***
38 ***-------------------------------------------------------------------*/
39
40 #include <string.h>
41
42 #include "ilint.h"
43 #include "ilcontext.h"
44 #include "ilefs.h"
45 #include "ilpipeint.h"
46 #include "ilerrors.h"
47
48     /*  Beginning of file and file type recs - separate so list heads are smaller. */
49 typedef struct {
50     ilObjectRec             o;                  /* std header: MUST BE FIRST */
51     struct _ilEFSFileTypeRec *pNext, *pPrev;    /* forward / back ptrs */
52     } ilEFSHeaderRec, *ilEFSHeaderPtr;
53
54     /*  Private definition of an ilEFSFileType: an IL object. */
55 typedef struct _ilEFSFileTypeRec {
56     ilEFSHeaderRec          h;                  /* header: MUST BE FIRST */
57     ilEFSFileTypeInfo       info;               /* public file type info */
58     } ilEFSFileTypeRec, *ilEFSFileTypePtr;
59
60
61     /*  EFS private data, hung off of context.pAlloc[IL_CONTEXT_ALLOC_EFS]. */
62 typedef struct {
63     ilEFSHeaderRec          fileTypeHead;       /* list of active file types */
64     ilEFSHeaderRec          replacedFileTypeHead; /* list of replaced file types */
65     } ilEFSPrivateRec, *ilEFSPrivatePtr;
66
67
68     /*  Private definition of an ilEFSFile: an IL object. */
69 typedef struct {
70     ilObjectRec             o;                  /* std header: MUST BE FIRST */
71     ilEFSFileInfo           info;               /* public file type info */
72     ilEFSFileTypePtr        pFileType;          /* convenience: ptr to file type */
73     } ilEFSFileRec, *ilEFSFilePtr;
74
75
76     /*  Add _pFileType in front of element _pNextFileType */
77 #define LINK_FILE_TYPE(_pFileType, _pNextFileType) { \
78     (_pFileType)->h.pNext = (_pNextFileType); \
79     (_pFileType)->h.pPrev = (_pNextFileType)->h.pPrev; \
80     (_pFileType)->h.pPrev->h.pNext = (_pFileType); \
81     (_pNextFileType)->h.pPrev = (_pFileType); \
82     }
83
84     /*  Remove the given file type from its linked list */
85 #define UNLINK_FILE_TYPE(_pFileType) { \
86     (_pFileType)->h.pPrev->h.pNext = (_pFileType)->h.pNext; \
87     (_pFileType)->h.pNext->h.pPrev = (_pFileType)->h.pPrev; \
88     }
89
90     /*  Return true if given two strings are equal */
91 #define STRING_EQUAL(str, cmpstr) (strcmp ((str), (cmpstr)) == 0)
92
93         /*  In efsinit.c :
94             Called by the IL when EFS function is called.  Calls the individual
95             Init() function for each file type to be supported by EFS.
96         */
97 extern ilBool _ilefsInitStandardFiles (
98     ilContext               context
99     );
100
101
102         /*  ------------------------ ilInitEFS ---------------------------------- */
103         /*  Init EFS if not already inited (non-null ptr off of context.)
104             Return ptr to EFS context private or null if error.
105         */
106 static ilEFSPrivatePtr ilInitEFS (
107     ilContext               context
108     )
109 {
110 register ilEFSPrivatePtr    pPriv;
111
112         /*  If EFS file type data not present malloc and zero it, and then point
113             context pAlloc to it - if not, could recurse forever.
114         */
115     context->error = IL_OK;
116     pPriv = (ilEFSPrivatePtr)((ilContextPtr)context)->pAlloc[IL_CONTEXT_ALLOC_EFS];
117     if (!pPriv) {
118         pPriv = (ilEFSPrivatePtr)IL_MALLOC (sizeof (ilEFSPrivateRec));
119         if (!pPriv) {
120             context->error = IL_ERROR_MALLOC;
121             return (ilEFSPrivatePtr)NULL;
122             }
123         ((ilContextPtr)context)->pAlloc[IL_CONTEXT_ALLOC_EFS] = (ilPtr)pPriv;
124
125             /*  Init file type list to null. */
126         pPriv->fileTypeHead.pNext = pPriv->fileTypeHead.pPrev = 
127             (ilEFSFileTypePtr)&pPriv->fileTypeHead;
128         pPriv->replacedFileTypeHead.pNext = pPriv->replacedFileTypeHead.pPrev = 
129             (ilEFSFileTypePtr)&pPriv->replacedFileTypeHead;
130
131             /*  Call to external lib(s) to callback and add each file type */
132         if (!_ilefsInitStandardFiles (context)) {
133             IL_FREE (pPriv);
134             return (ilEFSPrivatePtr)NULL;
135             }
136         }
137     return pPriv;
138 }
139
140
141 /*  ================================== FILE TYPE CODE =============================== */
142
143         /*  ------------------------ ilFindFileType ---------------------------------- */
144         /*  Find the file type with the given "name" in the list of file types whose
145             head is pointed to by "pListHead".  Return ptr to found file type or null.
146         */
147 static ilEFSFileTypePtr ilFindFileType (
148     char                   *name,
149     ilEFSFileTypePtr        pListHead
150     )
151 {
152 register ilEFSFileTypePtr   pFileType;
153
154     pFileType = pListHead->h.pNext;
155     while (pFileType != pListHead) {
156         if (STRING_EQUAL (name, pFileType->info.name))
157             return pFileType;                   /* found, EXIT */
158         pFileType = pFileType->h.pNext;
159         }
160     return (ilEFSFileTypePtr)NULL;              /* not found, return null */
161 }
162
163
164         /*  ------------------------ ilAddFileTypeToList --------------------------- */
165         /*  Add the file type pointed to by "pFileType" to the list of file types whose
166             head is pointed to by "pListHead".  Element is placed in list based its
167             checkOrder.
168         */
169 static void ilAddFileTypeToList (
170     register ilEFSFileTypePtr pFileType,
171     ilEFSFileTypePtr        pListHead
172     )
173 {
174 register ilEFSFileTypePtr   pListFileType;
175 register int                checkOrder;
176
177     checkOrder = pFileType->info.checkOrder;
178     pListFileType = pListHead->h.pNext;
179     while (pListFileType != pListHead) {
180         if (checkOrder > pListFileType->info.checkOrder)
181             break;                              /* spot found; break */
182         pListFileType = pListFileType->h.pNext;
183         }
184     LINK_FILE_TYPE (pFileType, pListFileType)   /* insert in front of pListFileType */
185 }
186
187
188         /*  ------------------------ ilEFSAddFileType ---------------------------- */
189         /*  Public function: see spec.
190         */
191
192         /*  Object Destroy() function for file type objects. */
193 static void ilDestroyFileType (
194     register ilEFSFileTypePtr pFileType
195     )
196 {
197 ilEFSPrivatePtr             pPriv;
198 register ilEFSFileTypePtr   pReplaced;
199
200     pPriv = (ilEFSPrivatePtr)
201         ((ilContextPtr)(pFileType->h.o.p.context))->pAlloc[IL_CONTEXT_ALLOC_EFS];
202
203         /*  Remove file type from its current list.  Search the "replaced" list for a
204             file type of same name; if found, move it from replaced to active list.
205         */
206     UNLINK_FILE_TYPE (pFileType)
207     pReplaced = ilFindFileType (pFileType->info.name, 
208                                 (ilEFSFileTypePtr)&pPriv->replacedFileTypeHead);
209     if (pReplaced) {
210         UNLINK_FILE_TYPE (pReplaced)
211         ilAddFileTypeToList (pReplaced, (ilEFSFileTypePtr)&pPriv->fileTypeHead);
212         }
213 }
214
215
216 ilEFSFileType ilEFSAddFileType (
217     ilContext               context,
218     register ilEFSFileTypeInfo *pInfo,
219     void                   *pOptions
220     )
221 {
222 ilEFSPrivatePtr             pPriv;
223 int                         i;
224 register ilEFSFileTypePtr   pFileType, pReplace;
225 register unsigned long      openModes;
226
227         /* masks for defined bits in ilEFSFileTypeInfo - others invalid */
228 #define OPEN_MODE_MASKS (1<<IL_EFS_READ | 1<<IL_EFS_READ_SEQUENTIAL | 1<<IL_EFS_WRITE)
229 #define ATTRIBUTES_MASKS (IL_EFS_MULTI_PAGE_READS | IL_EFS_MULTI_PAGE_WRITES | \
230                           IL_EFS_MASK_READS | IL_EFS_MASK_WRITES | IL_EFS_SCALEABLE_READS)
231
232     if (pOptions) {
233         context->error = IL_ERROR_PAR_NOT_ZERO;
234         return (ilEFSFileType)NULL;
235         }
236
237         /*  Validate *pInfo: strings present, unused mask bits zero, functions right. */
238     if ((strlen (pInfo->name) > (IL_EFS_MAX_NAME_CHARS - 1))
239      || (strlen (pInfo->displayName) > (IL_EFS_MAX_DISPLAY_NAME_CHARS - 1))
240      || (pInfo->nExtensions > IL_EFS_MAX_EXTENSIONS))
241         goto badFileTypeInfo;
242
243     for (i = 0; i < pInfo->nExtensions; i++)
244         if (strlen (pInfo->extensions[i]) > (IL_EFS_MAX_EXTENSION_CHARS - 1))
245             goto badFileTypeInfo;
246
247     openModes = pInfo->openModes;
248     if ((openModes & ~OPEN_MODE_MASKS)
249      || (pInfo->attributes & ~ATTRIBUTES_MASKS))
250         goto badFileTypeInfo;
251
252     if (((!pInfo->Open || !pInfo->Open) && openModes)
253      || (!pInfo->Seek && (openModes & 1<<IL_EFS_READ) 
254            && (pInfo->attributes & IL_EFS_MULTI_PAGE_READS))
255      || ((!pInfo->GetPageInfo || !pInfo->ReadImage) 
256           && (openModes & (1<<IL_EFS_READ | 1<<IL_EFS_READ_SEQUENTIAL)))
257      || (!pInfo->WriteImage && (openModes & 1<<IL_EFS_WRITE)))
258         goto badFileTypeInfo;
259
260     for (i = 0; i < IL_EFS_TYPE_RESERVED_SIZE; i++)
261         if (pInfo->reserved[i] != 0)
262             goto badFileTypeInfo;
263
264         /*  Init EFS file types if not already inited. */
265     if (!(pPriv = ilInitEFS (context))) 
266         return (ilEFSFileType)NULL;
267
268         /*  Create a file type object, exit if failure. Set *pInfo into it. */
269     pFileType = (ilEFSFileTypePtr)_ilCreateObject (context, IL_EFS_FILE_TYPE, 
270                 ilDestroyFileType, sizeof (ilEFSFileTypeRec));
271     if (!pFileType) return (ilEFSFileType)NULL;
272     pFileType->info = *pInfo;
273
274         /*  Search the active list for file type with same name.  If found, remove it
275             from active list and add to replaced list, in front of any with same name.
276         */
277     pReplace = ilFindFileType (pFileType->info.name, 
278                                (ilEFSFileTypePtr)&pPriv->fileTypeHead);
279     if (pReplace) {
280         ilEFSFileTypePtr pReplaceFront;
281         UNLINK_FILE_TYPE (pReplace)
282         pReplaceFront = ilFindFileType (pFileType->info.name, 
283                                         (ilEFSFileTypePtr)&pPriv->fileTypeHead);
284         if (!pReplaceFront)
285             pReplaceFront = (ilEFSFileTypePtr)&pPriv->fileTypeHead;
286         LINK_FILE_TYPE (pReplace, pReplaceFront)
287         }
288
289         /*  Add the file type to the active list */
290     ilAddFileTypeToList (pFileType, (ilEFSFileTypePtr)&pPriv->fileTypeHead);
291
292     context->error = IL_OK;
293     return (ilEFSFileType)pFileType;
294
295         /*  goto point if invalid file type info: return error. */
296 badFileTypeInfo:
297     context->error = IL_ERROR_EFS_FILE_TYPE_INFO;
298     return (ilEFSFileType)NULL;
299 }
300
301
302         /*  ------------------------ ilEFSGetFileTypeInfo ---------------------------- */
303         /*  Public function: see spec.
304         */
305 ilBool ilEFSGetFileTypeInfo (
306     ilEFSFileType           fileType,
307     ilEFSFileTypeInfo      *pInfo
308     )
309 {
310 register ilEFSFileTypePtr   pFileType;
311
312     pFileType = (ilEFSFileTypePtr)fileType;
313     if (pFileType->h.o.p.objectType != IL_EFS_FILE_TYPE) {
314         pFileType->h.o.p.context->error = IL_ERROR_OBJECT_TYPE;
315         return FALSE;
316         }
317
318     *pInfo = pFileType->info;
319     pFileType->h.o.p.context->error = IL_OK;
320     return TRUE;
321 }
322
323
324         /*  ------------------------ ilEFSListFileTypes ------------------------------ */
325         /*  Public function: see spec.
326         */
327 ilBool ilEFSListFileTypes (
328     ilContext               context,
329      int           *pNFileTypes,
330     ilEFSFileType         **pfileTypes
331     )
332 {
333 ilEFSPrivatePtr             pPriv;
334 register int                nFileTypes;
335 register ilEFSFileTypePtr   pFileType;
336 register ilEFSFileType     *pfileType;
337
338     *pNFileTypes = 0;
339     *pfileTypes = (ilEFSFileType *)NULL;
340
341         /*  Init EFS file types if not already inited. */
342     if (!(pPriv = ilInitEFS (context)))
343         return FALSE;
344
345         /*  Count the number of file types in the list */
346     nFileTypes = 0;
347     pFileType = pPriv->fileTypeHead.pNext;
348     while (pFileType != (ilEFSFileTypePtr)&pPriv->fileTypeHead) {
349         pFileType = pFileType->h.pNext;
350         nFileTypes++;
351         }
352
353         /*  Malloc space for returned file types - use malloc(); caller uses free().
354             If no file types, still malloc something to return non-null ptr.
355         */
356     pfileType = (ilEFSFileType *)malloc ((nFileTypes > 0) ? 
357                                           nFileTypes * sizeof (ilEFSFileType) : 4);
358     if (!pfileType) {
359         context->error = IL_ERROR_MALLOC;
360         return FALSE;
361         }
362
363         /*  Return # of file types; traverse list to return ptrs to them. */
364     *pfileTypes = pfileType;
365     *pNFileTypes = nFileTypes;
366     pFileType = pPriv->fileTypeHead.pNext;
367     while (nFileTypes-- > 0) {
368         *pfileType++ = (ilEFSFileType)pFileType;
369         pFileType = pFileType->h.pNext;
370         }
371
372     context->error = IL_OK;
373     return TRUE;
374 }
375
376
377 /*  =================================== FILE CODE ================================== */
378
379
380         /*  --------------------------- ilEFSOpenFile ------------------------------- */
381         /*  Public function: see spec.
382         */
383
384         /*  Object Destroy() function for file objects. */
385 static void ilDestroyFile (
386     ilEFSFilePtr            pFile
387     )
388 {
389 register ilEFSFileTypePtr   pFileType;
390
391         /*  Get ptr to file type; if null, file not actually open yet; skip Close() */
392     pFileType = (ilEFSFileTypePtr)pFile->info.fileType;
393     if (pFileType)
394         (*pFileType->info.Close) (pFile);
395 }
396
397
398 ilEFSFile ilEFSOpen (
399     ilContext               context,
400     char                   *fileName,
401     unsigned int            openMode,
402     unsigned long           searchOptions,
403     char                   *typeName,
404     void                   *pOptions
405     )
406 {
407 ilEFSPrivatePtr             pPriv;
408 register ilEFSFilePtr       pFile;
409 register ilEFSFileTypePtr   pFileType, pListHead;
410 ilBool                      readOpen;
411 long                        nPages;
412 ilPtr                       pOpenPriv;
413 char                        extension [IL_EFS_MAX_EXTENSION_CHARS];
414
415         /*  Validate pOptions, openMode (set readOpen true if a read). */
416     context->error = IL_OK;
417     if (pOptions) {
418         context->error = IL_ERROR_PAR_NOT_ZERO;
419         return (ilEFSFileType)NULL;
420         }
421     switch (openMode) {
422       case IL_EFS_READ: 
423       case IL_EFS_READ_SEQUENTIAL: 
424           readOpen = TRUE; break;
425       case IL_EFS_WRITE: 
426           readOpen = FALSE; break;
427       default:
428         context->error = IL_ERROR_EFS_OPEN_MODE;
429         return (ilEFSFile)NULL;
430         }
431
432         /*  Init EFS file types if not already inited. */
433     if (!(pPriv = ilInitEFS (context)))
434         return (ilEFSFile)NULL;
435
436         /*  Add a file type object - goto openError to destroy it if an error later. */
437     pFile = (ilEFSFilePtr)_ilCreateObject (context, IL_EFS_FILE, ilDestroyFile, 
438                                           sizeof (ilEFSFileRec));
439     if (!pFile) return (ilEFSFile)NULL;
440
441         /*  Find pFileType for this file, searches enabled by mask in searchOptions.
442             First try typeName, if non-null.  When found at any point: if openMode
443             not supported, error - except for checking mode - else call Open() for
444             the file type.  If it returns any error other than "not mine" abort.
445         */
446     pFileType = (ilEFSFileTypePtr)NULL;
447     pListHead = (ilEFSFileTypePtr)&pPriv->fileTypeHead;
448     if (typeName && (searchOptions & IL_EFS_BY_TYPE_NAME)) {
449         pFileType = ilFindFileType (typeName, pListHead);
450         if (pFileType) {                                    /* file type found */
451             if (!(pFileType->info.openModes & (1 << openMode))) {
452                 context->error = IL_ERROR_EFS_OPEN_MODE;
453                 goto openError;
454                 }
455             pOpenPriv = (*pFileType->info.Open) (pFileType, fileName, openMode, &nPages);
456             if (!pOpenPriv) {
457                 if (context->error == IL_ERROR_EFS_NOT_MINE)
458                     pFileType = (ilEFSFileTypePtr)NULL;     /* try next search method */
459                 else goto openError;
460                 }
461             pFile->info.howFound = IL_EFS_BY_CHECKING;
462             }
463         }   /* END open by type name */
464
465
466         /*  If not found, search for extension if enabled. */
467     if (!pFileType && (searchOptions & IL_EFS_BY_EXTENSION)) {
468         char                       *pExtension;
469         register ilEFSFileTypePtr   pSearch;
470         int                         nChars;
471
472         pExtension = strrchr (fileName, '.');
473         if (pExtension) {                               /* is a "." in fileName */
474             pExtension++;                               /* point past "." */
475             nChars = strlen (pExtension);
476             if (nChars > (IL_EFS_MAX_EXTENSION_CHARS - 1))
477                 nChars = IL_EFS_MAX_EXTENSION_CHARS - 1;
478             bcopy (pExtension, extension, nChars);      /* extract "extension" */
479             extension [nChars] = 0;
480
481                 /* Search list for extension match until pFileType found or list done */
482             pSearch = pListHead->h.pNext;
483             while (!pFileType && (pSearch != pListHead)) {
484                 register int nExtensions = pSearch->info.nExtensions;
485                 while (nExtensions-- > 0)
486                     if (STRING_EQUAL (extension, pSearch->info.extensions[nExtensions])) {
487                         pFileType = pSearch;            /* extension found; quit */
488                         pFile->info.howFound = IL_EFS_BY_CHECKING;
489                         break;
490                         }
491                 pSearch = pSearch->h.pNext;
492                 }
493             if (pFileType) {
494                 if (!(pFileType->info.openModes & (1 << openMode))) {
495                     context->error = IL_ERROR_EFS_OPEN_MODE;
496                     goto openError;
497                     }
498                 pOpenPriv = (*pFileType->info.Open) (pFileType, fileName, openMode, &nPages);
499                 if (!pOpenPriv) {
500                     if (context->error == IL_ERROR_EFS_NOT_MINE)
501                         pFileType = (ilEFSFileTypePtr)NULL;
502                     else goto openError;
503                     }
504                 }
505             }   /* END have extension */
506         }       /* END open by extension */
507
508
509         /*  If not found, search by checking if a read openMode.   For each file type,
510             try open if enabled (checkOrder != 0) and openMode supported for file type.
511         */
512     if (!pFileType && readOpen && (searchOptions & IL_EFS_BY_CHECKING)) {
513         register ilEFSFileTypePtr   pSearch;
514
515         pSearch = pListHead->h.pNext;
516         while (pSearch != pListHead) {
517             if (pSearch->info.checkOrder && (pSearch->info.openModes & (1 << openMode))) {
518                 pOpenPriv = (*pSearch->info.Open) (pSearch, fileName, openMode, &nPages);
519                 if (pOpenPriv) {
520                     pFileType = pSearch;                /* found right file type; break */
521                     pFile->info.howFound = IL_EFS_BY_CHECKING;
522                     break;
523                     }
524                 else if (context->error != IL_ERROR_EFS_NOT_MINE)
525                     goto openError;                     /* some error; give up */
526                 }
527             pSearch = pSearch->h.pNext;
528             }
529         }   /* END open by checking */
530
531         /*  If not found above, error: can't find file type handler for this file. */
532     if (!pFileType) {
533         context->error = IL_ERROR_EFS_NO_FILE_TYPE;
534         goto openError;
535         }
536
537         /*  File type found.  Fill in info for the file, return pFile.  The object's
538             pPrivate is set to the ptr returned from file type's Open().
539         */
540     pFile->o.p.pPrivate = pOpenPriv;
541     pFile->info.fileType = (ilEFSFileType)pFileType;
542     pFile->info.openMode = openMode;
543     pFile->info.attributes = pFileType->info.attributes;
544     pFile->info.nPages = nPages;
545     pFile->pFileType = pFileType;
546
547     context->error = IL_OK;
548     return (ilEFSFile)pFile;                            /* success; return file */
549
550         /*  openError: goto here on error after file object created. The Open() was not
551             successful, so set fileType to null so ilDestroyFile() does not call Close().
552         */
553 openError:
554 {   ilError     error;
555     error = context->error;                 /* save error code */
556     pFile->info.fileType = (ilEFSFileType)NULL;
557     ilDestroyObject ((ilObject)pFile);
558     context->error = error;                 /* restore error code */
559     return (ilEFSFile)NULL;
560 }
561 }
562
563
564         /*  ------------------------ ilEFSGetFileInfo ---------------------------- */
565         /*  Public function: see spec.
566         */
567 ilBool ilEFSGetFileInfo (
568     ilEFSFile               file,
569     ilEFSFileInfo          *pInfo                   /* RETURNED */
570     )
571 {
572 register ilEFSFilePtr       pFile;
573
574     pFile = (ilEFSFilePtr)file;
575     if (pFile->o.p.objectType != IL_EFS_FILE) {
576         pFile->o.p.context->error = IL_ERROR_OBJECT_TYPE;
577         return FALSE;
578         }
579
580         /*  Return file info; fill in "inUse": file in use if refCount > 1 */
581     *pInfo = pFile->info;
582     pInfo->inUse = (pFile->o.refCount > 1);
583     pFile->o.p.context->error = IL_OK;
584     return TRUE;
585 }
586
587
588         /*  ------------------------ ilEFSSeek ---------------------------- */
589         /*  Public function: see spec.
590         */
591 ilBool ilEFSSeek (
592     ilEFSFile               file,
593     long                    page,
594     void                   *pOptions
595     )
596 {
597 register ilEFSFilePtr       pFile;
598
599     pFile = (ilEFSFilePtr)file;
600     if (pOptions) {
601         pFile->o.p.context->error = IL_ERROR_PAR_NOT_ZERO;
602         return FALSE;
603         }
604     if (pFile->o.p.objectType != IL_EFS_FILE) {
605         pFile->o.p.context->error = IL_ERROR_OBJECT_TYPE;
606         return FALSE;
607         }
608
609         /*  Validate that file was opened for random read; error if not. */
610     if (pFile->info.openMode != IL_EFS_READ) {
611         pFile->o.p.context->error = IL_ERROR_EFS_OPEN_MODE;
612         return FALSE;
613         }
614
615         /*  Call Seek() only if multi-page reads supported; not error if not. */
616     pFile->o.p.context->error = IL_OK;
617     if (!(pFile->info.attributes & IL_EFS_MULTI_PAGE_READS))
618         return TRUE;
619     else return (*pFile->pFileType->info.Seek) (file, page);
620 }
621
622
623         /*  ------------------------ ilEFSGetPageInfo ---------------------------- */
624         /*  Public function: see spec.
625         */
626 ilBool ilEFSGetPageInfo (
627     ilEFSFile               file,
628     ilEFSPageInfo          *pInfo
629     )
630 {
631 register ilEFSFilePtr       pFile;
632
633     pFile = (ilEFSFilePtr)file;
634     if (pFile->o.p.objectType != IL_EFS_FILE) {
635         pFile->o.p.context->error = IL_ERROR_OBJECT_TYPE;
636         return FALSE;
637         }
638
639         /*  Validate that file was opened for read; call GetPageInfo() if so. */
640     if ((pFile->info.openMode != IL_EFS_READ) 
641      && (pFile->info.openMode != IL_EFS_READ_SEQUENTIAL)) {
642         pFile->o.p.context->error = IL_ERROR_EFS_OPEN_MODE;
643         return FALSE;
644         }
645
646     pFile->o.p.context->error = IL_OK;
647     return (*pFile->pFileType->info.GetPageInfo) (file, pInfo);
648 }
649
650
651         /*  ------------------------ ilEFSReadImage ---------------------------- */
652         /*  Public function: see spec.
653         */
654 ilBool ilEFSReadImage (
655     ilPipe                  pipe,
656     ilEFSFile               file,
657     unsigned int            readMode,
658     long                    width,
659     long                    height,
660     void                   *pOptions
661     )
662 {
663 register ilEFSFilePtr       pFile;
664
665     pFile = (ilEFSFilePtr)file;
666     if (pOptions) {
667         pFile->o.p.context->error = IL_ERROR_PAR_NOT_ZERO;
668         return FALSE;
669         }
670     if ((pipe->objectType != IL_PIPE) || (pFile->o.p.objectType != IL_EFS_FILE)) {
671         pFile->o.p.context->error = IL_ERROR_OBJECT_TYPE;
672         return FALSE;
673         }
674
675         /*  Validate readMode: mask allowed only if supported by file type. */
676     switch (readMode) {
677       case IL_EFS_READ_MAIN:
678         break;
679       case IL_EFS_READ_MASK:
680         if (pFile->pFileType->info.attributes & IL_EFS_MASK_READS)
681             break;                                      /* else fall thru for error */
682       default:
683         pFile->o.p.context->error = IL_ERROR_EFS_READ_MODE;
684         return FALSE;
685         }
686
687         /*  Validate that file was opened for read. */
688     if ((pFile->info.openMode != IL_EFS_READ) 
689      && (pFile->info.openMode != IL_EFS_READ_SEQUENTIAL)) {
690         pFile->o.p.context->error = IL_ERROR_EFS_OPEN_MODE;
691         return FALSE;
692         }
693
694         /*  If pipe element added successfully inc file's refCount to mark in use,
695             and add file to list of objects to be destroyed when pipe emptied.
696         */
697     pFile->o.p.context->error = IL_OK;
698     if ((*pFile->pFileType->info.ReadImage) (pipe, file, readMode, width, height)) {
699         pFile->o.refCount++;
700         return _ilAddPipeDestroyObject (pipe, (ilObject)pFile);
701         }
702     else return FALSE;
703 }
704
705
706         /*  ------------------------ ilEFSWriteImage ---------------------------- */
707         /*  Public function: see spec.
708         */
709 ilBool ilEFSWriteImage (
710     ilPipe                  pipe,
711     ilEFSFile               file,
712     long                    xRes,
713     long                    yRes,
714     ilClientImage           maskImage,
715     void                   *pOptions
716     )
717 {
718 register ilEFSFilePtr       pFile;
719
720     pFile = (ilEFSFilePtr)file;
721     if (pOptions) {
722         pFile->o.p.context->error = IL_ERROR_PAR_NOT_ZERO;
723         return FALSE;
724         }
725     if ((pipe->objectType != IL_PIPE) || (pFile->o.p.objectType != IL_EFS_FILE)) {
726         pFile->o.p.context->error = IL_ERROR_OBJECT_TYPE;
727         return FALSE;
728         }
729
730         /*  Validate that file was opened for write. */
731     if (pFile->info.openMode != IL_EFS_WRITE) {
732         pFile->o.p.context->error = IL_ERROR_EFS_OPEN_MODE;
733         return FALSE;
734         }
735
736         /*  If file type doesnt handle masks, ignore maskImage, else validate it */
737     if (maskImage) {
738         if (!(pFile->pFileType->info.attributes & IL_EFS_MASK_WRITES))
739             maskImage = (ilClientImage)NULL;
740         else {
741             ilImageInfo            *pInfo;
742             register const ilImageDes    *pDes;
743             register const ilImageFormat *pFormat;
744
745             if (!ilQueryClientImage (maskImage, &pInfo, 0))
746                 return FALSE;
747             pDes = pInfo->pDes;
748             pFormat = pInfo->pFormat;
749             if ((pDes->compression != IL_UNCOMPRESSED)
750              || (pDes->nSamplesPerPixel != 1)
751              || (pFormat->rowBitAlign != 32)
752              || (pFormat->nBitsPerSample[0] != 1)) {
753                 pFile->o.p.context->error = IL_ERROR_EFS_OPEN_MODE;
754                 return FALSE;
755                 }
756             }
757         }
758
759         /*  If pipe element added successfully inc file's refCount to mark in use,
760             and add file/maskImage to list of objects to be destroyed when pipe emptied.
761         */
762     pFile->o.p.context->error = IL_OK;
763     if ((*pFile->pFileType->info.WriteImage) (pipe, file, xRes, yRes, maskImage)) {
764         if (maskImage) {
765             ((ilObjectPtr)maskImage)->refCount++;
766             _ilAddPipeDestroyObject (pipe, maskImage);
767             }
768         pFile->o.refCount++;
769         return _ilAddPipeDestroyObject (pipe, (ilObject)pFile);
770         }
771     else return FALSE;
772 }
773