home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
tolkit45.zip
/
os2tk45
/
samples
/
os2
/
eaedit
/
easea.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-05-11
|
56KB
|
1,270 lines
/*static char *SCCSID = "@(#)easea.c 6.7 92/02/18";*/
/*==============================================================*\
* *
* EASEA.C - sample PM application *
* (C) Copyright IBM Corporation 1992. *
*--------------------------------------------------------------*
* This module contains subroutines for eas.c that *
* specifically deal with the manipulation of EAs. *
* *
*--------------------------------------------------------------*
* Procedures in this file: *
* AddEA() Handles the Add button press *
* QueryEAs() Reads in all the EAs associated with a file
* CheckEAIntegrity()Checks an EA buffer to see if it is valid*
* Free_FEAList() Deallocates memory associated with EA list
* LookupEAType() Gets an offset into table for an EA type *
* DeleteCurEA() Deletes the highlighted EA *
* CurEAType() Returns EA Type given a HoldFEA ptr *
* GetUSHORT() Returns nth USHORT in ->aValue *
* WriteEAs() Updates EAs state on the disk *
* EditEAValue() Handles editing a given EA ( m-m EAs) *
* EAExists() Determines if the given EA Name exists *
* ChangeName() Handles the change of an EA's name *
* MultiTypeIndex() Gets a specific field in a m-m structure *
* EAValueString() Returns a representational string for EA*
* MultiAdd() Handles addition of a field for m-m *
\*==============================================================*/
/*--------------------------------------------------------------*\
* Include files, macros, defined constants, and externs *
\*--------------------------------------------------------------*/
#include "eas.h"
extern EADATA ConvTable[EATABLESIZE];
/****************************************************************\
* *
* Name: AddEA(hwnd) *
* *
* Purpose: This routine handles the addition of a new EA to *
* the linked list. *
* *
* Usage : *
* *
* Method : Routine does NOT do full memory error trapping and *
* the insert message to l-box is not error checked. *
* *
* Returns: TRUE if the EA is successfully added. *
* *
\****************************************************************/
BOOL AddEA(HWND hwnd)
{
HOLDFEA *pFEA=pHoldFEA; /* Points to the beginning of the EA list */
HOLDFEA *pNewFEA=NULL; /* Used to temporarily hold the new EA */
PASSDATA PData;
if(!FILE_ISOPEN)
{
MessageBox(hwnd, IDMSG_NOFILEOPEN, "Error !",
MB_OK | MB_ERROR, TRUE);
return(FALSE);
}
if(!WinDlgBox(HWND_DESKTOP, /* get new EA name and type */
hwnd,
AddEAProc,
'\0',
IDD_ADDEA,
'\0'))
return(FALSE); /* they said cancel */
GetMem((PPVOID)&pNewFEA, sizeof(HOLDFEA));/* Allocate space for new EA struct */
pNewFEA->cbName = (CHAR) strlen(szEAName); /* Fill in new structure */
pNewFEA->cbValue= 0;
pNewFEA->fEA = 0; /* Need bit NOT set */
/* Name returned in szEAName */
GetMem((PPVOID)&pNewFEA->szName, pNewFEA->cbName+1);
strcpy(pNewFEA->szName,strupr(szEAName));
pNewFEA->aValue = '\0';
pNewFEA->next = '\0';
if(pHoldFEA == '\0') /* It's the first EA for the file */
pHoldFEA = pNewFEA;
else /* Add EA to the end of the linked list */
{
while(pFEA->next)
pFEA = pFEA->next;
pFEA->next = pNewFEA;
}
PData.Point = (CHAR *) pNewFEA; /* Setup user data for call */
PData.cbMulti = 0; /* to edit of the name and */
PData.usMultiOffset = 0; /* EA Value */
if(!EditEAValue(hwnd,&PData)) /* They canceled the edit */
{
if(pFEA) /* It's not the only EA */
pFEA->next = '\0'; /* Disconnect the partial new EA */
else
pHoldFEA = '\0'; /* The new EA was the first one */
FreeMem(pNewFEA->szName);
FreeMem(pNewFEA);
return(FALSE);
}
WinSendDlgItemMsg(hwnd, IDD_WINLBOX, LM_INSERTITEM,/* Insert name in L-Box */
MPFROM2SHORT(LIT_END,0),
MPFROMP(pNewFEA->szName));
return(TRUE);
}
/****************************************************************\
* *
* Name: QueryEAs(pszPath) *
* *
* Purpose: Call DOS to Query a file's EA names and values. *
* *
* Usage: *
* *
* Method : Routine does NOT do full memory error trapping. *
* NOTE: This routine does NOT prevent other *
* processes from accessing the file's EAs while it is*
* reading them in, or while the program is editing *
* them. *
* *
* Returns: TRUE if it successfully reads in the EAs. Upon exit*
* , globalp HoldFEA points to a linked list of the *
* EAs for the current file. *
* *
\****************************************************************/
BOOL QueryEAs(CHAR *pszPath)
{
CHAR *pAllocc=NULL; /* Holds the FEA struct returned by DosEnumAttribute */
/* used to create the GEA2LIST for DosQueryPathInfo */
CHAR *pBigAlloc=NULL; /* Temp buffer to hold each EA as it is read in */
USHORT cbBigAlloc=0; /* Size of buffer */
ULONG ulEntryNum = 1; /* count of current EA to read (1-relative) */
ULONG ulEnumCnt; /* Number of EAs for Enum to return, always 1 */
HOLDFEA *pLastIn=0; /* Points to last EA added, so new EA can link */
HOLDFEA *pNewFEA=NULL; /* Struct to build the new EA in */
FEA2 *pFEA; /* Used to read from Enum's return buffer */
GEA2LIST *pGEAList;/*Ptr used to set up buffer for DosQueryPathInfo call */
EAOP2 eaopGet; /* Used to call DosQueryPathInfo */
/* Allocate enough room for any GEA List */
GetMem((PPVOID)&pAllocc, MAX_GEA);
pFEA = (FEA2 *) pAllocc; /* pFEA always uses pAlloc buffer */
pHoldFEA = '\0'; /* Reset the pointer for the EA linked list */
while(TRUE) /* Loop continues until there are no more EAs */
{
ulEnumCnt = 1; /* Only want to get one EA at a time */
if(DosEnumAttribute(Ref_ASCIIZ, /* Read into pAlloc Buffer */
pszPath, /* Note that this does not */
ulEntryNum, /* get the aValue field, */
pAllocc, /* so DosQueryPathInfo must*/
MAX_GEA, /* be called to get it. */
&ulEnumCnt,
(LONG) GetInfoLevel1))
break; /* There was some sort of error */
if(ulEnumCnt != 1) /* All the EAs have been read */
break;
ulEntryNum++;
GetMem((PPVOID)&pNewFEA, sizeof(HOLDFEA));
if (pNewFEA == '\0') /* Out of memory */
{
FreeMem(pAllocc);
Free_FEAList(pHoldFEA,pDelList);
return (FALSE);
}
pNewFEA->cbName = pFEA->cbName; /* Fill in the HoldFEA structure */
pNewFEA->cbValue= pFEA->cbValue;
pNewFEA->fEA = pFEA->fEA;
pNewFEA->next = '\0';
GetMem((PPVOID)&pNewFEA->szName, pFEA->cbName +1); /* Allocate for 2 arrays */
GetMem((PPVOID)&pNewFEA->aValue, pFEA->cbValue);
if (!pNewFEA->szName || !pNewFEA->aValue) /* Out of memory */
{
if(pNewFEA->szName)
FreeMem(pNewFEA->szName);
if(pNewFEA->aValue)
FreeMem(pNewFEA->aValue);
FreeMem(pAllocc);
FreeMem(pNewFEA);
Free_FEAList(pHoldFEA,pDelList);
return (FALSE);
}
strcpy(pNewFEA->szName,pFEA->szName); /* Copy in EA Name */
cbBigAlloc = sizeof(FEA2LIST) + pNewFEA->cbName+1 +
pNewFEA->cbValue;
GetMem((PPVOID)&pBigAlloc, cbBigAlloc);
if (pBigAlloc == '\0')
{
FreeMem(pNewFEA->szName);
FreeMem(pNewFEA->aValue);
FreeMem(pAllocc);
FreeMem(pNewFEA);
Free_FEAList(pHoldFEA,pDelList);
return (FALSE);
}
pGEAList = (GEA2LIST *) pAllocc; /* Set up GEAList structure */
pGEAList->cbList = sizeof(GEA2LIST) + pNewFEA->cbName; /* +1 for NULL */
pGEAList->list[0].oNextEntryOffset = 0L;
pGEAList->list[0].cbName = pNewFEA->cbName;
strcpy(pGEAList->list[0].szName,pNewFEA->szName);
eaopGet.fpGEA2List = (GEA2LIST FAR *) pAllocc;
eaopGet.fpFEA2List = (FEA2LIST FAR *) pBigAlloc;
eaopGet.fpFEA2List->cbList = cbBigAlloc;
DosQueryPathInfo(pszPath, /* Get the complete EA info */
FIL_QUERYEASFROMLIST,
(PVOID) &eaopGet,
sizeof(EAOP2));
memcpy(pNewFEA->aValue, /* Copy the value to HoldFEA */
pBigAlloc+sizeof(FEA2LIST)+pNewFEA->cbName,
pNewFEA->cbValue);
FreeMem(pBigAlloc); /* Release the temp Enum buffer */
if(!CheckEAIntegrity(pNewFEA->aValue,pNewFEA->cbValue)) /* Bad EA */
{
FreeMem(pNewFEA->szName);
FreeMem(pNewFEA->aValue);
FreeMem(pNewFEA);
continue; /* Don't add this EA to linked list */
}
if(pHoldFEA == '\0') /* If first EA, set pHoldFEA */
pHoldFEA = pNewFEA;
else /* Otherwise, add to end of list */
pLastIn->next = pNewFEA;
pLastIn = pNewFEA; /* Update the end of the list */
}
FreeMem(pAllocc); /* Free up the GEA buf for DosEnum */
return (TRUE);
}
/****************************************************************\
* *
* Function name: CheckEAIntegrity(aBuf, cbBuf) *
* *
* Returns: TRUE if the buffer is a valid EA structure. *
* *
* Purpose: This routine checks the integrity of the passed EA *
* buffer by seeing if there are any non-standard EA *
* types, or bad data that isn't sized correctly. *
* Usage : *
* Method : Routine uses MultiTypeIndex() to check m-m type EAs*
* since they are potentially recursive. However, this*
* may not be a good idea if the m-m EA is severly *
* corrupted because it may cause MTI() to attempt a *
* read from protected memory. Routine does NOT modify*
* the buffer under any circumstance. *
* *
* Returns: TRUE if the buffer is a valid EA structure. *
* *
\****************************************************************/
BOOL CheckEAIntegrity(CHAR *aBuf, ULONG cbBuf)
{
USHORT *pusPtr = (USHORT *) aBuf;
USHORT usOffset;
CHAR *aEndPtr;
usOffset = LookupEAType(*pusPtr); /* Get the EA type */
switch(ConvTable[usOffset].usFldType)
{
case IDD_LPDATA:
pusPtr++;
if(*pusPtr + 2*sizeof(USHORT) == cbBuf)
return TRUE;
else
return FALSE;
case IDD_MULTILIST:
if(*pusPtr == EA_MVMT)
{
pusPtr += 2;
/* This checks where the end of the m-m list ends to determine
the size of the EA. This is probably not good if the EA is
badly corrupted and it points to protected memory */
aEndPtr = MultiTypeIndex(aBuf,*pusPtr);
if(aEndPtr - aBuf == (CHAR) cbBuf)
return TRUE;
else
return FALSE;
}
else /* Single type, multi-value is not yet implemented */
{
return TRUE;
}
default:
return FALSE;
}
return TRUE;
}
/****************************************************************\
* *
* Name: Free_FEAList(pFEA, pDList) *
* *
* Purpose: This routine frees up the current list of EAs by *
* deallocating the space used by the szName and *
* aValue fields, then deallocating the HoldFEA struct*
* Next, it deletes the EAName space, then the *
* DeleteList structure. *
* Usage : *
* Method: Note that EAS always passes in pHoldFEA and *
* pDelList which is unnecessary since they are global*
* pointers;however, this is done to make the routine *
* more flexible by allowing multiple linked lists to *
* exist. *
* *
* Returns: VOID. The two linked lists passed in are cleaned *
* out though. *
* *
\****************************************************************/
VOID Free_FEAList(HOLDFEA *pFEA, DELETELIST *pDList)
{
HOLDFEA *next; /* Holds the next field since we free the structure */
/* before reading the current next field */
DELETELIST *Dnext; /* Same purpose as *next */
while(pFEA)
{
next = pFEA->next;
if(pFEA->szName) /* Free if non-NULL name */
FreeMem(pFEA->szName);
if(pFEA->aValue) /* Free if non-NULL value */
FreeMem(pFEA->aValue);
FreeMem(pFEA); /* Free HoldFEA struct */
pFEA = next;
}
while(pDList)
{
Dnext = pDList->next;
if(pDList->EAName)
FreeMem(pDList->EAName);
FreeMem(pDList);
pDList = Dnext;
}
return;
}
/****************************************************************\
* *
* Name: LookupEAType(usType) *
* *
* Purpose: This routine takes EA type and returns an offset *
* into ConvTable which points to an entry that *
* describes the type passed in. *
* *
* Usage: *
* Method: *
* *
* Returns: An offset into the ConvTable to the appropriate *
* entry. If no match is found, the return value *
* points to the last entry, non-conventional format. *
* *
\****************************************************************/
ULONG LookupEAType(ULONG usType)
{
USHORT cnt;
for(cnt=0;cnt<EATABLESIZE-1;cnt++)
if(ConvTable[cnt].usPrefix == usType)
return(cnt);
return(cnt);
}
/****************************************************************\
* *
* Name: DeleteCurEA(hwnd) *
* *
* Purpose: This routine removes in memory the currently *
* highlighted EA from the EA list. It places the *
* deleted EA in the global pDelList linked list. *
* *
* Usage: This routine is called by MainDlgProc when DELETE *
* button selected. *
* *
* Method: The memory allocation routines are NOT fully error *
* trapped. *
* *
* Returns: VOID. Removes one item from global pHoldFEA list *
* and adds one to global pDelList. *
* *
\****************************************************************/
VOID DeleteCurEA(HWND hwnd)
{
HOLDFEA *pFEA,*pFEAPrev;
DELETELIST *pDL=NULL, *pDLcnt;/*Utility ptrs for manipulating the Del list*/
SHORT sOffset;
SHORT i;
if(!FILE_ISOPEN)
{
MessageBox(hwnd, IDMSG_ERRORSELECT, "Error !",
MB_OK | MB_ERROR, TRUE);
return;
}
sOffset = (SHORT) WinSendDlgItemMsg(hwnd, IDD_WINLBOX,
LM_QUERYSELECTION,0,0);
if(sOffset<0) /* No item is currently selected */
{
MessageBox(hwnd, IDMSG_ERRORSELECT, "Error !",
MB_OK | MB_ERROR, TRUE);
return;
}
pFEA = GetCurFEA(hwnd,pHoldFEA); /* Gets a pointer to item to delete */
if (pFEA == '\0')
return;
/* These two allocations should be checked for out of memory */
GetMem((PPVOID)&pDL, sizeof(DELETELIST)); /* Add Name to Delete List */
GetMem((PPVOID)&pDL->EAName, pFEA->cbName+1);
strcpy(pDL->EAName,pFEA->szName);
pDL->next = '\0';
if(pDelList == '\0') /* The del list was previously empty */
pDelList = pDL;
else /* tack name onto the end of the list */
{
pDLcnt = pDelList;
while(pDLcnt->next)
pDLcnt = pDLcnt->next;
pDLcnt->next = pDL;
}
WinSendDlgItemMsg(hwnd, IDD_WINLBOX,
LM_DELETEITEM,MPFROMSHORT(sOffset),0L);
if(sOffset<1) /* Remove pFEA from the linked list */
{
pHoldFEA = pFEA->next;
}
else
{
pFEAPrev = pHoldFEA;
--sOffset;
while(sOffset) /* Find previous EA */
{
pFEAPrev = pFEAPrev->next;
--sOffset;
}
pFEAPrev->next = pFEA->next;
}
/* Check Type Name is in the list of MVST or not */
for (i=0; i<MSNUM && MSdata[i].szName!=NULL &&
strcmp(pFEA->szName,MSdata[i].szName)!=0;)
i++;
if(i<MSNUM && MSdata[i].szName!=NULL) /* Found the EA type in MVST list */
{
FreeMem(MSdata[i].szName);
for (; i<MSNUM && MSdata[i+1].szName!=NULL; i++)
{
MSdata[i].szName = MSdata[i+1].szName;
MSdata[i].usType = MSdata[i+1].usType;
}
}
FreeMem(pFEA->szName); /* Release the memory */
FreeMem(pFEA->aValue);
FreeMem(pFEA);
FILE_CHANGED = TRUE;
return;
}
/****************************************************************\
* *
* Name: CurEAType(pFEA) *
* *
* Purpose: Given an EA structure, this routine returns the *
* Type of the EA which resides in the first USHORT of*
* the aValue member. This function is the same as *
* GetUSHORT(pFEA,0). *
* Usage : *
* Method : Assumes a valid HoldFEA struct. *
* *
* Returns: The EA type. *
* *
\****************************************************************/
ULONG CurEAType(HOLDFEA *pFEA) /* Same as GetUSHORT(,0); */
{
USHORT *pusType; /* EA Type is stored in first USHORT of aValue field */
pusType = (USHORT *) pFEA->aValue;
return(*pusType);
}
/****************************************************************\
* *
* Name: GetUSHORT(pFEA, index) *
* *
* Purpose: This routine returns the nth USHORT value in the *
* aValue member of pFEA using index as the offset. *
* Usage : *
* Method : Assumes a valid HoldFEA struct and that index *
* doesn't point outside the aValue buffer. *
* *
* Returns: The appropriate USHORT from the aValue field *
* *
\****************************************************************/
USHORT GetUSHORT(HOLDFEA *pFEA, ULONG index)
{
USHORT *pusType;
pusType = (USHORT *) pFEA->aValue;
while(index-- > 0)
pusType++;
return(*pusType);
}
/****************************************************************\
* *
* Name: WriteEAs() *
* *
* Purpose: This routine updates the EAs on disk to reflect *
* their current condition in memory. First, all EAs *
* in the delete list are removed from the disk, then *
* all EAs in the pHoldFEA list are written to disk. *
* Usage : *
* Method : This routine is not bulletproof as it does not get *
* exclusive access to the file EAs, nor does it *
* handle out of disk space sort of errors. Also, *
* memory fetches are not fully error trapped. *
* *
* Returns: VOID. But cleans out the pDelList linked list. *
* *
\****************************************************************/
VOID WriteEAs()
{
DELETELIST *pDL = pDelList,*pDLnext;
HOLDFEA *pHFEA= pHoldFEA;
EAOP2 eaopWrite;
CHAR aBuf[MAX_GEA],*aPtr=NULL;
FEA2 *pFEA = (FEA2 *) &aBuf[sizeof(ULONG)];
USHORT usMemNeeded, usRet;
ULONG *pulPtr=(ULONG *) aBuf; /* Initally points to top of FEALIST */
if(!FILE_ISOPEN)
{
MessageBox(HWND_DESKTOP, IDMSG_NOFILEOPEN, "Error !",
MB_OK | MB_ERROR, TRUE);
return;
}
if (!FILE_CHANGED) /* Don't write unless it's necessary */
return;
eaopWrite.fpFEA2List = (FEA2LIST FAR *) aBuf; /* Setup fields that won't */
pFEA->fEA = 0; /* change for the delete */
pFEA->cbValue = 0; /* calls to DosSetPathInfo */
while(pDL) /* Clean out all the deleted EA names */
{
pFEA->cbName = (UCHAR) strlen(pDL->EAName);
*pulPtr = sizeof(FEA2LIST) + pFEA->cbName;
strcpy(pFEA->szName,pDL->EAName);
pFEA->oNextEntryOffset = 0L;
/* Delete EA's by saying cbValue=0 */
DosSetPathInfo(szFileName,
SetInfoLevel2,
(PVOID) &eaopWrite,
sizeof(EAOP2),
DSPI_WRTTHRU);
pDLnext = pDL->next; /* Temp hold next pDL */
FreeMem(pDL->EAName); /* Free up current Del struct */
FreeMem(pDL);
pDL = pDLnext; /* Set pDL to saved value */
}
pDelList = '\0'; /* DelList is now empty */
while(pHFEA) /* Go through each HoldFEA */
{
usMemNeeded = sizeof(FEA2LIST) + pHFEA->cbName+1 +
pHFEA->cbValue;
GetMem((PPVOID)&aPtr, usMemNeeded);
eaopWrite.fpFEA2List = (FEA2LIST FAR *) aPtr; /* Fill in eaop struct */
eaopWrite.fpFEA2List->cbList = usMemNeeded;
eaopWrite.fpFEA2List->list[0].fEA = pHFEA->fEA;
eaopWrite.fpFEA2List->list[0].cbName = pHFEA->cbName;
eaopWrite.fpFEA2List->list[0].cbValue = pHFEA->cbValue;
strcpy(eaopWrite.fpFEA2List->list[0].szName, pHFEA->szName);
memcpy(eaopWrite.fpFEA2List->list[0].szName + pHFEA->cbName+1,
pHFEA->aValue, pHFEA->cbValue);
usRet = DosSetPathInfo(szFileName, /* Write out the EA */
FIL_QUERYEASIZE,
(PVOID) &eaopWrite,
sizeof(EAOP2),
DSPI_WRTTHRU);
if (usRet)
{
MessageBox(HWND_DESKTOP, IDMSG_WRITEERROR, "Error !",
MB_OK | MB_ERROR, TRUE);
FreeMem(aPtr); /* Free up the FEALIST struct */
FILE_CHANGED = FALSE;
return;
}
FreeMem(aPtr); /* Free up the FEALIST struct */
pHFEA = pHFEA->next;
}
FILE_CHANGED = FALSE;
MessageBox(HWND_DESKTOP, IDMSG_WRITEOK, "Note !", MB_OK, FALSE);
return;
}
/****************************************************************\
* *
* Function name: EditEAValue(hwnd, pPDat) *
* *
* Purpose: This routine allows the entry/edit of an EA value *
* condition in memory. First, all EAs in the delete *
* list are removed from the disk, then all EAs in the*
* pHoldFEA list are written out to disk. *
* Usage : *
* Method : Expects the PassData structure to tell it the *
* HoldFEA to edit, and if it is a subfield of a multi*
* -multi EA, the rest of the PassData structure will *
* be filled into indicated which m-m is being edited.*
* Note that if this is a new edit, usRetEAType is *
* expected to be set to the proper EA type upon entry*
* NOTE: memory sizing requests are not fully error trapped*
* *
* Returns: TRUE if the edit was successful. *
* *
\****************************************************************/
BOOL EditEAValue(HWND hwnd, PPASSDATA pPDat)
{
USHORT usEAType; /* Holds the field type to be edited */
USHORT *pusPtr;
USHORT usSize; /* Holds the delta difference of the old and new buffers */
CHAR *szNew=NULL,*szTrash; /* Temporary pointers */
PASSDATA PDat;
HOLDFEA *pFEA = (HOLDFEA *) pPDat->Point; /* The EA to be edited */
/* Determine the type of EA that will be edited */
if(pPDat->cbMulti) /* It's a multi-type job */
{
pusPtr = (USHORT *) MultiTypeIndex(pFEA->aValue+pPDat->usMultiOffset,
pPDat->usIndex);
usEAType = *pusPtr;
}
else if(pFEA->cbValue) /* It isn't a new EA name */
{
pusPtr = (USHORT *)pFEA->aValue;
usEAType = *pusPtr;
}
else /* It's a new EA */
usEAType = ConvTable[usRetEAType].usPrefix;
PDat.Point = pFEA->szName; /* General setup for AsciiEditProc */
/* =1 if there is a multi */
PDat.usIndex =(USHORT)( pPDat->cbMulti ? 1 : 0);
PDat.fFlag = (BYTE) ((pFEA->fEA & 0x80) ? TRUE : FALSE);
switch(usEAType)
{
case EA_ASCIIZ:
case EA_ASCIIZFN:
case EA_ASCIIZEA:
case EA_ASN1:
if(pPDat->cbMulti) /* It is a multi-type field */
szAscii=MultiTypeIndex(pFEA->aValue + pPDat->usMultiOffset,
pPDat->usIndex)
+sizeof(USHORT);
else if(pFEA->cbValue) /* There is a current value */
szAscii=pFEA->aValue+sizeof(USHORT);
else /* It's a new EA */
szAscii='\0';
if(!WinDlgBox(HWND_DESKTOP, /* Do an ascii text edit */
hwnd,
AsciiEditProc,
'\0',
IDD_ASCIIEDIT,
&PDat))
return(FALSE); /* They said cancel */
if(PDat.fFlag) /* Handle the need/nice bit */
PDat.fFlag = 0x80;
if(PDat.fFlag != (BYTE)(PDat.fFlag & 0x80))
FILE_CHANGED = TRUE;
pFEA->fEA =(BYTE)( (pFEA->fEA & 0x7f) | PDat.fFlag );
if(stricmp(strupr(szEAName),pFEA->szName)) /* The name changed */
ChangeName(pFEA,szEAName);
if(pFEA->cbValue) /* There is a current value */
{
if(!strcmp(szAscii,szScratch)) /* It hasn't changed */
return(TRUE);
if(pPDat->cbMulti) /* Do the whole thing here if m-m */
{ /* Change in size */
usSize = (strlen(szScratch)-strlen(szAscii));
if(usSize > 0) /* The new string is longer */
{
ResizeMem((PPVOID)&pFEA->aValue, /* Enlarge the EA size */
pFEA->cbValue,
pFEA->cbValue+usSize);
szTrash=MultiTypeIndex(pFEA->aValue + pPDat->usMultiOffset,
(pPDat->usIndex+1));
memmove(szTrash+usSize, /* Move end of EA to make room */
szTrash,
pFEA->cbValue-(szTrash-pFEA->aValue));
}
else
{
szTrash= MultiTypeIndex(pFEA->aValue + pPDat->usMultiOffset,
(pPDat->usIndex+1));
memmove(szTrash+usSize, /* Move back the end of the EA */
szTrash,
pFEA->cbValue-(szTrash-pFEA->aValue));
DosSetMem(pFEA->aValue, pFEA->cbValue+usSize, fPERM|PAG_COMMIT);
}
szTrash=MultiTypeIndex(pFEA->aValue + pPDat->usMultiOffset,
pPDat->usIndex);
strcpy(szTrash+sizeof(USHORT),szScratch); /* Copy in new val */
pFEA->cbValue+=usSize; /* Change buffer count */
FILE_CHANGED = TRUE;
return(FILE_CHANGED); /* Done with m-m edit */
}
else
{
FreeMem(pFEA->aValue); /* Release old Value mem */
}
}
GetMem((PPVOID)&szNew, strlen(szScratch)+3); /* +3 for Type & NULL */
pusPtr = (USHORT *) szNew;
*pusPtr= usEAType; /* Set type in new buffer */
strcpy(szNew+2,szScratch); /* Copy in the new value */
pFEA->aValue = szNew; /* Fix up the structure */
pFEA->cbValue= (USHORT)(strlen(szScratch)+3);
FILE_CHANGED = TRUE;
return(FILE_CHANGED);
case EA_LPBITMAP:
case EA_LPICON:
case EA_LPBINARY:
case EA_LPASCII:
case EA_LPMETAFILE:
if (usEAType==EA_LPBITMAP || usEAType==EA_LPICON)
{
WinDlgBox(HWND_DESKTOP,
hwnd,
IconDlgProc,
'\0',
IDD_ABOUTBOX,
NULL);
}
if(pPDat->cbMulti) /* It is a multi-type field */
{ /* szTrash points to field to edit, pusPtr to the field length */
szTrash=MultiTypeIndex(pFEA->aValue + pPDat->usMultiOffset,
pPDat->usIndex);
pusPtr = (USHORT *) ((CHAR *) szTrash + sizeof(USHORT));
usSize = *pusPtr;
if(usSize) /* It isn't a new EA */
{ /* Set up inital value for edit */
GetMem((PPVOID)&szAscii, usSize+1);
memcpy(szAscii,szTrash+2*sizeof(USHORT),usSize);
*( ( CHAR *)szAscii + usSize ) ='\0';
}
else /* No inital value */
szAscii = '\0';
}
else if(pFEA->cbValue) /* Single type && there is current value */
{
usSize=GetUSHORT(pFEA,1); /* Get size and set inital value */
if(usSize)
{
GetMem((PPVOID)&szTrash, usSize+1); /* +1 for null */
memcpy(szTrash,pFEA->aValue+4,usSize);
szTrash[usSize]='\0';
szAscii=szTrash;
}
else
szAscii = '\0';
}
else
szAscii = '\0';
if(!WinDlgBox(HWND_DESKTOP, /* Do an ascii text edit */
hwnd,
AsciiEditProc,
'\0',
IDD_ASCIIEDIT,
&PDat))
{ /* Cancel, but check if memory needs to be freed before exit */
if(pPDat->cbMulti || pFEA->cbValue)
if(szAscii) /* It's not NULL */
FreeMem(szAscii); /* +1 for NULL */
return(FALSE);
}
if(PDat.fFlag) /* Handle the need/nice bit */
PDat.fFlag = 0x80;
if(PDat.fFlag != (BYTE)(PDat.fFlag & 0x80))
FILE_CHANGED = TRUE;
pFEA->fEA = (BYTE)((pFEA->fEA & 0x7f) | PDat.fFlag);
if(stricmp(strupr(szEAName),pFEA->szName)) /* The name changed */
ChangeName(pFEA,szEAName);
if(pFEA->cbValue) /* There is a current value */
{
if(szAscii && !strcmp(szAscii,szScratch)) /* It hasn't changed */
{
if(szAscii)
FreeMem(szAscii);
return(TRUE);
}
if(szAscii) /* Free default value buffer */
FreeMem(szAscii);
if(pPDat->cbMulti) /* Do the whole thing here is multi-type */
{ /* Change in len */
USHORT usDelta = (USHORT)(strlen(szScratch) - usSize);
if(usDelta > 0) /* The new string is longer, resize first */
{
ResizeMem((PPVOID)&pFEA->aValue, pFEA->cbValue, pFEA->cbValue+usDelta);
szTrash= MultiTypeIndex(pFEA->aValue + pPDat->usMultiOffset,
(pPDat->usIndex+1));
memmove(szTrash+usDelta,szTrash,
pFEA->cbValue-(szTrash-pFEA->aValue));
}
else
{
szTrash= MultiTypeIndex(pFEA->aValue + pPDat->usMultiOffset,
(pPDat->usIndex+1));
memmove(szTrash+usDelta,szTrash,
pFEA->cbValue-(szTrash-pFEA->aValue));
ResizeMem((PPVOID)&pFEA->aValue, pFEA->cbValue+usDelta, fPERM|PAG_COMMIT);
}
szTrash=MultiTypeIndex(pFEA->aValue + pPDat->usMultiOffset,
pPDat->usIndex);
memmove(szTrash+2*sizeof(USHORT),szScratch,strlen(szScratch));
pusPtr = (USHORT *) ((CHAR *)szTrash + sizeof(USHORT));
*pusPtr= strlen(szScratch); /* Set the length field */
pFEA->cbValue += usDelta; /* Adjust struct len field */
FILE_CHANGED = TRUE;
return(FILE_CHANGED);
}
FreeMem(pFEA->aValue); /* Free up old value */
}
GetMem((PPVOID)&szNew, strlen(szScratch)+4); /* Get space for new value */
pusPtr = (USHORT *) szNew;
*pusPtr= usEAType; /* Set type field */
pusPtr++;
*pusPtr= strlen(szScratch); /* Set length field */
memcpy(szNew+4,szScratch,*pusPtr); /* Copy in new value */
pFEA->aValue = szNew; /* Adjust pointers */
pFEA->cbValue= strlen(szScratch)+4;/* +4 for type and LP cnt */
FILE_CHANGED = TRUE;
return(FILE_CHANGED);
case EA_MVST:
case EA_MVMT: /* It's multi-value multi-type */
if(pFEA->cbValue == 0) /* It's a new EA */
{ /* Allocate empty m-m EA */
GetMem((PPVOID)&pFEA->aValue, 3*sizeof(USHORT));
pFEA->cbValue = 3*sizeof(USHORT);
pusPtr = (USHORT *) pFEA->aValue;
if(usEAType == EA_MVMT)
*pusPtr = 0xffdf; /* Multi-value, multi-type */
else
*pusPtr = 0xffde; /* Multi-value, single-type */
pusPtr+=2; /* Skip type, codepage */
*pusPtr = 0; /* No fields initially */
FILE_CHANGED = TRUE;
}
/* Set up passed in data */
if(pPDat->cbMulti) /* It's a multi-type job */
{
szNew = MultiTypeIndex(pFEA->aValue + pPDat->usMultiOffset,
pPDat->usIndex);
szTrash = MultiTypeIndex(pFEA->aValue + pPDat->usMultiOffset,
(pPDat->usIndex+1));
PDat.usMultiOffset = (USHORT)(szNew - pFEA->aValue);
PDat.cbMulti = (USHORT)(szTrash - szNew);
}
else
{
PDat.usMultiOffset = 0;
PDat.cbMulti = pFEA->cbValue;
}
PDat.Point = (CHAR *) pFEA;
WinDlgBox(HWND_DESKTOP, /* Do the Multi-type edit */
hwnd,
MultiTypeProc,
'\0',
IDD_MULTIBOX,
&PDat);
return(TRUE);
default:
return(FALSE);
}
return(FALSE);
}
/****************************************************************\
* *
* Name: EAExists(szEAName) *
* *
* Purpose: This routine goes through the linked list pointed *
* to by global pHoldFEA and determines whether or not*
* an EA othe passed name already exists. *
* Usage: *
* Method : The comparison is NOT case sensitive. *
* *
* Returns: TRUE if an EA with a name matching szEAName exists.*
* *
\****************************************************************/
BOOL EAExists(CHAR *szEAName)
{
HOLDFEA *phFEA=pHoldFEA;
while(phFEA)
{
if(!stricmp(szEAName,phFEA->szName))
return(TRUE);
phFEA=phFEA->next;
}
return(FALSE);
}
/****************************************************************\
* *
* Name: ChangeName(pFEA, szName) *
* *
* Purpose: This routine copies the current EA Name to the *
* delete list, then allocates a new space, copies the*
* new name into it, and sets the FEA pointer to it. *
* Usage : *
* Method : Not all the memory allocations are fully error *
* trapped. *
* *
* Returns: VOID. Fixes up the pFEA structure and global *
* pDelList. *
* *
\****************************************************************/
VOID ChangeName(HOLDFEA *pFEA, CHAR *szName)
{
CHAR *szTemp=NULL;
DELETELIST *pDL=NULL;
GetMem((PPVOID)&szTemp, strlen(szName+1));/* Allocate space for new name */
if(!szTemp)
return;
/* Allocate a new delete struct */
GetMem((PPVOID)&pDL, sizeof(DELETELIST));
pDL->EAName = pFEA->szName; /* Fill in DeleteList struct */
pDL->next = pDelList;
pDelList = pDL;
strcpy(szTemp,szName); /* Copy name to permanent buffer */
pFEA->szName = szTemp; /* Fix up struct */
pFEA->cbName = (CHAR) strlen(szName);
FILE_CHANGED = TRUE;
return;
}
/****************************************************************\
* *
* Name: MultiTypeIndex(pMulti, usIndex) *
* *
* Purpose: This routine takes a pointer to a Multi-Multi data *
* field and returns a pointer to the nth data field *
* in this buffer. *
* Usage: *
* Method: Memory bounds are not checked and a corrupt EA field
* could cause unspecified results. Recursively calls *
* itself to handle nesting. Does not support multi- *
* value single type fields. *
* *
* Returns: a pointer to the field specified by the usIndex *
* parameters. *
* *
* Calls: LookupEAType, MultiTypeIndex() *
* *
\****************************************************************/
CHAR *MultiTypeIndex(CHAR *pMulti, ULONG usIndex)
{
USHORT *pusPtr;
USHORT usOffset;
/* skip over 0xffdf, codepage, and field cnt */
pMulti += 3*sizeof(USHORT);
while(usIndex--) /* loop to skip over correct # of flds */
{
pusPtr = (USHORT *) pMulti; /* The address of EA data type stored */
usOffset = LookupEAType(*pusPtr); /* Get offset of field type */
pMulti += sizeof(USHORT); /* Skip over the type field to first data */
switch(ConvTable[usOffset].usFldType)
{
case IDD_ASCIIZ:
while(*pMulti) /* Increment to point after NULL */
pMulti++;
pMulti++;
break;
case IDD_LPDATA:
pusPtr = (USHORT *) pMulti; /* Get the length of a data */
pMulti += *pusPtr + sizeof(USHORT); /* skip to end */
break;
case IDD_MULTILIST:
if(*pusPtr == EA_MVMT) /* m-m, do a recursive call to skip fld */
{
pusPtr = (USHORT *) pMulti; /* points to field cnt */
pMulti = MultiTypeIndex(pMulti-sizeof(USHORT),*pusPtr);
break;
}
/* implemented for Multi-valued single-type stuff... */
pusPtr = (USHORT *) pMulti; /* Get the length of a data */
pMulti += *pusPtr + sizeof(USHORT); /* skip to end */
break;
}
}
return(pMulti);
}
/****************************************************************\
* *
* Name: EAValueString(aEAVal) *
* *
* Purpose: This routine takes a pointer to an EA Value (i.e. *
* starting with $ffxx) and returns a pointer to a *
* string representing the value of the EA. This string
* must be Freed by the user when finished with it. * *
* Usage: *
* Method : Not all GetMem's are totally error trapped. The *
* string returned is allocated in this procedure, but*
* it is the caller's responsibility to free the buffer
* *
* Returns: a pointer to an ASCII description of the field value
* *
\****************************************************************/
CHAR *EAValueString(CHAR *aEAVal)
{
USHORT *pusPtr= (USHORT *) aEAVal; /* Points to EA Type */
CHAR *szRet=NULL, *szTemp; /* szRet points to return string */
switch(*pusPtr)
{
case EA_ASCIIZ: /* For asciiz strings, return MAXSHOWSIZE-1 chars */
case EA_ASCIIZFN:
case EA_ASCIIZEA:
case EA_ASN1:
aEAVal += sizeof(USHORT);
if(strlen(aEAVal)<MAXSHOWSIZE)
{
GetMem((PPVOID)&szRet, strlen(aEAVal)+1);
strcpy(szRet,aEAVal);
}
else
{
GetMem((PPVOID)&szRet, MAXSHOWSIZE);
strncpy(szRet,aEAVal,MAXSHOWSIZE-4);
strcpy (szRet+MAXSHOWSIZE-4,"...");
szRet[MAXSHOWSIZE-1]='\0';
}
return(szRet);
case EA_LPASCII: /* Display up to first MAXSHOWSIZE-1 chars */
case EA_LPMETAFILE:
pusPtr++;
aEAVal += 2*sizeof(USHORT);
if(*pusPtr < MAXSHOWSIZE)
{
GetMem((PPVOID)&szRet, *pusPtr +1);
strncpy(szRet,aEAVal,*pusPtr);
szRet[*pusPtr]='\0';
}
else
{
GetMem((PPVOID)&szRet, MAXSHOWSIZE);
strncpy(szRet,aEAVal,MAXSHOWSIZE-4);
strcpy (szRet+MAXSHOWSIZE-4,"...");
szRet[MAXSHOWSIZE-1]='\0';
}
return(szRet);
/* For the rest of the types, just display the field type */
case EA_LPBINARY:
szTemp = "*** LP Binary ***";
break;
case EA_LPBITMAP:
szTemp = "*** LP Bitmap ***";
break;
case EA_LPICON:
szTemp = "*** LP Icon ***";
break;
case EA_MVMT:
szTemp = "*** Multi-value Multi-type ***";
break;
case EA_MVST:
szTemp = "*** Multi-value Single-type ***";
break;
default:
szTemp = "*** Unknown EA type ***";
break;
}
GetMem((PPVOID)&szRet, strlen(szTemp)+1); /* Copy string from static to dynamic */
strcpy(szRet,szTemp);
return(szRet);
}
/****************************************************************\
* *
* Function name: MultiAdd(hwnd, pFEA, pPDat) *
* *
* Purpose: This routine is called by MultiTypeProc and handles*
* the addition of a subvalue to a multi-value, multi-*
* type EA. *
* Usage : *
* Method : Not all GetMem's are totally error trapped. It is *
* possible that the add to the listbox could fail. *
* *
* Returns: VOID. Modifies the current pFEA. *
* *
\****************************************************************/
VOID MultiAdd(HWND hwnd, HOLDFEA *pFEA, PPASSDATA pPDat)
{
USHORT usSize, i;
USHORT *pusPtr;
CHAR aUtility[6]; /* Used to hold the header for all EA types */
CHAR *pInsert,*pValue;
PASSDATA PDat;
PDat.Point = pFEA->szName;
/* Check Type Name is in the list of MVST or not */
for (i=0; i<MSNUM && MSdata[i].szName!=NULL &&
strcmp(PDat.Point,MSdata[i].szName)!=0;)
i++;
if(ConvTable[usRetEAType].usPrefix != EA_MVST && i==MSNUM)
{
if(!WinDlgBox(HWND_DESKTOP, /* Get the name and type */
hwnd,
AddEAProc,
'\0',
IDD_ADDEA,
&PDat))
return; /* They said cancel */
}
else /* MVST */
{
if (i < MSNUM && MSdata[i].szName!=NULL && MSdata[i].usType<10)
usRetEAType = MSdata[i].usType; /* EAname & type exist */
else
if(!WinDlgBox(HWND_DESKTOP, /* EAname is new, get the new type */
hwnd,
AddEAProc,
'\0',
IDD_ADDEA,
&PDat))
return; /* They said cancel */
}
pusPtr = (USHORT *) aUtility;
*pusPtr= ConvTable[usRetEAType].usPrefix; /* Set the type in header buf */
switch(ConvTable[usRetEAType].usFldType)
{
case IDD_ASCIIZ: /* make buffer look like: xx FF 00, size 3 */
usSize = 3;
aUtility[2]=0;
break;
case IDD_LPDATA: /* make the buffer look like: xx FF 00 00, size 4 */
usSize = 4;
pusPtr = (USHORT *) &aUtility[2];
*pusPtr= 0;
break;
case IDD_MULTILIST:
usSize = 6;
pusPtr = (USHORT *) &aUtility[2];
*pusPtr= 0; /* Zero out codepage */
pusPtr++;
*pusPtr= 0; /* Zero out fld cnt */
break;
}
/* Increase EA size to accomodate the header */
ResizeMem((PPVOID)&pFEA->aValue, pFEA->cbValue, pFEA->cbValue+usSize);
pusPtr = (USHORT *) ((CHAR *) pFEA->aValue + pPDat->usMultiOffset);
pusPtr+=2; /* Point to the current number of m-m fields */
/* Get ptr to beginning of current EA, scoot the rest down and insert
the 3-4 byte header at the end of the list. */
pInsert = MultiTypeIndex(pFEA->aValue+pPDat->usMultiOffset, *pusPtr);
memmove(pInsert+usSize,pInsert, pFEA->cbValue-(pInsert-pFEA->aValue));
memcpy(pInsert,aUtility,usSize);
pFEA->cbValue += usSize; /* Fix up the counts */
pPDat->cbMulti+= usSize;
/* Set the PDat for call */
PDat.Point = (CHAR *) pFEA;
PDat.cbMulti = pPDat->cbMulti;
PDat.usMultiOffset = pPDat->usMultiOffset;
PDat.usIndex = *pusPtr;
if(!EditEAValue(hwnd,&PDat)) /* They canceled the edit */
{ /* Move the EA's back to effectively kill the inserted header */
memmove(pInsert,pInsert+usSize,pFEA->cbValue-(pInsert-pFEA->aValue));
DosSetMem(pFEA->aValue, pFEA->cbValue-usSize, fPERM|PAG_COMMIT);
pFEA->cbValue -= usSize; /* Adjust counters */
pPDat->cbMulti-= usSize;
return;
}
/* Reset pusPtr since EditEAValue could have moved the base address */
pusPtr = (USHORT *) ((CHAR *) pFEA->aValue + pPDat->usMultiOffset);
pusPtr+=2;
pInsert = MultiTypeIndex(pFEA->aValue+pPDat->usMultiOffset, *pusPtr);
*pusPtr += 1; /* Field cnt incremented AFTER call to Edit */
pValue = EAValueString(pInsert); /* Add new field to the list box */
WinSendDlgItemMsg(hwnd, IDD_LBOX, LM_INSERTITEM,
MPFROM2SHORT(LIT_END,0),
MPFROMP(pValue));
FreeMem(pValue);
FILE_CHANGED = TRUE;
return;
}