PageRenderTime 44ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/LightOPC/src/browse.cpp

https://gitlab.com/fheinemann/opc_ads
C++ | 507 lines | 398 code | 76 blank | 33 comment | 120 complexity | cb6fcade208c683445c1465f76fcc136 MD5 | raw file
  1. /**************************************************************************
  2. * *
  3. * Light OPC Server development library *
  4. * *
  5. * Copyright (c) 2000 Timofei Bondarenko *
  6. *
  7. IOPCBrowseServerAddressSpace
  8. **************************************************************************/
  9. #include <opcerror.h>
  10. #include "privopc.h"
  11. #include "enum.h"
  12. extern BOOL MatchPattern(LPCWSTR String, LPCWSTR Pattern, BOOL bCaseSensitive);
  13. /**************************************************************************/
  14. static loTagId lo_browse_tag(loService *se, loTagId first,
  15. const loWchar *name, unsigned len,
  16. OPCBROWSETYPE btype);
  17. static loTagId lo_browse_branch(loService *se, const loWchar *name);
  18. #if 1
  19. #define loLOCK_MGMT_I(x) lw_rw_rdlock(&se->lkMgmt)
  20. #define loLOCK_MGMT_O(x)
  21. #define loUnLOCK_MGMT_I(x) lw_rw_unlock(&se->lkMgmt)
  22. #define loUnLOCK_MGMT_O(x)
  23. #else
  24. #define loLOCK_MGMT_I(x)
  25. #define loLOCK_MGMT_O(x) lw_rw_rdlock(&se->lkMgmt)
  26. #define loUnLOCK_MGMT_I(x)
  27. #define loUnLOCK_MGMT_O(x) lw_rw_unlock(&se->lkMgmt)
  28. #endif
  29. /**************************************************************************/
  30. int lo_name_level(loWchar brsep, const loWchar *name)
  31. {
  32. int ii;
  33. const loWchar *ls;
  34. if (!name || !*name) return 0; /* root */
  35. if (!brsep) return 1;
  36. for(ii = 1, ls = name; 0 != (ls = wcschr(ls, brsep)); ls++) ii++;
  37. return ii;
  38. }
  39. int lo_name_levlen(loWchar brsep, const loWchar *name, int level)
  40. {
  41. const loWchar *ls;
  42. if (!name) return 0;
  43. if (level <= 0) return 0;
  44. for(ls = name; (ls = wcschr(ls, brsep)) && --level > 0; ls++);
  45. return ls? ls - name: wcslen(name);
  46. }
  47. /**************************************************************************/
  48. STDMETHODIMP LightOPCServer::QueryOrganization(OPCNAMESPACETYPE *pNameSpaceType)
  49. {
  50. HRESULT hr = S_OK;
  51. LO_CHECK_STATEz0("QueryOrganisation");
  52. if (!pNameSpaceType) hr = E_INVALIDARG;
  53. else
  54. {
  55. *pNameSpaceType = se->branch_sep? OPC_NS_HIERARCHIAL: OPC_NS_FLAT;
  56. }
  57. LO_FINISH();
  58. return hr;
  59. }
  60. STDMETHODIMP LightOPCServer::BrowseAccessPaths(
  61. /* [string][in] */ LPCWSTR szItemID,
  62. /* [out] */ LPENUMSTRING *ppIEnumString)
  63. {
  64. HRESULT hr = E_NOTIMPL;
  65. LO_CHECK_STATEz1("BrowseAccessPath", ppIEnumString);
  66. if (!ppIEnumString) hr = E_INVALIDARG;
  67. else
  68. {
  69. if (se->driver.ldBrowseAccessPath)
  70. {
  71. loEnumString *es = new loEnumString(0);
  72. if (es)
  73. {
  74. *ppIEnumString = es;
  75. hr = se->driver.ldBrowseAccessPath(&ctxt.cactx, szItemID, ppIEnumString);
  76. if (!*ppIEnumString && !FAILED(hr)) hr = E_FAIL;
  77. if (FAILED(hr))
  78. {
  79. if (*ppIEnumString == (LPENUMSTRING)es) *ppIEnumString = 0;
  80. delete es;
  81. }
  82. else if (*ppIEnumString != (LPENUMSTRING)es)
  83. delete es;
  84. else if (S_OK != (hr = es->initiate(&otrk)))
  85. delete es;
  86. }
  87. else hr = E_OUTOFMEMORY;
  88. }
  89. }
  90. UL_NOTICE((LOG_SR("BrowseAccessPath(%ls) = %s"),
  91. loWnul(szItemID), loStrError(hr)));
  92. LO_FINISH();
  93. return hr;
  94. }
  95. /**************************************************************************/
  96. HRESULT LightOPCServer::set_browsepos(const loWchar *pos, int len)
  97. {
  98. loWchar *opos;
  99. if (!pos) pos = L"";
  100. if (-1 == len) len = wcslen(pos);
  101. opos = browsepos.sb_str;
  102. if (!loStringBuf_REALLOC(&browsepos, (unsigned)len + 1))
  103. return E_OUTOFMEMORY;
  104. if (opos != pos) wcsncpy(browsepos.sb_str, pos, len);
  105. browsepos.sb_str[len] = 0;
  106. // UL_DEBUG((LOG_SR("SetBrowsePosition(%p=%ls)"), browsepos.sb_str, browsepos.sb_str));
  107. return S_OK;
  108. }
  109. int LightOPCServer::cat_browsepos(const loWchar *cpos)
  110. {
  111. int len_n, len_o, len_b;
  112. loWchar brsep;
  113. if (!cpos) cpos = L"";
  114. len_n = wcslen(cpos);
  115. len_o = len_b = 0;
  116. if (browsepos.sb_str &&
  117. (len_o = wcslen(browsepos.sb_str)) && len_n &&
  118. (brsep = se->branch_sep)) len_b = 1;
  119. if (S_OK != set_browsepos(browsepos.sb_str, len_o + len_b + len_n)) return -1;
  120. if (len_b) browsepos.sb_str[len_o] = brsep;
  121. memcpy(browsepos.sb_str + len_o + len_b, cpos, len_n * sizeof(loWchar));
  122. browsepos.sb_str[len_o + len_b + len_n] = 0;
  123. // UL_DEBUG((LOG_SR("CatBrowsePosition( %ls + %ls)"), browsepos.sb_str, cpos));
  124. return len_o;
  125. }
  126. /**************************************************************************/
  127. STDMETHODIMP LightOPCServer::ChangeBrowsePosition(
  128. /* [in] */ OPCBROWSEDIRECTION dwBrowseDirection,
  129. /* [string][in] */ LPCWSTR szString)
  130. {
  131. HRESULT hr = S_OK;
  132. LO_CHECK_STATEz0("ChangeBrowsePosition");
  133. lock_browse();
  134. {
  135. loWchar brsep;
  136. int ii;
  137. //UL_WARNING((LOG_SR("ChangeBrowsePosition->(%ls)(%ls)"), loWnul(browsepos.sb_str),loWnul(szString)));
  138. if (!(brsep = se->branch_sep))
  139. {
  140. hr = E_FAIL;
  141. UL_TRACE((LOG_SR("ChangeBrowsePosition() on the FLAT")));
  142. }
  143. else
  144. switch(dwBrowseDirection)
  145. {
  146. case OPC_BROWSE_UP:
  147. if (0 >= (ii = lo_name_level(brsep, browsepos.sb_str)))
  148. {
  149. hr = E_FAIL; /* already on root */
  150. UL_TRACE((LOG_SR("ChangeBrowsePosition() already on root")));
  151. }
  152. else
  153. {
  154. hr = set_browsepos(browsepos.sb_str,
  155. lo_name_levlen(brsep, browsepos.sb_str, ii - 1));
  156. }
  157. break;
  158. case OPC_BROWSE_DOWN:
  159. if (!szString || !*szString) hr = E_INVALIDARG;//loOPC_E_NOTFOUND;
  160. else if (0 > (ii = cat_browsepos(szString))) hr = E_OUTOFMEMORY;
  161. else if (!lo_browse_branch(se, browsepos.sb_str))
  162. {
  163. browsepos.sb_str[ii] = 0;
  164. hr = E_INVALIDARG;//loOPC_E_NOTFOUND;
  165. }
  166. break;
  167. case OPC_BROWSE_TO:
  168. if (!szString || !*szString) hr = set_browsepos(0);
  169. else
  170. hr = lo_browse_branch(se, szString)?
  171. set_browsepos(szString): E_INVALIDARG;//loOPC_E_NOTFOUND;
  172. break;
  173. default: hr = E_INVALIDARG;
  174. UL_TRACE((LOG_SR("ChangeBrowsePosition() unknown direction")));
  175. break;
  176. }
  177. }
  178. UL_TRACE((LOG_SR("ChangeBrowsePosition(%X <%ls>) = %ls"),
  179. dwBrowseDirection, loWnul(szString), loWnul(browsepos.sb_str)));
  180. unlock_browse();
  181. if (S_OK != hr)
  182. {
  183. UL_INFO((LOG_SR("ChangeBrowsePosition(%X <%ls>) = %s"),
  184. dwBrowseDirection, loWnul(szString), loStrError(hr)));
  185. }
  186. LO_FINISH();
  187. return hr;
  188. }
  189. /**************************************************************************/
  190. STDMETHODIMP LightOPCServer::GetItemID(
  191. /* [in] */ LPWSTR szItemDataID,
  192. /* [string][out] */ LPWSTR *szItemID)
  193. {
  194. HRESULT hr = S_OK;
  195. LO_CHECK_STATEz1("GetItemID", szItemID);
  196. if (!szItemID) hr = E_INVALIDARG;
  197. else
  198. {
  199. loWchar *itemid = 0;
  200. int ii = -1;
  201. lock_browse();
  202. // UL_DEBUG((LOG_SR("GetItemID->(%ls)(%ls)"), loWnul(browsepos.sb_str),loWnul(szItemDataID)));
  203. if (0 <= (ii = cat_browsepos(szItemDataID)))
  204. {
  205. itemid = loComWstrdup(browsepos.sb_str/*? browsepos.sb_str: L""*/);
  206. browsepos.sb_str[ii] = 0;
  207. }
  208. unlock_browse();
  209. if (!itemid)
  210. {
  211. hr = E_OUTOFMEMORY;
  212. UL_INFO((LOG_SR("GetItemID(%ls) = %s"),
  213. loWnul(szItemDataID), loStrError(hr)));
  214. }
  215. else
  216. {
  217. /* loFindItemID() will go faster */
  218. if (loFindItemID(se, &ctxt.cactx, 0, itemid, 0,
  219. VT_EMPTY, loDAIG_BROWSE, 0, &hr) ||
  220. lo_browse_branch(se, itemid) )
  221. *szItemID = itemid, hr = S_OK;
  222. else
  223. {
  224. //if (!FAILED(hr)) loOPC_E_NOTFOUND;
  225. hr = E_INVALIDARG;
  226. UL_INFO((LOG_SR("GetItemID(%ls)(%ls) = %s"),
  227. loWnul(szItemDataID), loWnul(itemid), loStrError(hr)));
  228. loComFree(itemid);
  229. }
  230. }
  231. }
  232. if (S_OK == hr)
  233. {
  234. UL_NOTICE((LOG_SR("GetItemID(%ls) = %ls"), loWnul(szItemDataID), *szItemID));
  235. }
  236. LO_FINISH();
  237. return hr;
  238. }
  239. /**************************************************************************/
  240. STDMETHODIMP LightOPCServer::BrowseOPCItemIDs(
  241. /* [in] */ OPCBROWSETYPE dwBrowseFilterType,
  242. /* [string][in] */ LPCWSTR szFilterCriteria,
  243. /* [in] */ VARTYPE vtDataTypeFilter,
  244. /* [in] */ DWORD dwAccessRightsFilter,
  245. /* [out] */ LPENUMSTRING *ppIEnumString)
  246. {
  247. HRESULT hr = S_OK;
  248. loEnumString *ulist = 0;
  249. LO_CHECK_STATEz1("BrowseOPCItemIDs", ppIEnumString);
  250. if (szFilterCriteria && !*szFilterCriteria) szFilterCriteria = 0;
  251. if (!ppIEnumString ||
  252. dwBrowseFilterType != OPC_FLAT &&
  253. dwBrowseFilterType != OPC_BRANCH &&
  254. dwBrowseFilterType != OPC_LEAF) { hr = E_INVALIDARG; goto Return; }
  255. if (!(ulist = new loEnumString(0)))
  256. { hr = E_OUTOFMEMORY; goto Return; }
  257. {
  258. loTagId ti;
  259. lo_hash *hash_list = 0;
  260. loWchar brsep = se->branch_sep;
  261. BOOL casesens = 0 == (/*se->driver.*/ldFlags & loDF_IGNCASE);
  262. loWchar *brpos = 0;
  263. unsigned brlen = 0;
  264. int am_mask;
  265. loCallerx cctx = ctxt;
  266. loStringBuf aname;
  267. loStringBuf_init(&aname);
  268. lock_browse();
  269. if (browsepos.sb_str)
  270. {
  271. brlen = wcslen(browsepos.sb_str);
  272. brpos = loWstrdup(browsepos.sb_str);
  273. }
  274. cctx.cta.vc_lcid = ctxt.cta.vc_lcid;
  275. unlock_browse();
  276. if (brlen && !brpos) { hr = E_OUTOFMEMORY; goto Return; }
  277. if (!brsep) dwBrowseFilterType = OPC_FLAT;
  278. // level = lo_name_level(brsep, browsepos.sb_str);
  279. UL_TRACE((LOG_SR("Browse for: %u/%ls/ access %d"),
  280. brlen, loWnul(brpos), dwAccessRightsFilter));
  281. dwAccessRightsFilter &= loOPC_RIGHTS;
  282. if (dwAccessRightsFilter == (OPC_READABLE | OPC_WRITEABLE))
  283. dwAccessRightsFilter = 0;
  284. am_mask = dwAccessRightsFilter;
  285. if (access_mode & loAM_RDONLY_BROWSE) am_mask &= ~OPC_WRITEABLE;
  286. //loMilliSec stst = lo_millisec();
  287. loLOCK_MGMT_O(&se->lkMgmt);
  288. for(ti = 0; ti = lo_browse_tag(se, ti, brpos, brlen, dwBrowseFilterType); ti++)
  289. {
  290. unsigned alen;
  291. loTagEntry *te = &se->tags[ti];
  292. const loWchar *item = te->attr.taName + brlen;
  293. if (!*item) continue; /* don't return itself */
  294. if (brsep == *item) item++;
  295. switch(dwBrowseFilterType)
  296. {
  297. case OPC_LEAF:
  298. if (wcschr(item, brsep)) continue;
  299. //if (1 < lo_name_level(brsep, item)) continue;
  300. case OPC_FLAT:
  301. alen = wcslen(item);
  302. if (dwAccessRightsFilter &&
  303. !(am_mask/*dwAccessRightsFilter*/ & te->attr.taRights)) continue;
  304. if (vtDataTypeFilter != VT_EMPTY &&
  305. S_OK != lo_checktype(&cctx, &te->attr,
  306. vtDataTypeFilter)) continue;
  307. break;
  308. case OPC_BRANCH:
  309. if (!wcschr(item, brsep)) continue;
  310. //if (1 >= lo_name_level(brsep, item)) continue;
  311. alen = lo_name_levlen(brsep, item, 1);
  312. {
  313. loWchar *uit;
  314. if (ulist->total &&
  315. !se->wstrncmp(item, uit = ulist->list[ulist->total - 1], alen) &&
  316. 0 == uit[alen]) continue; /* duplicate */
  317. }
  318. break;
  319. }
  320. if (!loStringBuf_REALLOC(&aname, alen + 1))
  321. {
  322. hr = E_OUTOFMEMORY; break;
  323. }
  324. wcsncpy(aname.sb_str, item, alen); aname.sb_str[alen] = 0;
  325. if (szFilterCriteria &&
  326. !MatchPattern(aname.sb_str, szFilterCriteria, casesens))
  327. continue;
  328. if (OPC_BRANCH == dwBrowseFilterType)
  329. {
  330. unsigned uu;
  331. lo_hash a_hash = loSTRHASH(se, aname.sb_str);
  332. for(uu = ulist->total; uu; uu--)
  333. if (a_hash == hash_list[uu-1] &&
  334. !se->wstrcmp(aname.sb_str, ulist->list[uu-1]) ) break;
  335. if (uu) continue;
  336. if (!preallocX((void**)&hash_list,
  337. sizeof(*hash_list)*(ulist->total+1)))
  338. {
  339. hr = E_OUTOFMEMORY; break;
  340. }
  341. hash_list[ulist->total] = a_hash;
  342. }
  343. //UL_DEBUG((LOG_SR("Browse %ls"), aname.sb_str));
  344. hr = ulist->add_item(&aname.sb_str);
  345. if (S_OK != hr) break;
  346. } /* end of for() */
  347. loUnLOCK_MGMT_O(&se->lkMgmt);
  348. /*
  349. UL_WARNING((LOG_SR("BrowseOPC <%ls> %d TIME %d"),
  350. loWnul(brpos), ulist->total, lo_millisec() - stst));
  351. //*/
  352. if (brpos) freeX(brpos);
  353. if (hash_list) freeX(hash_list);
  354. loStringBuf_clear(&aname);
  355. }
  356. Return:
  357. if (S_OK == hr &&
  358. S_OK == (hr = ulist->initiate(&otrk)))
  359. {
  360. *ppIEnumString = (LPENUMSTRING)ulist;
  361. UL_NOTICE((LOG_SR("BrowseOPCItemIDs() = %u"), ulist->total));
  362. if (!ulist->total) { ENUM_EMPTY(hr, ldFlags, ppIEnumString); }
  363. }
  364. else
  365. {
  366. if (ulist) { delete ulist; ulist = 0; }
  367. UL_INFO((LOG_SR("BrowseOPCItemIDs() = %s"), loStrError(hr)));
  368. }
  369. LO_FINISH();
  370. return hr;
  371. }
  372. /***************************************************************************/
  373. loTagId lo_browse_tag(loService *se, loTagId first,
  374. const loWchar *name, unsigned len,
  375. OPCBROWSETYPE btype)
  376. {
  377. loTagEntry *te, *stop;
  378. if (!loSERVICE_OK(se)) return 0;
  379. if (-1 == len) len = name? wcslen(name): 0;
  380. else if (!name && len) return 0;
  381. loLOCK_MGMT_I(&se->lkMgmt);
  382. // if (!first) first = 1;
  383. te = &se->tags[first];
  384. stop = &se->tags[se->lastnamed];
  385. while(te <= stop)
  386. {
  387. loWchar *tail;
  388. if ((loTt_VISIBLE & te->attr.taFlags) && /* loTE_USED(te) && */
  389. (tail = te->attr.taName) &&
  390. !se->wstrncmp(tail, name, len) &&
  391. (0 == len ||
  392. 0 != *(tail += len) && /* only branches allowed */
  393. *(tail++) == se->branch_sep))
  394. {
  395. switch(btype)
  396. {
  397. case OPC_BRANCH:
  398. if (0 != wcschr(tail, se->branch_sep)) goto Found;
  399. break;
  400. case OPC_LEAF:
  401. if (!se->branch_sep ||
  402. 0 == wcschr(tail, se->branch_sep)) goto Found;
  403. break;
  404. case OPC_FLAT:
  405. default:
  406. goto Found;
  407. }
  408. }
  409. te++;
  410. }
  411. te = se->tags;
  412. Found:
  413. first = te - se->tags;
  414. loUnLOCK_MGMT_I(&se->lkMgmt);
  415. return first;
  416. }
  417. loTagId lo_browse_branch(loService *se, const loWchar *name)
  418. {
  419. loTagId ti;
  420. unsigned len;
  421. if (!loSERVICE_OK(se) || !se->branch_sep) return 0;
  422. len = name? wcslen(name): 0;
  423. loLOCK_MGMT_O(&se->lkMgmt);
  424. for(ti = 0; ti = lo_browse_tag(se, ti, name, len, OPC_FLAT); ti++)
  425. if (wcslen(se->tags[ti].attr.taName) > len) goto Break;
  426. ti = 0;
  427. Break:
  428. loUnLOCK_MGMT_O(&se->lkMgmt);
  429. return ti;
  430. }
  431. /* end of browse.cpp */