mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
773 lines
28 KiB
C
773 lines
28 KiB
C
/*
|
|
* CDE - Common Desktop Environment
|
|
*
|
|
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
|
|
*
|
|
* These libraries and programs are free software; you can
|
|
* redistribute them and/or modify them under the terms of the GNU
|
|
* Lesser General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* These libraries and programs are distributed in the hope that
|
|
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with these librararies and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
/* $XConsortium: ilefs.c /main/3 1995/10/23 15:47:01 rswiston $ */
|
|
/**---------------------------------------------------------------------
|
|
***
|
|
*** (c)Copyright 1992 Hewlett-Packard Co.
|
|
***
|
|
*** RESTRICTED RIGHTS LEGEND
|
|
*** Use, duplication, or disclosure by the U.S. Government is subject to
|
|
*** restrictions as set forth in sub-paragraph (c)(1)(ii) of the Rights in
|
|
*** Technical Data and Computer Software clause in DFARS 252.227-7013.
|
|
*** Hewlett-Packard Company
|
|
*** 3000 Hanover Street
|
|
*** Palo Alto, CA 94304 U.S.A.
|
|
*** Rights for non-DOD U.S. Government Departments and Agencies are as set
|
|
*** forth in FAR 52.227-19(c)(1,2).
|
|
***
|
|
***-------------------------------------------------------------------*/
|
|
|
|
#include <string.h>
|
|
|
|
#include "ilint.h"
|
|
#include "ilcontext.h"
|
|
#include "ilefs.h"
|
|
#include "ilpipeint.h"
|
|
#include "ilerrors.h"
|
|
|
|
/* Beginning of file and file type recs - separate so list heads are smaller. */
|
|
typedef struct {
|
|
ilObjectRec o; /* std header: MUST BE FIRST */
|
|
struct _ilEFSFileTypeRec *pNext, *pPrev; /* forward / back ptrs */
|
|
} ilEFSHeaderRec, *ilEFSHeaderPtr;
|
|
|
|
/* Private definition of an ilEFSFileType: an IL object. */
|
|
typedef struct _ilEFSFileTypeRec {
|
|
ilEFSHeaderRec h; /* header: MUST BE FIRST */
|
|
ilEFSFileTypeInfo info; /* public file type info */
|
|
} ilEFSFileTypeRec, *ilEFSFileTypePtr;
|
|
|
|
|
|
/* EFS private data, hung off of context.pAlloc[IL_CONTEXT_ALLOC_EFS]. */
|
|
typedef struct {
|
|
ilEFSHeaderRec fileTypeHead; /* list of active file types */
|
|
ilEFSHeaderRec replacedFileTypeHead; /* list of replaced file types */
|
|
} ilEFSPrivateRec, *ilEFSPrivatePtr;
|
|
|
|
|
|
/* Private definition of an ilEFSFile: an IL object. */
|
|
typedef struct {
|
|
ilObjectRec o; /* std header: MUST BE FIRST */
|
|
ilEFSFileInfo info; /* public file type info */
|
|
ilEFSFileTypePtr pFileType; /* convenience: ptr to file type */
|
|
} ilEFSFileRec, *ilEFSFilePtr;
|
|
|
|
|
|
/* Add _pFileType in front of element _pNextFileType */
|
|
#define LINK_FILE_TYPE(_pFileType, _pNextFileType) { \
|
|
(_pFileType)->h.pNext = (_pNextFileType); \
|
|
(_pFileType)->h.pPrev = (_pNextFileType)->h.pPrev; \
|
|
(_pFileType)->h.pPrev->h.pNext = (_pFileType); \
|
|
(_pNextFileType)->h.pPrev = (_pFileType); \
|
|
}
|
|
|
|
/* Remove the given file type from its linked list */
|
|
#define UNLINK_FILE_TYPE(_pFileType) { \
|
|
(_pFileType)->h.pPrev->h.pNext = (_pFileType)->h.pNext; \
|
|
(_pFileType)->h.pNext->h.pPrev = (_pFileType)->h.pPrev; \
|
|
}
|
|
|
|
/* Return true if given two strings are equal */
|
|
#define STRING_EQUAL(str, cmpstr) (strcmp ((str), (cmpstr)) == 0)
|
|
|
|
/* In efsinit.c :
|
|
Called by the IL when EFS function is called. Calls the individual
|
|
Init() function for each file type to be supported by EFS.
|
|
*/
|
|
extern ilBool _ilefsInitStandardFiles (
|
|
ilContext context
|
|
);
|
|
|
|
|
|
/* ------------------------ ilInitEFS ---------------------------------- */
|
|
/* Init EFS if not already inited (non-null ptr off of context.)
|
|
Return ptr to EFS context private or null if error.
|
|
*/
|
|
static ilEFSPrivatePtr ilInitEFS (
|
|
ilContext context
|
|
)
|
|
{
|
|
register ilEFSPrivatePtr pPriv;
|
|
|
|
/* If EFS file type data not present malloc and zero it, and then point
|
|
context pAlloc to it - if not, could recurse forever.
|
|
*/
|
|
context->error = IL_OK;
|
|
pPriv = (ilEFSPrivatePtr)((ilContextPtr)context)->pAlloc[IL_CONTEXT_ALLOC_EFS];
|
|
if (!pPriv) {
|
|
pPriv = (ilEFSPrivatePtr)IL_MALLOC (sizeof (ilEFSPrivateRec));
|
|
if (!pPriv) {
|
|
context->error = IL_ERROR_MALLOC;
|
|
return (ilEFSPrivatePtr)NULL;
|
|
}
|
|
((ilContextPtr)context)->pAlloc[IL_CONTEXT_ALLOC_EFS] = (ilPtr)pPriv;
|
|
|
|
/* Init file type list to null. */
|
|
pPriv->fileTypeHead.pNext = pPriv->fileTypeHead.pPrev =
|
|
(ilEFSFileTypePtr)&pPriv->fileTypeHead;
|
|
pPriv->replacedFileTypeHead.pNext = pPriv->replacedFileTypeHead.pPrev =
|
|
(ilEFSFileTypePtr)&pPriv->replacedFileTypeHead;
|
|
|
|
/* Call to external lib(s) to callback and add each file type */
|
|
if (!_ilefsInitStandardFiles (context)) {
|
|
IL_FREE (pPriv);
|
|
return (ilEFSPrivatePtr)NULL;
|
|
}
|
|
}
|
|
return pPriv;
|
|
}
|
|
|
|
|
|
/* ================================== FILE TYPE CODE =============================== */
|
|
|
|
/* ------------------------ ilFindFileType ---------------------------------- */
|
|
/* Find the file type with the given "name" in the list of file types whose
|
|
head is pointed to by "pListHead". Return ptr to found file type or null.
|
|
*/
|
|
static ilEFSFileTypePtr ilFindFileType (
|
|
char *name,
|
|
ilEFSFileTypePtr pListHead
|
|
)
|
|
{
|
|
register ilEFSFileTypePtr pFileType;
|
|
|
|
pFileType = pListHead->h.pNext;
|
|
while (pFileType != pListHead) {
|
|
if (STRING_EQUAL (name, pFileType->info.name))
|
|
return pFileType; /* found, EXIT */
|
|
pFileType = pFileType->h.pNext;
|
|
}
|
|
return (ilEFSFileTypePtr)NULL; /* not found, return null */
|
|
}
|
|
|
|
|
|
/* ------------------------ ilAddFileTypeToList --------------------------- */
|
|
/* Add the file type pointed to by "pFileType" to the list of file types whose
|
|
head is pointed to by "pListHead". Element is placed in list based its
|
|
checkOrder.
|
|
*/
|
|
static void ilAddFileTypeToList (
|
|
register ilEFSFileTypePtr pFileType,
|
|
ilEFSFileTypePtr pListHead
|
|
)
|
|
{
|
|
register ilEFSFileTypePtr pListFileType;
|
|
register int checkOrder;
|
|
|
|
checkOrder = pFileType->info.checkOrder;
|
|
pListFileType = pListHead->h.pNext;
|
|
while (pListFileType != pListHead) {
|
|
if (checkOrder > pListFileType->info.checkOrder)
|
|
break; /* spot found; break */
|
|
pListFileType = pListFileType->h.pNext;
|
|
}
|
|
LINK_FILE_TYPE (pFileType, pListFileType) /* insert in front of pListFileType */
|
|
}
|
|
|
|
|
|
/* ------------------------ ilEFSAddFileType ---------------------------- */
|
|
/* Public function: see spec.
|
|
*/
|
|
|
|
/* Object Destroy() function for file type objects. */
|
|
static void ilDestroyFileType (
|
|
register ilEFSFileTypePtr pFileType
|
|
)
|
|
{
|
|
ilEFSPrivatePtr pPriv;
|
|
register ilEFSFileTypePtr pReplaced;
|
|
|
|
pPriv = (ilEFSPrivatePtr)
|
|
((ilContextPtr)(pFileType->h.o.p.context))->pAlloc[IL_CONTEXT_ALLOC_EFS];
|
|
|
|
/* Remove file type from its current list. Search the "replaced" list for a
|
|
file type of same name; if found, move it from replaced to active list.
|
|
*/
|
|
UNLINK_FILE_TYPE (pFileType)
|
|
pReplaced = ilFindFileType (pFileType->info.name,
|
|
(ilEFSFileTypePtr)&pPriv->replacedFileTypeHead);
|
|
if (pReplaced) {
|
|
UNLINK_FILE_TYPE (pReplaced)
|
|
ilAddFileTypeToList (pReplaced, (ilEFSFileTypePtr)&pPriv->fileTypeHead);
|
|
}
|
|
}
|
|
|
|
|
|
ilEFSFileType ilEFSAddFileType (
|
|
ilContext context,
|
|
register ilEFSFileTypeInfo *pInfo,
|
|
void *pOptions
|
|
)
|
|
{
|
|
ilEFSPrivatePtr pPriv;
|
|
int i;
|
|
register ilEFSFileTypePtr pFileType, pReplace;
|
|
register unsigned long openModes;
|
|
|
|
/* masks for defined bits in ilEFSFileTypeInfo - others invalid */
|
|
#define OPEN_MODE_MASKS (1<<IL_EFS_READ | 1<<IL_EFS_READ_SEQUENTIAL | 1<<IL_EFS_WRITE)
|
|
#define ATTRIBUTES_MASKS (IL_EFS_MULTI_PAGE_READS | IL_EFS_MULTI_PAGE_WRITES | \
|
|
IL_EFS_MASK_READS | IL_EFS_MASK_WRITES | IL_EFS_SCALEABLE_READS)
|
|
|
|
if (pOptions) {
|
|
context->error = IL_ERROR_PAR_NOT_ZERO;
|
|
return (ilEFSFileType)NULL;
|
|
}
|
|
|
|
/* Validate *pInfo: strings present, unused mask bits zero, functions right. */
|
|
if ((strlen (pInfo->name) > (IL_EFS_MAX_NAME_CHARS - 1))
|
|
|| (strlen (pInfo->displayName) > (IL_EFS_MAX_DISPLAY_NAME_CHARS - 1))
|
|
|| (pInfo->nExtensions > IL_EFS_MAX_EXTENSIONS))
|
|
goto badFileTypeInfo;
|
|
|
|
for (i = 0; i < pInfo->nExtensions; i++)
|
|
if (strlen (pInfo->extensions[i]) > (IL_EFS_MAX_EXTENSION_CHARS - 1))
|
|
goto badFileTypeInfo;
|
|
|
|
openModes = pInfo->openModes;
|
|
if ((openModes & ~OPEN_MODE_MASKS)
|
|
|| (pInfo->attributes & ~ATTRIBUTES_MASKS))
|
|
goto badFileTypeInfo;
|
|
|
|
if (((!pInfo->Open || !pInfo->Open) && openModes)
|
|
|| (!pInfo->Seek && (openModes & 1<<IL_EFS_READ)
|
|
&& (pInfo->attributes & IL_EFS_MULTI_PAGE_READS))
|
|
|| ((!pInfo->GetPageInfo || !pInfo->ReadImage)
|
|
&& (openModes & (1<<IL_EFS_READ | 1<<IL_EFS_READ_SEQUENTIAL)))
|
|
|| (!pInfo->WriteImage && (openModes & 1<<IL_EFS_WRITE)))
|
|
goto badFileTypeInfo;
|
|
|
|
for (i = 0; i < IL_EFS_TYPE_RESERVED_SIZE; i++)
|
|
if (pInfo->reserved[i] != 0)
|
|
goto badFileTypeInfo;
|
|
|
|
/* Init EFS file types if not already inited. */
|
|
if (!(pPriv = ilInitEFS (context)))
|
|
return (ilEFSFileType)NULL;
|
|
|
|
/* Create a file type object, exit if failure. Set *pInfo into it. */
|
|
pFileType = (ilEFSFileTypePtr)_ilCreateObject (context, IL_EFS_FILE_TYPE,
|
|
ilDestroyFileType, sizeof (ilEFSFileTypeRec));
|
|
if (!pFileType) return (ilEFSFileType)NULL;
|
|
pFileType->info = *pInfo;
|
|
|
|
/* Search the active list for file type with same name. If found, remove it
|
|
from active list and add to replaced list, in front of any with same name.
|
|
*/
|
|
pReplace = ilFindFileType (pFileType->info.name,
|
|
(ilEFSFileTypePtr)&pPriv->fileTypeHead);
|
|
if (pReplace) {
|
|
ilEFSFileTypePtr pReplaceFront;
|
|
UNLINK_FILE_TYPE (pReplace)
|
|
pReplaceFront = ilFindFileType (pFileType->info.name,
|
|
(ilEFSFileTypePtr)&pPriv->fileTypeHead);
|
|
if (!pReplaceFront)
|
|
pReplaceFront = (ilEFSFileTypePtr)&pPriv->fileTypeHead;
|
|
LINK_FILE_TYPE (pReplace, pReplaceFront)
|
|
}
|
|
|
|
/* Add the file type to the active list */
|
|
ilAddFileTypeToList (pFileType, (ilEFSFileTypePtr)&pPriv->fileTypeHead);
|
|
|
|
context->error = IL_OK;
|
|
return (ilEFSFileType)pFileType;
|
|
|
|
/* goto point if invalid file type info: return error. */
|
|
badFileTypeInfo:
|
|
context->error = IL_ERROR_EFS_FILE_TYPE_INFO;
|
|
return (ilEFSFileType)NULL;
|
|
}
|
|
|
|
|
|
/* ------------------------ ilEFSGetFileTypeInfo ---------------------------- */
|
|
/* Public function: see spec.
|
|
*/
|
|
ilBool ilEFSGetFileTypeInfo (
|
|
ilEFSFileType fileType,
|
|
ilEFSFileTypeInfo *pInfo
|
|
)
|
|
{
|
|
register ilEFSFileTypePtr pFileType;
|
|
|
|
pFileType = (ilEFSFileTypePtr)fileType;
|
|
if (pFileType->h.o.p.objectType != IL_EFS_FILE_TYPE) {
|
|
pFileType->h.o.p.context->error = IL_ERROR_OBJECT_TYPE;
|
|
return FALSE;
|
|
}
|
|
|
|
*pInfo = pFileType->info;
|
|
pFileType->h.o.p.context->error = IL_OK;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/* ------------------------ ilEFSListFileTypes ------------------------------ */
|
|
/* Public function: see spec.
|
|
*/
|
|
ilBool ilEFSListFileTypes (
|
|
ilContext context,
|
|
int *pNFileTypes,
|
|
ilEFSFileType **pfileTypes
|
|
)
|
|
{
|
|
ilEFSPrivatePtr pPriv;
|
|
register int nFileTypes;
|
|
register ilEFSFileTypePtr pFileType;
|
|
register ilEFSFileType *pfileType;
|
|
|
|
*pNFileTypes = 0;
|
|
*pfileTypes = (ilEFSFileType *)NULL;
|
|
|
|
/* Init EFS file types if not already inited. */
|
|
if (!(pPriv = ilInitEFS (context)))
|
|
return FALSE;
|
|
|
|
/* Count the number of file types in the list */
|
|
nFileTypes = 0;
|
|
pFileType = pPriv->fileTypeHead.pNext;
|
|
while (pFileType != (ilEFSFileTypePtr)&pPriv->fileTypeHead) {
|
|
pFileType = pFileType->h.pNext;
|
|
nFileTypes++;
|
|
}
|
|
|
|
/* Malloc space for returned file types - use malloc(); caller uses free().
|
|
If no file types, still malloc something to return non-null ptr.
|
|
*/
|
|
pfileType = (ilEFSFileType *)malloc ((nFileTypes > 0) ?
|
|
nFileTypes * sizeof (ilEFSFileType) : 4);
|
|
if (!pfileType) {
|
|
context->error = IL_ERROR_MALLOC;
|
|
return FALSE;
|
|
}
|
|
|
|
/* Return # of file types; traverse list to return ptrs to them. */
|
|
*pfileTypes = pfileType;
|
|
*pNFileTypes = nFileTypes;
|
|
pFileType = pPriv->fileTypeHead.pNext;
|
|
while (nFileTypes-- > 0) {
|
|
*pfileType++ = (ilEFSFileType)pFileType;
|
|
pFileType = pFileType->h.pNext;
|
|
}
|
|
|
|
context->error = IL_OK;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/* =================================== FILE CODE ================================== */
|
|
|
|
|
|
/* --------------------------- ilEFSOpenFile ------------------------------- */
|
|
/* Public function: see spec.
|
|
*/
|
|
|
|
/* Object Destroy() function for file objects. */
|
|
static void ilDestroyFile (
|
|
ilEFSFilePtr pFile
|
|
)
|
|
{
|
|
register ilEFSFileTypePtr pFileType;
|
|
|
|
/* Get ptr to file type; if null, file not actually open yet; skip Close() */
|
|
pFileType = (ilEFSFileTypePtr)pFile->info.fileType;
|
|
if (pFileType)
|
|
(*pFileType->info.Close) (pFile);
|
|
}
|
|
|
|
|
|
ilEFSFile ilEFSOpen (
|
|
ilContext context,
|
|
char *fileName,
|
|
unsigned int openMode,
|
|
unsigned long searchOptions,
|
|
char *typeName,
|
|
void *pOptions
|
|
)
|
|
{
|
|
ilEFSPrivatePtr pPriv;
|
|
register ilEFSFilePtr pFile;
|
|
register ilEFSFileTypePtr pFileType, pListHead;
|
|
ilBool readOpen;
|
|
long nPages;
|
|
ilPtr pOpenPriv;
|
|
char extension [IL_EFS_MAX_EXTENSION_CHARS];
|
|
|
|
/* Validate pOptions, openMode (set readOpen true if a read). */
|
|
context->error = IL_OK;
|
|
if (pOptions) {
|
|
context->error = IL_ERROR_PAR_NOT_ZERO;
|
|
return (ilEFSFileType)NULL;
|
|
}
|
|
switch (openMode) {
|
|
case IL_EFS_READ:
|
|
case IL_EFS_READ_SEQUENTIAL:
|
|
readOpen = TRUE; break;
|
|
case IL_EFS_WRITE:
|
|
readOpen = FALSE; break;
|
|
default:
|
|
context->error = IL_ERROR_EFS_OPEN_MODE;
|
|
return (ilEFSFile)NULL;
|
|
}
|
|
|
|
/* Init EFS file types if not already inited. */
|
|
if (!(pPriv = ilInitEFS (context)))
|
|
return (ilEFSFile)NULL;
|
|
|
|
/* Add a file type object - goto openError to destroy it if an error later. */
|
|
pFile = (ilEFSFilePtr)_ilCreateObject (context, IL_EFS_FILE, ilDestroyFile,
|
|
sizeof (ilEFSFileRec));
|
|
if (!pFile) return (ilEFSFile)NULL;
|
|
|
|
/* Find pFileType for this file, searches enabled by mask in searchOptions.
|
|
First try typeName, if non-null. When found at any point: if openMode
|
|
not supported, error - except for checking mode - else call Open() for
|
|
the file type. If it returns any error other than "not mine" abort.
|
|
*/
|
|
pFileType = (ilEFSFileTypePtr)NULL;
|
|
pListHead = (ilEFSFileTypePtr)&pPriv->fileTypeHead;
|
|
if (typeName && (searchOptions & IL_EFS_BY_TYPE_NAME)) {
|
|
pFileType = ilFindFileType (typeName, pListHead);
|
|
if (pFileType) { /* file type found */
|
|
if (!(pFileType->info.openModes & (1 << openMode))) {
|
|
context->error = IL_ERROR_EFS_OPEN_MODE;
|
|
goto openError;
|
|
}
|
|
pOpenPriv = (*pFileType->info.Open) (pFileType, fileName, openMode, &nPages);
|
|
if (!pOpenPriv) {
|
|
if (context->error == IL_ERROR_EFS_NOT_MINE)
|
|
pFileType = (ilEFSFileTypePtr)NULL; /* try next search method */
|
|
else goto openError;
|
|
}
|
|
pFile->info.howFound = IL_EFS_BY_CHECKING;
|
|
}
|
|
} /* END open by type name */
|
|
|
|
|
|
/* If not found, search for extension if enabled. */
|
|
if (!pFileType && (searchOptions & IL_EFS_BY_EXTENSION)) {
|
|
char *pExtension;
|
|
register ilEFSFileTypePtr pSearch;
|
|
int nChars;
|
|
|
|
pExtension = strrchr (fileName, '.');
|
|
if (pExtension) { /* is a "." in fileName */
|
|
pExtension++; /* point past "." */
|
|
nChars = strlen (pExtension);
|
|
if (nChars > (IL_EFS_MAX_EXTENSION_CHARS - 1))
|
|
nChars = IL_EFS_MAX_EXTENSION_CHARS - 1;
|
|
bcopy (pExtension, extension, nChars); /* extract "extension" */
|
|
extension [nChars] = 0;
|
|
|
|
/* Search list for extension match until pFileType found or list done */
|
|
pSearch = pListHead->h.pNext;
|
|
while (!pFileType && (pSearch != pListHead)) {
|
|
register int nExtensions = pSearch->info.nExtensions;
|
|
while (nExtensions-- > 0)
|
|
if (STRING_EQUAL (extension, pSearch->info.extensions[nExtensions])) {
|
|
pFileType = pSearch; /* extension found; quit */
|
|
pFile->info.howFound = IL_EFS_BY_CHECKING;
|
|
break;
|
|
}
|
|
pSearch = pSearch->h.pNext;
|
|
}
|
|
if (pFileType) {
|
|
if (!(pFileType->info.openModes & (1 << openMode))) {
|
|
context->error = IL_ERROR_EFS_OPEN_MODE;
|
|
goto openError;
|
|
}
|
|
pOpenPriv = (*pFileType->info.Open) (pFileType, fileName, openMode, &nPages);
|
|
if (!pOpenPriv) {
|
|
if (context->error == IL_ERROR_EFS_NOT_MINE)
|
|
pFileType = (ilEFSFileTypePtr)NULL;
|
|
else goto openError;
|
|
}
|
|
}
|
|
} /* END have extension */
|
|
} /* END open by extension */
|
|
|
|
|
|
/* If not found, search by checking if a read openMode. For each file type,
|
|
try open if enabled (checkOrder != 0) and openMode supported for file type.
|
|
*/
|
|
if (!pFileType && readOpen && (searchOptions & IL_EFS_BY_CHECKING)) {
|
|
register ilEFSFileTypePtr pSearch;
|
|
|
|
pSearch = pListHead->h.pNext;
|
|
while (pSearch != pListHead) {
|
|
if (pSearch->info.checkOrder && (pSearch->info.openModes & (1 << openMode))) {
|
|
pOpenPriv = (*pSearch->info.Open) (pSearch, fileName, openMode, &nPages);
|
|
if (pOpenPriv) {
|
|
pFileType = pSearch; /* found right file type; break */
|
|
pFile->info.howFound = IL_EFS_BY_CHECKING;
|
|
break;
|
|
}
|
|
else if (context->error != IL_ERROR_EFS_NOT_MINE)
|
|
goto openError; /* some error; give up */
|
|
}
|
|
pSearch = pSearch->h.pNext;
|
|
}
|
|
} /* END open by checking */
|
|
|
|
/* If not found above, error: can't find file type handler for this file. */
|
|
if (!pFileType) {
|
|
context->error = IL_ERROR_EFS_NO_FILE_TYPE;
|
|
goto openError;
|
|
}
|
|
|
|
/* File type found. Fill in info for the file, return pFile. The object's
|
|
pPrivate is set to the ptr returned from file type's Open().
|
|
*/
|
|
pFile->o.p.pPrivate = pOpenPriv;
|
|
pFile->info.fileType = (ilEFSFileType)pFileType;
|
|
pFile->info.openMode = openMode;
|
|
pFile->info.attributes = pFileType->info.attributes;
|
|
pFile->info.nPages = nPages;
|
|
pFile->pFileType = pFileType;
|
|
|
|
context->error = IL_OK;
|
|
return (ilEFSFile)pFile; /* success; return file */
|
|
|
|
/* openError: goto here on error after file object created. The Open() was not
|
|
successful, so set fileType to null so ilDestroyFile() does not call Close().
|
|
*/
|
|
openError:
|
|
{ ilError error;
|
|
error = context->error; /* save error code */
|
|
pFile->info.fileType = (ilEFSFileType)NULL;
|
|
ilDestroyObject ((ilObject)pFile);
|
|
context->error = error; /* restore error code */
|
|
return (ilEFSFile)NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/* ------------------------ ilEFSGetFileInfo ---------------------------- */
|
|
/* Public function: see spec.
|
|
*/
|
|
ilBool ilEFSGetFileInfo (
|
|
ilEFSFile file,
|
|
ilEFSFileInfo *pInfo /* RETURNED */
|
|
)
|
|
{
|
|
register ilEFSFilePtr pFile;
|
|
|
|
pFile = (ilEFSFilePtr)file;
|
|
if (pFile->o.p.objectType != IL_EFS_FILE) {
|
|
pFile->o.p.context->error = IL_ERROR_OBJECT_TYPE;
|
|
return FALSE;
|
|
}
|
|
|
|
/* Return file info; fill in "inUse": file in use if refCount > 1 */
|
|
*pInfo = pFile->info;
|
|
pInfo->inUse = (pFile->o.refCount > 1);
|
|
pFile->o.p.context->error = IL_OK;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/* ------------------------ ilEFSSeek ---------------------------- */
|
|
/* Public function: see spec.
|
|
*/
|
|
ilBool ilEFSSeek (
|
|
ilEFSFile file,
|
|
long page,
|
|
void *pOptions
|
|
)
|
|
{
|
|
register ilEFSFilePtr pFile;
|
|
|
|
pFile = (ilEFSFilePtr)file;
|
|
if (pOptions) {
|
|
pFile->o.p.context->error = IL_ERROR_PAR_NOT_ZERO;
|
|
return FALSE;
|
|
}
|
|
if (pFile->o.p.objectType != IL_EFS_FILE) {
|
|
pFile->o.p.context->error = IL_ERROR_OBJECT_TYPE;
|
|
return FALSE;
|
|
}
|
|
|
|
/* Validate that file was opened for random read; error if not. */
|
|
if (pFile->info.openMode != IL_EFS_READ) {
|
|
pFile->o.p.context->error = IL_ERROR_EFS_OPEN_MODE;
|
|
return FALSE;
|
|
}
|
|
|
|
/* Call Seek() only if multi-page reads supported; not error if not. */
|
|
pFile->o.p.context->error = IL_OK;
|
|
if (!(pFile->info.attributes & IL_EFS_MULTI_PAGE_READS))
|
|
return TRUE;
|
|
else return (*pFile->pFileType->info.Seek) (file, page);
|
|
}
|
|
|
|
|
|
/* ------------------------ ilEFSGetPageInfo ---------------------------- */
|
|
/* Public function: see spec.
|
|
*/
|
|
ilBool ilEFSGetPageInfo (
|
|
ilEFSFile file,
|
|
ilEFSPageInfo *pInfo
|
|
)
|
|
{
|
|
register ilEFSFilePtr pFile;
|
|
|
|
pFile = (ilEFSFilePtr)file;
|
|
if (pFile->o.p.objectType != IL_EFS_FILE) {
|
|
pFile->o.p.context->error = IL_ERROR_OBJECT_TYPE;
|
|
return FALSE;
|
|
}
|
|
|
|
/* Validate that file was opened for read; call GetPageInfo() if so. */
|
|
if ((pFile->info.openMode != IL_EFS_READ)
|
|
&& (pFile->info.openMode != IL_EFS_READ_SEQUENTIAL)) {
|
|
pFile->o.p.context->error = IL_ERROR_EFS_OPEN_MODE;
|
|
return FALSE;
|
|
}
|
|
|
|
pFile->o.p.context->error = IL_OK;
|
|
return (*pFile->pFileType->info.GetPageInfo) (file, pInfo);
|
|
}
|
|
|
|
|
|
/* ------------------------ ilEFSReadImage ---------------------------- */
|
|
/* Public function: see spec.
|
|
*/
|
|
ilBool ilEFSReadImage (
|
|
ilPipe pipe,
|
|
ilEFSFile file,
|
|
unsigned int readMode,
|
|
long width,
|
|
long height,
|
|
void *pOptions
|
|
)
|
|
{
|
|
register ilEFSFilePtr pFile;
|
|
|
|
pFile = (ilEFSFilePtr)file;
|
|
if (pOptions) {
|
|
pFile->o.p.context->error = IL_ERROR_PAR_NOT_ZERO;
|
|
return FALSE;
|
|
}
|
|
if ((pipe->objectType != IL_PIPE) || (pFile->o.p.objectType != IL_EFS_FILE)) {
|
|
pFile->o.p.context->error = IL_ERROR_OBJECT_TYPE;
|
|
return FALSE;
|
|
}
|
|
|
|
/* Validate readMode: mask allowed only if supported by file type. */
|
|
switch (readMode) {
|
|
case IL_EFS_READ_MAIN:
|
|
break;
|
|
case IL_EFS_READ_MASK:
|
|
if (pFile->pFileType->info.attributes & IL_EFS_MASK_READS)
|
|
break; /* else fall thru for error */
|
|
default:
|
|
pFile->o.p.context->error = IL_ERROR_EFS_READ_MODE;
|
|
return FALSE;
|
|
}
|
|
|
|
/* Validate that file was opened for read. */
|
|
if ((pFile->info.openMode != IL_EFS_READ)
|
|
&& (pFile->info.openMode != IL_EFS_READ_SEQUENTIAL)) {
|
|
pFile->o.p.context->error = IL_ERROR_EFS_OPEN_MODE;
|
|
return FALSE;
|
|
}
|
|
|
|
/* If pipe element added successfully inc file's refCount to mark in use,
|
|
and add file to list of objects to be destroyed when pipe emptied.
|
|
*/
|
|
pFile->o.p.context->error = IL_OK;
|
|
if ((*pFile->pFileType->info.ReadImage) (pipe, file, readMode, width, height)) {
|
|
pFile->o.refCount++;
|
|
return _ilAddPipeDestroyObject (pipe, (ilObject)pFile);
|
|
}
|
|
else return FALSE;
|
|
}
|
|
|
|
|
|
/* ------------------------ ilEFSWriteImage ---------------------------- */
|
|
/* Public function: see spec.
|
|
*/
|
|
ilBool ilEFSWriteImage (
|
|
ilPipe pipe,
|
|
ilEFSFile file,
|
|
long xRes,
|
|
long yRes,
|
|
ilClientImage maskImage,
|
|
void *pOptions
|
|
)
|
|
{
|
|
register ilEFSFilePtr pFile;
|
|
|
|
pFile = (ilEFSFilePtr)file;
|
|
if (pOptions) {
|
|
pFile->o.p.context->error = IL_ERROR_PAR_NOT_ZERO;
|
|
return FALSE;
|
|
}
|
|
if ((pipe->objectType != IL_PIPE) || (pFile->o.p.objectType != IL_EFS_FILE)) {
|
|
pFile->o.p.context->error = IL_ERROR_OBJECT_TYPE;
|
|
return FALSE;
|
|
}
|
|
|
|
/* Validate that file was opened for write. */
|
|
if (pFile->info.openMode != IL_EFS_WRITE) {
|
|
pFile->o.p.context->error = IL_ERROR_EFS_OPEN_MODE;
|
|
return FALSE;
|
|
}
|
|
|
|
/* If file type doesnt handle masks, ignore maskImage, else validate it */
|
|
if (maskImage) {
|
|
if (!(pFile->pFileType->info.attributes & IL_EFS_MASK_WRITES))
|
|
maskImage = (ilClientImage)NULL;
|
|
else {
|
|
ilImageInfo *pInfo;
|
|
register const ilImageDes *pDes;
|
|
register const ilImageFormat *pFormat;
|
|
|
|
if (!ilQueryClientImage (maskImage, &pInfo, 0))
|
|
return FALSE;
|
|
pDes = pInfo->pDes;
|
|
pFormat = pInfo->pFormat;
|
|
if ((pDes->compression != IL_UNCOMPRESSED)
|
|
|| (pDes->nSamplesPerPixel != 1)
|
|
|| (pFormat->rowBitAlign != 32)
|
|
|| (pFormat->nBitsPerSample[0] != 1)) {
|
|
pFile->o.p.context->error = IL_ERROR_EFS_OPEN_MODE;
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* If pipe element added successfully inc file's refCount to mark in use,
|
|
and add file/maskImage to list of objects to be destroyed when pipe emptied.
|
|
*/
|
|
pFile->o.p.context->error = IL_OK;
|
|
if ((*pFile->pFileType->info.WriteImage) (pipe, file, xRes, yRes, maskImage)) {
|
|
if (maskImage) {
|
|
((ilObjectPtr)maskImage)->refCount++;
|
|
_ilAddPipeDestroyObject (pipe, maskImage);
|
|
}
|
|
pFile->o.refCount++;
|
|
return _ilAddPipeDestroyObject (pipe, (ilObject)pFile);
|
|
}
|
|
else return FALSE;
|
|
}
|
|
|