home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 32 / IOPROG_32.ISO / SOFT / SqlEval7 / devtools / samples / ODBC / loaddata / getdata.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-10-30  |  28.3 KB  |  1,034 lines

  1. // GetData.cpp -- Data file consumption routines
  2. //
  3. // This file is part of Microsoft SQL Server online documentation.
  4. // Copyright (C) 1992-1997 Microsoft Corporation. All rights reserved.
  5. //
  6. // This source code is an intended supplement to the Microsoft SQL
  7. // Server online references and related electronic documentation.
  8. #include "stdafx.h"
  9. #include "afxtempl.h"
  10.  
  11. #include "resource.h"
  12. #include "GetData.h"
  13.  
  14. #define MAXINTSTR       32
  15.  
  16. #define DATETIMEADD(pval, c)            (*pval) = (((*pval) * 10) + ((c) - '0'))
  17. #define CHECKBUFFER(cbData,pDataAtExec) (cbData % ALLOCBLOCK ? 0 : 1)
  18.  
  19. static PSTR ConsumeStringTail(PSTR pin, BOOL bInQuote);
  20. static PSTR ConsumeValue(PSTR pin);
  21. static PSTR CheckExtendBuffer(PDATA_AT_EXEC pDataAtExec, UINT cbData);
  22.  
  23. //////////////////////////////////////////////////////////////////////////
  24. // ConsumeStringTail -- Chew through the end of a string data item that's
  25. //  too long.
  26. PSTR ConsumeStringTail
  27.     (
  28.     PSTR pin,
  29.     BOOL bInQuote
  30.     )
  31.     {
  32.     char        c;
  33.  
  34.     while ((c = *pin++) != NULL)
  35.         {
  36.         switch (c)
  37.             {
  38.             case ('"'):
  39.                 {
  40.                 // Check to see if it's an escaped quote character.
  41.                 if (!(bInQuote && *pin == '"'))
  42.                     {
  43.                     bInQuote = !(bInQuote);
  44.                     }
  45.                 break;
  46.                 }
  47.  
  48.             case (','):
  49.             case ('\n'):
  50.                 {
  51.                 if (!bInQuote)
  52.                     {
  53.                     return (pin);
  54.                     }
  55.  
  56.                 break;
  57.                 }
  58.             }
  59.         }
  60.  
  61.     // Hit NULL, returns bad pointer.
  62.     return (pin);
  63.     }
  64.  
  65. //////////////////////////////////////////////////////////////////////////
  66. // ConsumeValue -- Chew through a data file to find the next delimiter
  67. //  (a ',' or line terminator).
  68. PSTR ConsumeValue(PSTR pin)
  69.     {
  70.     char        c;
  71.  
  72.     while ((c = *pin++) != NULL)
  73.         {
  74.         switch (c)
  75.             {
  76.             case (','):
  77.             case ('\n'):
  78.                 {
  79.                 return (pin);
  80.                 }
  81.  
  82.             default:
  83.                 break;
  84.             }
  85.         }
  86.  
  87.     // Hit NULL, return current pointer.
  88.     return (pin);
  89.     }
  90.  
  91. //////////////////////////////////////////////////////////////////////////
  92. // FieldData -- Extracts a value from the data file as character data.
  93. //  Ignores enclosing '"' characters, escapes SQL Server quotes.
  94. //
  95. // The caller indicates a return buffer for the character data and must
  96. //  ensure that the buffer is large enough to hold the extracted string.
  97. //
  98. // Returns:  The position of the next data value or NULL on data error.
  99. PSTR FieldData
  100.     (
  101.     PSTR pin,
  102.     PSTR pout,
  103.     UINT cboutMax,
  104.     UINT* pcbout
  105.     )
  106.     {
  107.     UINT        cbData = 0;
  108.     char        c;
  109.     BOOL        bQuotedText = (*pin == '"' ? TRUE : FALSE);
  110.     BOOL        bInQuote = FALSE;
  111.  
  112.     *pcbout = 0;
  113.  
  114.     // Catch case of NULL string as ...,"",... in a data file.
  115.     if (bQuotedText)
  116.         {
  117.         bInQuote = TRUE;
  118.         pin++;
  119.         }
  120.  
  121.     while (cbData < cboutMax)
  122.         {
  123.         switch (c = *pin++)
  124.             {
  125.             case ('"'):
  126.                 {
  127.                 // Check to see if it's an escaped quote character.
  128.                 if (bInQuote && *pin == '"')
  129.                     {
  130.                     pout[cbData++] = c;
  131.                     pin++;
  132.                     }
  133.                 else
  134.                     {
  135.                     bInQuote = !(bInQuote);
  136.                     }
  137.                 break;
  138.                 }
  139.  
  140.             case (NULL):
  141.                 {
  142.                 // Check to see if it's a valid terminator. Either way
  143.                 //  we're returning from here.
  144.                 if (!bQuotedText)
  145.                     {
  146.                     pout[cbData] = (char) NULL;
  147.                     *pcbout = cbData;
  148.                     }
  149.  
  150.                 return (pin);
  151.                 }
  152.  
  153.             case ('\r'):
  154.                 {
  155.                 if (bInQuote)
  156.                     {
  157.                     pout[cbData++] = c;
  158.                     }
  159.                 break;
  160.                 }
  161.  
  162.             case (','):
  163.             case ('\n'):
  164.                 {
  165.                 if (bInQuote)
  166.                     {
  167.                     pout[cbData++] = c;
  168.                     }
  169.                 else
  170.                     {
  171.                     pout[cbData] = (char) NULL;
  172.                     *pcbout = cbData;
  173.  
  174.                     return (pin);
  175.                     }
  176.  
  177.                 break;
  178.                 }
  179.  
  180.             default:
  181.                 {
  182.                 pout[cbData++] = c;
  183.                 break;
  184.                 }
  185.             }
  186.         }
  187.  
  188.     // We fell through, truncating due to too small a buffer used
  189.     //  by our caller. Chew up the rest of the column's data.
  190.     pout[--cbData] = (char) NULL;
  191.     *pcbout = cbData;
  192.  
  193.     return (ConsumeStringTail(pin, bInQuote));
  194.     }
  195.  
  196. //////////////////////////////////////////////////////////////////////////
  197. // GetColNamesFromData -- Yanks column names out of the first line of a 
  198. //  data file. Sets the value of pnDataCols to the number of columns found
  199. //  in pin. Builds an array of column names into ppColNames.
  200. //
  201. // Returns TRUE if it looks like the line contains column names (all
  202. //  comma delimited strings are enclosed in quotes). FALSE otherwise.
  203. BOOL GetColNamesFromData
  204.     (
  205.     PSTR pin,
  206.     UINT* pnDataCols,
  207.     PTSTR** ppColNames
  208.     )
  209.     {
  210.     PSTR    pColumn;
  211.     PTSTR   pColName;
  212.     UINT    nDataCols = 0;
  213.     UINT    nDataCol;
  214.     UINT    cbColName;
  215.     BOOL    bGoodCols = TRUE;
  216.     PTSTR*  pColNames;
  217.     CList<PTSTR, PTSTR> listColNames;
  218.  
  219.     *pnDataCols = 0;
  220.     *ppColNames = NULL;
  221.  
  222.     pColumn = strtok(pin, ",");
  223.     while (pColumn != NULL && bGoodCols == TRUE)
  224.         {
  225.         cbColName = strlen(pColumn);
  226.         if (*pColumn == '"')
  227.             {
  228.             pColName = new TCHAR[cbColName];
  229. #ifdef _UNICODE
  230.             MultiByteToWideChar(CP_ACP, 0, pColumn + 1, -1, pColName,
  231.                 cbColName);
  232. #else
  233.             strcpy(pColName, pColumn + 1);
  234. #endif
  235.             if (pColName[cbColName - 2] == _T('"'))
  236.                 {
  237.                 pColName[cbColName - 2] = (TCHAR) NULL;
  238.                 listColNames.AddTail(pColName);
  239.                 nDataCols++;
  240.                 }
  241.             else
  242.                 {
  243.                 bGoodCols = FALSE;
  244.                 }
  245.             }
  246.         else
  247.             {
  248.             bGoodCols = FALSE;
  249.             }
  250.  
  251.         pColumn = strtok(NULL, ",");
  252.         }
  253.  
  254.     if (bGoodCols == TRUE)
  255.         {
  256.         pColNames = new PTSTR[nDataCols];
  257.  
  258.         for (nDataCol = 0; nDataCol < nDataCols; nDataCol++)
  259.             {
  260.             pColNames[nDataCol] = 
  261.                 listColNames.GetAt(listColNames.FindIndex(nDataCol));
  262.             }
  263.  
  264.         *ppColNames = pColNames;
  265.         *pnDataCols = nDataCols;
  266.         }
  267.     else
  268.         {
  269.         for (nDataCol = 0; nDataCol < nDataCols; nDataCol++)
  270.             {
  271.             pColName = listColNames.GetAt(listColNames.FindIndex(nDataCol));
  272.             delete [] pColName;
  273.             }
  274.         }
  275.  
  276.     return (bGoodCols);
  277.     }
  278.  
  279. //////////////////////////////////////////////////////////////////////////
  280. // GetBinaryData --  Converts a character representation of a binary
  281. //  value to its binary equivalent. The character representation is
  282. //  prefixed with "0x" and each binary byte is represented by a two
  283. //  character hexidecimal number. For example, the characters
  284. //  "0x476F6F64" translates to the four byte string "Good".
  285. //
  286. // The converted string is returned in the DataAtExec structure passed
  287. //  in. The structure holds the data pointer and the length of the
  288. //  binary data.
  289. //
  290. //  Returns:  The position of the next data value.
  291. PSTR GetBinaryData
  292.     (
  293.     PSTR pin,
  294.     PBYTE pout,
  295.     UINT cboutMax,
  296.     UINT* pcbout
  297.     )
  298.     {
  299.     UINT        cbData = 0;
  300.     char        c;
  301.     BYTE        bUpper;
  302.     BYTE        bLower;
  303.  
  304.     *pcbout = 0;
  305.     if (*pin == ',')
  306.         {
  307.         return (pin++);
  308.         }
  309.  
  310.     if (*pin != '0' || (*(pin + 1) & 0x5F) != 'X')
  311.         {
  312.         AfxMessageBox(IDS_ERR_BINARYFORMAT);
  313.         return (ConsumeValue(pin));
  314.         }
  315.  
  316.     pin += 2;
  317.     while (cbData < cboutMax)
  318.         {
  319.         switch (c = *pin++)
  320.             {
  321.             case ('\r'):
  322.                 {
  323.                 break;
  324.                 }
  325.  
  326.             case (NULL):
  327.             case (','):
  328.             case ('\n'):
  329.                 {
  330.                 // Any of our field terminators.
  331.                 *pcbout = cbData;
  332.                 return (pin);
  333.                 }
  334.  
  335.             default:
  336.                 {
  337.                 bUpper = (BYTE) (c > '9' ? c - 'A' + 10 : c - '0');
  338.  
  339.                 c = *pin++;
  340.                 bLower = (BYTE) (c > '9' ? c - 'A' + 10 : c - '0');
  341.  
  342.                 if (bUpper > 15 || bLower > 15)
  343.                     {
  344.                     AfxMessageBox(IDS_ERR_BINARYCHARACTER);
  345.                     return (ConsumeValue(pin));
  346.                     }
  347.  
  348.                 pout[cbData++] = (bUpper <<= 4) + bLower;
  349.                 break;
  350.                 }
  351.             }
  352.         }
  353.  
  354.     // Past the end of allowed space.
  355.     return (ConsumeValue(pin));
  356.     }
  357.  
  358. //////////////////////////////////////////////////////////////////////////
  359. // GetCharData -- Extracts a character value from the data file. The
  360. //  character string must be enclosed in '"' characters.
  361. //
  362. // The caller indicates a return buffer for the character data and must
  363. //  ensure that the buffer is large enough to hold the extracted string.
  364. //
  365. // Returns:  The position of the next data value.
  366. PSTR GetCharData
  367.     (
  368.     PSTR pin, 
  369.     PSTR pout, 
  370.     UINT cboutMax, 
  371.     UINT* pcbout
  372.     )
  373.     {
  374.     UINT        cbData;
  375.     char        c;
  376.     BOOL        bInQuote = FALSE;
  377.  
  378.     *pcbout = cbData = 0;
  379.     while (cbData < cboutMax)
  380.         {
  381.         switch (c = *pin++)
  382.             {
  383.             case (NULL):
  384.                 {
  385.                 // NULL is not a valid terminator for a quoted text string.
  386.                 return (pin);
  387.                 }
  388.  
  389.             case ('"'):
  390.                 {
  391.                 // Check to see if it's an escaped quote character.
  392.                 if (bInQuote && *pin == '"')
  393.                     {
  394.                     pout[cbData++] = c;
  395.                     pin++;
  396.                     }
  397.                 else
  398.                     {
  399.                     bInQuote = !(bInQuote);
  400.                     }
  401.                 break;
  402.                 }
  403.  
  404.             case ('\r'):
  405.                 {
  406.                 if (bInQuote)
  407.                     {
  408.                     pout[cbData++] = c;
  409.                     }
  410.                 break;
  411.                 }
  412.  
  413.             case (','):
  414.             case ('\n'):
  415.                 {
  416.                 if (bInQuote)
  417.                     {
  418.                     pout[cbData++] = c;
  419.                     }
  420.                 else
  421.                     {
  422.                     pout[cbData] = (char) NULL;
  423.                     *pcbout = cbData;
  424.                     return (pin);
  425.                     }
  426.  
  427.                 break;
  428.                 }
  429.  
  430.             default:
  431.                 {
  432.                 pout[cbData++] = c;
  433.                 break;
  434.                 }
  435.             }
  436.         }
  437.  
  438.     // Too much data for our parameter; chew up the rest of the
  439.     //  data item.
  440.     pout[--cbData] = (char) NULL;
  441.     *pcbout = cbData;
  442.  
  443.     return (ConsumeStringTail(pin, bInQuote));
  444.     }
  445.  
  446. //////////////////////////////////////////////////////////////////////////
  447. // GetDateData -- Extracts a date value from the data file. Data file
  448. //  dates are in ODBC yyyy-mm-dd hh:mm:ss:ffff format. The string is
  449. //  not enclosed in quotes.
  450. //
  451. // The converted string is returned in the ODBC defined timestamp
  452. //  structure received. The length of data chewed is returned so that 
  453. //  the caller can determine if the value is NULL.
  454. //
  455. // Returns:  The position of the next data value.
  456. PSTR GetDateData(PSTR pin, SQL_TIMESTAMP_STRUCT* pts, UINT* pcbout)
  457.     {
  458.     UINT        cbData = 0;
  459.     BOOL        bHaveYe = FALSE;
  460.     BOOL        bHaveMo = FALSE;
  461.     BOOL        bHaveDa = FALSE;
  462.     BOOL        bHaveHo = FALSE;
  463.     BOOL        bHaveMi = FALSE;
  464.     BOOL        bHaveSe = FALSE;
  465.     char        c;
  466.  
  467.     // Set default date and time.
  468.     pts->year = 0;
  469.     pts->month = 0;
  470.     pts->day = 0;
  471.     pts->hour = 0;
  472.     pts->minute = 0;
  473.     pts->second = 0;
  474.     pts->fraction = 0;
  475.  
  476.     *pcbout = 0;
  477.     while (TRUE)
  478.         {
  479.         switch (c = *pin++)
  480.             {
  481.             // Handle CRLF as well as LF only text files.
  482.             case ('\r'):
  483.                 {
  484.                 break;
  485.                 }
  486.  
  487.             case (NULL):
  488.             case (','):
  489.             case ('\n'):
  490.                 {
  491.                 if (bHaveYe && bHaveMo && bHaveDa)
  492.                     {
  493.                     *pcbout = cbData;
  494.                     }
  495.  
  496.                 return (pin);
  497.                 }
  498.  
  499.             case ('-'):
  500.                 {
  501.                 // Data error if first char or all date parts are parsed.
  502.                 if ((!bHaveYe && pts->year == 0) || 
  503.                     (bHaveYe && bHaveMo && bHaveDa))
  504.                     {
  505.                     return (ConsumeValue(pin));
  506.                     }
  507.  
  508.                 if (!bHaveYe)
  509.                     {
  510.                     bHaveYe = TRUE;
  511.                     }
  512.                 else
  513.                     {
  514.                     bHaveMo = TRUE;
  515.                     }
  516.  
  517.                 break;
  518.                 }
  519.  
  520.             case (' '):
  521.                 {
  522.                 // If we hit the delimeter between date and time and
  523.                 //  we don't have all date parts, or we've hit it a 
  524.                 //  second time, error, return NULL data.
  525.                 if (pts->day == 0 || (bHaveYe && bHaveMo && bHaveDa))
  526.                     {
  527.                     return (ConsumeValue(pin));
  528.                     }
  529.  
  530.                 bHaveDa = TRUE;
  531.                 break;
  532.                 }
  533.  
  534.             case (':'):
  535.                 {
  536.                 if (bHaveHo && bHaveMi && bHaveSe)
  537.                     {
  538.                     return (ConsumeValue(pin));
  539.                     }
  540.  
  541.                 if (!bHaveHo)
  542.                     {
  543.                     bHaveHo = TRUE;
  544.                     }
  545.                 else
  546.                     {
  547.                     bHaveMi = TRUE;
  548.                     }
  549.                 break;
  550.                 }
  551.  
  552.             case ('.'):
  553.                 {
  554.                 // If encountered before hours and minutes retrieved,
  555.                 //  or after we've got the number of seconds in the time,
  556.                 //  then the thousands of a second delimiter's an error.
  557.                 if (!bHaveHo || !bHaveMi || bHaveSe)
  558.                     {
  559.                     return (ConsumeValue(pin));
  560.                     }
  561.  
  562.                 bHaveSe = TRUE;
  563.                 }
  564.  
  565.             default:
  566.                 {
  567.                 if (!isdigit(c))
  568.                     {
  569.                     return (ConsumeValue(pin));
  570.                     }
  571.  
  572.                 if (!bHaveYe)
  573.                     {
  574.                     DATETIMEADD(&(pts->year), c);
  575.                     }
  576.                 else if (!bHaveMo)
  577.                     {
  578.                     DATETIMEADD(&(pts->month), c);
  579.                     }
  580.                 else if (!bHaveDa)
  581.                     {
  582.                     DATETIMEADD(&(pts->day), c);
  583.                     }
  584.                 else if (!bHaveHo)
  585.                     {
  586.                     DATETIMEADD(&(pts->hour), c);
  587.                     }
  588.                 else if (!bHaveMi)
  589.                     {
  590.                     DATETIMEADD(&(pts->minute), c);
  591.                     }
  592.                 else if (!bHaveSe)
  593.                     {
  594.                     DATETIMEADD(&(pts->second), c);
  595.                     }
  596.                 else
  597.                     {
  598.                     DATETIMEADD(&(pts->fraction), c);
  599.                     }
  600.  
  601.                 cbData++;
  602.                 break;
  603.                 }
  604.             }
  605.         }
  606.  
  607.     // Function returns from switch statement. Dummy return to satisify
  608.     //  compiler.
  609.     return (pin);
  610.     }
  611.  
  612. //////////////////////////////////////////////////////////////////////////
  613. // GetIntegerData -- Extracts an integral value from the data file.
  614. //
  615. // The number of digit characters converted is returned to the caller.
  616. //  Zero characters indicate a NULL value.
  617. //
  618. // Returns:  The position of the next data value.
  619. PSTR GetIntegerData(PSTR pin, int* piout, UINT* pcbout)
  620.     {
  621.     UINT        cbData = 0;
  622.     CHAR        c;
  623.     CHAR        acData[MAXINTSTR];
  624.  
  625.     *pcbout = 0;
  626.     while (cbData < MAXINTSTR)
  627.         {
  628.         switch (c = *pin++)
  629.             {
  630.             // Handle CRLF as well as LF only text files
  631.             case ('\r'):
  632.                 {
  633.                 break;
  634.                 }
  635.  
  636.             case (NULL):
  637.             case (','):
  638.             case ('\n'):
  639.                 {
  640.                 acData[cbData] = (char) NULL;
  641.                 if (cbData)
  642.                     {
  643.                     *piout = atoi(acData);
  644.                     }
  645.  
  646.                 *pcbout = cbData;
  647.                 return (pin);
  648.                 }
  649.  
  650.             default:
  651.                 {
  652.                 // If it's a digit, add it to our string. If it's a
  653.                 //  decimal point and everything up until now has been
  654.                 //  a digit, return the integer portion.
  655.                 if (isdigit(c))
  656.                     {
  657.                     acData[cbData++] = c;
  658.                     }
  659.                 else if (c == '.' && cbData)
  660.                     {
  661.                     acData[cbData] = (char) NULL;
  662.                     *piout = atoi(acData);
  663.                     *pcbout = cbData;
  664.                     return (ConsumeValue(pin));
  665.                     }
  666.                 else
  667.                     {
  668.                     return (ConsumeValue(pin));
  669.                     }
  670.  
  671.                 break;
  672.                 }
  673.             }
  674.         }
  675.  
  676.     // We've got some really long string of digits. Whatever it is, we can't
  677.     //  do anything of value with it.
  678.     return (ConsumeValue(pin));
  679.     }
  680.  
  681. //////////////////////////////////////////////////////////////////////////
  682. // GetNumericData -- Extracts a numeric value from the data file.
  683. //  Numeric values are fixed in precision and scale and are represented
  684. //  by NULL-terminated strings of digit characters.
  685. //
  686. // Approximate numerics (float and double) are handled here as well,
  687. //  allowing the server (or driver) to convert to internal representation.
  688. //
  689. // The number of digit characters extracted is returned to the caller
  690. //  Zero characters extracted indicates a NULL value.
  691. //
  692. // Returns:  The position of the next data value.
  693. PSTR GetNumericData
  694.     (
  695.     PSTR pin,
  696.     PSTR pout,
  697.     UINT cboutMax,
  698.     UINT* pcbout
  699.     )
  700.     {
  701.     UINT        cbData = 0;
  702.     char        c;
  703.  
  704.     *pcbout = 0;
  705.     while (cbData < cboutMax)
  706.         {
  707.         switch (c = *pin++)
  708.             {
  709.             // Handle CRLF as well as LF only text files.
  710.             case ('\r'):
  711.                 {
  712.                 break;
  713.                 }
  714.  
  715.             case (NULL):
  716.             case (','):
  717.             case ('\n'):
  718.                 {
  719.                 pout[cbData] = (char) NULL;
  720.                 *pcbout = cbData;
  721.                 return (pin);
  722.                 }
  723.  
  724.             default:
  725.                 {
  726.                 if (isdigit(c) || c == '.' || c == '+' || c == '-'
  727.                     || c == 'e' || c == 'E')
  728.                     {
  729.                     pout[cbData++] = c;
  730.                     }
  731.  
  732.                 break;
  733.                 }
  734.             }
  735.         }
  736.  
  737.     pout[--cbData] = (char) NULL;
  738.     *pcbout = cbData;
  739.     return (ConsumeValue(pin));
  740.     }
  741.  
  742. //////////////////////////////////////////////////////////////////////////
  743. // GetWCharData -- Extracts a character value from the data file, then
  744. //  converts the character value to wide char. The character string must
  745. //  be enclosed in '"' characters.
  746. //
  747. // The caller indicates a return buffer for the character data and must
  748. //  ensure that the buffer is large enough to hold the extracted string.
  749. //
  750. // Returns:  The position of the next data value.
  751. PSTR GetWCharData
  752.     (
  753.     PSTR pin, 
  754.     WCHAR* pout, 
  755.     UINT cboutMax, 
  756.     UINT* pcbout
  757.     )
  758.     {
  759.     PSTR        pdatanext;
  760.     UINT        nchars = cboutMax >> 1;
  761.     PSTR        pdatain = new char[nchars];
  762.     UINT        cbdatain = 0;
  763.  
  764.     *pcbout = 0;
  765.  
  766.     if (pdatain == NULL)
  767.         {
  768.         return (ConsumeValue(pin));
  769.         }
  770.  
  771.     pdatanext = GetCharData(pin, pdatain, nchars, &cbdatain);
  772.  
  773.     if (cbdatain)
  774.         {
  775.         MultiByteToWideChar(CP_ACP, 0, pdatain, cbdatain,
  776.             pout, nchars);
  777.         *pcbout = cbdatain << 1;
  778.         }
  779.  
  780.     delete [] pdatain;
  781.  
  782.     return (pdatanext);
  783.     }
  784.  
  785. //////////////////////////////////////////////////////////////////////////
  786. // GetLongBinaryData -- Extracts a character value from the data file.
  787. //   The character string begins with the characters "0x" or "0X".
  788. //
  789. // The string is returned in the DataAtExec structure passed. The 
  790. //  structure holds the data pointer and the length of the text data.
  791. //
  792. // Returns:  The position of the next data value.
  793. PSTR GetLongBinaryData
  794.     (
  795.     PSTR pin,
  796.     PDATA_AT_EXEC pDataAtExec
  797.     )
  798.     {
  799.     UINT        cbData = 0;
  800.     char        c;
  801.     PSTR        pDataOut;
  802.  
  803.     if (pDataAtExec->pData == NULL)
  804.         {
  805.         pDataAtExec->pData = new BYTE[ALLOCBLOCK];
  806.         pDataAtExec->cbBuffer = ALLOCBLOCK;
  807.         }
  808.  
  809.     pDataAtExec->cbData = 0;
  810.     if (*pin == _T('0'))
  811.         {
  812.         pin++;
  813.         if (((*pin) & 0x5F) != _T('X'))
  814.             {
  815.             return (ConsumeValue(pin));
  816.             }
  817.         
  818.         pin++;
  819.         }
  820.  
  821.     pDataOut = (PSTR) pDataAtExec->pData;
  822.     while (TRUE)
  823.         {
  824.         switch (c = *pin++)
  825.             {
  826.             case ('\r'):
  827.                 {
  828.                 break;
  829.                 }
  830.  
  831.             case (NULL):
  832.             case (','):
  833.             case ('\n'):
  834.                 {
  835.                 pDataOut[cbData] = (char) NULL;
  836.                 pDataAtExec->cbData = cbData;
  837.  
  838.                 return (pin);
  839.                 }
  840.  
  841.             default:
  842.                 {
  843.                 if (!isxdigit(c))
  844.                     {
  845.                     return (ConsumeValue(pin));
  846.                     }
  847.  
  848.                 pDataOut[cbData++] = c;
  849.                 if (CHECKBUFFER(cbData, pDataAtExec))
  850.                     {
  851.                     pDataOut = CheckExtendBuffer(pDataAtExec, cbData);
  852.                     if (pDataOut == NULL)
  853.                         {
  854.                         return (ConsumeValue(pin));
  855.                         }
  856.                     }
  857.  
  858.                 break;
  859.                 }
  860.             }
  861.         }
  862.  
  863.     // Dummy return for compiler.
  864.     return (pin);
  865.     }
  866.  
  867. //////////////////////////////////////////////////////////////////////////
  868. // GetLongCharData -- Extracts a character value from the data file. The 
  869. //  character string must be enclosed in '"' characters.
  870. //
  871. // The string is returned in the DataAtExec structure passed. The 
  872. //  structure holds the data pointer and the length of the text data.
  873. //
  874. // Returns:  The position of the next data value.
  875. PSTR GetLongCharData
  876.     (
  877.     PSTR pin,
  878.     PDATA_AT_EXEC pDataAtExec
  879.     )
  880.     {
  881.     UINT        cbData = 0;
  882.     char        c;
  883.     BOOL        bInQuote = FALSE;
  884.     PSTR        pDataOut;
  885.  
  886.     pDataAtExec->cbData = 0;
  887.     if (pDataAtExec->pData == NULL)
  888.         {
  889.         pDataAtExec->pData = new BYTE[ALLOCBLOCK];
  890.         if (pDataAtExec->pData == NULL)
  891.             {
  892.             return (ConsumeStringTail(pin, bInQuote));
  893.             }
  894.  
  895.         pDataAtExec->cbBuffer = ALLOCBLOCK;
  896.         }
  897.  
  898.     pDataOut = (PSTR) pDataAtExec->pData;
  899.     while (TRUE)
  900.         {
  901.         switch (c = *pin++)
  902.             {
  903.             case ('"'):
  904.                 {
  905.                 // If in quotes, test for escaped quote character.
  906.                 if (bInQuote && *pin == '"')
  907.                     {
  908.                     pDataOut[cbData++] = c;
  909.                     if (CHECKBUFFER(cbData, pDataAtExec))
  910.                         {
  911.                         pDataOut = CheckExtendBuffer(pDataAtExec, cbData);
  912.                         if (pDataOut == NULL)
  913.                             {
  914.                             return (ConsumeStringTail(pin, bInQuote));
  915.                             }
  916.                         }
  917.  
  918.                     pin++;
  919.                     }
  920.                 else
  921.                     {
  922.                     bInQuote = !(bInQuote);
  923.                     }
  924.                 break;
  925.                 }
  926.  
  927.             // CRLF within the string is respected, otherwise CR is
  928.             //  ignored.
  929.             case ('\r'):
  930.                 {
  931.                 if (bInQuote)
  932.                     {
  933.                     pDataOut[cbData++] = c;
  934.                     if (CHECKBUFFER(cbData, pDataAtExec))
  935.                         {
  936.                         pDataOut = CheckExtendBuffer(pDataAtExec, cbData);
  937.                         if (pDataOut == NULL)
  938.                             {
  939.                             return (ConsumeStringTail(pin, bInQuote));
  940.                             }
  941.                         }
  942.                     }
  943.                 
  944.                 break;
  945.                 }
  946.  
  947.             case (NULL):
  948.                 {
  949.                 // If we unexpectedly ran out of string, just return. Else
  950.                 //  fall through to normal terminator processing.
  951.                 if (bInQuote)
  952.                     {
  953.                     return (pin);
  954.                     }
  955.                 }
  956.             case (','):
  957.             case ('\n'):
  958.                 {
  959.                 if (bInQuote)
  960.                     {
  961.                     pDataOut[cbData++] = c;
  962.                     if (CHECKBUFFER(cbData, pDataAtExec))
  963.                         {
  964.                         pDataOut = CheckExtendBuffer(pDataAtExec, cbData);
  965.                         if (pDataOut == NULL)
  966.                             {
  967.                             return (ConsumeStringTail(pin, bInQuote));
  968.                             }
  969.                         }
  970.                     }
  971.                 else
  972.                     {
  973.                     pDataAtExec->cbData = cbData;
  974.                     pDataOut[cbData] = (char) NULL;
  975.  
  976.                     return (pin);
  977.                     }
  978.  
  979.                 break;
  980.                 }
  981.  
  982.             default:
  983.                 {
  984.                 pDataOut[cbData++] = c;
  985.                 if (CHECKBUFFER(cbData, pDataAtExec))
  986.                     {
  987.                     pDataOut = CheckExtendBuffer(pDataAtExec, cbData);
  988.                     if (pDataOut == NULL)
  989.                         {
  990.                         return (ConsumeStringTail(pin, bInQuote));
  991.                         }
  992.                     }
  993.  
  994.                 break;
  995.                 }
  996.             }
  997.         }
  998.  
  999.     // Dummy return for compiler.
  1000.     return (pin);
  1001.     }
  1002.  
  1003. //////////////////////////////////////////////////////////////////////////
  1004. // CheckExtendBuffer(PDATA_AT_EXEC pDataAtExec, UINT cbData)
  1005. //
  1006. // Static reallocates buffer if macro check indicates need.
  1007. PSTR CheckExtendBuffer(PDATA_AT_EXEC pDataAtExec, UINT cbData)
  1008.     {
  1009.     if (cbData == pDataAtExec->cbBuffer)
  1010.         {
  1011.         UINT    cbNew = pDataAtExec->cbBuffer + ALLOCBLOCK;
  1012.         PBYTE   pNew = new BYTE[cbNew];
  1013.  
  1014.         if (pNew == NULL)
  1015.             {
  1016.             // We're out of memory. Free what's allocated here and
  1017.             //  attempt to launch an error message before doing
  1018.             //  anything else.
  1019.             delete [] pDataAtExec->pData;
  1020.             pDataAtExec->pData = NULL;
  1021.  
  1022.             AfxMessageBox(_T("Memory allocation error."));
  1023.             return (NULL);
  1024.             }
  1025.  
  1026.         memcpy(pNew, pDataAtExec->pData, cbData);
  1027.         delete [] pDataAtExec->pData;
  1028.         
  1029.         pDataAtExec->pData = pNew;
  1030.         pDataAtExec->cbBuffer = cbNew;
  1031.         }
  1032.  
  1033.     return ((PSTR) pDataAtExec->pData);
  1034.     }