home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 February / CHIP_2_98.iso / software / pelne / optionp / iis4_07.cab / KEYS.CPP < prev    next >
C/C++ Source or Header  |  1997-10-25  |  37KB  |  1,533 lines

  1. /*++
  2.  
  3. Copyright (c) 1997  Microsoft Corporation
  4.  
  5. Module Name:    keys.cpp
  6.  
  7. Abstract:
  8.  
  9.    This module contains functions which deal with keys and values 
  10.    on inbound form data. Please, see keys.h for details.
  11.  
  12. --*/
  13. #define WIN32_LEAN_AND_MEAN     // the bare essential Win32 API
  14. #include <windows.h>                                                                    
  15. #include <httpext.h>
  16.  
  17. //
  18. // If your application plans to receive huge amounts of data
  19. // and you don't want megabytes of memory allocated, define
  20. // the USE_TEMPORARY_FILES.  It is recommended to leave the
  21. // define line below commented out unless absolutely necessary.
  22. // 
  23.  
  24. //#define USE_TEMPORARY_FILES
  25.  
  26. #include "keys.h"
  27.  
  28. #ifndef USE_MEMORY
  29.  
  30. #ifndef USE_TEMPORARY_FILES
  31. #define USE_MEMORY
  32. #endif
  33.  
  34. #endif
  35.  
  36.  
  37. //
  38. // If you want to record errors, modify this macro definition to
  39. // call your own logging function.  This sample does not save
  40. // error strings.
  41. // 
  42. #define LOG(errorstring)        // OutputDebugString( errorstring ); \
  43.                                 // OutputDebugString ( "\r\n" )
  44.  
  45. //
  46. // 
  47. // Intended external interface:
  48. // 
  49. // GetKeyList       Determines if data was sent, and if it was, the
  50. // data is extracted by GetPostKeys or GetUrlKeys,
  51. // two private functions within this file.  A 
  52. // pointer to a linked list is returned ( as a 
  53. // handle ).
  54. // 
  55. // GetKeyInfo       Returns a pointer to the key name,
  56. // the length of the data, a flag indicating if
  57. // the data has control characters in it, and an
  58. // instance number for duplicate key names.
  59. // 
  60. // GetKeyBuffer Returns a pointer to the buffer holding the key's
  61. // data.
  62. // 
  63. // FindKey          Sequentially searches linked list for key name.
  64. // 
  65. // FreeKeyList      Deallocates memory used by the linked list of
  66. // keys.  Also deletes content resources.
  67. // 
  68. // GetKeyOffset Returns the offset to either the content memory
  69. // buffer or the content temporary file.
  70. // 
  71. // GetContentFile   Returns a pointer to the temporary file, only
  72. // when USE_TEMPORARY_FILES is defined.
  73. // 
  74. // CloseContentFile Closes the content file, normally left open
  75. // until FreeKeyList is called, available only
  76. // when USE_TEMPORARY_FILES is defined.
  77. // 
  78. // OpenContentFile Reopens the content file for additional use
  79. // by GetKeyBuffer, available only when 
  80. // USE_TEMPORARY_FILES is defined.
  81. // 
  82. // GetDataBuffer    Returns a pointer to the content, only if the
  83. // USE_TEMPORARY_FILES constant is NOT defined.
  84. // 
  85. // Helper functions called only in this source file:
  86. // 
  87. // GetQueryByte Similar to GetPostedByte, this function
  88. // extracts data from the query string.
  89. // 
  90. // HexDigitToInt    Returns the decimal value of a hex character.
  91. // 
  92. // GetFirstByte Sets up POSDATA struct and calls GetNextByte.
  93. // Caller specifies function used to retrieve
  94. // data, either GetPostedByte or GetQueryByte.
  95. // 
  96. // GetNextByte      Uses GetInboundByte ( specified in GetFirstByte )
  97. // to retrieve inbound data, and decodes it using
  98. // the URL encoding rules.
  99. // 
  100. // BKL_Alloc        Allocates memory used in GetPostKeys.
  101. // 
  102. // BKL_Dealloc      Deallocates memory used in GetPostKeys.
  103. // 
  104. // BKL_Abort        Cleans up all resources for abnormal exits from
  105. // GetPostKeys.
  106. // 
  107. // IsKeySeparator   Returns TRUE if character is one of "=\r\n&\0".
  108. // 
  109. // BuildKeyList Given a data extraction function ( i.e.
  110. // GetPostedByte or GetQueryByte ), this function
  111. // converts all keys into a linked list of POSTKEY
  112. // structures.
  113. // 
  114. // GetPostKeys      Takes inbound data off the wire by calling
  115. // BuildKeyList with GetPostedByte as the extraction
  116. // function.
  117. // 
  118. // GetUrlKeys       Extracts data from the query string by calling
  119. // BuildKeyList with GetQueryByte as the extraction
  120. // function.
  121. // 
  122. // GetPropAddr      Calculates the address of the list's properties,
  123. // appended to the first key in a list.
  124. // 
  125. // The typedef for the linked list is kept privately in this file,
  126. // and our interface isolates other source files from the 
  127. // implementation details.
  128. // 
  129.  
  130. //
  131. // Constants for this source file only
  132. // 
  133.  
  134. #define MAX_KEY_NAME_LENGTH 256 // maximum size of an inbound key name
  135. #define CONTENT_BUF_LENGTH 8192 // amount of content buffered before
  136.                                 // WriteFile call
  137.                                     // ( used for temporary files only )
  138.  
  139. #define GNB_NOTHING_LEFT 0      // GetNextByte return values
  140. #define GNB_DECODED_CHAR 1
  141. #define GNB_NORMAL_CHAR 2
  142.  
  143.  
  144. //
  145. // POSDATA struct is used with GetInboundByte to keep
  146. // track of the position within incoming data.
  147. // GETINBOUNDBYTE is a function pointer type.
  148. // 
  149.  
  150. typedef struct _tagPOSDATA {
  151.     EXTENSION_CONTROL_BLOCK *pECB;
  152.     int nCurrentPos;            // overall position
  153.  
  154.     int nBufferLength;          // length of buffer
  155.  
  156.     int nBufferPos;             // position within buffer
  157.  
  158.     int nAllocLength;           // size of buffer as allocated
  159.  
  160.     LPBYTE pData;
  161.     int (*GetInboundByte)(struct _tagPOSDATA * p);
  162. } POSDATA, *PPOSDATA;
  163.  
  164. typedef int (*GETINBOUNDBYTE)(PPOSDATA p);
  165.  
  166.  
  167. #ifdef USE_MEMORY
  168.  
  169. //
  170. // LISTPROP struct is used to maintain a set of
  171. // list-wide properties.  This implementation
  172. // uses the properties list to hold a buffer
  173. // pointer.
  174. // 
  175.  
  176. typedef struct _tagLISTPROP {
  177.     LPBYTE lpbyBuf;
  178. } LISTPROP, *PLISTPROP;
  179.  
  180. #elif defined USE_TEMPORARY_FILES
  181.  
  182. //
  183. // This LISTPROP struct holds temporary
  184. // file information.
  185. // 
  186.  
  187. typedef struct _tagLISTPROP {
  188.     char szTempFileName[MAX_PATH];
  189.     HANDLE hFile;
  190. } LISTPROP, *PLISTPROP;
  191.  
  192. #endif
  193.  
  194.  
  195. // This private helper needs a prototype
  196. PLISTPROP GetPropAddr( HKEYLIST hKey );
  197.  
  198.  
  199. int 
  200. GetPostedByte( 
  201.     PPOSDATA pPosData 
  202. )
  203. /*++
  204.  
  205. Purpose:
  206.  
  207.     GetPostedByte returns a waiting character that is not
  208.     decoded yet.  We have this function to smooth out the
  209.     inbound data: the server gives us blocks of data, one at
  210.     a time, and there can be any number of blocks.
  211.      
  212.     For the first call, pPosData->nAllocLength must be zero,
  213.     and pECB must be set.
  214.  
  215. Arguments:
  216.  
  217.     pPostData - pointer to POSTDATA struct
  218.  
  219. Returns:
  220.  
  221.     incoming byte value or
  222.     -1 to indicate an error
  223.  
  224. --*/
  225. {
  226.     int nBytesToCopy;
  227.  
  228.     // For readability only...
  229.     EXTENSION_CONTROL_BLOCK *pECB;
  230.  
  231.     pECB = pPosData->pECB;
  232.  
  233.     // 
  234.     // Initialize position struct on first call.
  235.     // 
  236.  
  237.     if ( !pPosData->nAllocLength ) {
  238.         // Initialize the members
  239.         pPosData->nCurrentPos = 0;
  240.         pPosData->nBufferPos = 0;
  241.         pPosData->nBufferLength = 0;
  242.         pPosData->nAllocLength = 0x10000;   // 65536 bytes
  243.  
  244.         // Allocate the memory
  245.         pPosData->pData = (LPBYTE) HeapAlloc( 
  246.             GetProcessHeap( ),
  247.             HEAP_ZERO_MEMORY,
  248.             pPosData->nAllocLength );
  249.     }
  250.     // 
  251.     // Was memory allocated?  Is it still allocated?
  252.     // If not, return right away.
  253.     // 
  254.  
  255.     if ( !pPosData->pData ) {
  256.         LOG( "GetPostedByte: Buffer not allocated." );
  257.         return -1;
  258.     }
  259.     // 
  260.     // Check for end.  Deallocate and return if we're done.
  261.     // 
  262.  
  263.     if ( (DWORD) pPosData->nCurrentPos == pECB->cbTotalBytes ) {
  264.  
  265.         HeapFree( GetProcessHeap( ), 0, (LPVOID) pPosData->pData );
  266.         pPosData->pData = 0;
  267.  
  268.         return -1;
  269.     }
  270.  
  271.     // 
  272.     // Check for buffer not loaded.  Load if necessary.
  273.     // 
  274.  
  275.     if ( pPosData->nBufferPos == pPosData->nBufferLength ) {
  276.  
  277.         // 
  278.         // Fill the buffer with new inbound data.
  279.         // Request it via ReadClient if necessary.
  280.         // 
  281.  
  282.         if ( pECB->cbAvailable < 1 ) {
  283.  
  284.             // Calculate how much we should go and get
  285.             nBytesToCopy = pECB->cbTotalBytes - pPosData->nCurrentPos;
  286.             if ( nBytesToCopy > pPosData->nAllocLength ) {
  287.                 nBytesToCopy = pPosData->nAllocLength;
  288.             }
  289.  
  290.             // Let's go get the data
  291.             if ( !pECB->ReadClient( 
  292.                     pECB->ConnID, 
  293.                     pPosData->pData, 
  294.                     (LPDWORD) & nBytesToCopy 
  295.                     )) {
  296.                 HeapFree( GetProcessHeap( ), 0, (LPVOID) pPosData->pData );
  297.                 pPosData->pData = 0;
  298.  
  299.                 LOG( "GetPostedByte: Error reading data via ReadClient" );
  300.                 return -1;
  301.             }
  302.         }else{
  303.             // Take at most nAllocLength bytes of data
  304.             if ( pECB->cbAvailable > (DWORD) (pPosData->nAllocLength) ) {
  305.                 nBytesToCopy = pPosData->nAllocLength;
  306.             }else{
  307.                 nBytesToCopy = pECB->cbAvailable;
  308.             }
  309.  
  310.             // Copy the inbound data to our buffer
  311.             memcpy( 
  312.                 pPosData->pData,
  313.                 &pECB->lpbData[pPosData->nCurrentPos],
  314.                 nBytesToCopy 
  315.                 );
  316.  
  317.             // Account for removed data
  318.             pECB->cbAvailable -= nBytesToCopy;
  319.         }
  320.  
  321.         // Our buffer is now full
  322.         pPosData->nBufferLength = nBytesToCopy;
  323.         pPosData->nBufferPos = 0;
  324.  
  325.         // Make sure we have something
  326.         if ( !nBytesToCopy ) {
  327.             HeapFree( GetProcessHeap( ), 0, (LPVOID) pPosData->pData );
  328.             pPosData->pData = 0;
  329.             return -1;
  330.         }
  331.     }
  332.     // 
  333.     // Inc current pos, buffer pos, and return a character
  334.     // 
  335.  
  336.     pPosData->nCurrentPos++;
  337.     pPosData->nBufferPos++;
  338.     return ( (int)pPosData->pData[pPosData->nBufferPos - 1] );
  339. }
  340.  
  341.  
  342.  
  343. int 
  344. GetQueryByte( 
  345.     IN OUT PPOSDATA pPosData 
  346. )
  347. /*++
  348.  
  349. Purpose:
  350.  
  351.     Returns a waiting character that is not
  352.     decoded yet.  We have this function to match GetPostedData.
  353.  
  354.     For the first call, pPosData->nAllocLength must be zero,
  355.     and pECB must be set.
  356.  
  357.  
  358. Arguments:
  359.  
  360.     pPostData - points to POSDATA structura
  361.  
  362. Returns:
  363.  
  364.     byte value or -1 to indicate an error
  365.  
  366. --*/
  367. {
  368.     // For readability only...
  369.     EXTENSION_CONTROL_BLOCK *pECB;
  370.  
  371.     pECB = pPosData->pECB;
  372.  
  373.     // 
  374.     // Initialize position struct on first call.
  375.     // 
  376.  
  377.     if ( !pPosData->nAllocLength ) {
  378.         // Initialize the useful members
  379.         pPosData->nBufferPos = 0;
  380.         pPosData->nBufferLength = lstrlen( (LPCSTR) pECB->lpszQueryString );
  381.         pPosData->nAllocLength = -1;
  382.  
  383.         char szMsg[256];
  384.  
  385.         wsprintf( 
  386.             szMsg, 
  387.             "pPosData->nBufferLength=%i", 
  388.             pPosData->nBufferLength 
  389.             );
  390.         LOG( szMsg );
  391.     }
  392.  
  393.     // 
  394.     // Check for end.  Deallocate and return if we're done.
  395.     // 
  396.  
  397.     if ( pPosData->nBufferPos == pPosData->nBufferLength ) {
  398.         return -1;
  399.     }
  400.  
  401.     // 
  402.     // Inc buffer pos and return a character
  403.     // 
  404.  
  405.     pPosData->nBufferPos++;
  406.     return ( (int)pECB->lpszQueryString[pPosData->nBufferPos - 1] );
  407. }
  408.  
  409.  
  410. //
  411. // Now that we have GetPostedByte, and GetQueryByte, we can 
  412. // build a more useful function that decodes URL-style 
  413. // encoded characters.
  414. // 
  415. // Recall that there are two special cases for this encoding:
  416. // 
  417. // 1. Each plus sign must be converted to a space
  418. // 2. A percent sign denotes a hex value-encoded character
  419. // 
  420. // Percents are used to specify characters that are otherwise
  421. // illegal.  This includes percents themselves, ampersands,
  422. // control characters, and so on.
  423. // 
  424. // GetNextByte returns the decoded byte, plus a flag indicating
  425. // normal character, decoded character, or failure.  See top of  
  426. // file for return value constants.
  427. // 
  428.  
  429.  
  430. int 
  431. HexDigitToInt( 
  432.     IN char c 
  433. )
  434. /*++
  435.  
  436. Purpose:
  437.     HexDigitToInt simply converts a hex-based character to an int.
  438.  
  439. Arguments:
  440.     tc - character to convert
  441.  
  442. Returns:
  443.     binary value of the character (0-15)
  444.     -1 if the character is not hex digit
  445.  
  446. --*/
  447. {
  448.     if ( c >= '0' && c <= '9' ) {
  449.         return ( c - '0' );
  450.     }
  451.  
  452.     if ( tolower( c ) >= 'a' && tolower( c ) <= 'f' ) {
  453.         return ( tolower( c ) - 'a'  + 10 );
  454.     }
  455.  
  456.     return -1;
  457. }
  458.  
  459.  
  460. int 
  461. GetNextByte( 
  462.     IN OUT PPOSDATA pPosData, 
  463.     OUT char * pc 
  464. )
  465. /*++
  466.  
  467. Purpose:
  468.     Decode single byte of the input data
  469.  
  470. Arguments:
  471.     pPostData - points to POSDATA struct
  472.     pc - points to variable to accept decoded byte
  473.  
  474. Returns:
  475.     GNB_NORMAL_CHAR, GNB_NOTHING_LEFT or GNB_DECODED_CHAR
  476.  
  477. --*/
  478. {
  479.     int nChar;
  480.     int nDigit;
  481.  
  482.     // Initialize character pointer
  483.     *pc = 0;
  484.  
  485.     // Fetch the next inbound character
  486.     nChar = pPosData->GetInboundByte( pPosData );
  487.     if ( nChar == -1 ) {
  488.         return GNB_NOTHING_LEFT;
  489.     }
  490.  
  491.     // Plus signs: convert to spaces
  492.     if ( nChar == '+' ) {
  493.         *pc = ' ';
  494.         return GNB_DECODED_CHAR;
  495.     }
  496.     // Percent signs: convert hex values
  497.     else if ( nChar == '%' ) {
  498.         nChar = pPosData->GetInboundByte( pPosData );
  499.         nDigit = HexDigitToInt( nChar );
  500.         if ( nDigit == -1 ) {
  501.             return GNB_NOTHING_LEFT;
  502.         }
  503.  
  504.         *pc = ( char ) ( ( UINT ) nDigit << 4 );
  505.  
  506.         nChar = pPosData->GetInboundByte( pPosData );
  507.         nDigit = HexDigitToInt( nChar );
  508.         if ( nDigit == -1 ) { 
  509.             *pc = 0;            // incomplete
  510.  
  511.             return GNB_NOTHING_LEFT;
  512.         }
  513.         *pc |= ( char ) ( UINT ) nDigit;
  514.  
  515.         return GNB_DECODED_CHAR;
  516.     }
  517.     // Must be normal character then
  518.     *pc = (char) nChar;
  519.  
  520.     return GNB_NORMAL_CHAR;
  521. }
  522.  
  523.  
  524. int 
  525. GetFirstByte( 
  526.     IN OUT PPOSDATA pPosData,
  527.     IN EXTENSION_CONTROL_BLOCK * pECB,
  528.     OUT char * pc, 
  529.     IN GETINBOUNDBYTE GetInboundByte 
  530. )
  531. /*++
  532.  
  533. Purpose:
  534.  
  535.     GetFirstByte eliminates the guesswork from initialization.
  536.     We call GetFirstByte with an uninitialized POSDATA structure,
  537.     and we call GetNextByte from there on.
  538.  
  539. Arguments:
  540.     pPosData - points to POSDATA struct to initialize
  541.     pECB - points to the extenstion control block 
  542.     pc - points to variable to accept decoded byte
  543.     GetInboundByte - points to function to get incoming bytes
  544.  
  545.  
  546. Returns:
  547.     same as GetNextByte()
  548.  
  549. --*/
  550. {
  551.     // Initialize struct
  552.     pPosData->nAllocLength = 0;
  553.     pPosData->pECB = pECB;
  554.     pPosData->GetInboundByte = GetInboundByte;
  555.  
  556.     // Make the call as usual
  557.     return GetNextByte( pPosData, pc );
  558. }
  559.  
  560.  
  561. //
  562. // Structure used in data processing - the elements of the
  563. // key list.
  564. // 
  565.  
  566. typedef struct _tagPOSTKEY {
  567.     int nInstance;              // used when key name is the same as another, 
  568.                                 // normally 0
  569.  
  570.     DWORD dwOffset;             // offset into content file
  571.     DWORD dwLength;             // length of data
  572.     BOOL bHasCtrlChars;         // a character value < 32 is in data
  573.     struct _tagPOSTKEY *pNext;  // linked list
  574.     struct _tagPOSTKEY *pHead;  // first in linked list
  575.     LPBYTE lpbyBuf;             // pointer to the key's data in the list
  576.                                 // buffer
  577.  
  578.     // key string appended to structure
  579.     // for the head key, list properties are appended
  580. } POSTKEY, *PPOSTKEY;
  581.  
  582.  
  583.  
  584. //
  585. // These three helper functions isolate the memory allocation, 
  586. // deallocation and abnormal exit code.  They are used only to 
  587. // keep BuildKeyList readable.
  588. // 
  589.  
  590.  
  591. BOOL 
  592. BKL_Alloc( 
  593.     OUT LPSTR * plpszKey, 
  594.     OUT LPBYTE * plpbyBuf 
  595. )
  596. {
  597.     // Allocate a buffer for the key name
  598.     *plpszKey = (LPSTR) HeapAlloc( GetProcessHeap( ),
  599.         HEAP_ZERO_MEMORY,
  600.         MAX_KEY_NAME_LENGTH );
  601.  
  602.     if ( !*plpszKey ) {
  603.         return FALSE;
  604.     }
  605.  
  606. #ifdef USE_MEMORY
  607.     // Init buffer to NULL
  608.     *plpbyBuf = NULL;
  609.  
  610. #elif defined USE_TEMPORARY_FILES
  611.  
  612.     // Allocate a buffer for the content
  613.     *plpbyBuf = (LPBYTE) HeapAlloc( GetProcessHeap( ),
  614.         HEAP_ZERO_MEMORY,
  615.         CONTENT_BUF_LENGTH );
  616.  
  617.     if ( !*plpbyBuf ) {
  618.         HeapFree( GetProcessHeap( ), 0, (LPVOID) * plpszKey );
  619.         return FALSE;
  620.     }
  621. #endif
  622.  
  623.     return TRUE;
  624. }
  625.  
  626.  
  627. void 
  628. BKL_Dealloc( 
  629.     IN LPSTR * plpsz, 
  630.     IN LPBYTE * plpby 
  631. )
  632. {
  633.     if ( plpsz && *plpsz ) {
  634.         HeapFree( GetProcessHeap( ), 0, (LPVOID) * plpsz );
  635.     }
  636.     if ( plpby && *plpby ) {
  637.         HeapFree( GetProcessHeap( ), 0, (LPVOID) * plpby );
  638.     }
  639. }
  640.  
  641. //
  642. // This allows us to clean up... with temporary files we have to close
  643. // and delete them.  Otherwise, we have to free a lot of memory.
  644. // 
  645.  
  646. #ifdef USE_TEMPORARY_FILES
  647. #define MACRO_AbortCleanup BKL_Abort( pHead, hDataFile, \
  648.     lpszKeyNameBuf, lpbyContentBuf );\
  649.     if ( hDataFile != INVALID_HANDLE_VALUE ) DeleteFile( szTempPath )
  650.  
  651. #elif defined USE_MEMORY
  652.  
  653. #define MACRO_AbortCleanup BKL_Abort( pHead, INVALID_HANDLE_VALUE, \
  654.     lpszKeyNameBuf,lpbyContentBuf ) 
  655. #endif
  656.  
  657.  
  658. void 
  659. BKL_Abort( 
  660.     IN PPOSTKEY pHead, 
  661.     IN HANDLE hFile, 
  662.     IN LPSTR lpszKey, 
  663.     IN LPBYTE lpbyBuf 
  664. )
  665. {
  666.     if ( pHead ) {
  667.         FreeKeyList( (HKEYLIST) pHead );
  668.     }
  669.  
  670.     if ( hFile != INVALID_HANDLE_VALUE ) {
  671.         CloseHandle( hFile );
  672.     }
  673.  
  674.     BKL_Dealloc( &lpszKey, &lpbyBuf );
  675. }
  676.  
  677.  
  678. BOOL 
  679. IsKeySeparator( 
  680.     char c 
  681. )
  682. /*++
  683.  
  684. Purpose:
  685.     Identify key separators
  686.  
  687. Arguments:
  688.     c - character
  689.  
  690. Returns:
  691.     TRUE if character is a key separator,
  692.     FALSE otherwise
  693.  
  694. --*/
  695. {
  696.     return ( c == '=' || c == '\r' || c == '\n' || c == '&' || !c );
  697. }
  698.  
  699.  
  700. PPOSTKEY 
  701. BuildKeyList( 
  702.     IN EXTENSION_CONTROL_BLOCK * pECB,
  703.     IN GETINBOUNDBYTE GetInboundByte 
  704. )
  705. /*++
  706.  
  707. Purpose:
  708.  
  709.     Now that we have a way to get a decoded byte from the stream,
  710.     we can parse POST data.  POST data comes in as:
  711.  
  712.     key=data&key=data&key=data\r\n
  713.  
  714.     A linked list of keys is established, and the head node
  715.     of the list is returned.  A NULL indicates no keys or
  716.     an error.
  717.  
  718.  
  719. Arguments:
  720.     pECB - pointer to the extension control block
  721.     GetInboundByte - pointer to function to get input data
  722.  
  723. Returns:
  724.     Pointer to the head node or NULL
  725.  
  726. --*/
  727. {
  728.     PPOSTKEY pHead = NULL;      // head of linked list ( the return val )
  729.     PPOSTKEY pTail = NULL;      // last member in linked list
  730.     PPOSTKEY pNewPostKey;       // pointer for unlinked, newly allocated
  731.                                 // objects
  732.  
  733.     PPOSTKEY pListWalk;         // linked list walking pointer
  734.     PLISTPROP pProp;            // pointer to list properties
  735.     LPSTR lpszKeyNameBuf;       // pointer to buffer, used in obtaining key
  736.                                 // name
  737.  
  738.     int nPos;                   // position within key name buffer
  739.     DWORD dwOffset;             // offset from start of content buffer or
  740.                                 // file
  741.  
  742.     DWORD dwLength;             // length of key data
  743.     char c;                     // general-purpose character
  744.     int nReturn;                // general-purpose return code
  745.     POSDATA pd;                 // POSDATA struct needed in GetInboundByte
  746.     int nContentPos;            // position within content buffer
  747.     LPBYTE lpbyContentBuf;      // pointer to buffer
  748.     BOOL bHasCtrlChars;         // flag to detect ctrl chars
  749.  
  750.     // Call helper to allocate a buffer
  751.     if ( !BKL_Alloc( &lpszKeyNameBuf, &lpbyContentBuf ) ) {
  752.         LOG( "BuildKeyList: Memory allocation failure" );
  753.         return NULL;
  754.     }
  755.     nContentPos = dwOffset = 0;
  756.  
  757.  
  758. #ifdef USE_MEMORY
  759.     // 
  760.     // Allocate enough memory for all the content.
  761.     // For the POST method, the cbTotalBytes gives us the number
  762.     // of bytes that are being sent by the browser.  We can 
  763.     // allocate that much but we'll really only use about 75% of it.
  764.     // For the GET method, we need to allocate the size of the
  765.     // query string plus 1.
  766.     // 
  767.  
  768.     lpbyContentBuf = (LPBYTE) HeapAlloc( GetProcessHeap( ),
  769.         HEAP_ZERO_MEMORY,
  770.         pECB->cbTotalBytes +
  771.         lstrlen( pECB->lpszQueryString ) + 1 );
  772.  
  773.     if ( !lpbyContentBuf ) {
  774.  
  775.         LOG( "BuildKeyList: Error allocating content memory" );
  776.         BKL_Dealloc( &lpszKeyNameBuf, &lpbyContentBuf );
  777.  
  778.         return NULL;
  779.     }
  780. #elif defined USE_TEMPORARY_FILES
  781.  
  782.     // 
  783.     // When USE_TEMPORARY_FILES is chosen, we create
  784.     // a temporary file to store all the inbound data.
  785.     // This is done to support huge amounts of inbound
  786.     // data, like file uploads.
  787.     // 
  788.  
  789.     char szTempDir[MAX_PATH];   // directory of temporary files
  790.     char szTempPath[MAX_PATH];  // path of content file
  791.     HANDLE hDataFile;           // handle to content file
  792.     DWORD dwBytesWritten;       // used with WriteFile
  793.  
  794.     // Get a temp file name
  795.     GetTempPath( MAX_PATH, szTempDir );
  796.     if ( !GetTempFileName( szTempDir, "key", 0, szTempPath ) ) {
  797.  
  798.         LOG( "BuildKeyList: Error creating temporary file" );
  799.         BKL_Dealloc( &lpszKeyNameBuf, &lpbyContentBuf );
  800.  
  801.         return NULL;
  802.     }
  803.     // Create the content file
  804.     hDataFile = CreateFile( szTempPath,
  805.         GENERIC_READ | GENERIC_WRITE,
  806.         0,                      // No sharing mode
  807.         NULL,                   // Default security attribs
  808.         CREATE_ALWAYS,
  809.         FILE_ATTRIBUTE_NORMAL,
  810.         NULL                    // No template file
  811.         );
  812.  
  813.     // Return if an error occured
  814.     if ( hDataFile == INVALID_HANDLE_VALUE ) {
  815.         LOG( "BuildKeyList: Error opening temporary file" );
  816.         MACRO_AbortCleanup;
  817.         return NULL;
  818.     }
  819. #endif
  820.  
  821.  
  822.     // 
  823.     // 'for' statement detects the start of a valid key name.
  824.     // 
  825.     // To do inside 'for' loop:
  826.     // Obtain key name
  827.     // Write data to buffer or content file
  828.     // Create POSTKEY object
  829.     // Update links
  830.     // 
  831.  
  832.     for ( nReturn = GetFirstByte( &pd, pECB, &c, GetInboundByte );
  833.         nReturn != GNB_NOTHING_LEFT;
  834.         nReturn = GetNextByte( &pd, &c ) ) {
  835.             
  836.         // If \r or \n, ignore and continue
  837.         if ( c == '\r' || c == '\n' ) {
  838.             continue;
  839.         }
  840.  
  841.         // Get a key name
  842.         nPos = 0;
  843.         while ( !IsKeySeparator( c ) ) {
  844.             if ( nPos < MAX_KEY_NAME_LENGTH ) {
  845.                 lpszKeyNameBuf[nPos] = c;
  846.                 nPos++;
  847.             }
  848.             nReturn = GetNextByte( &pd, &c );
  849.             if ( nReturn == GNB_NOTHING_LEFT )  { // abrupt end!
  850.                 break;
  851.             }
  852.         }
  853.  
  854.         // If no equals sign or name too long,
  855.         // we have a browser formatting error
  856.         if ( c != '=' || nPos == MAX_KEY_NAME_LENGTH ) {
  857.             LOG( "BuildKeyList: Browser formatting error" );
  858.  
  859.             MACRO_AbortCleanup;
  860.             return NULL;
  861.         }
  862.  
  863.         // Truncate the name string, reset data info variables
  864.         lpszKeyNameBuf[nPos] = 0;
  865.         nPos++;
  866.         dwLength = 0;
  867.         bHasCtrlChars = FALSE;
  868.  
  869.         // 
  870.         // Move the data to the content buffer or file.
  871.         // 
  872.         for ( nReturn = GetNextByte( &pd, &c );
  873.             !IsKeySeparator( c ) || nReturn == GNB_DECODED_CHAR;
  874.             nReturn = GetNextByte( &pd, &c ) ) {
  875.  
  876.             lpbyContentBuf[nContentPos] = c;
  877.  
  878.             nContentPos += sizeof ( char );
  879.             dwLength++;
  880.  
  881.             // Check for ctrl chars
  882.             if ( c < 0x20 ) {
  883.                 bHasCtrlChars = TRUE;
  884.             }
  885.  
  886. #ifdef USE_TEMPORARY_FILES
  887.             // If we have enough data, write buffer to disk
  888.             if ( nContentPos == CONTENT_BUF_LENGTH ) {
  889.                 if ( !WriteFile( hDataFile, lpbyContentBuf,
  890.                     nContentPos, &dwBytesWritten, NULL ) ) {
  891.  
  892.                     LOG( "BuildKeyList: Error writing to content file" );
  893.                     MACRO_AbortCleanup;
  894.                     return NULL;
  895.                 }
  896.                 nContentPos = 0;
  897.             }
  898. #endif
  899.  
  900.         } // for( nReturn
  901.  
  902.  
  903. #ifdef USE_MEMORY
  904.         // 
  905.         // Put a terminating NULL at the end of the key data.
  906.         // 
  907.  
  908.         lpbyContentBuf[nContentPos] = 0;
  909.         nContentPos++;
  910.  
  911. #elif defined USE_TEMPORARY_FILES
  912.  
  913.         // Drain buffer
  914.         if ( nContentPos ) {
  915.             if ( !WriteFile( hDataFile, lpbyContentBuf,
  916.                 nContentPos, &dwBytesWritten, NULL ) ) {
  917.  
  918.                 LOG( "BuildKeyList: Error writing to content file" );
  919.                 MACRO_AbortCleanup;
  920.                 return NULL;
  921.             }
  922.             nContentPos = 0;
  923.         }
  924. #endif
  925.  
  926.  
  927.         // Allocate a POSTKEY object, allocate extra for first key
  928.         if ( pHead ) {
  929.             pNewPostKey = (PPOSTKEY) HeapAlloc( 
  930.                 GetProcessHeap( ),
  931.                 HEAP_ZERO_MEMORY,
  932.                 sizeof (POSTKEY) + nPos 
  933.                 );
  934.         }else{
  935.             pNewPostKey = (PPOSTKEY) HeapAlloc( 
  936.                 GetProcessHeap( ),
  937.                 HEAP_ZERO_MEMORY,
  938.                 sizeof (POSTKEY) + nPos +
  939.                 sizeof (LISTPROP) );
  940.  
  941.             pProp = (PLISTPROP) ( (LPBYTE)pNewPostKey + 
  942.                     sizeof (POSTKEY) + nPos );
  943.         }
  944.  
  945.         // Check for valid pointer
  946.         if ( !pNewPostKey ) {
  947.             LOG( "BuildKeyList: POSTKEY memory allocation failure" );
  948.             MACRO_AbortCleanup;
  949.             return NULL;
  950.         }
  951.  
  952.         // 
  953.         // Set pNewPostKey members
  954.         // 
  955.  
  956.         // Set nInstance
  957.         pNewPostKey->nInstance = 0;
  958.         pListWalk = pHead;
  959.         while ( pListWalk ) {
  960.             // Check for duplicate key names
  961.             if ( !lstrcmpi( (LPCSTR) ( &pListWalk[1] ), lpszKeyNameBuf )) {
  962.                 pNewPostKey->nInstance++;
  963.             }
  964.             pListWalk = pListWalk->pNext;
  965.         }
  966.  
  967.         // Set dwOffset, dwLength, bHasCtrlChars, lpbyBuf
  968.         pNewPostKey->dwOffset = dwOffset;
  969.         pNewPostKey->dwLength = dwLength;
  970.         pNewPostKey->bHasCtrlChars = bHasCtrlChars;
  971.  
  972. #ifdef USE_MEMORY
  973.         pNewPostKey->lpbyBuf = &lpbyContentBuf[dwOffset];
  974.         dwOffset += dwLength + 1;
  975.  
  976. #elif defined USE_TEMPORARY_FILES
  977.  
  978.         pNewPostKey->lpbyBuf = NULL;
  979.         dwOffset += dwLength;
  980. #endif
  981.  
  982.  
  983.         // Copy key name
  984.         lstrcpy( (LPSTR) ( &pNewPostKey[1] ), lpszKeyNameBuf );
  985.  
  986.         // Link
  987.         if ( pTail ) {
  988.             pTail->pNext = pNewPostKey;
  989.         }else{
  990.  
  991. #ifdef USE_TEMPORARY_FILES
  992.             // Copy content file name to list properties
  993.             lstrcpy( pProp->szTempFileName, szTempPath );
  994.  
  995.             // Set handle
  996.             pProp->hFile = hDataFile;
  997.  
  998. #elif defined USE_MEMORY
  999.  
  1000.             // Set content buffer pointer
  1001.             pProp->lpbyBuf = lpbyContentBuf;
  1002. #endif
  1003.  
  1004.             // Set head
  1005.             pHead = pNewPostKey;
  1006.         }
  1007.  
  1008.         pNewPostKey->pNext = NULL;
  1009.         pTail = pNewPostKey;
  1010.  
  1011.         pNewPostKey->pHead = pHead;     // may point to itself
  1012.  
  1013.     } // for ( nReturn
  1014.  
  1015. #ifdef USE_TEMPORARY_FILES
  1016.     // 
  1017.     // If content file is empty, close it and delete it
  1018.     // 
  1019.  
  1020.     if ( !pHead ) {
  1021.         LOG( "Empty content file is being deleted." );
  1022.         CloseHandle( hDataFile );
  1023.         DeleteFile( szTempPath );
  1024.     }
  1025.     // Free work buffer
  1026.     BKL_Dealloc( &lpszKeyNameBuf, &lpbyContentBuf );
  1027.  
  1028. #elif defined USE_MEMORY
  1029.  
  1030.     // Free work buffer
  1031.     BKL_Dealloc( &lpszKeyNameBuf, pHead ? NULL : &lpbyContentBuf );
  1032. #endif
  1033.  
  1034.  
  1035.     return pHead;
  1036. }
  1037.  
  1038.  
  1039. //
  1040. // We are now pretty much done with anything complex. BuildKeyList 
  1041. // will do all our parse work, so now we need a few wrappers to
  1042. // make a nice, clean external interface.
  1043. // 
  1044. // GetPostKeys calls BuildKeyList with GetPostedByte.
  1045. // 
  1046. // GetUrlKeys calls BuildKeyList with GetQueryByte.
  1047. // 
  1048.  
  1049. PPOSTKEY 
  1050. GetPostKeys( 
  1051.     IN EXTENSION_CONTROL_BLOCK * pECB 
  1052. )
  1053. {
  1054.     return BuildKeyList( pECB, GetPostedByte );
  1055. }
  1056.  
  1057. PPOSTKEY 
  1058. GetUrlKeys( 
  1059.     IN EXTENSION_CONTROL_BLOCK * pECB 
  1060. )
  1061. {
  1062.     return BuildKeyList( pECB, GetQueryByte );
  1063. }
  1064.  
  1065.  
  1066. PLISTPROP 
  1067. GetPropAddr( 
  1068.     IN HKEYLIST hKey 
  1069. )
  1070. /*++
  1071.  
  1072. Purpose:
  1073.  
  1074.     GetPropAddr returns the address of the end of
  1075.     the first key.  We stuff list properties there.
  1076.     This implementation of keys.cpp keeps a pointer
  1077.     to the content buffer.  The second version ( used
  1078.     in IS2WCGI ) appends a temporary file name
  1079.     to the first key.
  1080.  
  1081. Arguments:
  1082.     hKey - pointer to a key list
  1083.  
  1084. Returns:
  1085.     The address of the end of the first key
  1086.  
  1087. --*/
  1088. {
  1089.     LPCSTR lpszKeyName;
  1090.     PPOSTKEY pHead;
  1091.  
  1092.     // Safety
  1093.     if ( !hKey ) {
  1094.         return NULL;
  1095.     }
  1096.  
  1097.     // ContentPath follows POSTKEY struct and key name
  1098.     pHead = (PPOSTKEY) hKey;
  1099.     pHead = pHead->pHead;
  1100.  
  1101.     lpszKeyName = (LPCSTR) ( &pHead[1] );
  1102.  
  1103.     return (PLISTPROP) ( lpszKeyName + lstrlen( lpszKeyName ) + 1 );
  1104. }
  1105.  
  1106.  
  1107. HKEYLIST 
  1108. GetKeyList( 
  1109.     IN EXTENSION_CONTROL_BLOCK * pECB 
  1110. )
  1111. /*++
  1112.  
  1113. Purpose:
  1114.  
  1115.     Examines the method and calls GetPostKeys or GetUrlKeys, 
  1116.     whichever is relevant.
  1117.  
  1118.  
  1119. Arguments:
  1120.     pECB - points to the extension control block
  1121.  
  1122. Returns:
  1123.     GetPropAddr returns the address of the end of
  1124.     the first key.  We stuff list properties there.
  1125.     This implementation of keys.cpp keeps a pointer
  1126.     to the content buffer.  The second version ( used
  1127.     in IS2WCGI ) appends a temporary file name
  1128.     to the first key.
  1129.  
  1130. --*/
  1131. {
  1132.     if ( !lstrcmpi( pECB->lpszMethod, "POST" ) ) {
  1133.         LOG( "Method=POST" );
  1134.         return (HKEYLIST) GetPostKeys( pECB );
  1135.     }else if ( !lstrcmpi( pECB->lpszMethod, "GET" ) ) {
  1136.         LOG( "Method=GET" );
  1137.         return (HKEYLIST) GetUrlKeys( pECB );
  1138.     }
  1139.     LOG( "Unknown method" );
  1140.  
  1141.     return NULL;
  1142. }
  1143.  
  1144.  
  1145. HKEYLIST 
  1146. GetKeyInfo( 
  1147.     IN HKEYLIST hKey, 
  1148.     OUT LPCSTR * plpszKeyName,
  1149.     OUT LPDWORD pdwLength, 
  1150.     OUT BOOL * pbHasCtrlChars,
  1151.     OUT LPINT pnInstance 
  1152. )
  1153. //
  1154. // GetKeyInfo is a wrapper for the POSTKEY linked list.
  1155. // It returns the members of the supplied POSTKEY object.
  1156. // 
  1157. {
  1158.     PPOSTKEY pPostKey;
  1159.  
  1160.     // Safety
  1161.     if ( !hKey ) {
  1162.         return NULL;
  1163.     }
  1164.  
  1165.     pPostKey = (PPOSTKEY) hKey;
  1166.  
  1167.     // Set the data members
  1168.     if ( plpszKeyName )
  1169.         *plpszKeyName = ( LPCSTR ) ( &pPostKey[1] );
  1170.     if ( pdwLength )
  1171.         *pdwLength = pPostKey->dwLength;
  1172.     if ( pbHasCtrlChars )
  1173.         *pbHasCtrlChars = pPostKey->bHasCtrlChars;
  1174.     if ( pnInstance )
  1175.         *pnInstance = pPostKey->nInstance;
  1176.  
  1177.     // Return a handle to the next object in the list
  1178.     return ( ( HKEYLIST ) pPostKey->pNext );
  1179. }
  1180.  
  1181.  
  1182.  
  1183. #ifdef USE_MEMORY
  1184. LPBYTE 
  1185. GetKeyBuffer( 
  1186.     IN HKEYLIST hKey 
  1187. )
  1188. {
  1189.     // 
  1190.     // We have two versions of this function because
  1191.     // we may want to use file i/o when the extension
  1192.     // deals with massive amounts of inbound data
  1193.     // ( like multi-megabyte uploads ).
  1194.     // 
  1195.  
  1196.     // 
  1197.     // This version uses a memory buffer.
  1198.     // 
  1199.  
  1200.     PPOSTKEY pKey;
  1201.  
  1202.     // Safety
  1203.     if ( !hKey ) {
  1204.         return NULL;
  1205.     }
  1206.  
  1207.     pKey = (PPOSTKEY) hKey;
  1208.  
  1209.     return (LPBYTE) pKey->lpbyBuf;
  1210. }
  1211.  
  1212. #elif defined USE_TEMPORARY_FILES
  1213.  
  1214. LPBYTE 
  1215. GetKeyBuffer( 
  1216.     IN HKEYLIST hKey 
  1217. )
  1218. {
  1219.     // 
  1220.     // This version uses slow temporary files.
  1221.     // 
  1222.  
  1223.     PLISTPROP pProp;
  1224.     PPOSTKEY pKey;
  1225.     DWORD dwRead;
  1226.  
  1227.     // Get pointer to list properties
  1228.     pProp = GetPropAddr( hKey );
  1229.  
  1230.     // Safety
  1231.     if ( !pProp ) {
  1232.         return NULL;
  1233.     }
  1234.  
  1235.     pKey = (PPOSTKEY) hKey;
  1236.  
  1237.     // Check if memory was already loaded for this key
  1238.     if ( pKey->lpbyBuf ) {
  1239.         return pKey->lpbyBuf;
  1240.     }
  1241.  
  1242.     // If not, let's allocate memory and do a ReadFile
  1243.     pKey->lpbyBuf = (LPBYTE) HeapAlloc( GetProcessHeap( ),
  1244.         HEAP_ZERO_MEMORY,
  1245.         pKey->dwLength + 1 );
  1246.     if ( !pKey->lpbyBuf ) {
  1247.         LOG( "GetKeyBuffer: HeapAlloc failed" );
  1248.         return NULL;
  1249.     }
  1250.     // Do the ReadFile
  1251.     SetFilePointer( pProp->hFile, pKey->dwOffset, NULL, FILE_BEGIN );
  1252.     if ( !ReadFile( pProp->hFile, pKey->lpbyBuf,
  1253.             pKey->dwLength, &dwRead, NULL ) ||
  1254.         dwRead != pKey->dwLength ) {
  1255.         HeapFree( GetProcessHeap( ), 0, (LPVOID) pKey->lpbyBuf );
  1256.         pKey->lpbyBuf = NULL;
  1257.  
  1258.         LOG( "GetKeyBuffer: ReadFile failed" );
  1259.         return NULL;
  1260.     }
  1261.     return pKey->lpbyBuf;
  1262. }
  1263. #endif
  1264.  
  1265.  
  1266. HKEYLIST 
  1267. FindKey( 
  1268.     IN HKEYLIST hKeyList, 
  1269.     IN LPCSTR lpszSearchName 
  1270. )
  1271. /*++
  1272.  
  1273. Purpose:
  1274.  
  1275.     FindKey sequentially searches the linked list for a given key.
  1276.  
  1277. Arguments:
  1278.  
  1279.     hKeyList - points to key list
  1280.     lpszSearchName - points to a key name to find 
  1281.  
  1282. Returns:
  1283.  
  1284.     The return handle points to the element within the linked list.
  1285.     Use it in GetKeyInfo, but not FreeKeyList.
  1286.  
  1287. --*/
  1288. {
  1289.     PPOSTKEY pFindKey;
  1290.  
  1291.     pFindKey = (PPOSTKEY) hKeyList;
  1292.     while ( pFindKey ) {
  1293.         if ( !lstrcmpi( lpszSearchName, ( LPCSTR ) ( &pFindKey[1] ) ) ) {
  1294.             return ( ( HKEYLIST ) pFindKey );
  1295.         }
  1296.  
  1297.         pFindKey = pFindKey->pNext;
  1298.     }
  1299.  
  1300.     return NULL;
  1301. }
  1302.  
  1303.  
  1304. void 
  1305. FreeKeyList( 
  1306.     IN HKEYLIST hHeadKey 
  1307. )
  1308. /*++
  1309.  
  1310. Purpose:
  1311.  
  1312.     FreeKeyList deallocates all the objects in the key list.
  1313.     The content file is also deleted.
  1314.  
  1315. Arguments:
  1316.     hHeadKey - points to the list head    
  1317.  
  1318. --*/
  1319. {
  1320.     PPOSTKEY pObject;
  1321.     PPOSTKEY pDel;
  1322.     PLISTPROP pProp;
  1323.  
  1324.     // Safety
  1325.     if ( !hHeadKey ) {
  1326.         return;
  1327.     }
  1328.  
  1329. #ifdef USE_TEMPORARY_FILES
  1330.     // Close the content file
  1331.     CloseContentFile( hHeadKey );
  1332.  
  1333.     // delete the content file
  1334.     pProp = GetPropAddr( hHeadKey );
  1335.     DeleteFile( pProp->szTempFileName );
  1336.  
  1337. #elif defined USE_MEMORY
  1338.  
  1339.     // delete content
  1340.     pProp = GetPropAddr( hHeadKey );
  1341.     HeapFree( GetProcessHeap( ), 0, (LPVOID) pProp->lpbyBuf );
  1342. #endif
  1343.  
  1344.     // delete all objects in the list
  1345.     pObject = (PPOSTKEY) hHeadKey;
  1346.     pObject = pObject->pHead;
  1347.     while ( pObject ) {
  1348.  
  1349. #ifdef USE_TEMPORARY_FILES
  1350.         // 
  1351.         // Free each buffer when using temporary files
  1352.         // 
  1353.  
  1354.         if ( pObject->lpbyBuf )
  1355.             HeapFree( GetProcessHeap( ), 0, (LPVOID) pObject->lpbyBuf );
  1356. #endif
  1357.  
  1358.         pDel = pObject;
  1359.         pObject = pObject->pNext;
  1360.  
  1361.         HeapFree( GetProcessHeap( ), 0, (LPVOID) pDel );
  1362.     }
  1363. }
  1364.  
  1365.  
  1366. DWORD 
  1367. GetKeyOffset( 
  1368.     IN HKEYLIST hKey 
  1369. )
  1370. /*++
  1371.  
  1372. Purpose:
  1373.  
  1374.     GetKeyOffset returns the offset of a key into the internal
  1375.     buffer or temporary file.  This is provided for IS2WCGI
  1376.     so it can return an offset within the content file.
  1377.  
  1378. Arguments:
  1379.     
  1380.     hKey - points to a key
  1381.  
  1382. Returns:
  1383.     
  1384.     Offset of a key or NULL if no key provided
  1385.  
  1386. --*/
  1387. {
  1388.     // Safety
  1389.     if ( !hKey )
  1390.         return NULL;
  1391.  
  1392.     return ( (PPOSTKEY) hKey )->dwOffset;
  1393. }
  1394.  
  1395.  
  1396. #ifdef USE_TEMPORARY_FILES
  1397.  
  1398. LPCSTR 
  1399. GetContentFile( 
  1400.     IN HKEYLIST hKeyList 
  1401. )
  1402. /*++
  1403.  
  1404. Purpose:
  1405.  
  1406.     GetContentFile returns a pointer to the name of the
  1407.     temporary file.  This is provided for the IS2WCGI
  1408.     sample.
  1409.  
  1410. Arguments:
  1411.  
  1412.  
  1413. Returns:
  1414.  
  1415. --*/
  1416. {
  1417.     PLISTPROP pProp;
  1418.  
  1419.     // safety
  1420.     if ( !hKeyList )
  1421.         return NULL;
  1422.  
  1423.     pProp = GetPropAddr( hKeyList );
  1424.  
  1425.     return ( LPCSTR ) pProp->szTempFileName;
  1426. }
  1427.  
  1428.  
  1429. void 
  1430. CloseContentFile( 
  1431.     IN HKEYLIST hKey 
  1432. )
  1433. /*++
  1434.  
  1435. Purpose:
  1436.  
  1437.     CloseContentFile forces the content file to be closed.  This
  1438.     allows you to pass the file to something else that may open
  1439.     it.  Call OpenContentFile before calling any other key
  1440.     function.
  1441.  
  1442. Arguments:
  1443.  
  1444. --*/
  1445. {
  1446.     PLISTPROP pProp;
  1447.  
  1448.     if ( !hKey )
  1449.         return;
  1450.  
  1451.     pProp = GetPropAddr( hKey );
  1452.     if ( pProp->hFile != INVALID_HANDLE_VALUE ) {
  1453.         CloseHandle( pProp->hFile );
  1454.         pProp->hFile = INVALID_HANDLE_VALUE;
  1455.     }
  1456. }
  1457.  
  1458.  
  1459. void 
  1460. OpenContentFile( 
  1461.     IN HKEYLIST hKey 
  1462. )
  1463. /*++
  1464.  
  1465. Purpose:
  1466.  
  1467.     OpenContentFile forces the content file to be reopened.
  1468.     GetKeyBuffer will fail if the content file was closed by
  1469.     CloseContentFile, but not reopened.
  1470.  
  1471. Arguments:
  1472.  
  1473.  
  1474. Returns:
  1475.  
  1476. --*/
  1477. {
  1478.     PLISTPROP pProp;
  1479.  
  1480.     if ( !hKey )
  1481.         return;
  1482.  
  1483.     pProp = GetPropAddr( hKey );
  1484.  
  1485.     if ( pProp->hFile != INVALID_HANDLE_VALUE )
  1486.         return;
  1487.  
  1488.     // Create the content file
  1489.     pProp->hFile = CreateFile( pProp->szTempFileName,
  1490.         GENERIC_READ | GENERIC_WRITE,
  1491.         0,                      // No sharing mode
  1492.          NULL,                  // Default security attribs
  1493.          OPEN_EXISTING,
  1494.         FILE_ATTRIBUTE_NORMAL,
  1495.         NULL );
  1496. }
  1497.  
  1498. #elif defined USE_MEMORY
  1499.  
  1500.  
  1501. LPBYTE 
  1502. GetDataBuffer( 
  1503.     IN HKEYLIST hKeyList 
  1504. )
  1505. /*++
  1506.  
  1507. Purpose:
  1508.  
  1509.     GetBufferPointer returns a pointer to the buffer used
  1510.     for content storage.
  1511.  
  1512. Arguments:
  1513.  
  1514.     hKeyList - points to a key list
  1515.     
  1516. Returns:
  1517.  
  1518.     pointer to the content buffer or NULL
  1519.  
  1520. --*/
  1521. {
  1522.     PLISTPROP pProp;
  1523.  
  1524.     // safety
  1525.     if ( !hKeyList )
  1526.         return NULL;
  1527.  
  1528.     pProp = GetPropAddr( hKeyList );
  1529.  
  1530.     return pProp->lpbyBuf;
  1531. }
  1532. #endif
  1533.