sdpchunk.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:42k
源码类别:

Symbian

开发平台:

C/C++

  1. /* ***** BEGIN LICENSE BLOCK ***** 
  2.  * Version: RCSL 1.0/RPSL 1.0 
  3.  *  
  4.  * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. 
  5.  *      
  6.  * The contents of this file, and the files included with this file, are 
  7.  * subject to the current version of the RealNetworks Public Source License 
  8.  * Version 1.0 (the "RPSL") available at 
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed 
  10.  * the file under the RealNetworks Community Source License Version 1.0 
  11.  * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, 
  12.  * in which case the RCSL will apply. You may also obtain the license terms 
  13.  * directly from RealNetworks.  You may not use this file except in 
  14.  * compliance with the RPSL or, if you have a valid RCSL with RealNetworks 
  15.  * applicable to this file, the RCSL.  Please see the applicable RPSL or 
  16.  * RCSL for the rights, obligations and limitations governing use of the 
  17.  * contents of the file.  
  18.  *  
  19.  * This file is part of the Helix DNA Technology. RealNetworks is the 
  20.  * developer of the Original Code and owns the copyrights in the portions 
  21.  * it created. 
  22.  *  
  23.  * This file, and the files included with this file, is distributed and made 
  24.  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  25.  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  26.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
  27.  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  28.  * 
  29.  * Technology Compatibility Kit Test Suite(s) Location: 
  30.  *    http://www.helixcommunity.org/content/tck 
  31.  * 
  32.  * Contributor(s): 
  33.  *  
  34.  * ***** END LICENSE BLOCK ***** */ 
  35. /****************************************************************************
  36.  *  Defines
  37.  */
  38. #define DFLT_PAYLOAD_MIME_TYPE   "data/x-unknown"
  39. #define CHAR_LF 0x0a
  40. #define CHAR_CR 0x0d
  41. #define BAD_PULL_TABLE_IDX  0xFFFFFFFF
  42. #define MAX_INT_TEXT_LENGTH 10
  43. #define N_CLIPRECT_COORDS   4
  44. #define FMPT_PREFIX     "FMTP"
  45. #define FMPT_PREFIX_SIZE    (sizeof(FMPT_PREFIX) - 1)
  46. /****************************************************************************
  47.  *  Includes
  48.  */
  49. //#include "hlxclib/stdlib.h"
  50. #include "hxstrutl.h"
  51. #include "hxassert.h"
  52. #include "sdpchunk.h"
  53. #include "hxstring.h"
  54. #include "hxslist.h"
  55. #include "sdppyldinfo.h"
  56. /****************************************************************************
  57.  *  Locals
  58.  */
  59. /****************************************************************************
  60.  *  Pull Functions
  61. */
  62. static HX_RESULT PullSessionName(char* pData,
  63.                                  ULONG32 ulLength,
  64.                                  IHXValues* pSDPValues,
  65.                                  IHXCommonClassFactory* pClassFactory);
  66. static HX_RESULT PullMediaDesc (char* pData,
  67.                                  ULONG32 ulLength, 
  68.                                  IHXValues* pSDPValues,
  69.                                  IHXCommonClassFactory* pClassFactory);
  70. static HX_RESULT PullRTPMap (char* pData,
  71.                                  ULONG32 ulLength, 
  72.                                  IHXValues* pSDPValues,
  73.                                  IHXCommonClassFactory* pClassFactory);
  74. static HX_RESULT PullControl (char* pData,
  75.                                  ULONG32 ulLength, 
  76.                                  IHXValues* pSDPValues,
  77.                                  IHXCommonClassFactory* pClassFactory);
  78. static HX_RESULT PullClipRect (char* pData, 
  79.                                  ULONG32 ulLength, 
  80.                                  IHXValues* pSDPValues,
  81.                                  IHXCommonClassFactory* pClassFactory);
  82. static HX_RESULT PullBufferDelay(char* pData, 
  83.                                  ULONG32 ulLength, 
  84.                                  IHXValues* pSDPValues,
  85.                                  IHXCommonClassFactory* pClassFactory);
  86. static HX_RESULT PullFormatParams(char* pData, 
  87.                                  ULONG32 ulLength, 
  88.                                  IHXValues* pSDPValues,
  89.                                  IHXCommonClassFactory* pClassFactory);
  90. static HX_RESULT PullGroupID (char* pData, 
  91.                                  ULONG32 ulLength, 
  92.                                  IHXValues* pSDPValues,
  93.                                  IHXCommonClassFactory* pClassFactory);
  94. static HX_RESULT PullGroupBitrate(char* pData, 
  95.                                  ULONG32 ulLength, 
  96.                                  IHXValues* pSDPValues,
  97.                                  IHXCommonClassFactory* pClassFactory);
  98. static HX_RESULT PullBandwidth (char* pData,
  99.                                  ULONG32 ulLength, 
  100.                                  IHXValues* pSDPValues,
  101.                                  IHXCommonClassFactory* pClassFactory);
  102. /****************************************************************************
  103.  *  Local Utilities
  104.  */
  105. inline static ULONG32 GetPullTableIdx(const SDPRecordPuller* pTable,
  106.                                       char* pData, 
  107.                                       ULONG32 ulRecordSize);
  108. inline static char* FindSDPFieldByIdx(char* pData, 
  109.                                       ULONG32 ulLength, 
  110.                                       ULONG32 ulIdx);
  111. inline static char* FindSDPFieldEnd(char* pData, 
  112.                                     ULONG32 ulLength);
  113. inline static char* FindCRLF(char* pData, 
  114.                              ULONG32 ulLength);
  115. inline static HX_RESULT  PullLine(char* pData, 
  116.                              ULONG32 ulLength,
  117.                              REF(IHXBuffer*) pLine,
  118.                              IHXCommonClassFactory* pClassFactory);
  119. inline static char* SkipSDPFieldEnd(char* pData,
  120.                                     ULONG32 ulLength);
  121. inline static void OrderUp(LONG32 &l1, LONG32 &l2);
  122. /****************************************************************************
  123.  *  Pull Tables - must be NULL terminated
  124.  */
  125. const SDPRecordPuller SessionPullTable[] =
  126. {
  127.     {"s=",     sizeof("s=") - 1, PullSessionName},
  128.     {"b=",     sizeof("b=") - 1, PullBandwidth},
  129.     {NULL,     0, NULL}
  130. };
  131. const SDPRecordPuller MediaPullTable[] =
  132. {
  133.     {"m=",     sizeof("m=") - 1, PullMediaDesc},
  134.     {"a=rtpmap:",    sizeof("a=rtpmap:") - 1, PullRTPMap},
  135.     {"a=control:",   sizeof("a=control:") - 1, NULL},
  136.     {"b=",     sizeof("b=") - 1, PullBandwidth},
  137.     {NULL,     0, NULL}
  138. };
  139. const SDPRecordPuller TimePullTable[] =
  140. {
  141.     {NULL,     0, NULL}
  142. };
  143. const SDPRecordPuller GenericPullTable[] =
  144. {
  145.     {NULL,     0, NULL}
  146. };
  147. const SDPRecordPuller RendererPullTable[] =
  148. {
  149.     {"a=cliprect:", sizeof("a=cliprect:") - 1, PullClipRect},
  150.     {"a=x-bufferdelay:", sizeof("a=x-bufferdelay:") - 1, PullBufferDelay}, 
  151.     {"a=fmtp:", sizeof("a=fmtp:") - 1, PullFormatParams},
  152.     {NULL, 0, NULL}
  153. };
  154. const SDPRecordPuller GroupPullTable[] =
  155. {
  156.     {"a=x-alternate:group=", sizeof("a=x-alternate:group=") - 1, PullGroupID},
  157.     {"a=x-alternate:datarate=", sizeof("a=x-alternate:datarate=") - 1, PullGroupBitrate},
  158.     {NULL, 0, NULL}
  159. };
  160. /****************************************************************************
  161.  *  Global Utility fuinctions
  162.  */
  163. /****************************************************************************
  164.  *  SDPParseChunk - use context
  165.  */
  166. HX_RESULT SDPParseChunk(char* pData,
  167.                         ULONG32 ulDataLen,
  168.                         IHXValues* &pSDPValues,
  169.                         IHXCommonClassFactory *pClassFactory,
  170.                         SDPChunkContext SDPContext,
  171.                         BOOL bPullRecords)
  172. {
  173.     HX_RESULT retVal = HXR_OK;
  174.     const SDPRecordPuller* pPullTable = NULL;
  175.     switch (SDPContext)
  176.     {
  177.     case SDPCTX_Media:
  178.         pPullTable = MediaPullTable;
  179.         break;
  180.     case SDPCTX_Session:
  181.         pPullTable = SessionPullTable;
  182.         break;
  183.     case SDPCTX_Group:
  184.         pPullTable = GroupPullTable;
  185.         break;
  186.     case SDPCTX_Time:
  187.         pPullTable = TimePullTable;
  188.         break;
  189.     case SDPCTX_Generic:
  190.         pPullTable = GenericPullTable;
  191.         break;
  192.     case SDPCTX_Renderer:
  193.         pPullTable = RendererPullTable;
  194.         break;
  195.     default:
  196.         retVal = HXR_INVALID_PARAMETER;
  197.         break;
  198.     }
  199.     if (SUCCEEDED(retVal))
  200.     {
  201.         retVal = SDPParseChunk(pData,
  202.                                ulDataLen,
  203.                                pSDPValues,
  204.                                pClassFactory,
  205.                                pPullTable,
  206.                                bPullRecords);
  207.     }
  208.     return retVal;
  209. }
  210. /****************************************************************************
  211.  *  SDPParseChunk - use custom pull table
  212.  */
  213. HX_RESULT SDPParseChunk(char* pData,
  214.                         ULONG32 ulDataLen,
  215.                         IHXValues* &pSDPValues,
  216.                         IHXCommonClassFactory *pClassFactory,
  217.                         const SDPRecordPuller* pPullTable,
  218.                         BOOL bPullRecords)
  219. {
  220.     HX_RESULT retVal = HXR_OK;
  221.     IHXBuffer* pSDPBuffer = NULL;
  222.     char* pSDPData = NULL;
  223.     char* pPattern;
  224.     ULONG32 ulRecordSize;
  225.     ULONG32 ulPullTableIdx;
  226.     BOOL bSDPValuesMadeHere = FALSE;
  227.     
  228.     if ((pData == NULL) || (ulDataLen == 0))
  229.     {
  230.         if (pSDPValues == NULL)
  231.         {
  232.             retVal = HXR_FAIL;
  233.         }
  234.         return retVal;
  235.     }
  236.     if (!pSDPValues)
  237.     {
  238.         bSDPValuesMadeHere = TRUE;
  239.         retVal = pClassFactory->CreateInstance(CLSID_IHXValues,
  240.                                                  (void**) &pSDPValues);
  241.     }
  242.     if (bPullRecords)
  243.     {
  244.         if (SUCCEEDED(retVal))
  245.         {
  246.             retVal = pClassFactory->CreateInstance(CLSID_IHXBuffer,
  247.                 (void**) &pSDPBuffer);
  248.         }
  249.         
  250.         if (SUCCEEDED(retVal))
  251.         {
  252.             retVal = pSDPBuffer->SetSize(ulDataLen + 1);
  253.         }
  254.     }
  255.     if (SUCCEEDED(retVal))
  256.     {
  257.         if (pPullTable == NULL)
  258.         {
  259.             retVal = HXR_INVALID_PARAMETER;
  260.         }
  261.     }
  262.     if (SUCCEEDED(retVal))
  263.     {
  264.         if (pSDPBuffer)
  265.         {
  266.             pSDPData = (char*) pSDPBuffer->GetBuffer();
  267.         }
  268.         
  269.         do
  270.         {
  271.             pPattern = StrNChr(pData, CHAR_LF, ulDataLen);
  272.             if (pPattern == NULL)
  273.             {
  274.                 ulRecordSize = ulDataLen;
  275.             }
  276.             else
  277.             {
  278.                 ulRecordSize = pPattern - pData;
  279.                 pPattern = SkipSDPFieldEnd(pPattern, 
  280.                                            ulDataLen - ulRecordSize);
  281.                 ulRecordSize = pPattern - pData;
  282.             }
  283.             
  284.             ulPullTableIdx = GetPullTableIdx(pPullTable, 
  285.                                              pData,
  286.                                              ulRecordSize);
  287.             if (ulPullTableIdx == BAD_PULL_TABLE_IDX)
  288.             {
  289.                 if (pSDPData)
  290.                 {
  291.                     // keep this entry as SDP data
  292.                     memcpy(pSDPData, pData, ulRecordSize); /* Flawfinder: ignore */
  293.                     pSDPData += ulRecordSize;
  294.                 }
  295.             }
  296.             else
  297.             {
  298.                 // pull this record out of SDP data
  299.                 if (pPullTable[ulPullTableIdx].pPullFunc)
  300.                 {
  301.                     retVal = (*(pPullTable[ulPullTableIdx].pPullFunc))(
  302.                                     pData,
  303.                                     ulRecordSize,
  304.                                     pSDPValues,
  305.                                     pClassFactory);
  306.                 }
  307.             }
  308.             pData +=  ulRecordSize;
  309.             ulDataLen -= ulRecordSize;
  310.         } while ((ulDataLen != 0) && SUCCEEDED(retVal));
  311.     }
  312.    
  313.     if (SUCCEEDED(retVal) && pSDPData)
  314.     {
  315.         HX_ASSERT(((ULONG32) (pSDPData - ((char *) pSDPBuffer->GetBuffer())) )
  316.                   < pSDPBuffer->GetSize());
  317.         if (((char *) pSDPBuffer->GetBuffer()) != pSDPData)
  318.         {
  319.             *pSDPData = '';
  320.             pSDPValues->SetPropertyCString("SDPData", pSDPBuffer);
  321.         }
  322.     }
  323.     HX_RELEASE(pSDPBuffer);
  324.     if (FAILED(retVal) && bSDPValuesMadeHere)
  325.     {
  326.         HX_RELEASE(pSDPValues);
  327.     }
  328.     return retVal;
  329. }
  330. /****************************************************************************
  331.  *  SDPMapPayloadToMime
  332.  */
  333. HX_RESULT SDPMapPayloadToMime(ULONG32 ulPayloadType,
  334.                               IHXBuffer* &pMimeType,
  335.                               IHXCommonClassFactory *pClassFactory)
  336. {
  337.     HX_RESULT retVal = HXR_OK;
  338.     HX_ASSERT(pClassFactory);
  339.     if (!pMimeType)
  340.     {
  341.         retVal = pClassFactory->CreateInstance(CLSID_IHXBuffer,
  342.                                                (void**) &pMimeType);
  343.     }
  344.     if (SUCCEEDED(retVal))
  345.     {
  346.         const char* pPayloadMime = DFLT_PAYLOAD_MIME_TYPE;
  347.         if (SDPIsKnownPayload(ulPayloadType))
  348.         {
  349.             pPayloadMime = SDPMapPayloadToMimeType(ulPayloadType);
  350.         }
  351.         retVal = pMimeType->Set((UCHAR*) pPayloadMime, 
  352.                                 strlen(pPayloadMime) + 1);
  353.     }
  354.     return retVal;
  355. }
  356. /****************************************************************************
  357.  *  SDPIsFixedRatePayload
  358.  */
  359. BOOL SDPIsFixedRatePayload(ULONG32 ulPayloadType)
  360. {
  361.     if (SDPIsStaticPayload(ulPayloadType))
  362.     {
  363.         return !SDPIsTimestampDeliverable(ulPayloadType);
  364.     }
  365.     return FALSE;
  366. }
  367. /****************************************************************************
  368.  *  SDPMapMimeToSamplesPerSecond
  369.  */
  370. ULONG32 SDPMapMimeToSamplesPerSecond(IHXBuffer* pMimeTypeBuffer)
  371. {
  372.     ULONG32 ulPayload = 0;
  373.     ULONG32 ulSamplesPerSecond = 0;
  374.     if (SUCCEEDED(SDPMapMimeToPayload(pMimeTypeBuffer, ulPayload)))
  375.     {
  376.         ulSamplesPerSecond = SDPMapPayloadToSamplesPerSecond(ulPayload);
  377.     }
  378.     else
  379.     {
  380.         const char* pTargetMimeType = (const char*)pMimeTypeBuffer->GetBuffer();
  381.         ulSamplesPerSecond = SDPMapMimeTypeToSampleRate(pTargetMimeType);
  382.     }
  383.     return ulSamplesPerSecond;
  384. }
  385. /****************************************************************************
  386.  *  SDPIsKnownPayload
  387.  */
  388. BOOL SDPIsKnownPayload(ULONG32 ulPayloadType)
  389. {
  390.     return (SDPIsStaticPayload(ulPayloadType) &&
  391.             (SDPMapPayloadToMimeType(ulPayloadType) != NULL));
  392. }
  393. /****************************************************************************
  394.  *  SDPMapMimeToPayloadID
  395.  */
  396. HX_RESULT SDPMapMimeToPayload(IHXBuffer* pMimeTypeBuffer, ULONG32 &ulPayload)
  397. {
  398.     ULONG32 ulId;
  399.     HX_RESULT retVal = HXR_FAIL;
  400.     char* pMimeType = NULL;
  401.     char* pEncodingName;
  402.     if (pMimeTypeBuffer)
  403.     {
  404.         pMimeType = (char *) pMimeTypeBuffer->GetBuffer();
  405.     }
  406.     if (pMimeType &&
  407.         (pEncodingName = strchr((char*) pMimeType, '/')))
  408.     {
  409.         pEncodingName++;
  410.         
  411.         for (ulId = 0; SDPIsStaticPayload(ulId); ulId++)
  412.         {
  413.             if (SDPMapPayloadToEncodingName(ulId) &&
  414.                 !strcasecmp(SDPMapPayloadToEncodingName(ulId),
  415.                             pEncodingName))
  416.             {
  417.                 ulPayload = ulId;
  418.                 retVal = HXR_OK;
  419.                 break;
  420.             }
  421.         }
  422.     }
  423.     return retVal;
  424. }
  425. /****************************************************************************
  426.  *  Pull Functions
  427.  */
  428. /****************************************************************************
  429.  *  Pull Functions
  430.  */
  431. /*
  432.  * "s=" text CRLF
  433.  */
  434. static HX_RESULT PullSessionName(char* pData,
  435.                                  ULONG32 ulLength,
  436.                                  IHXValues* pSDPValues,
  437.                                  IHXCommonClassFactory* pClassFactory)
  438. {
  439.     HX_ASSERT(pData && !strncmp(pData, "s=", 2));
  440.     HX_RESULT retVal = HXR_FAIL;
  441.     IHXBuffer* pSessionName = NULL;
  442.     retVal = PullLine(pData + 2, ulLength - 2, pSessionName, pClassFactory);
  443.     if (SUCCEEDED(retVal))
  444.     {
  445.       retVal = pSDPValues->SetPropertyCString("Title", pSessionName);
  446.     }
  447.     HX_RELEASE(pSessionName);
  448.     return retVal;
  449. }
  450. static HX_RESULT PullMediaDesc (char* pData, 
  451.                                  ULONG32 ulLength, 
  452.                                  IHXValues* pSDPValues,
  453.                                  IHXCommonClassFactory* pClassFactory)
  454. {
  455.     char* pPattern;
  456.     ULONG32 ulPayloadType = 0;
  457.     IHXBuffer* pMimeType = NULL;
  458.     HX_RESULT retVal = HXR_FAIL;
  459.     // Extract Payload Type
  460.     pPattern = FindSDPFieldByIdx(pData, ulLength, 3);
  461.     if (pPattern != NULL)
  462.     {
  463.         char pNumBuffer[MAX_INT_TEXT_LENGTH + 1]; /* Flawfinder: ignore */
  464.         char* pNumEnd;
  465.         ULONG32 ulNumTextLength = (ulLength - (pPattern - pData));
  466.         if (ulNumTextLength > MAX_INT_TEXT_LENGTH)
  467.         {
  468.             ulNumTextLength = MAX_INT_TEXT_LENGTH;
  469.         }
  470.         memcpy(pNumBuffer, pPattern, ulNumTextLength); /* Flawfinder: ignore */
  471.         pNumBuffer[ulNumTextLength] = '';
  472.         ulPayloadType = strtol(pNumBuffer, &pNumEnd, 10);
  473.         if (pNumEnd > pNumBuffer)
  474.         {
  475.             retVal = HXR_OK;
  476.         }
  477.     }
  478.     // Prepare Mime Type
  479.     if (SUCCEEDED(retVal))
  480.     {
  481.         const char* pPayloadMime = NULL;
  482.         ULONG32 ulPayloadMimeLength = 0;
  483.         char* pMimeStart = NULL;
  484.         ULONG32 ulMimeLength = 0;
  485.         if (SDPIsStaticPayload(ulPayloadType))
  486.         {
  487.             pPayloadMime = SDPMapPayloadToEncodingName(ulPayloadType);
  488.             retVal = HXR_FAIL;
  489.             if (pPayloadMime != NULL)
  490.             {
  491.                 ulPayloadMimeLength = strlen(pPayloadMime) + 1;
  492.                 pSDPValues->SetPropertyULONG32(
  493.                     "SamplesPerSecond",
  494.                     SDPMapPayloadToSamplesPerSecond(ulPayloadType));
  495.                 UINT16 uChannels = 
  496.                     SDPMapPayloadToChannels(ulPayloadType);
  497.                 if (uChannels > 0)
  498.                 {
  499.                     pSDPValues->SetPropertyULONG32(
  500.                         "Channels",
  501.                         uChannels);
  502.                 }
  503.                 retVal = HXR_OK;
  504.             }
  505.         }
  506.         if (SUCCEEDED(retVal))
  507.         {
  508.             // extract portion of mime type
  509.             // - will be completed when rtp map encountered
  510.             // if this is not a static payload
  511.             pPattern = StrNChr((char *) pData, ' ', ulLength);
  512.             pMimeStart = pData + 2;
  513.             
  514.             retVal = HXR_FAIL;
  515.             
  516.             if ((pPattern != NULL) &&
  517.                 ((pPattern - pData) > 2))
  518.             {
  519.                 ulMimeLength = pPattern - pData - 2;
  520.                 
  521.                 retVal = pClassFactory->CreateInstance(
  522.                     CLSID_IHXBuffer,
  523.                     (void**) &pMimeType);
  524.             }
  525.             
  526.             if (SUCCEEDED(retVal))
  527.             {
  528.                 retVal = pMimeType->SetSize(ulMimeLength + 
  529.                                             ulPayloadMimeLength + 
  530.                                             1);
  531.             }
  532.             
  533.             if (SUCCEEDED(retVal))
  534.             {
  535.                 memcpy(pMimeType->GetBuffer(), /* Flawfinder: ignore */
  536.                        pMimeStart, 
  537.                        ulMimeLength);
  538.                 if (ulPayloadMimeLength > 0)
  539.                 {
  540.                     memcpy(pMimeType->GetBuffer() + ulMimeLength + 1, /* Flawfinder: ignore */
  541.                            pPayloadMime, 
  542.                            ulPayloadMimeLength - 1);
  543.                     pMimeType->GetBuffer()[ulMimeLength] = '/';
  544.                 }
  545.                 
  546.                 pMimeType->GetBuffer()[ulMimeLength + 
  547.                                        ulPayloadMimeLength] = '';
  548.             }
  549.         }
  550.     }
  551.     if (SUCCEEDED(retVal))
  552.     {
  553.         pSDPValues->SetPropertyULONG32("RTPPayloadType", ulPayloadType);
  554.         pSDPValues->SetPropertyCString("MimeType", pMimeType);
  555.     }
  556.     HX_RELEASE(pMimeType);
  557.     return retVal;
  558. }
  559. static HX_RESULT PullRTPMap(char* pData, 
  560.                             ULONG32 ulLength, 
  561.                             IHXValues* pSDPValues,
  562.                             IHXCommonClassFactory* pClassFactory)
  563. {
  564.     char* pPattern = NULL;
  565.     char* pPatternEnd = NULL;
  566.     char pNumBuffer[MAX_INT_TEXT_LENGTH + 1]; /* Flawfinder: ignore */
  567.     char* pNumEnd = NULL;
  568.     ULONG32 ulPatternLength = 0;
  569.     ULONG32 ulPayloadType = 0;
  570.     ULONG32 ulMediaPayloadType = 0;
  571.     HX_RESULT retVal = HXR_FAIL;
  572.     // Extract the Payload Type
  573.     pPattern = StrNChr((char *) pData, ':',  ulLength);
  574.     if (pPattern)
  575.     {
  576.         ulPatternLength = (ulLength - ((++pPattern) - pData));
  577.         if (ulPatternLength > MAX_INT_TEXT_LENGTH)
  578.         {
  579.             ulPatternLength = MAX_INT_TEXT_LENGTH;
  580.         }
  581.         memcpy(pNumBuffer, pPattern, ulPatternLength); /* Flawfinder: ignore */
  582.         pNumBuffer[ulPatternLength] = '';
  583.         ulPayloadType = strtol(pNumBuffer, &pNumEnd, 10);
  584.         
  585.         if (pNumEnd > pNumBuffer)
  586.         {
  587.             retVal = pSDPValues->GetPropertyULONG32(
  588.                 "RTPPayloadType", ulMediaPayloadType);
  589.         }
  590.     }
  591.     // Check if this is the payload type entry we are looking for
  592.     if (SUCCEEDED(retVal) && 
  593.         (ulMediaPayloadType == ulPayloadType))
  594.     {
  595.         IHXBuffer* pMimeType = NULL;
  596.         ULONG32 ulOldMimeTextLength;
  597.         BOOL bHasParams = TRUE;
  598.         // Locate New and Old Mime Name Section
  599.         pPattern = StrNChr((char *) pData, ' ',  ulLength);
  600.         retVal = HXR_FAIL;
  601.         if (pPattern)
  602.         {
  603.             pPattern++;
  604.             
  605.             pPatternEnd = StrNChr(pPattern, 
  606.                                   '/',
  607.                                   ulLength - (pPattern - pData));
  608.             if (pPatternEnd == NULL)
  609.             {
  610.                 bHasParams = FALSE;
  611.                 pPatternEnd = FindSDPFieldEnd(pPattern,
  612.                                               ulLength - (pPattern - pData));
  613.             }
  614.             
  615.             ulPatternLength = pPatternEnd - pPattern;
  616.             
  617.             if (ulPatternLength != 0)
  618.             {
  619.                 retVal = pSDPValues->GetPropertyCString(
  620.                     "MimeType", pMimeType);
  621.             }
  622.         }
  623.         // Realocate memory for combined name
  624.         if (SUCCEEDED(retVal))
  625.         {
  626.             pMimeType->Release();   // OK since pSDPValues has ref.
  627.             ulOldMimeTextLength = pMimeType->GetSize() - 1;
  628.             retVal = pMimeType->SetSize(
  629.                 ulOldMimeTextLength + ulPatternLength + 2);
  630.         }
  631.         // Copy in new Mime Name section
  632.         if (SUCCEEDED(retVal))
  633.         {
  634.             char *pMimeData = (char*) pMimeType->GetBuffer();
  635.             memcpy(pMimeData + ulOldMimeTextLength + 1, /* Flawfinder: ignore */
  636.                    pPattern,
  637.                    ulPatternLength);
  638.             pMimeData[ulOldMimeTextLength] = '/';
  639.             pMimeData[pMimeType->GetSize() - 1] = '';
  640.         }
  641.         // Check for parameters following mime type
  642.         if (SUCCEEDED(retVal))
  643.         {
  644.             ULONG32 ulParamIdx = 0;
  645.             while (bHasParams)
  646.             {
  647.                 pPattern += ulPatternLength + 1;
  648.                  
  649.                 pPatternEnd = StrNChr(pPattern, 
  650.                                       '/',
  651.                                       ulLength - (pPattern - pData));
  652.                 if (pPatternEnd == NULL)
  653.                 {
  654.                     bHasParams = FALSE;
  655.                     pPatternEnd = FindSDPFieldEnd(
  656.                                     pPattern,
  657.                                     ulLength - (pPattern - pData));
  658.                 }
  659.                 ulPatternLength = pPatternEnd - pPattern;
  660.             
  661.                 if (ulPatternLength != 0)
  662.                 {
  663.                     LONG32 lValue;
  664.                     if (ulPatternLength > MAX_INT_TEXT_LENGTH)
  665.                     {
  666.                         ulPatternLength = MAX_INT_TEXT_LENGTH;
  667.                     }
  668.                     
  669.                     memcpy(pNumBuffer, pPattern, ulPatternLength); /* Flawfinder: ignore */
  670.                     pNumBuffer[ulPatternLength] = '';
  671.                     
  672.                     lValue = strtol(pNumBuffer, &pNumEnd, 10);
  673.                     if (pNumEnd > pNumBuffer)
  674.                     {
  675.                         switch (ulParamIdx)
  676.                         {
  677.                         case 0:
  678.                             pSDPValues->SetPropertyULONG32(
  679.                                 "SamplesPerSecond", (ULONG32) lValue);
  680.                             break;
  681.                         case 1:
  682.                             pSDPValues->SetPropertyULONG32(
  683.                                 "Channels", (ULONG32) lValue);
  684.                             break;
  685.                         default:
  686.                             // do nothing
  687.                             break;
  688.                         }
  689.                     }
  690.                 }
  691.                 ulParamIdx++;
  692.             }
  693.         }
  694.     }
  695.     return retVal;
  696. }
  697. static HX_RESULT PullControl(char* pData, 
  698.                              ULONG32 ulLength, 
  699.                              IHXValues* pSDPValues,
  700.                              IHXCommonClassFactory* pClassFactory)
  701. {
  702.     char* pPattern = NULL;
  703.     char* pPatternEnd = NULL;
  704.     ULONG32 ulPatternLength = 0;
  705.     IHXBuffer* pControl = NULL;
  706.     HX_RESULT retVal = HXR_FAIL;
  707.     pPattern = StrNChr((char *) pData, ':', ulLength);
  708.     if (pPattern)
  709.     {
  710.         pPattern++;
  711.         pPatternEnd = FindSDPFieldEnd(
  712.             pPattern, ulLength - (pPattern - pData));
  713.         ulPatternLength = pPatternEnd - pPattern;
  714.         if (ulPatternLength > 0)
  715.         {
  716.             retVal = pClassFactory->CreateInstance(
  717.                 CLSID_IHXBuffer,
  718.                 (void**) &pControl);
  719.         }
  720.     }
  721.     if (SUCCEEDED(retVal))
  722.     {
  723.         retVal = pControl->SetSize(ulPatternLength + 1);
  724.         memcpy(pControl->GetBuffer(), /* Flawfinder: ignore */
  725.                pPattern, 
  726.                ulPatternLength);
  727.         (pControl->GetBuffer())[ulPatternLength] = '';
  728.         pSDPValues->SetPropertyCString("Control", pControl);
  729.         HX_RELEASE(pControl);
  730.     }
  731.     return retVal;
  732. }
  733. static HX_RESULT PullClipRect(char* pData, 
  734.                               ULONG32 ulLength, 
  735.                               IHXValues* pSDPValues,
  736.                               IHXCommonClassFactory* pClassFactory)
  737. {
  738.     char* pPattern;
  739.     ULONG32 ulPatternLength;
  740.     char pNumBuffer[MAX_INT_TEXT_LENGTH + 1]; /* Flawfinder: ignore */
  741.     char* pNumEnd;
  742.     ULONG32 ulIdx = 0;
  743.     LONG32 lCoord[N_CLIPRECT_COORDS];
  744.     HX_RESULT retVal = HXR_FAIL;
  745.     pPattern = StrNChr((char *) pData, ':', ulLength);
  746.     if (pPattern)
  747.     {
  748.         do
  749.         {
  750.             ulPatternLength = (ulLength - ((++pPattern) - pData));
  751.             
  752.             if (ulPatternLength > MAX_INT_TEXT_LENGTH)
  753.             {
  754.                 ulPatternLength = MAX_INT_TEXT_LENGTH;
  755.             }
  756.             
  757.             memcpy(pNumBuffer, pPattern, ulPatternLength); /* Flawfinder: ignore */
  758.             pNumBuffer[ulPatternLength] = '';
  759.             
  760.             lCoord[ulIdx] = strtol(pNumBuffer, &pNumEnd, 10);
  761.             if (pNumEnd == pNumBuffer)
  762.             {
  763.                 break;
  764.             }
  765.         } while (((++ulIdx) < N_CLIPRECT_COORDS) &&
  766.                  (pPattern = StrNChr((char *) pPattern, ',', ulLength)));
  767.         if (ulIdx == N_CLIPRECT_COORDS)
  768.         {
  769.             retVal = HXR_OK;
  770.         }
  771.     }
  772.     if (SUCCEEDED(retVal))
  773.     {
  774.         OrderUp(lCoord[0], lCoord[2]);
  775.         OrderUp(lCoord[1], lCoord[3]);
  776.         pSDPValues->SetPropertyULONG32("ClipFrameLeft", lCoord[1]);
  777.         pSDPValues->SetPropertyULONG32("ClipFrameRight", lCoord[3]);
  778.         pSDPValues->SetPropertyULONG32("ClipFrameTop", lCoord[0]);
  779.         pSDPValues->SetPropertyULONG32("ClipFrameBottom", lCoord[2]);
  780.     }
  781.     return retVal;
  782. }
  783. static HX_RESULT PullFormatParams(char* pData, 
  784.                                   ULONG32 ulLength, 
  785.                                   IHXValues* pSDPValues,
  786.                                   IHXCommonClassFactory* pClassFactory)
  787. {
  788.     char* pPattern = NULL;
  789.     char* pPatternEnd = NULL;
  790.     BOOL bParmNumeric = FALSE;
  791.     ULONG32 ulParmValue = 0;
  792.     ULONG32 ulPatternLength = 0;
  793.     char* pParmName = NULL;
  794.     IHXBuffer* pParmValue = NULL;
  795.     HX_RESULT retVal = HXR_FAIL;
  796.     // Find the start of name-value tuple
  797.     pPattern = FindSDPFieldEnd((char*) pData, ulLength);
  798.     if (pPattern)
  799.     {
  800.         ulPatternLength = (ulLength - (pPattern - pData));
  801.         retVal = HXR_OK;
  802.     }
  803.     do
  804.     {
  805.         // Find the start of name-value tuple
  806.         if (SUCCEEDED(retVal))
  807.         {
  808.             retVal = HXR_FAIL;
  809.             
  810.             pPattern = SkipSDPFieldEnd(pPattern, ulPatternLength);
  811.             if (pPattern)
  812.             {
  813.                 ulPatternLength = (ulLength - (pPattern - pData));
  814.                 retVal = HXR_OK;
  815.             }
  816.         }
  817.         if (SUCCEEDED(retVal))
  818.         {
  819.             if (ulPatternLength == 0)
  820.             {
  821.                 // Done: no more tuples
  822.                 break;
  823.             }
  824.         }
  825.         // Parse the tuple name
  826.         if (SUCCEEDED(retVal))
  827.         {
  828.             retVal = HXR_FAIL;
  829.             pPatternEnd = StrNChr((char*) pPattern, '=', ulPatternLength);
  830.             if (pPatternEnd)
  831.             {
  832.                 retVal = HXR_OK;
  833.             }
  834.         }
  835.         if (SUCCEEDED(retVal))
  836.         {
  837.             retVal = HXR_FAIL;
  838.             ulPatternLength = pPatternEnd - pPattern;
  839.             if (ulPatternLength > 0)
  840.             {
  841.                 retVal = HXR_OK;
  842.             }
  843.         }
  844.         if (SUCCEEDED(retVal))
  845.         {
  846.             retVal = HXR_OUTOFMEMORY;
  847.             pParmName = new char [ulPatternLength + FMPT_PREFIX_SIZE + 1];
  848.             if (pParmName)
  849.             {
  850.                 retVal = HXR_OK;
  851.             }
  852.         }
  853.         if (SUCCEEDED(retVal))
  854.         {
  855.             memcpy(pParmName, /* Flawfinder: ignore */
  856.                    FMPT_PREFIX,
  857.                    FMPT_PREFIX_SIZE);
  858.             memcpy(pParmName + FMPT_PREFIX_SIZE, /* Flawfinder: ignore */
  859.                    pPattern, 
  860.                    ulPatternLength);
  861.             pParmName[ulPatternLength + FMPT_PREFIX_SIZE] = '';
  862.             pPattern = pPatternEnd;
  863.             ulPatternLength = (ulLength - ((++pPattern) - pData));
  864.         }
  865.         // Parse the tuple value
  866.         if (SUCCEEDED(retVal))
  867.         {
  868.             retVal = HXR_FAIL;
  869.             pPatternEnd = StrNChr(pPattern, ';', ulPatternLength);
  870.             if (!pPatternEnd)
  871.             {
  872.                 pPatternEnd = FindSDPFieldEnd(pPattern, ulPatternLength);
  873.             }
  874.             if (pPatternEnd)
  875.             {
  876.                 ulPatternLength = pPatternEnd - pPattern;
  877.             }
  878.             if (ulPatternLength > 0)
  879.             {
  880.                 retVal = HXR_OK;
  881.             }
  882.         }
  883.         bParmNumeric = FALSE;
  884.         if (SUCCEEDED(retVal) && (ulPatternLength <= (MAX_INT_TEXT_LENGTH - 1)))
  885.         {
  886.             char pNumBuffer[MAX_INT_TEXT_LENGTH + 1]; /* Flawfinder: ignore */
  887.             char* pNumEnd = NULL;
  888.             memcpy(pNumBuffer, pPattern, ulPatternLength); /* Flawfinder: ignore */
  889.             pNumBuffer[ulPatternLength] = '';
  890.             ulParmValue = strtol(pNumBuffer, &pNumEnd, 10);
  891.             if (pNumEnd && (pNumEnd == (pNumBuffer + ulPatternLength)))
  892.             {
  893.                 bParmNumeric = TRUE;
  894.             }
  895.         }
  896.         if (bParmNumeric)
  897.         {
  898.             if (SUCCEEDED(retVal))
  899.             {
  900.                 retVal = pSDPValues->SetPropertyULONG32(pParmName, 
  901.                                                         ulParmValue);
  902.             }
  903.         }
  904.         else
  905.         {
  906.             if (SUCCEEDED(retVal))
  907.             {
  908.                 retVal = pClassFactory->CreateInstance(CLSID_IHXBuffer,
  909.                     (void**) &pParmValue);
  910.             }
  911.             
  912.             if (SUCCEEDED(retVal))
  913.             {
  914.                 retVal = pParmValue->SetSize(ulPatternLength + 1);
  915.             }
  916.             
  917.             if (SUCCEEDED(retVal))
  918.             {
  919.                 UINT8* pBufferData = pParmValue->GetBuffer();
  920.                 memcpy(pBufferData, pPattern, ulPatternLength); /* Flawfinder: ignore */
  921.                 pBufferData[ulPatternLength] = '';
  922.                 
  923.                 retVal = pSDPValues->SetPropertyCString(pParmName, pParmValue);
  924.             }
  925.         }
  926.         if (SUCCEEDED(retVal))
  927.         {
  928.             ulPatternLength = 0;
  929.             pPattern = pPatternEnd;
  930.             if (pPattern)
  931.             {
  932.                 ulPatternLength = (ulLength - ((++pPattern) - pData));
  933.             }
  934.         }
  935.         HX_VECTOR_DELETE(pParmName);
  936.         HX_RELEASE(pParmValue);
  937.     } while (SUCCEEDED(retVal) && (ulPatternLength != 0));
  938.     return retVal;
  939. }
  940. static HX_RESULT PullBufferDelay(char* pData, 
  941.                                  ULONG32 ulLength, 
  942.                                  IHXValues* pSDPValues,
  943.                                  IHXCommonClassFactory* pClassFactory)
  944. {
  945.     char* pPattern;
  946.     ULONG32 ulPatternLength;
  947.     char pNumBuffer[MAX_INT_TEXT_LENGTH + 1]; /* Flawfinder: ignore */
  948.     char* pNumEnd;
  949.     ULONG32 ulPreroll;
  950.     double fPreroll;
  951.     HX_RESULT retVal = HXR_FAIL;
  952.     if (pSDPValues->GetPropertyULONG32("Preroll", ulPreroll) != HXR_OK)
  953.     {
  954.         pPattern = StrNChr((char *) pData, ':', ulLength);
  955.         if (pPattern)
  956.         {
  957.             ulPatternLength = (ulLength - ((++pPattern) - pData));
  958.             
  959.             if (ulPatternLength > MAX_INT_TEXT_LENGTH)
  960.             {
  961.                 ulPatternLength = MAX_INT_TEXT_LENGTH;
  962.             }
  963.             
  964.             memcpy(pNumBuffer, pPattern, ulPatternLength); /* Flawfinder: ignore */
  965.             pNumBuffer[ulPatternLength] = '';
  966.             
  967.             fPreroll = strtod(pNumBuffer, &pNumEnd);
  968.             
  969.             if (pNumEnd > pNumBuffer)
  970.             {
  971.                 retVal = pSDPValues->SetPropertyULONG32(
  972.                     "Preroll", 
  973.                     (ULONG32) (fPreroll * 1000.0 + 0.5));
  974.             }
  975.         }
  976.     }
  977.     return retVal;
  978. }
  979. static HX_RESULT PullGroupID(char* pData, 
  980.                              ULONG32 ulLength, 
  981.                              IHXValues* pSDPValues,
  982.                              IHXCommonClassFactory* pClassFactory)
  983. {
  984.     char* pPattern;
  985.     ULONG32 ulPatternLength;
  986.     char pNumBuffer[MAX_INT_TEXT_LENGTH + 1]; /* Flawfinder: ignore */
  987.     char* pNumEnd;
  988.     ULONG32 ulGroupID;
  989.     HX_RESULT retVal = HXR_FAIL;
  990.     pPattern = StrNChr((char *) pData, ':', ulLength);
  991.     if (pPattern)
  992.     {
  993.         ulPatternLength = (ulLength - ((++pPattern) - pData));
  994.         pPattern = StrNChr((char *) pPattern, '=', ulPatternLength);
  995.     }
  996.     
  997.     if (pPattern)
  998.     {
  999.         ulPatternLength = (ulLength - ((++pPattern) - pData));
  1000.         
  1001.         if (ulPatternLength > MAX_INT_TEXT_LENGTH)
  1002.         {
  1003.             ulPatternLength = MAX_INT_TEXT_LENGTH;
  1004.         }
  1005.         
  1006.         memcpy(pNumBuffer, pPattern, ulPatternLength); /* Flawfinder: ignore */
  1007.         pNumBuffer[ulPatternLength] = '';
  1008.         
  1009.         ulGroupID = strtol(pNumBuffer, &pNumEnd, 10);
  1010.                 
  1011.         if (pNumEnd > pNumBuffer)
  1012.         {
  1013.             retVal = pSDPValues->SetPropertyULONG32(
  1014.                 "AlternateGroupID",
  1015.                 ulGroupID);
  1016.         }
  1017.     }
  1018.     return retVal;
  1019. }
  1020. static HX_RESULT PullGroupBitrate(char* pData, 
  1021.                                   ULONG32 ulLength, 
  1022.                                   IHXValues* pSDPValues,
  1023.                                   IHXCommonClassFactory* pClassFactory)
  1024. {
  1025.     char* pPattern;
  1026.     ULONG32 ulPatternLength;
  1027.     char pNumBuffer[MAX_INT_TEXT_LENGTH + 1]; /* Flawfinder: ignore */
  1028.     char* pNumEnd;
  1029.     ULONG32 ulGroupBitrate;
  1030.     HX_RESULT retVal = HXR_FAIL;
  1031.     pPattern = StrNChr((char *) pData, ':', ulLength);
  1032.    
  1033.     if (pPattern)
  1034.     {
  1035.         ulPatternLength = (ulLength - ((++pPattern) - pData));
  1036.         
  1037.         pPattern = StrNChr((char *) pPattern, '=', ulPatternLength);
  1038.     }
  1039.     if (pPattern)
  1040.     {
  1041.         ulPatternLength = (ulLength - ((++pPattern) - pData));
  1042.         
  1043.         if (ulPatternLength > MAX_INT_TEXT_LENGTH)
  1044.         {
  1045.             ulPatternLength = MAX_INT_TEXT_LENGTH;
  1046.         }
  1047.         
  1048.         memcpy(pNumBuffer, pPattern, ulPatternLength); /* Flawfinder: ignore */
  1049.         pNumBuffer[ulPatternLength] = '';
  1050.         
  1051.         ulGroupBitrate = strtol(pNumBuffer, &pNumEnd, 10);
  1052.                 
  1053.         if (pNumEnd > pNumBuffer)
  1054.         {
  1055.             retVal = pSDPValues->SetPropertyULONG32(
  1056.                 "AlternateGroupBitrate",
  1057.                 ulGroupBitrate);
  1058.         }
  1059.     }
  1060.     return retVal;
  1061. }
  1062. static HX_RESULT PullBandwidth (char* pData,
  1063.                                  ULONG32 ulLength, 
  1064.                                  IHXValues* pSDPValues,
  1065.                                  IHXCommonClassFactory* pClassFactory)
  1066. {        
  1067.     char* pPattern;
  1068.     ULONG32 ulPatternLength;
  1069.     char pNumBuffer[MAX_INT_TEXT_LENGTH + 1]; /* Flawfinder: ignore */
  1070.     char* pNumEnd;
  1071.     HX_RESULT retVal = HXR_FAIL;
  1072.     char* pPropName = NULL;
  1073.     ULONG32 ulBandwidth = 0;
  1074.     
  1075.     pPattern = StrNChr((char *) pData, ':', ulLength);           
  1076.     if (pPattern)
  1077.     {
  1078.         ulPatternLength = (ulLength - ((++pPattern) - pData));
  1079.         
  1080.         if (ulPatternLength > MAX_INT_TEXT_LENGTH)
  1081.         {
  1082.             ulPatternLength = MAX_INT_TEXT_LENGTH;
  1083.         }
  1084.         
  1085.         memcpy(pNumBuffer, pPattern, ulPatternLength); /* Flawfinder: ignore */
  1086.         pNumBuffer[ulPatternLength] = '';
  1087.         
  1088.         ulBandwidth = strtol(pNumBuffer, &pNumEnd, 10);
  1089.         if (pNumEnd > pNumBuffer)
  1090.         {     
  1091.     // skip b=
  1092.     pData += 2;
  1093.     ulLength -= 2;
  1094.     if (StrNStr((char*)pData, "AS:", ulLength, 3))
  1095.     {        
  1096. pPropName = "AvgBitRate";
  1097. ulBandwidth *= 1000;
  1098.     }
  1099.     else if (StrNStr((char*)pData, "RR:", ulLength, 3))
  1100.     {        
  1101. pPropName = "RtcpRRRate";
  1102.     }
  1103.     else if (StrNStr((char*)pData, "RS:", ulLength, 3))
  1104.     {        
  1105. pPropName = "RtcpRSRate";
  1106.     }
  1107.     else
  1108.     {
  1109. // fine, ignore
  1110. retVal = HXR_OK;
  1111.     }    
  1112.         }
  1113. if (pPropName)
  1114. {
  1115.     retVal = pSDPValues->SetPropertyULONG32(pPropName, ulBandwidth);     
  1116. }
  1117.     }
  1118.     return retVal;
  1119. }
  1120. /****************************************************************************
  1121.  *  Local Utilities
  1122.  */
  1123. inline static ULONG32 GetPullTableIdx(const SDPRecordPuller* pTable,
  1124.                                       char* pData, 
  1125.                                       ULONG32 ulRecordSize)
  1126. {
  1127.     ULONG32 ulIdx = 0;
  1128.     HX_ASSERT(pTable);
  1129.     while (pTable->pSDPMatch != NULL)
  1130.     {
  1131.         if (pTable->ulSDPMatchSize <= ulRecordSize)
  1132.         {
  1133.             if (!strncmp(pTable->pSDPMatch, 
  1134.                          pData, 
  1135.                          pTable->ulSDPMatchSize))
  1136.             {
  1137.                 return ulIdx;
  1138.             }
  1139.         }
  1140.         pTable++;
  1141.         ulIdx++;
  1142.     }
  1143.     return BAD_PULL_TABLE_IDX;
  1144. }
  1145. inline static char* FindSDPFieldByIdx(char* pData, 
  1146.                                        ULONG32 ulLength, 
  1147.                                        ULONG32 ulIdx)
  1148. {
  1149.     char* pField;
  1150.     while((ulIdx != 0) && (pData != NULL))
  1151.     {
  1152.         pField = StrNChr((char *) pData, ' ', ulLength);
  1153.         if (pField)
  1154.         {
  1155.             ulLength -= ((++pField) - pData);  
  1156.             ulIdx--;
  1157.         }
  1158.         pData = pField;
  1159.     } 
  1160.     if (ulLength == 0)
  1161.     {
  1162.         pData = NULL;
  1163.     }
  1164.     return pData;
  1165. }
  1166. inline static char* FindSDPFieldEnd(char* pData, 
  1167.                                      ULONG32 ulLength)
  1168. {
  1169.     while((ulLength != 0) &&
  1170.           (*pData != ' ') &&
  1171.           (*pData != CHAR_CR) &&
  1172.           (*pData != CHAR_LF))
  1173.     {
  1174.         pData++;
  1175.         ulLength--;
  1176.     } 
  1177.     return pData;
  1178. }
  1179. inline static char* FindCRLF(char* pData, 
  1180.                              ULONG32 ulLength)
  1181. {
  1182.     HX_ASSERT(pData && ulLength);
  1183.     
  1184.     while((0 != ulLength) &&
  1185.           (CHAR_CR != *pData))
  1186.     {
  1187.         pData++;
  1188.         ulLength--;
  1189.     } 
  1190.     if (ulLength)
  1191.     {
  1192.         if (*(pData+1) == CHAR_LF)
  1193.         {
  1194.             // found it
  1195.             return pData;
  1196.         }
  1197.         else
  1198.         {
  1199.             pData++;
  1200.             ulLength--;
  1201.             return FindCRLF(pData, ulLength);
  1202.         }
  1203.     }
  1204.     return NULL;
  1205. }
  1206. /*
  1207.  * saves what pData points to upto CRLF sequence in pLine ('' terminated)
  1208.  */
  1209. inline static HX_RESULT PullLine(char* pData, 
  1210.                              ULONG32 ulLength,
  1211.                              REF(IHXBuffer*) pLine,
  1212.                              IHXCommonClassFactory* pClassFactory)
  1213. {
  1214.     HX_ASSERT(pData && ulLength);
  1215.     
  1216.     char* pc = NULL;
  1217.     HX_RESULT retVal = HXR_FAIL;
  1218.     pc = FindCRLF((char*)pData, ulLength);
  1219.     if (pc)
  1220.     {
  1221.         HX_ASSERT((pc > pData) && (ulLength > (ULONG32)(pc - pData)));
  1222.         ulLength = pc - pData;
  1223.         retVal = HXR_OK;
  1224.     }
  1225.     if (SUCCEEDED(retVal))
  1226.     {
  1227.         retVal = pClassFactory->CreateInstance
  1228.             (CLSID_IHXBuffer, (void**) &pLine);
  1229.     }
  1230.     if (SUCCEEDED(retVal))
  1231.     {
  1232.         retVal = pLine->SetSize(ulLength + 1);
  1233.         BYTE* pcLine = pLine->GetBuffer();
  1234.         memcpy(pcLine, pData, ulLength); /* Flawfinder: ignore */
  1235.         pcLine[ulLength] = '';
  1236.     }
  1237.     return retVal;            
  1238. }
  1239. inline static char* SkipSDPFieldEnd(char* pData, ULONG32 ulSize)
  1240. {
  1241.     while((ulSize > 0) &&
  1242.           ((*pData == CHAR_CR) ||
  1243.            (*pData == CHAR_LF) ||
  1244.            (*pData == ' ')))
  1245.     {
  1246.         pData++;
  1247.         ulSize--;
  1248.     } 
  1249.     return pData;
  1250. }
  1251. inline static void OrderUp(LONG32 &l1, LONG32 &l2)
  1252. {
  1253.     LONG32 temp;
  1254.     if (l1 > l2)
  1255.     {
  1256.         temp = l1;
  1257.         l1 = l2;
  1258.         l2 = temp;
  1259.     }
  1260. }