Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

913 lines
24 KiB

  1. /*
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. sdp.cpp
  5. Abstract:
  6. Author:
  7. */
  8. #include "sdppch.h"
  9. #include <strstrea.h>
  10. #include "sdp.h"
  11. #include "sdpstran.h"
  12. // state transitions for each of the states
  13. const STATE_TRANSITION g_StateStartTransitions[] = {
  14. {CHAR_VERSION, STATE_VERSION}
  15. };
  16. const STATE_TRANSITION g_StateVersionTransitions[] = {
  17. {CHAR_ORIGIN, STATE_ORIGIN}
  18. };
  19. const STATE_TRANSITION g_StateOriginTransitions[] = {
  20. {CHAR_SESSION_NAME, STATE_SESSION_NAME}
  21. };
  22. const STATE_TRANSITION g_StateSessionNameTransitions[] = {
  23. {CHAR_TITLE, STATE_TITLE},
  24. {CHAR_URI, STATE_URI},
  25. {CHAR_EMAIL, STATE_EMAIL},
  26. {CHAR_PHONE, STATE_PHONE},
  27. {CHAR_CONNECTION, STATE_CONNECTION}
  28. };
  29. const STATE_TRANSITION g_StateTitleTransitions[] = {
  30. {CHAR_URI, STATE_URI},
  31. {CHAR_EMAIL, STATE_EMAIL},
  32. {CHAR_PHONE, STATE_PHONE},
  33. {CHAR_CONNECTION, STATE_CONNECTION}
  34. };
  35. const STATE_TRANSITION g_StateUriTransitions[] = {
  36. {CHAR_EMAIL, STATE_EMAIL},
  37. {CHAR_PHONE, STATE_PHONE},
  38. {CHAR_CONNECTION, STATE_CONNECTION}
  39. };
  40. const STATE_TRANSITION g_StateEmailTransitions[] = {
  41. {CHAR_EMAIL, STATE_EMAIL},
  42. {CHAR_PHONE, STATE_PHONE},
  43. {CHAR_CONNECTION, STATE_CONNECTION}
  44. };
  45. const STATE_TRANSITION g_StatePhoneTransitions[] = {
  46. {CHAR_PHONE, STATE_PHONE},
  47. {CHAR_CONNECTION, STATE_CONNECTION}
  48. };
  49. const STATE_TRANSITION g_StateConnectionTransitions[] = {
  50. {CHAR_BANDWIDTH, STATE_BANDWIDTH},
  51. {CHAR_TIME, STATE_TIME},
  52. {CHAR_KEY, STATE_KEY},
  53. {CHAR_ATTRIBUTE, STATE_ATTRIBUTE},
  54. {CHAR_MEDIA, STATE_MEDIA}
  55. };
  56. const STATE_TRANSITION g_StateBandwidthTransitions[] = {
  57. {CHAR_TIME, STATE_TIME},
  58. {CHAR_KEY, STATE_KEY},
  59. {CHAR_ATTRIBUTE, STATE_ATTRIBUTE},
  60. {CHAR_MEDIA, STATE_MEDIA}
  61. };
  62. const STATE_TRANSITION g_StateTimeTransitions[] = {
  63. {CHAR_TIME, STATE_TIME},
  64. {CHAR_REPEAT, STATE_REPEAT},
  65. {CHAR_ADJUSTMENT, STATE_ADJUSTMENT},
  66. {CHAR_KEY, STATE_KEY},
  67. {CHAR_ATTRIBUTE, STATE_ATTRIBUTE},
  68. {CHAR_MEDIA, STATE_MEDIA}
  69. };
  70. const STATE_TRANSITION g_StateRepeatTransitions[] = {
  71. {CHAR_TIME, STATE_TIME},
  72. {CHAR_REPEAT, STATE_REPEAT},
  73. {CHAR_ADJUSTMENT, STATE_ADJUSTMENT},
  74. {CHAR_KEY, STATE_KEY},
  75. {CHAR_ATTRIBUTE, STATE_ATTRIBUTE},
  76. {CHAR_MEDIA, STATE_MEDIA}
  77. };
  78. const STATE_TRANSITION g_StateAdjustmentTransitions[] = {
  79. {CHAR_KEY, STATE_KEY},
  80. {CHAR_ATTRIBUTE, STATE_ATTRIBUTE},
  81. {CHAR_MEDIA, STATE_MEDIA}
  82. };
  83. const STATE_TRANSITION g_StateKeyTransitions[] = {
  84. {CHAR_ATTRIBUTE, STATE_ATTRIBUTE},
  85. {CHAR_MEDIA, STATE_MEDIA}
  86. };
  87. const STATE_TRANSITION g_StateAttributeTransitions[] = {
  88. {CHAR_ATTRIBUTE, STATE_ATTRIBUTE},
  89. {CHAR_MEDIA, STATE_MEDIA}
  90. };
  91. const STATE_TRANSITION g_StateMediaTransitions[] = {
  92. {CHAR_MEDIA, STATE_MEDIA},
  93. {CHAR_MEDIA_TITLE, STATE_MEDIA_TITLE},
  94. {CHAR_MEDIA_CONNECTION, STATE_MEDIA_CONNECTION},
  95. {CHAR_MEDIA_BANDWIDTH, STATE_MEDIA_BANDWIDTH},
  96. {CHAR_MEDIA_KEY, STATE_MEDIA_KEY},
  97. {CHAR_MEDIA_ATTRIBUTE, STATE_MEDIA_ATTRIBUTE}
  98. };
  99. const STATE_TRANSITION g_StateMediaTitleTransitions[] = {
  100. {CHAR_MEDIA, STATE_MEDIA},
  101. {CHAR_MEDIA_CONNECTION, STATE_MEDIA_CONNECTION},
  102. {CHAR_MEDIA_BANDWIDTH, STATE_MEDIA_BANDWIDTH},
  103. {CHAR_MEDIA_KEY, STATE_MEDIA_KEY},
  104. {CHAR_MEDIA_ATTRIBUTE, STATE_MEDIA_ATTRIBUTE}
  105. };
  106. const STATE_TRANSITION g_StateMediaConnectionTransitions[]= {
  107. {CHAR_MEDIA, STATE_MEDIA},
  108. {CHAR_MEDIA_BANDWIDTH, STATE_MEDIA_BANDWIDTH},
  109. {CHAR_MEDIA_KEY, STATE_MEDIA_KEY},
  110. {CHAR_MEDIA_ATTRIBUTE, STATE_MEDIA_ATTRIBUTE}
  111. };
  112. const STATE_TRANSITION g_StateMediaBandwidthTransitions[]= {
  113. {CHAR_MEDIA, STATE_MEDIA},
  114. {CHAR_MEDIA_KEY, STATE_MEDIA_KEY},
  115. {CHAR_MEDIA_ATTRIBUTE, STATE_MEDIA_ATTRIBUTE}
  116. };
  117. const STATE_TRANSITION g_StateMediaKeyTransitions[] = {
  118. {CHAR_MEDIA, STATE_MEDIA},
  119. {CHAR_MEDIA_ATTRIBUTE, STATE_MEDIA_ATTRIBUTE}
  120. };
  121. const STATE_TRANSITION g_StateMediaAttributeTransitions[]={
  122. {CHAR_MEDIA, STATE_MEDIA},
  123. {CHAR_MEDIA_ATTRIBUTE, STATE_MEDIA_ATTRIBUTE},
  124. {CHAR_MEDIA, STATE_MEDIA}
  125. };
  126. // const state transition table definition
  127. const TRANSITION_INFO g_TransitionTable[STATE_NUM_STATES] = {
  128. STATE_TRANSITION_ENTRY(STATE_START, g_StateStartTransitions),
  129. STATE_TRANSITION_ENTRY(STATE_VERSION, g_StateVersionTransitions),
  130. STATE_TRANSITION_ENTRY(STATE_ORIGIN, g_StateOriginTransitions),
  131. STATE_TRANSITION_ENTRY(STATE_SESSION_NAME, g_StateSessionNameTransitions),
  132. STATE_TRANSITION_ENTRY(STATE_TITLE, g_StateTitleTransitions),
  133. STATE_TRANSITION_ENTRY(STATE_URI, g_StateUriTransitions),
  134. STATE_TRANSITION_ENTRY(STATE_EMAIL, g_StateEmailTransitions),
  135. STATE_TRANSITION_ENTRY(STATE_PHONE, g_StatePhoneTransitions),
  136. STATE_TRANSITION_ENTRY(STATE_CONNECTION, g_StateConnectionTransitions),
  137. STATE_TRANSITION_ENTRY(STATE_BANDWIDTH, g_StateBandwidthTransitions),
  138. STATE_TRANSITION_ENTRY(STATE_TIME, g_StateTimeTransitions),
  139. STATE_TRANSITION_ENTRY(STATE_REPEAT, g_StateRepeatTransitions),
  140. STATE_TRANSITION_ENTRY(STATE_ADJUSTMENT, g_StateAdjustmentTransitions),
  141. STATE_TRANSITION_ENTRY(STATE_KEY, g_StateKeyTransitions),
  142. STATE_TRANSITION_ENTRY(STATE_ATTRIBUTE, g_StateAttributeTransitions),
  143. STATE_TRANSITION_ENTRY(STATE_MEDIA, g_StateMediaTransitions),
  144. STATE_TRANSITION_ENTRY(STATE_MEDIA_TITLE, g_StateMediaTitleTransitions),
  145. STATE_TRANSITION_ENTRY(STATE_MEDIA_CONNECTION, g_StateMediaConnectionTransitions),
  146. STATE_TRANSITION_ENTRY(STATE_MEDIA_BANDWIDTH, g_StateMediaBandwidthTransitions),
  147. STATE_TRANSITION_ENTRY(STATE_MEDIA_KEY, g_StateMediaKeyTransitions),
  148. STATE_TRANSITION_ENTRY(STATE_MEDIA_ATTRIBUTE, g_StateMediaAttributeTransitions)
  149. };
  150. BOOL
  151. SDP::Init(
  152. )
  153. {
  154. // check if already initialized
  155. if ( NULL != m_MediaList )
  156. {
  157. SetLastError(ERROR_ALREADY_INITIALIZED);
  158. return FALSE;
  159. }
  160. // create media and time lists
  161. // set flags to destroy them when the sdp instance destructs
  162. try
  163. {
  164. m_MediaList = new SDP_MEDIA_LIST;
  165. }
  166. catch(...)
  167. {
  168. m_MediaList = NULL;
  169. }
  170. if ( NULL == m_MediaList )
  171. {
  172. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  173. return FALSE;
  174. }
  175. m_DestroyMediaList = TRUE;
  176. try
  177. {
  178. m_TimeList = new SDP_TIME_LIST;
  179. }
  180. catch(...)
  181. {
  182. m_TimeList = NULL;
  183. }
  184. if ( NULL == m_TimeList )
  185. {
  186. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  187. return FALSE;
  188. }
  189. m_DestroyTimeList = TRUE;
  190. return TRUE;
  191. }
  192. // determine the character set implicit from the packet
  193. BOOL
  194. SDP::DetermineCharacterSet(
  195. IN CHAR *SdpPacket,
  196. OUT SDP_CHARACTER_SET &CharacterSet
  197. )
  198. {
  199. ASSERT(NULL != SdpPacket);
  200. // search for charset string (attribute "\na=charset:")
  201. CHAR *AttributeString = strstr(SdpPacket, SDP_CHARACTER_SET_STRING);
  202. // check if the character set is supplied
  203. if ( NULL == AttributeString )
  204. {
  205. // ASCII is the default character set
  206. CharacterSet = CS_ASCII;
  207. return TRUE;
  208. }
  209. else
  210. {
  211. // the character set attribute string must be present before the first media field
  212. CHAR *FirstMediaField = strstr(SdpPacket, MEDIA_SEARCH_STRING);
  213. // there is a media field and it doesn't occur after the character set string, signal error
  214. if ( (NULL != FirstMediaField) &&
  215. (FirstMediaField <= AttributeString) )
  216. {
  217. SetLastError(SDP_INVALID_CHARACTER_SET_FORMAT);
  218. return FALSE;
  219. }
  220. // advance attribute string beyond the attribute specification
  221. AttributeString += SDP_CHARACTER_SET_STRLEN;
  222. // compare the character set string with each of the well known
  223. // character set strings
  224. for ( UINT i=0; i < NUM_SDP_CHARACTER_SET_ENTRIES; i++ )
  225. {
  226. // NOTE: no need to null terminate the character string as
  227. // strncmp will return on finding the first character that
  228. // doesn't match
  229. if ( !strncmp(
  230. AttributeString,
  231. SDP_CHARACTER_SET_TABLE[i].m_CharSetString,
  232. SDP_CHARACTER_SET_TABLE[i].m_Length
  233. ) )
  234. {
  235. CharacterSet = SDP_CHARACTER_SET_TABLE[i].m_CharSetCode;
  236. return TRUE;
  237. }
  238. }
  239. // unrecognized character set
  240. SetLastError(SDP_INVALID_CHARACTER_SET);
  241. return FALSE;
  242. }
  243. // the code should not reach here
  244. ASSERT(FALSE);
  245. }
  246. /*
  247. Assumption: We are at the start of a new line. There may or may not be a
  248. new line character before current
  249. */
  250. BOOL
  251. SDP::GetType(
  252. OUT CHAR &Type,
  253. OUT BOOL &EndOfPacket
  254. )
  255. {
  256. // ensure that we don't peek beyond the end of the string
  257. if ( EOS == m_Current[0] )
  258. {
  259. EndOfPacket = TRUE;
  260. return TRUE;
  261. }
  262. // check if the second char is EQUAL_CHAR
  263. if ( CHAR_EQUAL != m_Current[1] )
  264. {
  265. SetLastError(SDP_INVALID_FORMAT);
  266. return FALSE;
  267. }
  268. EndOfPacket = FALSE;
  269. Type = m_Current[0];
  270. return TRUE;
  271. }
  272. BOOL
  273. SDP::CheckTransition(
  274. IN CHAR Type,
  275. IN PARSE_STATE CurrentParseState,
  276. OUT PARSE_STATE &NewParseState
  277. )
  278. {
  279. // validate the current state
  280. ASSERT(STATE_NUM_STATES > CurrentParseState);
  281. // validate transition table entry
  282. ASSERT(g_TransitionTable[CurrentParseState].m_ParseState == CurrentParseState);
  283. // see if such a trigger exists for the current state
  284. for( UINT i=0; i < g_TransitionTable[CurrentParseState].m_NumTransitions; i++ )
  285. {
  286. // check if trigger has been found
  287. if ( Type == g_TransitionTable[CurrentParseState].m_Transitions[i].m_Type )
  288. {
  289. NewParseState = g_TransitionTable[CurrentParseState].m_Transitions[i].m_NewParseState;
  290. break;
  291. }
  292. }
  293. // check if a trigger was found
  294. if ( g_TransitionTable[CurrentParseState].m_NumTransitions <= i )
  295. {
  296. SetLastError(SDP_INVALID_FORMAT);
  297. return FALSE;
  298. }
  299. return TRUE;
  300. }
  301. BOOL
  302. SDP::GetValue(
  303. IN CHAR Type
  304. )
  305. {
  306. PARSE_STATE NewParseState;
  307. // check if such a transition (current parse state --Type--> new parse state) exists
  308. if ( !CheckTransition(Type, m_ParseState, NewParseState) )
  309. {
  310. return FALSE;
  311. }
  312. BOOL LineParseResult = FALSE;
  313. // fire corresponding action
  314. switch(NewParseState)
  315. {
  316. case STATE_VERSION:
  317. {
  318. LineParseResult = m_ProtocolVersion.ParseLine(m_Current);
  319. }
  320. break;
  321. case STATE_ORIGIN:
  322. {
  323. LineParseResult = m_Origin.ParseLine(m_Current);
  324. }
  325. break;
  326. case STATE_SESSION_NAME:
  327. {
  328. LineParseResult = m_SessionName.ParseLine(m_Current);
  329. }
  330. break;
  331. case STATE_TITLE:
  332. {
  333. LineParseResult = m_SessionTitle.ParseLine(m_Current);
  334. }
  335. break;
  336. case STATE_URI:
  337. {
  338. LineParseResult = m_Uri.ParseLine(m_Current);
  339. }
  340. break;
  341. case STATE_EMAIL:
  342. {
  343. LineParseResult = m_EmailList.ParseLine(m_Current);
  344. }
  345. break;
  346. case STATE_PHONE:
  347. {
  348. LineParseResult = m_PhoneList.ParseLine(m_Current);
  349. }
  350. break;
  351. case STATE_CONNECTION:
  352. {
  353. LineParseResult = m_Connection.ParseLine(m_Current);
  354. }
  355. break;
  356. case STATE_BANDWIDTH:
  357. {
  358. LineParseResult = m_Bandwidth.ParseLine(m_Current);
  359. }
  360. break;
  361. case STATE_TIME:
  362. {
  363. LineParseResult = GetTimeList().ParseLine(m_Current);
  364. }
  365. break;
  366. case STATE_REPEAT:
  367. {
  368. ParseMember(SDP_TIME, GetTimeList(), SDP_REPEAT_LIST, GetRepeatList, m_Current, LineParseResult);
  369. }
  370. break;
  371. case STATE_ADJUSTMENT:
  372. {
  373. LineParseResult = GetTimeList().GetAdjustment().ParseLine(m_Current);
  374. }
  375. break;
  376. case STATE_KEY:
  377. {
  378. LineParseResult = m_EncryptionKey.ParseLine(m_Current);
  379. }
  380. break;
  381. case STATE_ATTRIBUTE:
  382. {
  383. LineParseResult = m_AttributeList.ParseLine(m_Current);
  384. }
  385. break;
  386. case STATE_MEDIA:
  387. {
  388. LineParseResult = GetMediaList().ParseLine(m_Current);
  389. }
  390. break;
  391. case STATE_MEDIA_TITLE:
  392. {
  393. ParseMember(SDP_MEDIA, GetMediaList(), SDP_REQD_BSTRING_LINE, GetTitle, m_Current, LineParseResult);
  394. }
  395. break;
  396. case STATE_MEDIA_CONNECTION:
  397. {
  398. ParseMember(SDP_MEDIA, GetMediaList(), SDP_CONNECTION, GetConnection, m_Current, LineParseResult);
  399. }
  400. break;
  401. case STATE_MEDIA_BANDWIDTH:
  402. {
  403. ParseMember(SDP_MEDIA, GetMediaList(), SDP_BANDWIDTH, GetBandwidth, m_Current, LineParseResult);
  404. }
  405. break;
  406. case STATE_MEDIA_KEY:
  407. {
  408. ParseMember(SDP_MEDIA, GetMediaList(), SDP_ENCRYPTION_KEY, GetEncryptionKey, m_Current, LineParseResult);
  409. }
  410. break;
  411. case STATE_MEDIA_ATTRIBUTE:
  412. {
  413. ParseMember(SDP_MEDIA, GetMediaList(), SDP_ATTRIBUTE_LIST, GetAttributeList, m_Current, LineParseResult);
  414. }
  415. break;
  416. default:
  417. {
  418. // should never reach here
  419. ASSERT(FALSE);
  420. SetLastError(SDP_INVALID_FORMAT);
  421. return FALSE;
  422. }
  423. break;
  424. };
  425. // check if parsing the line succeeded
  426. if ( !LineParseResult )
  427. {
  428. return FALSE;
  429. }
  430. // change to the new state
  431. m_ParseState = NewParseState;
  432. return TRUE;
  433. }
  434. BOOL
  435. SDP::IsValidEndState(
  436. ) const
  437. {
  438. if ( (STATE_CONNECTION <= m_ParseState) &&
  439. (STATE_NUM_STATES > m_ParseState) )
  440. {
  441. return TRUE;
  442. }
  443. SetLastError(SDP_INVALID_FORMAT);
  444. return FALSE;
  445. }
  446. void
  447. SDP::Reset(
  448. )
  449. {
  450. // perform the destructor actions (release any allocated resources)
  451. // free the sdp packet if one was created
  452. if ( NULL != m_SdpPacket )
  453. {
  454. delete m_SdpPacket;
  455. m_SdpPacket = NULL;
  456. }
  457. // perform the constructor actions (initialize variables, resources)
  458. // initialize the parse state
  459. m_ParseState = STATE_START;
  460. m_LastGenFailed = FALSE;
  461. m_BytesAllocated = 0;
  462. m_SdpPacketLength = 0;
  463. m_Current = NULL;
  464. m_ParseState = STATE_START;
  465. // m_CharacterSet - nothing needs to be set
  466. m_CharacterSet = CS_UTF8;
  467. // reset the member instances
  468. m_ProtocolVersion.Reset();
  469. m_Origin.Reset();
  470. m_SessionName.Reset();
  471. m_SessionTitle.Reset();
  472. m_Uri.Reset();
  473. m_EmailList.Reset();
  474. m_PhoneList.Reset();
  475. m_Connection.Reset();
  476. m_Bandwidth.Reset();
  477. GetTimeList().Reset();
  478. m_EncryptionKey.Reset();
  479. m_AttributeList.Reset();
  480. GetMediaList().Reset();
  481. }
  482. BOOL
  483. SDP::ParseSdpPacket(
  484. IN CHAR *SdpPacket,
  485. IN SDP_CHARACTER_SET CharacterSet
  486. )
  487. {
  488. ASSERT(NULL != m_MediaList);
  489. ASSERT(NULL != m_TimeList);
  490. // check if the instance has already parsed an sdp packet
  491. if ( NULL != m_Current )
  492. {
  493. // reset the instance and try to parse the sdp packet
  494. Reset();
  495. }
  496. // check if the passed in parameters are valid
  497. if ( (NULL == SdpPacket) || (CS_INVALID == CharacterSet) )
  498. {
  499. SetLastError(SDP_INVALID_PARAMETER);
  500. return FALSE;
  501. }
  502. // point the current pointer to the start of sdp packet
  503. m_Current = SdpPacket;
  504. // if the character set has not yet been determined
  505. if ( CS_IMPLICIT == CharacterSet )
  506. {
  507. // determine the character set
  508. if ( !DetermineCharacterSet(SdpPacket, m_CharacterSet) )
  509. {
  510. return FALSE;
  511. }
  512. }
  513. else // it cannot be CS_UNRECOGNIZED (checked on entry)
  514. {
  515. ASSERT(CS_INVALID != CharacterSet);
  516. m_CharacterSet = CharacterSet;
  517. }
  518. // set the character sets for all the SDP_BSTRING instances that make up the SDP description
  519. m_Origin.GetUserName().SetCharacterSet(m_CharacterSet);
  520. m_SessionName.GetBstring().SetCharacterSet(m_CharacterSet);
  521. m_SessionTitle.GetBstring().SetCharacterSet(m_CharacterSet);
  522. m_EmailList.SetCharacterSet(m_CharacterSet);
  523. m_PhoneList.SetCharacterSet(m_CharacterSet);
  524. // set the character set for the SDP_MEDIA_LIST instance
  525. GetMediaList().SetCharacterSet(m_CharacterSet);
  526. // parse the type and its value for each line in the sdp packet
  527. do
  528. {
  529. BOOL EndOfPacket;
  530. CHAR Type;
  531. // get the next type
  532. if ( !GetType(Type, EndOfPacket) )
  533. {
  534. return FALSE;
  535. }
  536. if ( EndOfPacket )
  537. {
  538. break;
  539. }
  540. // advance the current pointer to beyond the Type= fields
  541. m_Current+=2;
  542. // get the value for the specified type
  543. if ( !GetValue(Type) )
  544. {
  545. return FALSE;
  546. }
  547. }
  548. while ( 1 );
  549. // validate if the parsing state is a valid end state
  550. if ( !IsValidEndState() )
  551. {
  552. return FALSE;
  553. }
  554. return TRUE;
  555. }
  556. // clears the modified state for each member field/value
  557. // this is used in sdpblb.dll to clear the modified state (when an sdp
  558. // is parsed in, the state of all parsed in fields/values is modified) and
  559. // the m_WasModified dirty flag
  560. void
  561. SDP::ClearModifiedState(
  562. )
  563. {
  564. m_ProtocolVersion.GetCharacterStringSize();
  565. m_Origin.GetCharacterStringSize();
  566. m_SessionName.GetCharacterStringSize();
  567. m_SessionTitle.GetCharacterStringSize();
  568. m_Uri.GetCharacterStringSize();
  569. m_EmailList.GetCharacterStringSize();
  570. m_PhoneList.GetCharacterStringSize();
  571. m_Connection.GetCharacterStringSize();
  572. m_Bandwidth.GetCharacterStringSize();
  573. GetTimeList().GetCharacterStringSize();
  574. m_EncryptionKey.GetCharacterStringSize();
  575. m_AttributeList.GetCharacterStringSize();
  576. GetMediaList().GetCharacterStringSize();
  577. }
  578. BOOL
  579. SDP::IsValid(
  580. )
  581. {
  582. // query only the mandatory values
  583. return
  584. m_ProtocolVersion.IsValid() &&
  585. m_Origin.IsValid() &&
  586. m_SessionName.IsValid() &&
  587. m_Connection.IsValid();
  588. }
  589. BOOL
  590. SDP::IsModified(
  591. )
  592. {
  593. ASSERT(IsValid());
  594. return
  595. m_ProtocolVersion.IsModified() ||
  596. m_Origin.IsModified() ||
  597. m_SessionName.IsModified() ||
  598. m_SessionTitle.IsModified() ||
  599. m_Uri.IsModified() ||
  600. m_EmailList.IsModified() ||
  601. m_PhoneList.IsModified() ||
  602. m_Connection.IsModified() ||
  603. m_Bandwidth.IsModified() ||
  604. GetTimeList().IsModified() ||
  605. m_EncryptionKey.IsModified() ||
  606. m_AttributeList.IsModified() ||
  607. GetMediaList().IsModified();
  608. }
  609. // an sdp packet is not generated the way a line is generated (using a SeparatorChar and
  610. // an sdp field carray). this is mainly because these carrays will have to be modified on
  611. // insertion of email and phone lists, media fields and attribute lists or specification of
  612. // other optional sdp properties.
  613. CHAR *
  614. SDP::GenerateSdpPacket(
  615. )
  616. {
  617. // check if valid
  618. if ( !IsValid() )
  619. {
  620. return NULL;
  621. }
  622. // check if the sdp packet needs to be regenerated
  623. // (if the sdp packet exists and no modifications have taken place since
  624. // the last time)
  625. BOOL HasChangedSinceLast = IsModified();
  626. if ( (!m_LastGenFailed) && (NULL != m_SdpPacket) && !HasChangedSinceLast )
  627. {
  628. return m_SdpPacket;
  629. }
  630. // determine the length of character string
  631. m_SdpPacketLength =
  632. m_ProtocolVersion.GetCharacterStringSize() +
  633. m_Origin.GetCharacterStringSize() +
  634. m_SessionName.GetCharacterStringSize() +
  635. m_SessionTitle.GetCharacterStringSize() +
  636. m_Uri.GetCharacterStringSize() +
  637. m_EmailList.GetCharacterStringSize() +
  638. m_PhoneList.GetCharacterStringSize() +
  639. m_Connection.GetCharacterStringSize() +
  640. m_Bandwidth.GetCharacterStringSize() +
  641. GetTimeList().GetCharacterStringSize() +
  642. m_EncryptionKey.GetCharacterStringSize() +
  643. m_AttributeList.GetCharacterStringSize() +
  644. GetMediaList().GetCharacterStringSize();
  645. // check if a buffer needs to be allocated, allocate if required
  646. if ( m_BytesAllocated < (m_SdpPacketLength+1) )
  647. {
  648. CHAR * NewSdpPacket;
  649. try
  650. {
  651. NewSdpPacket = new CHAR[m_SdpPacketLength+1];
  652. }
  653. catch(...)
  654. {
  655. NewSdpPacket = NULL;
  656. }
  657. if (NewSdpPacket == NULL)
  658. {
  659. m_LastGenFailed = TRUE;
  660. return NULL;
  661. }
  662. // if we have an old sdp packet, get rid of it now
  663. if ( NULL != m_SdpPacket )
  664. {
  665. delete m_SdpPacket;
  666. }
  667. m_SdpPacket = NewSdpPacket;
  668. m_BytesAllocated = m_SdpPacketLength+1;
  669. }
  670. // fill in the buffer
  671. ostrstream OutputStream(m_SdpPacket, m_BytesAllocated);
  672. // if this method ever fails here for this instance, further calls to the
  673. // method without modification will return a ptr
  674. if ( !( m_ProtocolVersion.PrintValue(OutputStream) &&
  675. m_Origin.PrintValue(OutputStream) &&
  676. m_SessionName.PrintValue(OutputStream) &&
  677. m_SessionTitle.PrintValue(OutputStream) &&
  678. m_Uri.PrintValue(OutputStream) &&
  679. m_EmailList.PrintValue(OutputStream) &&
  680. m_PhoneList.PrintValue(OutputStream) &&
  681. m_Connection.PrintValue(OutputStream) &&
  682. m_Bandwidth.PrintValue(OutputStream) &&
  683. GetTimeList().PrintValue(OutputStream) &&
  684. m_EncryptionKey.PrintValue(OutputStream) &&
  685. m_AttributeList.PrintValue(OutputStream) &&
  686. GetMediaList().PrintValue(OutputStream) )
  687. )
  688. {
  689. m_LastGenFailed = TRUE;
  690. return NULL;
  691. }
  692. OutputStream << EOS;
  693. m_LastGenFailed = FALSE;
  694. // dirty flag - is initially false and is set to TRUE when an sdp is generated because it had
  695. // been modified since the last time the sdp was generated.
  696. // NOTE: at this point IsModified() is false, so m_WasModified captures the fact that
  697. // the sdp was modified at some point
  698. if ( !m_WasModified && HasChangedSinceLast )
  699. {
  700. m_WasModified = TRUE;
  701. }
  702. return m_SdpPacket;
  703. }
  704. SDP::~SDP(
  705. )
  706. {
  707. if ( NULL != m_SdpPacket )
  708. {
  709. delete m_SdpPacket;
  710. }
  711. if ( m_DestroyMediaList && (NULL != m_MediaList) )
  712. {
  713. delete m_MediaList;
  714. }
  715. if ( m_DestroyTimeList && (NULL != m_TimeList) )
  716. {
  717. delete m_TimeList;
  718. }
  719. }