Source code of Windows XP (NT5)
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.

926 lines
27 KiB

  1. //
  2. // util.cpp
  3. //
  4. // utility functions used by updiag.exe
  5. //
  6. #include "pch.h"
  7. #pragma hdrstop
  8. #include "oleauto.h"
  9. #include "ncbase.h"
  10. #include "ncinet.h"
  11. #include "ssdpapi.h"
  12. #include "util.h"
  13. //
  14. // Functions for Standard State Table Operations
  15. //
  16. DWORD Do_Set(UPNPSVC * psvc, OPERATION_DATA * pOpData, DWORD cArgs, ARG *rgArgs);
  17. DWORD Do_Assign(UPNPSVC * psvc, OPERATION_DATA * pOpData, DWORD cArgs, ARG *rgArgs);
  18. DWORD Do_Toggle(UPNPSVC * psvc, OPERATION_DATA * pOpData, DWORD cArgs, ARG *rgArgs);
  19. DWORD Do_Increment(UPNPSVC * psvc, OPERATION_DATA * pOpData, DWORD cArgs, ARG *rgArgs);
  20. DWORD Do_Decrement(UPNPSVC * psvc, OPERATION_DATA * pOpData, DWORD cArgs, ARG *rgArgs);
  21. DWORD Do_IncrementWrap(UPNPSVC * psvc, OPERATION_DATA * pOpData, DWORD cArgs, ARG *rgArgs);
  22. DWORD Do_DecrementWrap(UPNPSVC * psvc, OPERATION_DATA * pOpData, DWORD cArgs, ARG *rgArgs);
  23. DWORD Do_IncrementBounded(UPNPSVC * psvc, OPERATION_DATA * pOpData, DWORD cArgs, ARG *rgArgs);
  24. DWORD Do_DecrementBounded(UPNPSVC * psvc, OPERATION_DATA * pOpData, DWORD cArgs, ARG *rgArgs);
  25. DWORD Do_NextStringWrap(UPNPSVC * psvc, OPERATION_DATA * pOpData, DWORD cArgs, ARG *rgArgs);
  26. DWORD Do_PrevStringWrap(UPNPSVC * psvc, OPERATION_DATA * pOpData, DWORD cArgs, ARG *rgArgs);
  27. DWORD Do_NextStringBounded(UPNPSVC * psvc, OPERATION_DATA * pOpData, DWORD cArgs, ARG *rgArgs);
  28. DWORD Do_PrevStringBounded(UPNPSVC * psvc, OPERATION_DATA * pOpData, DWORD cArgs, ARG *rgArgs);
  29. //
  30. // List of Standard State Table Operations
  31. //
  32. extern const STANDARD_OPERATION_LIST c_Ops =
  33. {
  34. // total number of standard operations
  35. 13,
  36. {
  37. // Operation name, # of arguments, # of constants, actual function
  38. { TEXT("SET"), 0, 1, Do_Set},
  39. { TEXT("ASSIGN"), 1, 0, Do_Assign},
  40. { TEXT("TOGGLE"), 0, 0, Do_Toggle},
  41. { TEXT("INCREMENT"), 0, 0, Do_Increment},
  42. { TEXT("DECREMENT"), 0, 0, Do_Decrement},
  43. { TEXT("INCREMENT_WRAP"), 0, 2, Do_IncrementWrap},
  44. { TEXT("DECREMENT_WRAP"), 0, 2, Do_DecrementWrap},
  45. { TEXT("INCREMENT_BOUNDED"), 0, 1, Do_IncrementBounded},
  46. { TEXT("DECREMENT_BOUNDED"), 0, 1, Do_DecrementBounded},
  47. { TEXT("NEXT_STRING_WRAP"), 0, 0, Do_NextStringWrap},
  48. { TEXT("PREV_STRING_WRAP"), 0, 0, Do_PrevStringWrap},
  49. { TEXT("NEXT_STRING_BOUNDED"), 0, 0, Do_NextStringBounded},
  50. { TEXT("PREV_STRING_BOUNDED"), 0, 0, Do_PrevStringBounded},
  51. },
  52. };
  53. VOID WcharToTcharInPlace(LPTSTR szT, LPWSTR szW)
  54. {
  55. DWORD cch = wcslen(szW) + 1;
  56. #ifndef UNICODE
  57. WideCharToMultiByte(CP_ACP, 0, szW, cch, szT, cch, NULL, NULL);
  58. #else
  59. lstrcpyW(szT, szW);
  60. #endif
  61. }
  62. //+---------------------------------------------------------------------------
  63. //
  64. // Function: HrSetupOpenConfigFile
  65. //
  66. // Purpose: Open a service's configuration file (INF format)
  67. //
  68. HRESULT HrSetupOpenConfigFile( PCTSTR pszFileName,
  69. UINT* punErrorLine,
  70. HINF* phinf)
  71. {
  72. HRESULT hr;
  73. HINF hinf;
  74. Assert (pszFileName);
  75. Assert (phinf);
  76. // Try to open the file.
  77. //
  78. hinf = SetupOpenInfFile (pszFileName, NULL, INF_STYLE_WIN4, punErrorLine);
  79. if (INVALID_HANDLE_VALUE != hinf)
  80. {
  81. hr = S_OK;
  82. *phinf = hinf;
  83. }
  84. else
  85. {
  86. hr = HrFromLastWin32Error ();
  87. *phinf = NULL;
  88. if (punErrorLine)
  89. {
  90. *punErrorLine = 0;
  91. }
  92. }
  93. TraceHr (ttidError, FAL, hr, FALSE,
  94. "HrSetupOpenConfigFile (%S)", pszFileName);
  95. return hr;
  96. }
  97. //+---------------------------------------------------------------------------
  98. //
  99. // Function: HrSetupFindFirstLine
  100. //
  101. // Purpose: Find the first line in an INF file with a matching section
  102. // and key.
  103. //
  104. HRESULT HrSetupFindFirstLine( HINF hinf,
  105. PCTSTR pszSection,
  106. PCTSTR pszKey,
  107. INFCONTEXT* pctx)
  108. {
  109. Assert (hinf);
  110. Assert (pszSection);
  111. Assert (pctx);
  112. HRESULT hr;
  113. if (SetupFindFirstLine (hinf, pszSection, pszKey, pctx))
  114. {
  115. hr = S_OK;
  116. }
  117. else
  118. {
  119. hr = HrFromLastWin32Error ();
  120. }
  121. TraceErrorOptional ("HrSetupFindFirstLine", hr,
  122. (SPAPI_E_LINE_NOT_FOUND == hr));
  123. return hr;
  124. }
  125. //+---------------------------------------------------------------------------
  126. //
  127. // Function: HrSetupFindNextLine
  128. //
  129. // Purpose: Find the next line in an INF file relative to ctxIn.
  130. //
  131. HRESULT HrSetupFindNextLine( const INFCONTEXT& ctxIn,
  132. INFCONTEXT* pctxOut)
  133. {
  134. Assert (pctxOut);
  135. HRESULT hr;
  136. if (SetupFindNextLine (const_cast<PINFCONTEXT>(&ctxIn), pctxOut))
  137. {
  138. hr = S_OK;
  139. }
  140. else
  141. {
  142. hr = HrFromLastWin32Error ();
  143. if (SPAPI_E_LINE_NOT_FOUND == hr)
  144. {
  145. // Translate ERROR_LINE_NOT_FOUND into S_FALSE
  146. hr = S_FALSE;
  147. }
  148. }
  149. TraceError ("HrSetupFindNextLine", (hr == S_FALSE) ? S_OK : hr);
  150. return hr;
  151. }
  152. //+---------------------------------------------------------------------------
  153. //
  154. // Function: HrSetupGetStringField
  155. //
  156. // Purpose: Gets a string from an INF field.
  157. //
  158. HRESULT HrSetupGetStringField( const INFCONTEXT& ctx,
  159. DWORD dwFieldIndex,
  160. PTSTR pszBuf,
  161. DWORD cchBuf,
  162. DWORD* pcchRequired)
  163. {
  164. HRESULT hr;
  165. if (SetupGetStringField ((PINFCONTEXT)&ctx, dwFieldIndex, pszBuf,
  166. cchBuf, pcchRequired))
  167. {
  168. hr = S_OK;
  169. }
  170. else
  171. {
  172. hr = HrFromLastWin32Error ();
  173. if (pszBuf)
  174. {
  175. *pszBuf = 0;
  176. }
  177. if (pcchRequired)
  178. {
  179. *pcchRequired = 0;
  180. }
  181. }
  182. TraceError ("HrSetupGetStringField", hr);
  183. return hr;
  184. }
  185. //+---------------------------------------------------------------------------
  186. //
  187. // Function: HrSetupGetLineText
  188. //
  189. // Purpose: Gets a line from an INF field.
  190. //
  191. HRESULT HrSetupGetLineText( const INFCONTEXT& ctx,
  192. PTSTR pszBuf,
  193. DWORD cchBuf,
  194. DWORD* pcchRequired)
  195. {
  196. HRESULT hr;
  197. if (SetupGetLineText((PINFCONTEXT)&ctx, NULL, NULL, NULL, pszBuf,
  198. cchBuf, pcchRequired))
  199. {
  200. hr = S_OK;
  201. }
  202. else
  203. {
  204. hr = HrFromLastWin32Error ();
  205. if (pszBuf)
  206. {
  207. *pszBuf = 0;
  208. }
  209. if (pcchRequired)
  210. {
  211. *pcchRequired = 0;
  212. }
  213. }
  214. TraceError ("HrSetupGetStringField", hr);
  215. return hr;
  216. }
  217. VOID SetupCloseInfFileSafe(HINF hinf)
  218. {
  219. if (IsValidHandle(hinf))
  220. {
  221. SetupCloseInfFile(hinf);
  222. }
  223. }
  224. // get the next field
  225. // returns FALSE if field not found or is empty
  226. BOOL fGetNextField(TCHAR ** pszLine, TCHAR * szBuffer)
  227. {
  228. Assert(*pszLine);
  229. Assert(szBuffer);
  230. *szBuffer = '\0';
  231. if (lstrlen(*pszLine))
  232. {
  233. TCHAR * pChar;
  234. if (**pszLine == '(')
  235. {
  236. pChar = _tcschr(*pszLine, TEXT(')'));
  237. pChar++;
  238. }
  239. else
  240. {
  241. pChar = _tcschr(*pszLine, TEXT(','));
  242. }
  243. if (pChar)
  244. {
  245. *pChar ='\0';
  246. lstrcpy(szBuffer, *pszLine);
  247. *pszLine = ++pChar;
  248. }
  249. else
  250. {
  251. lstrcpy(szBuffer, *pszLine);
  252. **pszLine = '\0';
  253. }
  254. }
  255. return (!!lstrlen(szBuffer));
  256. }
  257. // Input: name of the operation
  258. // Output: number of arguments and constants
  259. BOOL IsStandardOperation(TCHAR * szOpName, DWORD * pnArgs, DWORD * pnConsts)
  260. {
  261. *pnArgs =0;
  262. *pnConsts=0;
  263. for (DWORD iOps = 0; iOps < c_Ops.cOperations; iOps++)
  264. {
  265. if (!_tcsicmp(c_Ops.rgOperations[iOps].szOperation, szOpName))
  266. {
  267. *pnArgs = c_Ops.rgOperations[iOps].nArguments;
  268. *pnConsts = c_Ops.rgOperations[iOps].nConstants;
  269. return TRUE;
  270. }
  271. }
  272. return FALSE;
  273. }
  274. // Find the row in the state table that needs to be changed
  275. //
  276. SST_ROW * FindSSTRowByVarName(SST * psst, TCHAR * szVariableName)
  277. {
  278. SST_ROW * pRow = NULL;
  279. for (DWORD iRow =0; iRow<psst->cRows; iRow++)
  280. {
  281. if (!lstrcmpi(psst->rgRows[iRow].szPropName, szVariableName))
  282. {
  283. pRow = &psst->rgRows[iRow];
  284. break;
  285. }
  286. }
  287. return pRow;
  288. }
  289. //
  290. // Functions for Standard State Table Operations
  291. //
  292. HRESULT HrSetVariantValue(VARIANT * pVar, TCHAR * szNewValue)
  293. {
  294. HRESULT hr;
  295. VARIANT varNew;
  296. VariantInit(&varNew);
  297. varNew.vt = VT_BSTR;
  298. WCHAR * wszNewValue = WszFromTsz(szNewValue);
  299. V_BSTR(&varNew) = SysAllocString(wszNewValue);
  300. hr = VariantChangeType(&varNew, &varNew, 0, pVar->vt);
  301. if (S_OK == hr)
  302. {
  303. hr = VariantCopy(pVar, &varNew);
  304. }
  305. TraceError("HrSetVariantValue", hr);
  306. return hr;
  307. }
  308. DWORD dwSubmitEvent(UPNPSVC * psvc, SST_ROW * pRow)
  309. {
  310. HRESULT hr;
  311. DWORD dwErr =0;
  312. CHAR szUri[INTERNET_MAX_URL_LENGTH];
  313. UPNP_PROPERTY Property = {0};
  314. // convert current value to string
  315. VARIANT varValue;
  316. VariantInit(&varValue);
  317. hr = VariantChangeType(&varValue, &pRow->varValue, 0, VT_BSTR);
  318. if (S_OK ==hr)
  319. {
  320. LPSTR pszUrl = SzFromTsz(psvc->szEvtUrl);
  321. if (pszUrl)
  322. {
  323. LPWSTR wszVal = varValue.bstrVal;
  324. Property.szValue = SzFromWsz(wszVal);
  325. if (Property.szValue)
  326. {
  327. hr = HrGetRequestUriA(pszUrl, INTERNET_MAX_URL_LENGTH, szUri);
  328. if (SUCCEEDED(hr))
  329. {
  330. if (SubmitUpnpPropertyEvent(szUri, 0, 1, &Property))
  331. {
  332. TraceTag(ttidUpdiag, "Successfully submitted event to %s.", psvc->szEvtUrl);
  333. }
  334. else
  335. {
  336. dwErr =1;
  337. TraceTag(ttidUpdiag, "Failed to submit event to %s! Error %d.",
  338. psvc->szEvtUrl, GetLastError());
  339. }
  340. }
  341. else
  342. {
  343. dwErr =1;
  344. TraceTag(ttidUpdiag, "Failed to crack URL %s! Error %d.",
  345. psvc->szEvtUrl, GetLastError());
  346. }
  347. delete [] Property.szValue;
  348. }
  349. else
  350. {
  351. dwErr =1;
  352. TraceTag(ttidUpdiag, "SzFromWsz (#2) failed");
  353. }
  354. }
  355. else
  356. {
  357. dwErr =1;
  358. TraceTag(ttidUpdiag, "SzFromWsz (#1) failed");
  359. }
  360. }
  361. else
  362. {
  363. dwErr =1;
  364. TraceTag(ttidUpdiag, "Failed to convert variable value to string. Error: %x.", hr);
  365. }
  366. return dwErr;
  367. }
  368. DWORD Do_Set(UPNPSVC * psvc, OPERATION_DATA * pOpData, DWORD cArgs, ARG *rgArgs)
  369. {
  370. TraceTag(ttidUpdiag, "Do_Set: set variable %s to constant %s",
  371. pOpData->szVariableName, pOpData->mszConstantList);
  372. DWORD dwError = 0;
  373. Assert(cArgs == 0);
  374. // find the SST row to update
  375. SST_ROW * pRow = FindSSTRowByVarName(&psvc->sst, pOpData->szVariableName);
  376. Assert(pRow);
  377. if (pRow)
  378. {
  379. HRESULT hr = HrSetVariantValue(&pRow->varValue, pOpData->mszConstantList);
  380. if (S_OK != hr)
  381. {
  382. dwError =1;
  383. }
  384. else
  385. {
  386. dwError = dwSubmitEvent(psvc, pRow);
  387. }
  388. }
  389. return dwError;
  390. };
  391. DWORD Do_Assign(UPNPSVC * psvc, OPERATION_DATA * pOpData, DWORD cArgs, ARG *rgArgs)
  392. {
  393. TraceTag(ttidUpdiag, "Do_Assign: assign variable %s to argument %s",
  394. pOpData->szVariableName, rgArgs[0].szValue);
  395. DWORD dwError = 0;
  396. Assert(cArgs == 1);
  397. // find the SST row to update
  398. SST_ROW * pRow = FindSSTRowByVarName(&psvc->sst, pOpData->szVariableName);
  399. Assert(pRow);
  400. if (pRow)
  401. {
  402. // check if the new value is within the range or is in the allowed value list
  403. if (*pRow->mszAllowedValueList)
  404. {
  405. TCHAR * pNextString = pRow->mszAllowedValueList;
  406. while (*pNextString && (lstrcmpi(rgArgs[0].szValue, pNextString) !=0))
  407. {
  408. pNextString += lstrlen(pNextString);
  409. pNextString ++;
  410. }
  411. if (!*pNextString)
  412. {
  413. TraceTag(ttidUpdiag, "Do_Assign: new variable value is not in the allowed value list !");
  414. dwError =1;
  415. }
  416. }
  417. else if (*pRow->szMin)
  418. {
  419. Assert(*pRow->szMax);
  420. // This should only work if the variable is a number ??
  421. Assert(pRow->varValue.vt == VT_I4);
  422. if (pRow->varValue.vt == VT_I4)
  423. {
  424. long lMin = _ttol(pRow->szMin);
  425. long lMax = _ttol(pRow->szMax);
  426. long lVal = _ttol(rgArgs[0].szValue);
  427. if ((lVal<lMin) || (lVal>lMax))
  428. {
  429. TraceTag(ttidUpdiag, "Do_Assign: new variable value is not in the allowed range !");
  430. dwError =1;
  431. }
  432. }
  433. }
  434. if (!dwError)
  435. {
  436. HRESULT hr = HrSetVariantValue(&pRow->varValue, rgArgs[0].szValue);
  437. if (S_OK != hr)
  438. {
  439. dwError =1;
  440. }
  441. else
  442. {
  443. dwError = dwSubmitEvent(psvc, pRow);
  444. }
  445. }
  446. }
  447. return dwError;
  448. };
  449. DWORD Do_Toggle(UPNPSVC * psvc, OPERATION_DATA * pOpData, DWORD cArgs, ARG *rgArgs)
  450. {
  451. TraceTag(ttidUpdiag, "Do_Toggle");
  452. DWORD dwError = 0;
  453. // find the SST row to update
  454. SST_ROW * pRow = FindSSTRowByVarName(&psvc->sst, pOpData->szVariableName);
  455. Assert(pRow);
  456. if (pRow)
  457. {
  458. Assert(pRow->varValue.vt == VT_BOOL);
  459. if (pRow->varValue.vt == VT_BOOL)
  460. {
  461. pRow->varValue.boolVal = ~pRow->varValue.boolVal;
  462. dwError = dwSubmitEvent(psvc, pRow);
  463. }
  464. else
  465. {
  466. TraceTag(ttidUpdiag, "Error: variable %s is not a boolean.",
  467. pOpData->szVariableName);
  468. dwError =1;
  469. }
  470. }
  471. return dwError;
  472. };
  473. DWORD Do_Increment(UPNPSVC * psvc, OPERATION_DATA * pOpData, DWORD cArgs, ARG *rgArgs)
  474. {
  475. TraceTag(ttidUpdiag, "Do_Increment");
  476. DWORD dwError = 0;
  477. // find the SST row to update
  478. SST_ROW * pRow = FindSSTRowByVarName(&psvc->sst, pOpData->szVariableName);
  479. Assert(pRow);
  480. if (pRow)
  481. {
  482. // This should only work if teh variable is a number ??
  483. Assert(pRow->varValue.vt == VT_I4);
  484. if (pRow->varValue.vt == VT_I4)
  485. {
  486. pRow->varValue.lVal++;
  487. dwError = dwSubmitEvent(psvc, pRow);
  488. }
  489. else
  490. {
  491. TraceTag(ttidUpdiag, "Error: variable %s is not a number.",
  492. pOpData->szVariableName);
  493. dwError =1;
  494. }
  495. }
  496. return dwError;
  497. };
  498. DWORD Do_Decrement(UPNPSVC * psvc, OPERATION_DATA * pOpData, DWORD cArgs, ARG *rgArgs)
  499. {
  500. TraceTag(ttidUpdiag, "Do_Decrement");
  501. DWORD dwError = 0;
  502. // find the SST row to update
  503. SST_ROW * pRow = FindSSTRowByVarName(&psvc->sst, pOpData->szVariableName);
  504. Assert(pRow);
  505. if (pRow)
  506. {
  507. // This should only work if teh variable is a number ??
  508. Assert(pRow->varValue.vt == VT_I4);
  509. if (pRow->varValue.vt == VT_I4)
  510. {
  511. pRow->varValue.lVal--;
  512. dwError = dwSubmitEvent(psvc, pRow);
  513. }
  514. else
  515. {
  516. TraceTag(ttidUpdiag, "Error: variable %s is not a number.",
  517. pOpData->szVariableName);
  518. dwError =1;
  519. }
  520. }
  521. return dwError;
  522. };
  523. DWORD Do_IncrementWrap(UPNPSVC * psvc, OPERATION_DATA * pOpData, DWORD cArgs, ARG *rgArgs)
  524. {
  525. TraceTag(ttidUpdiag, "Do_IncrementWrap");
  526. DWORD dwError = 0;
  527. // find the SST row to update
  528. SST_ROW * pRow = FindSSTRowByVarName(&psvc->sst, pOpData->szVariableName);
  529. Assert(pRow);
  530. if (pRow)
  531. {
  532. // This should only work if the variable is a number ??
  533. Assert(pRow->varValue.vt == VT_I4);
  534. if (pRow->varValue.vt == VT_I4)
  535. {
  536. // get the max and min values from the constant list
  537. TCHAR * szMax = pOpData->mszConstantList;
  538. szMax += lstrlen(szMax)+1;
  539. long lMin = _ttol(pOpData->mszConstantList);
  540. long lMax = _ttol(szMax);
  541. Assert(lMax >= lMin);
  542. TraceTag(ttidUpdiag, "Do_IncrementWrap: variable= %d, min= %d, max= %d",
  543. pRow->varValue.lVal, lMin, lMax);
  544. pRow->varValue.lVal = lMin + ((pRow->varValue.lVal-lMin+1) % (lMax-lMin+1));
  545. Assert((lMin<=pRow->varValue.lVal) && (lMax>=pRow->varValue.lVal));
  546. dwError = dwSubmitEvent(psvc, pRow);
  547. }
  548. else
  549. {
  550. TraceTag(ttidUpdiag, "Error: variable %s is not a number.",
  551. pOpData->szVariableName);
  552. dwError =1;
  553. }
  554. }
  555. return dwError;
  556. };
  557. DWORD Do_DecrementWrap(UPNPSVC * psvc, OPERATION_DATA * pOpData, DWORD cArgs, ARG *rgArgs)
  558. {
  559. TraceTag(ttidUpdiag, "Do_DecrementWrap");
  560. DWORD dwError = 0;
  561. // find the SST row to update
  562. SST_ROW * pRow = FindSSTRowByVarName(&psvc->sst, pOpData->szVariableName);
  563. Assert(pRow);
  564. if (pRow)
  565. {
  566. // This should only work if the variable is a number ??
  567. Assert(pRow->varValue.vt == VT_I4);
  568. if (pRow->varValue.vt == VT_I4)
  569. {
  570. // get the max and min values from the constant list
  571. TCHAR * szMax = pOpData->mszConstantList;
  572. szMax += lstrlen(szMax)+1;
  573. long lMin = _ttol(pOpData->mszConstantList);
  574. long lMax = _ttol(szMax);
  575. Assert(lMax >= lMin);
  576. TraceTag(ttidUpdiag, "Do_DecrementWrap: variable= %d, min= %d, max= %d",
  577. pRow->varValue.lVal, lMin, lMax);
  578. pRow->varValue.lVal = lMax - ((lMax-pRow->varValue.lVal+1) % (lMax-lMin+1));
  579. Assert((lMin<=pRow->varValue.lVal) && (lMax>=pRow->varValue.lVal));
  580. dwError = dwSubmitEvent(psvc, pRow);
  581. }
  582. else
  583. {
  584. TraceTag(ttidUpdiag, "Error: variable %s is not a number.",
  585. pOpData->szVariableName);
  586. dwError =1;
  587. }
  588. }
  589. return dwError;
  590. };
  591. DWORD Do_IncrementBounded(UPNPSVC * psvc, OPERATION_DATA * pOpData, DWORD cArgs, ARG *rgArgs)
  592. {
  593. TraceTag(ttidUpdiag, "Do_IncrementBounded");
  594. DWORD dwError = 0;
  595. // find the SST row to update
  596. SST_ROW * pRow = FindSSTRowByVarName(&psvc->sst, pOpData->szVariableName);
  597. Assert(pRow);
  598. if (pRow)
  599. {
  600. // This should only work if the variable is a number ??
  601. Assert(pRow->varValue.vt == VT_I4);
  602. if (pRow->varValue.vt == VT_I4)
  603. {
  604. // max value is the only constant
  605. long lMax = _ttol(pOpData->mszConstantList);
  606. if (pRow->varValue.lVal < lMax)
  607. {
  608. pRow->varValue.lVal++;
  609. dwError = dwSubmitEvent(psvc, pRow);
  610. }
  611. else
  612. {
  613. TraceTag(ttidUpdiag, "IncrementBounded: variable %s already has the maximum value.",
  614. pOpData->szVariableName);
  615. }
  616. }
  617. else
  618. {
  619. TraceTag(ttidUpdiag, "Error: variable %s is not a number.",
  620. pOpData->szVariableName);
  621. dwError =1;
  622. }
  623. }
  624. return dwError;
  625. };
  626. DWORD Do_DecrementBounded(UPNPSVC * psvc, OPERATION_DATA * pOpData, DWORD cArgs, ARG *rgArgs)
  627. {
  628. TraceTag(ttidUpdiag, "Do_DecrementBounded");
  629. DWORD dwError = 0;
  630. // find the SST row to update
  631. SST_ROW * pRow = FindSSTRowByVarName(&psvc->sst, pOpData->szVariableName);
  632. Assert(pRow);
  633. if (pRow)
  634. {
  635. // This should only work if the variable is a number ??
  636. Assert(pRow->varValue.vt == VT_I4);
  637. if (pRow->varValue.vt == VT_I4)
  638. {
  639. // max value is the only constant
  640. long lMin = _ttol(pOpData->mszConstantList);
  641. if (pRow->varValue.lVal > lMin)
  642. {
  643. pRow->varValue.lVal--;
  644. dwError = dwSubmitEvent(psvc, pRow);
  645. }
  646. else
  647. {
  648. TraceTag(ttidUpdiag, "DecrementBounded: variable %s already has the minimal value.",
  649. pOpData->szVariableName);
  650. }
  651. }
  652. else
  653. {
  654. TraceTag(ttidUpdiag, "Error: variable %s is not a number.",
  655. pOpData->szVariableName);
  656. dwError =1;
  657. }
  658. }
  659. return dwError;
  660. };
  661. DWORD dwMoveToNextString(UPNPSVC * psvc, OPERATION_DATA * pOpData, BOOL fWrap)
  662. {
  663. DWORD dwError = 0;
  664. // find the SST row to update
  665. SST_ROW * pRow = FindSSTRowByVarName(&psvc->sst, pOpData->szVariableName);
  666. Assert(pRow);
  667. if (pRow)
  668. {
  669. // This should only work if the variable is a string
  670. // and we have a list of allowed values
  671. Assert(pRow->varValue.vt == VT_BSTR);
  672. if (pRow->varValue.vt == VT_BSTR)
  673. {
  674. if (lstrlen(pRow->mszAllowedValueList)>0)
  675. {
  676. TCHAR * pNextString = pRow->mszAllowedValueList;
  677. while (*pNextString && (lstrcmpi(TszFromWsz(pRow->varValue.bstrVal),
  678. pNextString) !=0))
  679. {
  680. pNextString += lstrlen(pNextString);
  681. pNextString ++;
  682. }
  683. if (!*pNextString)
  684. {
  685. TraceTag(ttidUpdiag, "dwSetToNextString: variable value is not in the allowed value list ??");
  686. dwError =1;
  687. }
  688. else
  689. {
  690. // is pNextString the last string in the list ?
  691. TCHAR * pChar = pNextString + lstrlen(pNextString);
  692. pChar++;
  693. if (*pChar)
  694. {
  695. // not the last string
  696. V_BSTR(&pRow->varValue) = SysAllocString(WszFromTsz(pChar));
  697. dwError = dwSubmitEvent(psvc, pRow);
  698. }
  699. else if (fWrap)
  700. {
  701. V_BSTR(&pRow->varValue) =
  702. SysAllocString(WszFromTsz(pRow->mszAllowedValueList));
  703. dwError = dwSubmitEvent(psvc, pRow);
  704. }
  705. }
  706. }
  707. else
  708. {
  709. TraceTag(ttidUpdiag, "dwSetToNextString: variable %s has no list of allowed values.",
  710. pOpData->szVariableName);
  711. dwError =1;
  712. }
  713. }
  714. else
  715. {
  716. TraceTag(ttidUpdiag, "dwSetToNextString: variable %s is not a string.",
  717. pOpData->szVariableName);
  718. dwError =1;
  719. }
  720. }
  721. return dwError;
  722. }
  723. DWORD dwMoveToPrevString(UPNPSVC * psvc, OPERATION_DATA * pOpData, BOOL fWrap)
  724. {
  725. DWORD dwError = 0;
  726. // find the SST row to update
  727. SST_ROW * pRow = FindSSTRowByVarName(&psvc->sst, pOpData->szVariableName);
  728. Assert(pRow);
  729. if (pRow)
  730. {
  731. // This should only work if the variable is a string
  732. // and we have a list of allowed values
  733. Assert(pRow->varValue.vt == VT_BSTR);
  734. if (pRow->varValue.vt == VT_BSTR)
  735. {
  736. if (lstrlen(pRow->mszAllowedValueList)>0)
  737. {
  738. TCHAR * pNextString = pRow->mszAllowedValueList;
  739. TCHAR * pPrevString = pNextString;
  740. while (*pNextString && (lstrcmpi(TszFromWsz(pRow->varValue.bstrVal),
  741. pNextString) !=0))
  742. {
  743. if (pPrevString != pNextString)
  744. {
  745. pPrevString = pNextString;
  746. }
  747. pNextString += lstrlen(pNextString);
  748. pNextString++;
  749. }
  750. if (!pNextString)
  751. {
  752. TraceTag(ttidUpdiag, "dwSetToNextString: variable value is not in the allowed value list ??");
  753. dwError =1;
  754. }
  755. else
  756. {
  757. // is pNextString the first string in the list ?
  758. if (pNextString != pPrevString)
  759. {
  760. // not the first string
  761. V_BSTR(&pRow->varValue) = SysAllocString(WszFromTsz(pPrevString));
  762. dwError = dwSubmitEvent(psvc, pRow);
  763. }
  764. else if (fWrap)
  765. {
  766. // go to the last string
  767. pNextString += lstrlen(pNextString);
  768. pNextString++;
  769. while (*pNextString)
  770. {
  771. pPrevString = pNextString;
  772. pNextString += lstrlen(pNextString);
  773. pNextString++;
  774. }
  775. V_BSTR(&pRow->varValue) = SysAllocString(WszFromTsz(pPrevString));
  776. dwError = dwSubmitEvent(psvc, pRow);
  777. }
  778. }
  779. }
  780. else
  781. {
  782. TraceTag(ttidUpdiag, "dwMoveToPrevString: variable %s has no list of allowed values.",
  783. pOpData->szVariableName);
  784. dwError =1;
  785. }
  786. }
  787. else
  788. {
  789. TraceTag(ttidUpdiag, "dwMoveToPrevString: variable %s is not a string.",
  790. pOpData->szVariableName);
  791. dwError =1;
  792. }
  793. }
  794. return dwError;
  795. }
  796. DWORD Do_NextStringWrap(UPNPSVC * psvc, OPERATION_DATA * pOpData, DWORD cArgs, ARG *rgArgs)
  797. {
  798. TraceTag(ttidUpdiag, "Do_NextStringWrap");
  799. return dwMoveToNextString(psvc, pOpData, TRUE);
  800. }
  801. DWORD Do_PrevStringWrap(UPNPSVC * psvc, OPERATION_DATA * pOpData, DWORD cArgs, ARG *rgArgs)
  802. {
  803. TraceTag(ttidUpdiag, "Do_PrevStringWrap");
  804. return dwMoveToPrevString(psvc, pOpData, TRUE);
  805. }
  806. DWORD Do_NextStringBounded(UPNPSVC * psvc, OPERATION_DATA * pOpData, DWORD cArgs, ARG *rgArgs)
  807. {
  808. TraceTag(ttidUpdiag, "Do_NextStringBounded");
  809. return dwMoveToNextString(psvc, pOpData, FALSE);
  810. }
  811. DWORD Do_PrevStringBounded(UPNPSVC * psvc, OPERATION_DATA * pOpData, DWORD cArgs, ARG *rgArgs)
  812. {
  813. TraceTag(ttidUpdiag, "Do_PrevStringBounded");
  814. return dwMoveToPrevString(psvc, pOpData, FALSE);
  815. }