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 >
C/C++ Source or Header  |  1999-05-11  |  56KB  |  1,270 lines

  1. /*static char *SCCSID = "@(#)easea.c    6.7 92/02/18";*/
  2. /*==============================================================*\
  3.  *                                                              *
  4.  *  EASEA.C - sample PM application                             *
  5.  *    (C) Copyright IBM Corporation 1992.                       *
  6.  *--------------------------------------------------------------*
  7.  *    This module contains subroutines for eas.c that           *
  8.  *    specifically deal with the manipulation of EAs.           *
  9.  *                                                              *
  10.  *--------------------------------------------------------------*
  11.  *  Procedures in this file:                                    *
  12.  *   AddEA()           Handles the Add button press             *
  13.  *   QueryEAs()        Reads in all the EAs associated with a file
  14.  *   CheckEAIntegrity()Checks an EA buffer to see if it is valid*
  15.  *   Free_FEAList()    Deallocates memory associated with EA list
  16.  *   LookupEAType()    Gets an offset into table for an EA type *
  17.  *   DeleteCurEA()     Deletes the highlighted EA               *
  18.  *   CurEAType()       Returns EA Type given a HoldFEA ptr      *
  19.  *   GetUSHORT()       Returns nth USHORT in ->aValue           *
  20.  *   WriteEAs()        Updates EAs state on the disk            *
  21.  *   EditEAValue()     Handles editing a given EA ( m-m EAs)    *
  22.  *   EAExists()        Determines if the given EA Name exists   *
  23.  *   ChangeName()      Handles the change of an EA's name       *
  24.  *   MultiTypeIndex()  Gets a specific field in a m-m structure *
  25.  *   EAValueString()   Returns a representational string for  EA*
  26.  *   MultiAdd()        Handles addition of a field for m-m      *
  27. \*==============================================================*/
  28. /*--------------------------------------------------------------*\
  29.  *  Include files, macros, defined constants, and externs       *
  30. \*--------------------------------------------------------------*/
  31. #include "eas.h"
  32.  
  33. extern EADATA ConvTable[EATABLESIZE];
  34.  
  35. /****************************************************************\
  36.  *                                                              *
  37.  *  Name:    AddEA(hwnd)                                        *
  38.  *                                                              *
  39.  *  Purpose: This routine handles the addition of a new EA to   *
  40.  *           the linked list.                                   *
  41.  *                                                              *
  42.  *  Usage  :                                                    *
  43.  *                                                              *
  44.  *  Method : Routine does NOT do full memory error trapping and *
  45.  *           the insert message to l-box is not error checked.  *
  46.  *                                                              *
  47.  *  Returns: TRUE if the EA is successfully added.              *
  48.  *                                                              *
  49. \****************************************************************/
  50. BOOL AddEA(HWND hwnd)
  51. {
  52.    HOLDFEA  *pFEA=pHoldFEA;       /* Points to the beginning of the EA list */
  53.    HOLDFEA  *pNewFEA=NULL;        /* Used to temporarily hold the new EA    */
  54.    PASSDATA PData;
  55.  
  56.    if(!FILE_ISOPEN)
  57.    {
  58.       MessageBox(hwnd, IDMSG_NOFILEOPEN, "Error !",
  59.                                 MB_OK | MB_ERROR, TRUE);
  60.       return(FALSE);
  61.    }
  62.    if(!WinDlgBox(HWND_DESKTOP,                  /* get new EA name and type */
  63.                  hwnd,
  64.                  AddEAProc,
  65.                  '\0',
  66.                  IDD_ADDEA,
  67.                  '\0'))
  68.       return(FALSE);                                    /* they said cancel */
  69.  
  70.    GetMem((PPVOID)&pNewFEA, sizeof(HOLDFEA));/* Allocate space for new EA struct */
  71.  
  72.    pNewFEA->cbName = (CHAR) strlen(szEAName);      /* Fill in new structure */
  73.    pNewFEA->cbValue= 0;
  74.    pNewFEA->fEA    = 0;                                 /* Need bit NOT set */
  75.                                                /* Name returned in szEAName */
  76.    GetMem((PPVOID)&pNewFEA->szName, pNewFEA->cbName+1);
  77.    strcpy(pNewFEA->szName,strupr(szEAName));
  78.    pNewFEA->aValue = '\0';
  79.    pNewFEA->next   = '\0';
  80.  
  81.    if(pHoldFEA == '\0')                   /* It's the first EA for the file */
  82.       pHoldFEA = pNewFEA;
  83.    else                             /* Add EA to the end of the linked list */
  84.    {
  85.       while(pFEA->next)
  86.          pFEA = pFEA->next;
  87.       pFEA->next = pNewFEA;
  88.    }
  89.    PData.Point         = (CHAR *) pNewFEA;      /* Setup user data for call */
  90.    PData.cbMulti       = 0;                     /* to edit of the name and  */
  91.    PData.usMultiOffset = 0;                     /* EA Value                 */
  92.  
  93.    if(!EditEAValue(hwnd,&PData))                  /* They canceled the edit */
  94.    {
  95.       if(pFEA)                                      /* It's not the only EA */
  96.          pFEA->next = '\0';                /* Disconnect the partial new EA */
  97.       else
  98.          pHoldFEA = '\0';                  /* The new EA was the first one  */
  99.  
  100.       FreeMem(pNewFEA->szName);
  101.       FreeMem(pNewFEA);
  102.  
  103.       return(FALSE);
  104.    }
  105.    WinSendDlgItemMsg(hwnd, IDD_WINLBOX, LM_INSERTITEM,/* Insert name in L-Box */
  106.                      MPFROM2SHORT(LIT_END,0),
  107.                      MPFROMP(pNewFEA->szName));
  108.    return(TRUE);
  109. }
  110.  
  111. /****************************************************************\
  112.  *                                                              *
  113.  *  Name:    QueryEAs(pszPath)                                  *
  114.  *                                                              *
  115.  *  Purpose: Call DOS to Query a file's EA names and values.    *
  116.  *                                                              *
  117.  *  Usage:                                                      *
  118.  *                                                              *
  119.  *  Method : Routine does NOT do full memory error trapping.    *
  120.  *           NOTE:  This routine does NOT prevent other         *
  121.  *           processes from accessing the file's EAs while it is*
  122.  *           reading them in, or while the program is editing   *
  123.  *           them.                                              *
  124.  *                                                              *
  125.  *  Returns: TRUE if it successfully reads in the EAs. Upon exit*
  126.  *           , globalp HoldFEA points to a linked list of the   *
  127.  *           EAs for the current file.                          *
  128.  *                                                              *
  129. \****************************************************************/
  130. BOOL QueryEAs(CHAR *pszPath)
  131. {
  132.    CHAR *pAllocc=NULL; /* Holds the FEA struct returned by DosEnumAttribute */
  133.                        /*  used to create the GEA2LIST for DosQueryPathInfo */
  134.    CHAR *pBigAlloc=NULL; /* Temp buffer to hold each EA as it is read in    */
  135.    USHORT cbBigAlloc=0;  /* Size of buffer                                  */
  136.  
  137.    ULONG ulEntryNum = 1; /* count of current EA to read (1-relative)        */
  138.    ULONG ulEnumCnt;      /* Number of EAs for Enum to return, always 1      */
  139.  
  140.    HOLDFEA *pLastIn=0;    /* Points to last EA added, so new EA can link    */
  141.    HOLDFEA *pNewFEA=NULL; /* Struct to build the new EA in                  */
  142.  
  143.    FEA2 *pFEA;           /* Used to read from Enum's return buffer          */
  144.    GEA2LIST *pGEAList;/*Ptr used to set up buffer for DosQueryPathInfo call */
  145.    EAOP2  eaopGet;       /* Used to call DosQueryPathInfo                   */
  146.                                    /* Allocate enough room for any GEA List */
  147.    GetMem((PPVOID)&pAllocc, MAX_GEA);
  148.    pFEA = (FEA2 *) pAllocc;               /* pFEA always uses pAlloc buffer */
  149.  
  150.    pHoldFEA = '\0';            /* Reset the pointer for the EA linked list  */
  151.  
  152.    while(TRUE)                /* Loop continues until there are no more EAs */
  153.    {
  154.       ulEnumCnt = 1;                   /* Only want to get one EA at a time */
  155.       if(DosEnumAttribute(Ref_ASCIIZ,            /* Read into pAlloc Buffer */
  156.                           pszPath,               /* Note that this does not */
  157.                           ulEntryNum,            /* get the aValue field,   */
  158.                           pAllocc,               /* so DosQueryPathInfo must*/
  159.                           MAX_GEA,               /* be called to get it.    */
  160.                           &ulEnumCnt,
  161.                           (LONG) GetInfoLevel1))
  162.         break;                              /* There was some sort of error */
  163.  
  164.       if(ulEnumCnt != 1)                      /* All the EAs have been read */
  165.          break;
  166.  
  167.       ulEntryNum++;
  168.  
  169.       GetMem((PPVOID)&pNewFEA, sizeof(HOLDFEA));
  170.  
  171.       if (pNewFEA == '\0')                                 /* Out of memory */
  172.       {
  173.          FreeMem(pAllocc);
  174.          Free_FEAList(pHoldFEA,pDelList);
  175.          return (FALSE);
  176.       }
  177.  
  178.       pNewFEA->cbName = pFEA->cbName;      /* Fill in the HoldFEA structure */
  179.       pNewFEA->cbValue= pFEA->cbValue;
  180.       pNewFEA->fEA    = pFEA->fEA;
  181.       pNewFEA->next = '\0';
  182.  
  183.       GetMem((PPVOID)&pNewFEA->szName, pFEA->cbName +1); /* Allocate for 2 arrays */
  184.       GetMem((PPVOID)&pNewFEA->aValue, pFEA->cbValue);
  185.  
  186.       if (!pNewFEA->szName || !pNewFEA->aValue)            /* Out of memory */
  187.       {
  188.          if(pNewFEA->szName)
  189.             FreeMem(pNewFEA->szName);
  190.          if(pNewFEA->aValue)
  191.             FreeMem(pNewFEA->aValue);
  192.  
  193.          FreeMem(pAllocc);
  194.          FreeMem(pNewFEA);
  195.  
  196.          Free_FEAList(pHoldFEA,pDelList);
  197.          return (FALSE);
  198.       }
  199.       strcpy(pNewFEA->szName,pFEA->szName);              /* Copy in EA Name */
  200.  
  201.       cbBigAlloc = sizeof(FEA2LIST) + pNewFEA->cbName+1 +
  202.                               pNewFEA->cbValue;
  203.       GetMem((PPVOID)&pBigAlloc, cbBigAlloc);
  204.       if (pBigAlloc == '\0')
  205.       {
  206.          FreeMem(pNewFEA->szName);
  207.          FreeMem(pNewFEA->aValue);
  208.          FreeMem(pAllocc);
  209.          FreeMem(pNewFEA);
  210.          Free_FEAList(pHoldFEA,pDelList);
  211.          return (FALSE);
  212.       }
  213.  
  214.       pGEAList = (GEA2LIST *) pAllocc;          /* Set up GEAList structure */
  215.  
  216.       pGEAList->cbList = sizeof(GEA2LIST) + pNewFEA->cbName; /* +1 for NULL */
  217.       pGEAList->list[0].oNextEntryOffset = 0L;
  218.       pGEAList->list[0].cbName = pNewFEA->cbName;
  219.       strcpy(pGEAList->list[0].szName,pNewFEA->szName);
  220.  
  221.       eaopGet.fpGEA2List = (GEA2LIST FAR *) pAllocc;
  222.       eaopGet.fpFEA2List = (FEA2LIST FAR *) pBigAlloc;
  223.  
  224.       eaopGet.fpFEA2List->cbList = cbBigAlloc;
  225.  
  226.       DosQueryPathInfo(pszPath,                     /* Get the complete EA info */
  227.                        FIL_QUERYEASFROMLIST,
  228.                       (PVOID) &eaopGet,
  229.                        sizeof(EAOP2));
  230.       memcpy(pNewFEA->aValue,                  /* Copy the value to HoldFEA */
  231.              pBigAlloc+sizeof(FEA2LIST)+pNewFEA->cbName,
  232.              pNewFEA->cbValue);
  233.  
  234.       FreeMem(pBigAlloc);                   /* Release the temp Enum buffer */
  235.  
  236.       if(!CheckEAIntegrity(pNewFEA->aValue,pNewFEA->cbValue))     /* Bad EA */
  237.       {
  238.          FreeMem(pNewFEA->szName);
  239.          FreeMem(pNewFEA->aValue);
  240.          FreeMem(pNewFEA);
  241.          continue;                      /* Don't add this EA to linked list */
  242.       }
  243.  
  244.       if(pHoldFEA == '\0')                     /* If first EA, set pHoldFEA */
  245.          pHoldFEA = pNewFEA;
  246.       else                                 /* Otherwise, add to end of list */
  247.          pLastIn->next = pNewFEA;
  248.  
  249.       pLastIn = pNewFEA;                      /* Update the end of the list */
  250.    }
  251.    FreeMem(pAllocc);                      /* Free up the GEA buf for DosEnum */
  252.    return (TRUE);
  253. }
  254.  
  255.  
  256. /****************************************************************\
  257.  *                                                              *
  258.  *  Function name: CheckEAIntegrity(aBuf, cbBuf)                *
  259.  *                                                              *
  260.  *  Returns: TRUE if the buffer is a valid EA structure.        *
  261.  *                                                              *
  262.  *  Purpose: This routine checks the integrity of the passed EA *
  263.  *           buffer by seeing if there are any non-standard EA  *
  264.  *           types, or bad data that isn't sized correctly.     *
  265.  *  Usage  :                                                    *
  266.  *  Method : Routine uses MultiTypeIndex() to check m-m type EAs*
  267.  *           since they are potentially recursive. However, this*
  268.  *           may not be a good idea if the m-m EA is severly    *
  269.  *           corrupted because it may cause MTI() to attempt a  *
  270.  *           read from protected memory. Routine does NOT modify*
  271.  *           the buffer under any circumstance.                 *
  272.  *                                                              *
  273.  *  Returns: TRUE if the buffer is a valid EA structure.        *
  274.  *                                                              *
  275. \****************************************************************/
  276. BOOL CheckEAIntegrity(CHAR *aBuf, ULONG cbBuf)
  277. {
  278.    USHORT *pusPtr = (USHORT *) aBuf;
  279.    USHORT usOffset;
  280.    CHAR   *aEndPtr;
  281.  
  282.    usOffset = LookupEAType(*pusPtr);                 /* Get the EA type */
  283.  
  284.    switch(ConvTable[usOffset].usFldType)
  285.    {
  286.       case IDD_LPDATA:
  287.          pusPtr++;
  288.          if(*pusPtr + 2*sizeof(USHORT) == cbBuf)
  289.             return TRUE;
  290.          else
  291.             return FALSE;
  292.  
  293.       case IDD_MULTILIST:
  294.          if(*pusPtr == EA_MVMT)
  295.          {
  296.             pusPtr += 2;
  297.  
  298.                 /* This checks where the end of the m-m list ends to determine
  299.                    the size of the EA.  This is probably not good if the EA is
  300.                    badly corrupted and it points to protected memory        */
  301.  
  302.             aEndPtr = MultiTypeIndex(aBuf,*pusPtr);
  303.             if(aEndPtr - aBuf == (CHAR) cbBuf)
  304.                return TRUE;
  305.             else
  306.                return FALSE;
  307.          }
  308.          else            /* Single type, multi-value is not yet implemented */
  309.          {
  310.             return TRUE;
  311.          }
  312.       default:
  313.          return FALSE;
  314.    }
  315.    return TRUE;
  316. }
  317.  
  318. /****************************************************************\
  319.  *                                                              *
  320.  *  Name:    Free_FEAList(pFEA, pDList)                         *
  321.  *                                                              *
  322.  *  Purpose: This routine frees up the current list of EAs by   *
  323.  *           deallocating the space used by the szName and      *
  324.  *           aValue fields, then deallocating the HoldFEA struct*
  325.  *           Next, it deletes the EAName space, then the        *
  326.  *           DeleteList structure.                              *
  327.  *  Usage :                                                     *
  328.  *  Method:  Note that EAS always passes in pHoldFEA and        *
  329.  *           pDelList which is unnecessary since they are global*
  330.  *           pointers;however, this is done to make the routine *
  331.  *           more flexible by allowing multiple linked lists to *
  332.  *           exist.                                             *
  333.  *                                                              *
  334.  *  Returns: VOID.  The two linked lists passed in are cleaned  *
  335.  *           out though.                                        *
  336.  *                                                              *
  337. \****************************************************************/
  338. VOID Free_FEAList(HOLDFEA *pFEA, DELETELIST *pDList)
  339. {
  340.    HOLDFEA *next;       /* Holds the next field since we free the structure */
  341.                         /* before reading the current next field            */
  342.    DELETELIST *Dnext;                              /* Same purpose as *next */
  343.  
  344.    while(pFEA)
  345.    {
  346.       next = pFEA->next;
  347.       if(pFEA->szName)                            /* Free if non-NULL name  */
  348.          FreeMem(pFEA->szName);
  349.       if(pFEA->aValue)                            /* Free if non-NULL value */
  350.          FreeMem(pFEA->aValue);
  351.  
  352.       FreeMem(pFEA);                                 /* Free HoldFEA struct */
  353.       pFEA = next;
  354.    }
  355.    while(pDList)
  356.    {
  357.       Dnext = pDList->next;
  358.       if(pDList->EAName)
  359.          FreeMem(pDList->EAName);
  360.       FreeMem(pDList);
  361.       pDList = Dnext;
  362.    }
  363.    return;
  364. }
  365.  
  366. /****************************************************************\
  367.  *                                                              *
  368.  *  Name:    LookupEAType(usType)                               *
  369.  *                                                              *
  370.  *  Purpose: This routine takes EA type and returns an offset   *
  371.  *           into ConvTable which points to an entry that       *
  372.  *           describes the type passed in.                      *
  373.  *                                                              *
  374.  *  Usage:                                                      *
  375.  *  Method:                                                     *
  376.  *                                                              *
  377.  *  Returns: An offset into the ConvTable to the appropriate    *
  378.  *           entry. If no match is found, the return value      *
  379.  *           points to the last entry, non-conventional format. *
  380.  *                                                              *
  381. \****************************************************************/
  382. ULONG LookupEAType(ULONG usType)
  383. {
  384.    USHORT cnt;
  385.  
  386.    for(cnt=0;cnt<EATABLESIZE-1;cnt++)
  387.       if(ConvTable[cnt].usPrefix == usType)
  388.          return(cnt);
  389.    return(cnt);
  390. }
  391.  
  392. /****************************************************************\
  393.  *                                                              *
  394.  *  Name:    DeleteCurEA(hwnd)                                  *
  395.  *                                                              *
  396.  *  Purpose: This routine removes in memory the currently       *
  397.  *           highlighted EA from the EA list.  It places the    *
  398.  *           deleted EA in the global pDelList linked list.     *
  399.  *                                                              *
  400.  *  Usage:   This routine is called by MainDlgProc when DELETE  *
  401.  *           button selected.                                   *
  402.  *                                                              *
  403.  *  Method:  The memory allocation routines are NOT fully error *
  404.  *           trapped.                                           *
  405.  *                                                              *
  406.  *  Returns: VOID.  Removes one item from global pHoldFEA list  *
  407.  *           and adds one to global pDelList.                   *
  408.  *                                                              *
  409. \****************************************************************/
  410. VOID DeleteCurEA(HWND hwnd)
  411. {
  412.    HOLDFEA    *pFEA,*pFEAPrev;
  413.    DELETELIST *pDL=NULL, *pDLcnt;/*Utility ptrs for manipulating the Del list*/
  414.    SHORT      sOffset;
  415.    SHORT      i;
  416.  
  417.    if(!FILE_ISOPEN)
  418.    {
  419.       MessageBox(hwnd, IDMSG_ERRORSELECT, "Error !",
  420.                                MB_OK | MB_ERROR, TRUE);
  421.       return;
  422.    }
  423.    sOffset = (SHORT) WinSendDlgItemMsg(hwnd, IDD_WINLBOX,
  424.                                          LM_QUERYSELECTION,0,0);
  425.    if(sOffset<0)                           /* No item is currently selected */
  426.    {
  427.       MessageBox(hwnd, IDMSG_ERRORSELECT, "Error !",
  428.                                      MB_OK | MB_ERROR, TRUE);
  429.       return;
  430.    }
  431.    pFEA = GetCurFEA(hwnd,pHoldFEA);     /* Gets a pointer to item to delete */
  432.    if (pFEA == '\0')
  433.       return;
  434.                /* These two allocations should be checked for out of memory */
  435.    GetMem((PPVOID)&pDL, sizeof(DELETELIST));     /* Add Name to Delete List */
  436.    GetMem((PPVOID)&pDL->EAName, pFEA->cbName+1);
  437.    strcpy(pDL->EAName,pFEA->szName);
  438.    pDL->next = '\0';
  439.  
  440.    if(pDelList == '\0')               /* The del list was previously empty  */
  441.       pDelList = pDL;
  442.    else                               /* tack name onto the end of the list */
  443.    {
  444.       pDLcnt = pDelList;
  445.       while(pDLcnt->next)
  446.          pDLcnt = pDLcnt->next;
  447.       pDLcnt->next = pDL;
  448.    }
  449.    WinSendDlgItemMsg(hwnd, IDD_WINLBOX,
  450.                      LM_DELETEITEM,MPFROMSHORT(sOffset),0L);
  451.  
  452.    if(sOffset<1)                        /* Remove pFEA from the linked list */
  453.    {
  454.       pHoldFEA = pFEA->next;
  455.    }
  456.    else
  457.    {
  458.       pFEAPrev = pHoldFEA;
  459.  
  460.       --sOffset;
  461.       while(sOffset)                                    /* Find previous EA */
  462.       {
  463.          pFEAPrev = pFEAPrev->next;
  464.          --sOffset;
  465.       }
  466.       pFEAPrev->next = pFEA->next;
  467.    }
  468.                            /* Check Type Name is in the list of MVST or not */
  469.    for (i=0; i<MSNUM && MSdata[i].szName!=NULL &&
  470.                         strcmp(pFEA->szName,MSdata[i].szName)!=0;)
  471.           i++;
  472.  
  473.    if(i<MSNUM && MSdata[i].szName!=NULL)         /* Found the EA type in MVST list */
  474.    {
  475.       FreeMem(MSdata[i].szName);
  476.       for (; i<MSNUM && MSdata[i+1].szName!=NULL; i++)
  477.       {
  478.          MSdata[i].szName = MSdata[i+1].szName;
  479.          MSdata[i].usType = MSdata[i+1].usType;
  480.       }
  481.    }
  482.    FreeMem(pFEA->szName);                             /* Release the memory */
  483.    FreeMem(pFEA->aValue);
  484.    FreeMem(pFEA);
  485.  
  486.    FILE_CHANGED = TRUE;
  487.    return;
  488. }
  489.  
  490. /****************************************************************\
  491.  *                                                              *
  492.  *  Name:    CurEAType(pFEA)                                    *
  493.  *                                                              *
  494.  *  Purpose: Given an EA structure, this routine returns the    *
  495.  *           Type of the EA which resides in the first USHORT of*
  496.  *           the aValue member. This function is the same as    *
  497.  *           GetUSHORT(pFEA,0).                                 *
  498.  *  Usage  :                                                    *
  499.  *  Method : Assumes a valid HoldFEA struct.                    *
  500.  *                                                              *
  501.  *  Returns: The EA type.                                       *
  502.  *                                                              *
  503. \****************************************************************/
  504. ULONG CurEAType(HOLDFEA *pFEA)                   /* Same as GetUSHORT(,0); */
  505. {
  506.    USHORT *pusType;    /* EA Type is stored in first USHORT of aValue field */
  507.  
  508.    pusType = (USHORT *) pFEA->aValue;
  509.    return(*pusType);
  510. }
  511.  
  512. /****************************************************************\
  513.  *                                                              *
  514.  *  Name:    GetUSHORT(pFEA, index)                             *
  515.  *                                                              *
  516.  *  Purpose: This routine returns the nth USHORT value in the   *
  517.  *           aValue member of pFEA using index as the offset.   *
  518.  *  Usage  :                                                    *
  519.  *  Method : Assumes a valid HoldFEA struct and that index      *
  520.  *           doesn't point outside the aValue buffer.           *
  521.  *                                                              *
  522.  *  Returns: The appropriate USHORT from the aValue field       *
  523.  *                                                              *
  524. \****************************************************************/
  525. USHORT GetUSHORT(HOLDFEA *pFEA, ULONG index)
  526. {
  527.    USHORT *pusType;
  528.  
  529.    pusType = (USHORT *) pFEA->aValue;
  530.    while(index-- > 0)
  531.       pusType++;
  532.    return(*pusType);
  533. }
  534.  
  535. /****************************************************************\
  536.  *                                                              *
  537.  *  Name:    WriteEAs()                                         *
  538.  *                                                              *
  539.  *  Purpose: This routine updates the EAs on disk to reflect    *
  540.  *           their current condition in memory.  First, all EAs *
  541.  *           in the delete list are removed from the disk, then *
  542.  *           all EAs in the pHoldFEA list are written to disk.  *
  543.  *  Usage  :                                                    *
  544.  *  Method : This routine is not bulletproof as it does not get *
  545.  *           exclusive access to the file EAs, nor does it      *
  546.  *           handle out of disk space sort of errors. Also,     *
  547.  *           memory fetches are not fully error trapped.        *
  548.  *                                                              *
  549.  *  Returns: VOID.  But cleans out the pDelList linked list.    *
  550.  *                                                              *
  551. \****************************************************************/
  552. VOID WriteEAs()
  553. {
  554.    DELETELIST *pDL = pDelList,*pDLnext;
  555.    HOLDFEA    *pHFEA= pHoldFEA;
  556.    EAOP2       eaopWrite;
  557.    CHAR       aBuf[MAX_GEA],*aPtr=NULL;
  558.    FEA2        *pFEA = (FEA2 *) &aBuf[sizeof(ULONG)];
  559.    USHORT     usMemNeeded, usRet;
  560.    ULONG      *pulPtr=(ULONG *) aBuf;  /* Initally points to top of FEALIST */
  561.  
  562.    if(!FILE_ISOPEN)
  563.    {
  564.       MessageBox(HWND_DESKTOP, IDMSG_NOFILEOPEN, "Error !",
  565.                                 MB_OK | MB_ERROR, TRUE);
  566.       return;
  567.    }
  568.    if (!FILE_CHANGED)                  /* Don't write unless it's necessary */
  569.       return;
  570.    eaopWrite.fpFEA2List = (FEA2LIST FAR *) aBuf; /* Setup fields that won't */
  571.    pFEA->fEA     = 0;                            /* change for the delete   */
  572.    pFEA->cbValue = 0;                            /* calls to DosSetPathInfo */
  573.  
  574.    while(pDL)                         /* Clean out all the deleted EA names */
  575.    {
  576.       pFEA->cbName = (UCHAR) strlen(pDL->EAName);
  577.       *pulPtr      = sizeof(FEA2LIST) + pFEA->cbName;
  578.       strcpy(pFEA->szName,pDL->EAName);
  579.       pFEA->oNextEntryOffset = 0L;
  580.                                          /* Delete EA's by saying cbValue=0 */
  581.       DosSetPathInfo(szFileName,
  582.                      SetInfoLevel2,
  583.                      (PVOID) &eaopWrite,
  584.                      sizeof(EAOP2),
  585.                      DSPI_WRTTHRU);
  586.       pDLnext = pDL->next;                            /* Temp hold next pDL */
  587.       FreeMem(pDL->EAName);                   /* Free up current Del struct */
  588.       FreeMem(pDL);
  589.       pDL = pDLnext;                              /* Set pDL to saved value */
  590.    }
  591.    pDelList = '\0';                                 /* DelList is now empty */
  592.  
  593.    while(pHFEA)                                  /* Go through each HoldFEA */
  594.    {
  595.       usMemNeeded = sizeof(FEA2LIST) + pHFEA->cbName+1 +
  596.                                 pHFEA->cbValue;
  597.       GetMem((PPVOID)&aPtr, usMemNeeded);
  598.  
  599.       eaopWrite.fpFEA2List = (FEA2LIST FAR *) aPtr;  /* Fill in eaop struct */
  600.       eaopWrite.fpFEA2List->cbList = usMemNeeded;
  601.  
  602.       eaopWrite.fpFEA2List->list[0].fEA     = pHFEA->fEA;
  603.       eaopWrite.fpFEA2List->list[0].cbName  = pHFEA->cbName;
  604.       eaopWrite.fpFEA2List->list[0].cbValue = pHFEA->cbValue;
  605.  
  606.       strcpy(eaopWrite.fpFEA2List->list[0].szName, pHFEA->szName);
  607.       memcpy(eaopWrite.fpFEA2List->list[0].szName + pHFEA->cbName+1,
  608.              pHFEA->aValue, pHFEA->cbValue);
  609.  
  610.       usRet = DosSetPathInfo(szFileName,         /* Write out the EA */
  611.                              FIL_QUERYEASIZE,
  612.                              (PVOID) &eaopWrite,
  613.                              sizeof(EAOP2),
  614.                              DSPI_WRTTHRU);
  615.       if (usRet)
  616.       {
  617.           MessageBox(HWND_DESKTOP, IDMSG_WRITEERROR, "Error !",
  618.                                   MB_OK | MB_ERROR, TRUE);
  619.           FreeMem(aPtr);                      /* Free up the FEALIST struct */
  620.           FILE_CHANGED = FALSE;
  621.           return;
  622.       }
  623.       FreeMem(aPtr);                          /* Free up the FEALIST struct */
  624.  
  625.       pHFEA = pHFEA->next;
  626.    }
  627.    FILE_CHANGED = FALSE;
  628.    MessageBox(HWND_DESKTOP, IDMSG_WRITEOK, "Note !", MB_OK, FALSE);
  629.    return;
  630. }
  631.  
  632. /****************************************************************\
  633.  *                                                              *
  634.  *  Function name: EditEAValue(hwnd, pPDat)                     *
  635.  *                                                              *
  636.  *  Purpose: This routine allows the entry/edit of an EA value  *
  637.  *           condition in memory.  First, all EAs in the delete *
  638.  *           list are removed from the disk, then all EAs in the*
  639.  *           pHoldFEA list are written out to disk.             *
  640.  *  Usage  :                                                    *
  641.  *  Method : Expects the PassData structure to tell it the      *
  642.  *           HoldFEA to edit, and if it is a subfield of a multi*
  643.  *           -multi EA, the rest of the PassData structure will *
  644.  *           be filled into indicated which m-m is being edited.*
  645.  *           Note that if this is a new edit, usRetEAType is    *
  646.  *           expected to be set to the proper EA type upon entry*
  647.  *    NOTE:  memory sizing  requests are not fully error trapped*
  648.  *                                                              *
  649.  *  Returns: TRUE if the edit was successful.                   *
  650.  *                                                              *
  651. \****************************************************************/
  652. BOOL EditEAValue(HWND hwnd, PPASSDATA pPDat)
  653. {
  654.    USHORT usEAType;                    /* Holds the field type to be edited */
  655.    USHORT *pusPtr;
  656.    USHORT usSize;  /* Holds the delta difference of the old and new buffers */
  657.    CHAR   *szNew=NULL,*szTrash;                            /* Temporary pointers */
  658.    PASSDATA PDat;
  659.    HOLDFEA *pFEA = (HOLDFEA *) pPDat->Point;         /* The EA to be edited */
  660.  
  661.                             /* Determine the type of EA that will be edited */
  662.    if(pPDat->cbMulti)                             /* It's a multi-type job  */
  663.    {
  664.       pusPtr = (USHORT *) MultiTypeIndex(pFEA->aValue+pPDat->usMultiOffset,
  665.                                          pPDat->usIndex);
  666.       usEAType = *pusPtr;
  667.    }
  668.    else if(pFEA->cbValue)                         /* It isn't a new EA name */
  669.    {
  670.       pusPtr   = (USHORT *)pFEA->aValue;
  671.       usEAType = *pusPtr;
  672.    }
  673.    else                                                    /* It's a new EA */
  674.       usEAType = ConvTable[usRetEAType].usPrefix;
  675.  
  676.    PDat.Point   = pFEA->szName;          /* General setup for AsciiEditProc */
  677.                                                   /* =1 if there is a multi */
  678.    PDat.usIndex =(USHORT)( pPDat->cbMulti ? 1 : 0);
  679.    PDat.fFlag   = (BYTE) ((pFEA->fEA & 0x80) ? TRUE : FALSE);
  680.  
  681.    switch(usEAType)
  682.    {
  683.       case EA_ASCIIZ:
  684.       case EA_ASCIIZFN:
  685.       case EA_ASCIIZEA:
  686.       case EA_ASN1:
  687.          if(pPDat->cbMulti)                     /* It is a multi-type field */
  688.             szAscii=MultiTypeIndex(pFEA->aValue + pPDat->usMultiOffset,
  689.                                    pPDat->usIndex)
  690.                     +sizeof(USHORT);
  691.          else if(pFEA->cbValue)                 /* There is a current value */
  692.             szAscii=pFEA->aValue+sizeof(USHORT);
  693.          else                                              /* It's a new EA */
  694.             szAscii='\0';
  695.  
  696.          if(!WinDlgBox(HWND_DESKTOP,               /* Do an ascii text edit */
  697.                        hwnd,
  698.                        AsciiEditProc,
  699.                        '\0',
  700.                        IDD_ASCIIEDIT,
  701.                        &PDat))
  702.             return(FALSE);                              /* They said cancel */
  703.  
  704.          if(PDat.fFlag)                         /* Handle the need/nice bit */
  705.             PDat.fFlag = 0x80;
  706.          if(PDat.fFlag != (BYTE)(PDat.fFlag & 0x80))
  707.             FILE_CHANGED = TRUE;
  708.          pFEA->fEA =(BYTE)( (pFEA->fEA & 0x7f) | PDat.fFlag );
  709.  
  710.          if(stricmp(strupr(szEAName),pFEA->szName))     /* The name changed */
  711.             ChangeName(pFEA,szEAName);
  712.  
  713.          if(pFEA->cbValue)                      /* There is a current value */
  714.          {
  715.             if(!strcmp(szAscii,szScratch))             /* It hasn't changed */
  716.                return(TRUE);
  717.  
  718.             if(pPDat->cbMulti)            /* Do the whole thing here if m-m */
  719.             {                                             /* Change in size */
  720.                usSize = (strlen(szScratch)-strlen(szAscii));
  721.  
  722.                if(usSize > 0)                   /* The new string is longer */
  723.                {
  724.                   ResizeMem((PPVOID)&pFEA->aValue,           /* Enlarge the EA size */
  725.                             pFEA->cbValue,
  726.                             pFEA->cbValue+usSize);
  727.                   szTrash=MultiTypeIndex(pFEA->aValue + pPDat->usMultiOffset,
  728.                                                (pPDat->usIndex+1));
  729.                   memmove(szTrash+usSize,    /* Move end of EA to make room */
  730.                           szTrash,
  731.                           pFEA->cbValue-(szTrash-pFEA->aValue));
  732.                }
  733.                else
  734.                {
  735.                   szTrash= MultiTypeIndex(pFEA->aValue + pPDat->usMultiOffset,
  736.                                                (pPDat->usIndex+1));
  737.                   memmove(szTrash+usSize,    /* Move back the end of the EA */
  738.                           szTrash,
  739.                           pFEA->cbValue-(szTrash-pFEA->aValue));
  740.                   DosSetMem(pFEA->aValue, pFEA->cbValue+usSize, fPERM|PAG_COMMIT);
  741.                }
  742.                szTrash=MultiTypeIndex(pFEA->aValue + pPDat->usMultiOffset,
  743.                                       pPDat->usIndex);
  744.                strcpy(szTrash+sizeof(USHORT),szScratch); /* Copy in new val */
  745.                pFEA->cbValue+=usSize;              /* Change buffer count   */
  746.  
  747.                FILE_CHANGED = TRUE;
  748.                return(FILE_CHANGED);                  /* Done with m-m edit */
  749.             }
  750.             else
  751.             {
  752.                FreeMem(pFEA->aValue);              /* Release old Value mem */
  753.             }
  754.          }
  755.          GetMem((PPVOID)&szNew, strlen(szScratch)+3); /* +3 for Type & NULL */
  756.          pusPtr = (USHORT *) szNew;
  757.          *pusPtr= usEAType;                       /* Set type in new buffer */
  758.          strcpy(szNew+2,szScratch);                /* Copy in the new value */
  759.          pFEA->aValue = szNew;                      /* Fix up the structure */
  760.          pFEA->cbValue= (USHORT)(strlen(szScratch)+3);
  761.  
  762.          FILE_CHANGED = TRUE;
  763.          return(FILE_CHANGED);
  764.  
  765.       case EA_LPBITMAP:
  766.       case EA_LPICON:
  767.       case EA_LPBINARY:
  768.       case EA_LPASCII:
  769.       case EA_LPMETAFILE:
  770.          if (usEAType==EA_LPBITMAP || usEAType==EA_LPICON)
  771.          {
  772.             WinDlgBox(HWND_DESKTOP,
  773.                       hwnd,
  774.                       IconDlgProc,
  775.                       '\0',
  776.                       IDD_ABOUTBOX,
  777.                       NULL);
  778.          }
  779.          if(pPDat->cbMulti)                     /* It is a multi-type field */
  780.          {   /* szTrash points to field to edit, pusPtr to the field length */
  781.             szTrash=MultiTypeIndex(pFEA->aValue + pPDat->usMultiOffset,
  782.                                    pPDat->usIndex);
  783.             pusPtr = (USHORT *) ((CHAR *) szTrash + sizeof(USHORT));
  784.             usSize = *pusPtr;
  785.             if(usSize)                                 /* It isn't a new EA */
  786.             {                               /* Set up inital value for edit */
  787.                GetMem((PPVOID)&szAscii, usSize+1);
  788.                memcpy(szAscii,szTrash+2*sizeof(USHORT),usSize);
  789.                *( ( CHAR *)szAscii + usSize ) ='\0';
  790.             }
  791.             else                                         /* No inital value */
  792.                szAscii = '\0';
  793.          }
  794.          else if(pFEA->cbValue)    /* Single type && there is current value */
  795.          {
  796.             usSize=GetUSHORT(pFEA,1);      /* Get size and set inital value */
  797.             if(usSize)
  798.             {
  799.                GetMem((PPVOID)&szTrash, usSize+1);           /* +1 for null */
  800.                memcpy(szTrash,pFEA->aValue+4,usSize);
  801.                szTrash[usSize]='\0';
  802.                szAscii=szTrash;
  803.             }
  804.             else
  805.                szAscii = '\0';
  806.          }
  807.          else
  808.             szAscii = '\0';
  809.  
  810.          if(!WinDlgBox(HWND_DESKTOP,               /* Do an ascii text edit */
  811.                        hwnd,
  812.                        AsciiEditProc,
  813.                        '\0',
  814.                        IDD_ASCIIEDIT,
  815.                        &PDat))
  816.          {     /* Cancel, but check if memory needs to be freed before exit */
  817.             if(pPDat->cbMulti || pFEA->cbValue)
  818.                if(szAscii)                                 /* It's not NULL */
  819.                   FreeMem(szAscii);                          /* +1 for NULL */
  820.             return(FALSE);
  821.          }
  822.          if(PDat.fFlag)                         /* Handle the need/nice bit */
  823.             PDat.fFlag = 0x80;
  824.          if(PDat.fFlag != (BYTE)(PDat.fFlag & 0x80))
  825.             FILE_CHANGED = TRUE;
  826.          pFEA->fEA = (BYTE)((pFEA->fEA & 0x7f) | PDat.fFlag);
  827.  
  828.          if(stricmp(strupr(szEAName),pFEA->szName))     /* The name changed */
  829.             ChangeName(pFEA,szEAName);
  830.  
  831.          if(pFEA->cbValue)                      /* There is a current value */
  832.          {
  833.             if(szAscii && !strcmp(szAscii,szScratch))  /* It hasn't changed */
  834.             {
  835.                if(szAscii)
  836.                   FreeMem(szAscii);
  837.                return(TRUE);
  838.             }
  839.             if(szAscii)                        /* Free default value buffer */
  840.                FreeMem(szAscii);
  841.  
  842.             if(pPDat->cbMulti)     /* Do the whole thing here is multi-type */
  843.             {                                              /* Change in len */
  844.                USHORT usDelta = (USHORT)(strlen(szScratch) - usSize);
  845.                if(usDelta > 0)    /* The new string is longer, resize first */
  846.                {
  847.                   ResizeMem((PPVOID)&pFEA->aValue, pFEA->cbValue, pFEA->cbValue+usDelta);
  848.                   szTrash= MultiTypeIndex(pFEA->aValue + pPDat->usMultiOffset,
  849.                                          (pPDat->usIndex+1));
  850.                   memmove(szTrash+usDelta,szTrash,
  851.                           pFEA->cbValue-(szTrash-pFEA->aValue));
  852.                }
  853.                else
  854.                {
  855.                   szTrash= MultiTypeIndex(pFEA->aValue + pPDat->usMultiOffset,
  856.                                          (pPDat->usIndex+1));
  857.                   memmove(szTrash+usDelta,szTrash,
  858.                           pFEA->cbValue-(szTrash-pFEA->aValue));
  859.                   ResizeMem((PPVOID)&pFEA->aValue, pFEA->cbValue+usDelta, fPERM|PAG_COMMIT);
  860.                }
  861.                szTrash=MultiTypeIndex(pFEA->aValue + pPDat->usMultiOffset,
  862.                                       pPDat->usIndex);
  863.                memmove(szTrash+2*sizeof(USHORT),szScratch,strlen(szScratch));
  864.                pusPtr = (USHORT *) ((CHAR *)szTrash + sizeof(USHORT));
  865.                *pusPtr= strlen(szScratch); /* Set the length field */
  866.  
  867.                pFEA->cbValue += usDelta;         /* Adjust struct len field */
  868.  
  869.                FILE_CHANGED = TRUE;
  870.                return(FILE_CHANGED);
  871.             }
  872.             FreeMem(pFEA->aValue);                     /* Free up old value */
  873.          }
  874.          GetMem((PPVOID)&szNew, strlen(szScratch)+4); /* Get space for new value */
  875.          pusPtr = (USHORT *) szNew;
  876.          *pusPtr= usEAType;                               /* Set type field */
  877.          pusPtr++;
  878.          *pusPtr= strlen(szScratch);            /* Set length field */
  879.          memcpy(szNew+4,szScratch,*pusPtr);            /* Copy in new value */
  880.          pFEA->aValue = szNew;                           /* Adjust pointers */
  881.          pFEA->cbValue= strlen(szScratch)+4;/* +4 for type and LP cnt */
  882.  
  883.          FILE_CHANGED = TRUE;
  884.          return(FILE_CHANGED);
  885.  
  886.       case EA_MVST:
  887.       case EA_MVMT:                          /* It's multi-value multi-type */
  888.          if(pFEA->cbValue == 0)                            /* It's a new EA */
  889.          {                                         /* Allocate empty m-m EA */
  890.             GetMem((PPVOID)&pFEA->aValue, 3*sizeof(USHORT));
  891.             pFEA->cbValue = 3*sizeof(USHORT);
  892.             pusPtr      = (USHORT *) pFEA->aValue;
  893.             if(usEAType == EA_MVMT)
  894.                *pusPtr = 0xffdf;                 /* Multi-value, multi-type */
  895.             else
  896.                *pusPtr = 0xffde;                /* Multi-value, single-type */
  897.             pusPtr+=2;                               /* Skip type, codepage */
  898.             *pusPtr = 0;                 /* No fields initially     */
  899.             FILE_CHANGED = TRUE;
  900.          }
  901.                                                    /* Set up passed in data */
  902.          if(pPDat->cbMulti)                       /* It's a multi-type job  */
  903.          {
  904.             szNew   = MultiTypeIndex(pFEA->aValue + pPDat->usMultiOffset,
  905.                                      pPDat->usIndex);
  906.             szTrash = MultiTypeIndex(pFEA->aValue + pPDat->usMultiOffset,
  907.                                            (pPDat->usIndex+1));
  908.             PDat.usMultiOffset = (USHORT)(szNew - pFEA->aValue);
  909.             PDat.cbMulti       = (USHORT)(szTrash - szNew);
  910.          }
  911.          else
  912.          {
  913.             PDat.usMultiOffset = 0;
  914.             PDat.cbMulti       = pFEA->cbValue;
  915.          }
  916.          PDat.Point = (CHAR *) pFEA;
  917.  
  918.          WinDlgBox(HWND_DESKTOP,                  /* Do the Multi-type edit */
  919.                    hwnd,
  920.                    MultiTypeProc,
  921.                    '\0',
  922.                    IDD_MULTIBOX,
  923.                    &PDat);
  924.          return(TRUE);
  925.  
  926.       default:
  927.          return(FALSE);
  928.    }
  929.    return(FALSE);
  930. }
  931.  
  932. /****************************************************************\
  933.  *                                                              *
  934.  *  Name:    EAExists(szEAName)                                 *
  935.  *                                                              *
  936.  *  Purpose: This routine goes through the linked list pointed  *
  937.  *           to by global pHoldFEA and determines whether or not*
  938.  *           an EA othe passed name already exists.             *
  939.  *  Usage:                                                      *
  940.  *  Method : The comparison is NOT case sensitive.              *
  941.  *                                                              *
  942.  *  Returns: TRUE if an EA with a name matching szEAName exists.*
  943.  *                                                              *
  944. \****************************************************************/
  945. BOOL EAExists(CHAR *szEAName)
  946. {
  947.    HOLDFEA *phFEA=pHoldFEA;
  948.  
  949.    while(phFEA)
  950.    {
  951.       if(!stricmp(szEAName,phFEA->szName))
  952.          return(TRUE);
  953.       phFEA=phFEA->next;
  954.    }
  955.    return(FALSE);
  956. }
  957.  
  958. /****************************************************************\
  959.  *                                                              *
  960.  *  Name:    ChangeName(pFEA, szName)                           *
  961.  *                                                              *
  962.  *  Purpose: This routine copies the current EA Name to the     *
  963.  *           delete list, then allocates a new space, copies the*
  964.  *           new name into it, and sets the FEA pointer to it.  *
  965.  *  Usage :                                                     *
  966.  *  Method : Not all the memory allocations are fully error     *
  967.  *           trapped.                                           *
  968.  *                                                              *
  969.  *  Returns: VOID.  Fixes up the pFEA structure and global      *
  970.  *           pDelList.                                          *
  971.  *                                                              *
  972. \****************************************************************/
  973. VOID ChangeName(HOLDFEA *pFEA, CHAR *szName)
  974. {
  975.    CHAR *szTemp=NULL;
  976.    DELETELIST *pDL=NULL;
  977.  
  978.    GetMem((PPVOID)&szTemp, strlen(szName+1));/* Allocate space for new name */
  979.    if(!szTemp)
  980.       return;
  981.                                             /* Allocate a new delete struct */
  982.    GetMem((PPVOID)&pDL,  sizeof(DELETELIST));
  983.    pDL->EAName = pFEA->szName;                 /* Fill in DeleteList struct */
  984.    pDL->next   = pDelList;
  985.    pDelList    = pDL;
  986.  
  987.    strcpy(szTemp,szName);                  /* Copy name to permanent buffer */
  988.    pFEA->szName = szTemp;                  /* Fix up struct                 */
  989.    pFEA->cbName = (CHAR) strlen(szName);
  990.  
  991.    FILE_CHANGED = TRUE;
  992.    return;
  993. }
  994.  
  995. /****************************************************************\
  996.  *                                                              *
  997.  *  Name:    MultiTypeIndex(pMulti, usIndex)                    *
  998.  *                                                              *
  999.  *  Purpose: This routine takes a pointer to a Multi-Multi data *
  1000.  *           field and returns a pointer to the nth data field  *
  1001.  *           in this buffer.                                    *
  1002.  *  Usage:                                                      *
  1003.  *  Method:  Memory bounds are not checked and a corrupt EA field
  1004.  *           could cause unspecified results. Recursively calls *
  1005.  *           itself to handle nesting. Does not support multi-  *
  1006.  *           value single type fields.                          *
  1007.  *                                                              *
  1008.  *  Returns: a pointer to the field specified by the usIndex    *
  1009.  *           parameters.                                        *
  1010.  *                                                              *
  1011.  *  Calls: LookupEAType, MultiTypeIndex()                       *
  1012.  *                                                              *
  1013. \****************************************************************/
  1014. CHAR *MultiTypeIndex(CHAR *pMulti, ULONG usIndex)
  1015. {
  1016.    USHORT *pusPtr;
  1017.    USHORT usOffset;
  1018.                                /* skip over 0xffdf, codepage, and field cnt */
  1019.    pMulti += 3*sizeof(USHORT);
  1020.  
  1021.    while(usIndex--)                 /* loop to skip over correct # of flds  */
  1022.    {
  1023.       pusPtr   = (USHORT *) pMulti;   /* The address of EA data type stored */
  1024.       usOffset = LookupEAType(*pusPtr);         /* Get offset of field type */
  1025.  
  1026.       pMulti += sizeof(USHORT);   /* Skip over the type field to first data */
  1027.  
  1028.       switch(ConvTable[usOffset].usFldType)
  1029.       {
  1030.          case IDD_ASCIIZ:
  1031.             while(*pMulti)                 /* Increment to point after NULL */
  1032.                 pMulti++;
  1033.             pMulti++;
  1034.             break;
  1035.  
  1036.          case IDD_LPDATA:
  1037.             pusPtr = (USHORT *) pMulti;         /* Get the length of a data */
  1038.             pMulti += *pusPtr + sizeof(USHORT);              /* skip to end */
  1039.             break;
  1040.  
  1041.          case IDD_MULTILIST:
  1042.             if(*pusPtr == EA_MVMT)  /* m-m, do a recursive call to skip fld */
  1043.             {
  1044.                pusPtr = (USHORT *) pMulti;           /* points to field cnt */
  1045.                pMulti = MultiTypeIndex(pMulti-sizeof(USHORT),*pusPtr);
  1046.                break;
  1047.             }
  1048.                /* implemented for Multi-valued single-type stuff... */
  1049.             pusPtr = (USHORT *) pMulti;         /* Get the length of a data */
  1050.             pMulti += *pusPtr + sizeof(USHORT);              /* skip to end */
  1051.             break;
  1052.       }
  1053.    }
  1054.    return(pMulti);
  1055. }
  1056.  
  1057. /****************************************************************\
  1058.  *                                                              *
  1059.  *  Name:    EAValueString(aEAVal)                              *
  1060.  *                                                              *
  1061.  *  Purpose: This routine takes a pointer to an EA Value (i.e.  *
  1062.  *           starting with $ffxx) and returns a pointer to a    *
  1063.  *           string representing the value of the EA. This string
  1064.  *           must be Freed by the user when finished with it.   *                          *
  1065.  *  Usage:                                                      *
  1066.  *  Method : Not all GetMem's are totally error trapped. The    *
  1067.  *           string returned is allocated in this procedure, but*
  1068.  *           it is the caller's responsibility to free the buffer
  1069.  *                                                              *
  1070.  *  Returns: a pointer to an ASCII description of the field value
  1071.  *                                                              *
  1072. \****************************************************************/
  1073. CHAR *EAValueString(CHAR *aEAVal)
  1074. {
  1075.    USHORT *pusPtr= (USHORT *) aEAVal;              /* Points to EA Type     */
  1076.    CHAR *szRet=NULL, *szTemp;                    /* szRet points to return string */
  1077.  
  1078.    switch(*pusPtr)
  1079.    {
  1080.       case EA_ASCIIZ:     /* For asciiz strings, return MAXSHOWSIZE-1 chars */
  1081.       case EA_ASCIIZFN:
  1082.       case EA_ASCIIZEA:
  1083.       case EA_ASN1:
  1084.          aEAVal += sizeof(USHORT);
  1085.          if(strlen(aEAVal)<MAXSHOWSIZE)
  1086.          {
  1087.             GetMem((PPVOID)&szRet, strlen(aEAVal)+1);
  1088.             strcpy(szRet,aEAVal);
  1089.          }
  1090.          else
  1091.          {
  1092.             GetMem((PPVOID)&szRet, MAXSHOWSIZE);
  1093.             strncpy(szRet,aEAVal,MAXSHOWSIZE-4);
  1094.             strcpy (szRet+MAXSHOWSIZE-4,"...");
  1095.             szRet[MAXSHOWSIZE-1]='\0';
  1096.          }
  1097.          return(szRet);
  1098.  
  1099.       case EA_LPASCII:           /* Display up to first MAXSHOWSIZE-1 chars */
  1100.       case EA_LPMETAFILE:
  1101.          pusPtr++;
  1102.          aEAVal += 2*sizeof(USHORT);
  1103.          if(*pusPtr < MAXSHOWSIZE)
  1104.          {
  1105.             GetMem((PPVOID)&szRet, *pusPtr +1);
  1106.             strncpy(szRet,aEAVal,*pusPtr);
  1107.             szRet[*pusPtr]='\0';
  1108.          }
  1109.          else
  1110.          {
  1111.             GetMem((PPVOID)&szRet, MAXSHOWSIZE);
  1112.             strncpy(szRet,aEAVal,MAXSHOWSIZE-4);
  1113.             strcpy (szRet+MAXSHOWSIZE-4,"...");
  1114.             szRet[MAXSHOWSIZE-1]='\0';
  1115.          }
  1116.          return(szRet);
  1117.                  /* For the rest of the types, just display the field type */
  1118.       case EA_LPBINARY:
  1119.          szTemp = "*** LP Binary ***";
  1120.          break;
  1121.  
  1122.       case EA_LPBITMAP:
  1123.          szTemp = "*** LP Bitmap ***";
  1124.          break;
  1125.  
  1126.       case EA_LPICON:
  1127.          szTemp = "*** LP Icon ***";
  1128.          break;
  1129.  
  1130.       case EA_MVMT:
  1131.          szTemp = "*** Multi-value Multi-type ***";
  1132.          break;
  1133.  
  1134.       case EA_MVST:
  1135.          szTemp = "*** Multi-value Single-type ***";
  1136.          break;
  1137.  
  1138.       default:
  1139.          szTemp = "*** Unknown EA type ***";
  1140.          break;
  1141.  
  1142.    }
  1143.    GetMem((PPVOID)&szRet, strlen(szTemp)+1); /* Copy string from static to dynamic */
  1144.    strcpy(szRet,szTemp);
  1145.    return(szRet);
  1146. }
  1147.  
  1148. /****************************************************************\
  1149.  *                                                              *
  1150.  *  Function name: MultiAdd(hwnd, pFEA, pPDat)                  *
  1151.  *                                                              *
  1152.  *  Purpose: This routine is called by MultiTypeProc and handles*
  1153.  *           the addition of a subvalue to a multi-value, multi-*
  1154.  *           type EA.                                           *
  1155.  *  Usage :                                                     *
  1156.  *  Method : Not all GetMem's are totally error trapped.  It is *
  1157.  *           possible that the add to the listbox could fail.   *
  1158.  *                                                              *
  1159.  *  Returns: VOID.  Modifies the current pFEA.                  *
  1160.  *                                                              *
  1161. \****************************************************************/
  1162. VOID MultiAdd(HWND hwnd, HOLDFEA *pFEA, PPASSDATA pPDat)
  1163. {
  1164.    USHORT   usSize, i;
  1165.    USHORT   *pusPtr;
  1166.    CHAR     aUtility[6];        /* Used to hold the header for all EA types */
  1167.    CHAR     *pInsert,*pValue;
  1168.    PASSDATA PDat;
  1169.  
  1170.    PDat.Point = pFEA->szName;
  1171.                            /* Check Type Name is in the list of MVST or not */
  1172.    for (i=0; i<MSNUM && MSdata[i].szName!=NULL &&
  1173.                              strcmp(PDat.Point,MSdata[i].szName)!=0;)
  1174.          i++;
  1175.  
  1176.    if(ConvTable[usRetEAType].usPrefix != EA_MVST && i==MSNUM)
  1177.    {
  1178.      if(!WinDlgBox(HWND_DESKTOP,                   /* Get the name and type */
  1179.                    hwnd,
  1180.                    AddEAProc,
  1181.                    '\0',
  1182.                    IDD_ADDEA,
  1183.                    &PDat))
  1184.         return;                                         /* They said cancel */
  1185.    }
  1186.    else                    /* MVST */
  1187.    {
  1188.      if (i < MSNUM && MSdata[i].szName!=NULL && MSdata[i].usType<10)
  1189.          usRetEAType = MSdata[i].usType;             /* EAname & type exist */
  1190.      else
  1191.         if(!WinDlgBox(HWND_DESKTOP,      /* EAname is new, get the new type */
  1192.                       hwnd,
  1193.                       AddEAProc,
  1194.                       '\0',
  1195.                       IDD_ADDEA,
  1196.                       &PDat))
  1197.            return;                                      /* They said cancel */
  1198.    }
  1199.    pusPtr = (USHORT *) aUtility;
  1200.    *pusPtr= ConvTable[usRetEAType].usPrefix;  /* Set the type in header buf */
  1201.  
  1202.    switch(ConvTable[usRetEAType].usFldType)
  1203.    {
  1204.       case IDD_ASCIIZ:           /* make buffer look like: xx FF 00, size 3 */
  1205.          usSize = 3;
  1206.          aUtility[2]=0;
  1207.          break;
  1208.  
  1209.       case IDD_LPDATA:    /* make the buffer look like: xx FF 00 00, size 4 */
  1210.          usSize = 4;
  1211.          pusPtr = (USHORT *) &aUtility[2];
  1212.          *pusPtr= 0;
  1213.          break;
  1214.  
  1215.       case IDD_MULTILIST:
  1216.          usSize = 6;
  1217.          pusPtr = (USHORT *) &aUtility[2];
  1218.          *pusPtr= 0;                                   /* Zero out codepage */
  1219.          pusPtr++;
  1220.          *pusPtr= 0;                                    /* Zero out fld cnt */
  1221.          break;
  1222.    }
  1223.                                /* Increase EA size to accomodate the header */
  1224.    ResizeMem((PPVOID)&pFEA->aValue, pFEA->cbValue, pFEA->cbValue+usSize);
  1225.  
  1226.    pusPtr  = (USHORT *) ((CHAR *) pFEA->aValue + pPDat->usMultiOffset);
  1227.    pusPtr+=2;                  /* Point to the current number of m-m fields */
  1228.  
  1229.         /* Get ptr to beginning of current EA, scoot the rest down and insert
  1230.          the 3-4 byte header at the end of the list.                        */
  1231.    pInsert = MultiTypeIndex(pFEA->aValue+pPDat->usMultiOffset, *pusPtr);
  1232.    memmove(pInsert+usSize,pInsert, pFEA->cbValue-(pInsert-pFEA->aValue));
  1233.    memcpy(pInsert,aUtility,usSize);
  1234.  
  1235.    pFEA->cbValue += usSize;                            /* Fix up the counts */
  1236.    pPDat->cbMulti+= usSize;
  1237.                                                    /* Set the PDat for call */
  1238.    PDat.Point         = (CHAR *) pFEA;
  1239.    PDat.cbMulti       = pPDat->cbMulti;
  1240.    PDat.usMultiOffset = pPDat->usMultiOffset;
  1241.    PDat.usIndex       = *pusPtr;
  1242.  
  1243.    if(!EditEAValue(hwnd,&PDat))                   /* They canceled the edit */
  1244.    {          /* Move the EA's back to effectively kill the inserted header */
  1245.       memmove(pInsert,pInsert+usSize,pFEA->cbValue-(pInsert-pFEA->aValue));
  1246.       DosSetMem(pFEA->aValue, pFEA->cbValue-usSize, fPERM|PAG_COMMIT);
  1247.       pFEA->cbValue -= usSize;                           /* Adjust counters */
  1248.       pPDat->cbMulti-= usSize;
  1249.  
  1250.       return;
  1251.    }
  1252.         /* Reset pusPtr since EditEAValue could have moved the base address */
  1253.    pusPtr  = (USHORT *) ((CHAR *) pFEA->aValue + pPDat->usMultiOffset);
  1254.    pusPtr+=2;
  1255.  
  1256.    pInsert = MultiTypeIndex(pFEA->aValue+pPDat->usMultiOffset, *pusPtr);
  1257.  
  1258.    *pusPtr += 1;                /* Field cnt incremented AFTER call to Edit */
  1259.  
  1260.    pValue = EAValueString(pInsert);        /* Add new field to the list box */
  1261.  
  1262.    WinSendDlgItemMsg(hwnd, IDD_LBOX, LM_INSERTITEM,
  1263.                      MPFROM2SHORT(LIT_END,0),
  1264.                      MPFROMP(pValue));
  1265.    FreeMem(pValue);
  1266.  
  1267.    FILE_CHANGED = TRUE;
  1268.    return;
  1269. }
  1270.