nsRDFContainer.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727
  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. /*
  6. Implementation for the RDF container.
  7. Notes
  8. -----
  9. 1. RDF containers are one-indexed. This means that a lot of the loops
  10. that you'd normally think you'd write like this:
  11. for (i = 0; i < count; ++i) {}
  12. You've gotta write like this:
  13. for (i = 1; i <= count; ++i) {}
  14. "Sure, right, yeah, of course.", you say. Well maybe I'm just
  15. thick, but it's easy to slip up.
  16. 2. The RDF:nextVal property on the container is an
  17. implementation-level hack that is used to quickly compute the
  18. next value for appending to the container. It will no doubt
  19. become royally screwed up in the case of aggregation.
  20. 3. The RDF:nextVal property is also used to retrieve the count of
  21. elements in the container.
  22. */
  23. #include "nsCOMPtr.h"
  24. #include "nsIRDFContainer.h"
  25. #include "nsIRDFContainerUtils.h"
  26. #include "nsIRDFInMemoryDataSource.h"
  27. #include "nsIRDFPropagatableDataSource.h"
  28. #include "nsIRDFService.h"
  29. #include "nsIServiceManager.h"
  30. #include "nsRDFCID.h"
  31. #include "nsString.h"
  32. #include "nsXPIDLString.h"
  33. #include "rdf.h"
  34. #define RDF_SEQ_LIST_LIMIT 8
  35. class RDFContainerImpl : public nsIRDFContainer
  36. {
  37. public:
  38. // nsISupports interface
  39. NS_DECL_ISUPPORTS
  40. // nsIRDFContainer interface
  41. NS_DECL_NSIRDFCONTAINER
  42. private:
  43. friend nsresult NS_NewRDFContainer(nsIRDFContainer** aResult);
  44. RDFContainerImpl();
  45. virtual ~RDFContainerImpl();
  46. nsresult Init();
  47. nsresult Renumber(int32_t aStartIndex, int32_t aIncrement);
  48. nsresult SetNextValue(int32_t aIndex);
  49. nsresult GetNextValue(nsIRDFResource** aResult);
  50. nsIRDFDataSource* mDataSource;
  51. nsIRDFResource* mContainer;
  52. // pseudo constants
  53. static int32_t gRefCnt;
  54. static nsIRDFService* gRDFService;
  55. static nsIRDFContainerUtils* gRDFContainerUtils;
  56. static nsIRDFResource* kRDF_nextVal;
  57. };
  58. int32_t RDFContainerImpl::gRefCnt = 0;
  59. nsIRDFService* RDFContainerImpl::gRDFService;
  60. nsIRDFContainerUtils* RDFContainerImpl::gRDFContainerUtils;
  61. nsIRDFResource* RDFContainerImpl::kRDF_nextVal;
  62. ////////////////////////////////////////////////////////////////////////
  63. // nsISupports interface
  64. NS_IMPL_ISUPPORTS(RDFContainerImpl, nsIRDFContainer)
  65. ////////////////////////////////////////////////////////////////////////
  66. // nsIRDFContainer interface
  67. NS_IMETHODIMP
  68. RDFContainerImpl::GetDataSource(nsIRDFDataSource** _retval)
  69. {
  70. *_retval = mDataSource;
  71. NS_IF_ADDREF(*_retval);
  72. return NS_OK;
  73. }
  74. NS_IMETHODIMP
  75. RDFContainerImpl::GetResource(nsIRDFResource** _retval)
  76. {
  77. *_retval = mContainer;
  78. NS_IF_ADDREF(*_retval);
  79. return NS_OK;
  80. }
  81. NS_IMETHODIMP
  82. RDFContainerImpl::Init(nsIRDFDataSource *aDataSource, nsIRDFResource *aContainer)
  83. {
  84. NS_PRECONDITION(aDataSource != nullptr, "null ptr");
  85. if (! aDataSource)
  86. return NS_ERROR_NULL_POINTER;
  87. NS_PRECONDITION(aContainer != nullptr, "null ptr");
  88. if (! aContainer)
  89. return NS_ERROR_NULL_POINTER;
  90. nsresult rv;
  91. bool isContainer;
  92. rv = gRDFContainerUtils->IsContainer(aDataSource, aContainer, &isContainer);
  93. if (NS_FAILED(rv)) return rv;
  94. // ``throw'' if we can't create a container on the specified
  95. // datasource/resource combination.
  96. if (! isContainer)
  97. return NS_ERROR_FAILURE;
  98. NS_IF_RELEASE(mDataSource);
  99. mDataSource = aDataSource;
  100. NS_ADDREF(mDataSource);
  101. NS_IF_RELEASE(mContainer);
  102. mContainer = aContainer;
  103. NS_ADDREF(mContainer);
  104. return NS_OK;
  105. }
  106. NS_IMETHODIMP
  107. RDFContainerImpl::GetCount(int32_t *aCount)
  108. {
  109. if (!mDataSource || !mContainer)
  110. return NS_ERROR_NOT_INITIALIZED;
  111. nsresult rv;
  112. // Get the next value, which hangs off of the bag via the
  113. // RDF:nextVal property. This is the _next value_ that will get
  114. // assigned in a one-indexed array. So, it's actually _one more_
  115. // than the actual count of elements in the container.
  116. //
  117. // XXX To handle aggregation, this should probably be a
  118. // GetTargets() that enumerates all of the values and picks the
  119. // largest one.
  120. nsCOMPtr<nsIRDFNode> nextValNode;
  121. rv = mDataSource->GetTarget(mContainer, kRDF_nextVal, true, getter_AddRefs(nextValNode));
  122. if (NS_FAILED(rv)) return rv;
  123. if (rv == NS_RDF_NO_VALUE)
  124. return NS_ERROR_UNEXPECTED;
  125. nsCOMPtr<nsIRDFLiteral> nextValLiteral;
  126. rv = nextValNode->QueryInterface(NS_GET_IID(nsIRDFLiteral), getter_AddRefs(nextValLiteral));
  127. if (NS_FAILED(rv)) return rv;
  128. const char16_t *s;
  129. rv = nextValLiteral->GetValueConst( &s );
  130. if (NS_FAILED(rv)) return rv;
  131. nsAutoString nextValStr(s);
  132. int32_t nextVal;
  133. nsresult err;
  134. nextVal = nextValStr.ToInteger(&err);
  135. if (NS_FAILED(err))
  136. return NS_ERROR_UNEXPECTED;
  137. *aCount = nextVal - 1;
  138. return NS_OK;
  139. }
  140. NS_IMETHODIMP
  141. RDFContainerImpl::GetElements(nsISimpleEnumerator **_retval)
  142. {
  143. if (!mDataSource || !mContainer)
  144. return NS_ERROR_NOT_INITIALIZED;
  145. return NS_NewContainerEnumerator(mDataSource, mContainer, _retval);
  146. }
  147. NS_IMETHODIMP
  148. RDFContainerImpl::AppendElement(nsIRDFNode *aElement)
  149. {
  150. if (!mDataSource || !mContainer)
  151. return NS_ERROR_NOT_INITIALIZED;
  152. NS_PRECONDITION(aElement != nullptr, "null ptr");
  153. if (! aElement)
  154. return NS_ERROR_NULL_POINTER;
  155. nsresult rv;
  156. nsCOMPtr<nsIRDFResource> nextVal;
  157. rv = GetNextValue(getter_AddRefs(nextVal));
  158. if (NS_FAILED(rv)) return rv;
  159. rv = mDataSource->Assert(mContainer, nextVal, aElement, true);
  160. if (NS_FAILED(rv)) return rv;
  161. return NS_OK;
  162. }
  163. NS_IMETHODIMP
  164. RDFContainerImpl::RemoveElement(nsIRDFNode *aElement, bool aRenumber)
  165. {
  166. if (!mDataSource || !mContainer)
  167. return NS_ERROR_NOT_INITIALIZED;
  168. NS_PRECONDITION(aElement != nullptr, "null ptr");
  169. if (! aElement)
  170. return NS_ERROR_NULL_POINTER;
  171. nsresult rv;
  172. int32_t idx;
  173. rv = IndexOf(aElement, &idx);
  174. if (NS_FAILED(rv)) return rv;
  175. if (idx < 0)
  176. return NS_OK;
  177. // Remove the element.
  178. nsCOMPtr<nsIRDFResource> ordinal;
  179. rv = gRDFContainerUtils->IndexToOrdinalResource(idx,
  180. getter_AddRefs(ordinal));
  181. if (NS_FAILED(rv)) return rv;
  182. rv = mDataSource->Unassert(mContainer, ordinal, aElement);
  183. if (NS_FAILED(rv)) return rv;
  184. if (aRenumber) {
  185. // Now slide the rest of the collection backwards to fill in
  186. // the gap. This will have the side effect of completely
  187. // renumber the container from index to the end.
  188. rv = Renumber(idx + 1, -1);
  189. if (NS_FAILED(rv)) return rv;
  190. }
  191. return NS_OK;
  192. }
  193. NS_IMETHODIMP
  194. RDFContainerImpl::InsertElementAt(nsIRDFNode *aElement, int32_t aIndex, bool aRenumber)
  195. {
  196. if (!mDataSource || !mContainer)
  197. return NS_ERROR_NOT_INITIALIZED;
  198. NS_PRECONDITION(aElement != nullptr, "null ptr");
  199. if (! aElement)
  200. return NS_ERROR_NULL_POINTER;
  201. NS_PRECONDITION(aIndex >= 1, "illegal value");
  202. if (aIndex < 1)
  203. return NS_ERROR_ILLEGAL_VALUE;
  204. nsresult rv;
  205. int32_t count;
  206. rv = GetCount(&count);
  207. if (NS_FAILED(rv)) return rv;
  208. NS_ASSERTION(aIndex <= count + 1, "illegal value");
  209. if (aIndex > count + 1)
  210. return NS_ERROR_ILLEGAL_VALUE;
  211. if (aRenumber) {
  212. // Make a hole for the element. This will have the side effect of
  213. // completely renumbering the container from 'aIndex' to 'count',
  214. // and will spew assertions.
  215. rv = Renumber(aIndex, +1);
  216. if (NS_FAILED(rv)) return rv;
  217. }
  218. nsCOMPtr<nsIRDFResource> ordinal;
  219. rv = gRDFContainerUtils->IndexToOrdinalResource(aIndex, getter_AddRefs(ordinal));
  220. if (NS_FAILED(rv)) return rv;
  221. rv = mDataSource->Assert(mContainer, ordinal, aElement, true);
  222. if (NS_FAILED(rv)) return rv;
  223. return NS_OK;
  224. }
  225. NS_IMETHODIMP
  226. RDFContainerImpl::RemoveElementAt(int32_t aIndex, bool aRenumber, nsIRDFNode** _retval)
  227. {
  228. if (!mDataSource || !mContainer)
  229. return NS_ERROR_NOT_INITIALIZED;
  230. *_retval = nullptr;
  231. if (aIndex< 1)
  232. return NS_ERROR_ILLEGAL_VALUE;
  233. nsresult rv;
  234. int32_t count;
  235. rv = GetCount(&count);
  236. if (NS_FAILED(rv)) return rv;
  237. if (aIndex > count)
  238. return NS_ERROR_ILLEGAL_VALUE;
  239. nsCOMPtr<nsIRDFResource> ordinal;
  240. rv = gRDFContainerUtils->IndexToOrdinalResource(aIndex, getter_AddRefs(ordinal));
  241. if (NS_FAILED(rv)) return rv;
  242. nsCOMPtr<nsIRDFNode> old;
  243. rv = mDataSource->GetTarget(mContainer, ordinal, true, getter_AddRefs(old));
  244. if (NS_FAILED(rv)) return rv;
  245. if (rv == NS_OK) {
  246. rv = mDataSource->Unassert(mContainer, ordinal, old);
  247. if (NS_FAILED(rv)) return rv;
  248. if (aRenumber) {
  249. // Now slide the rest of the collection backwards to fill in
  250. // the gap. This will have the side effect of completely
  251. // renumber the container from index to the end.
  252. rv = Renumber(aIndex + 1, -1);
  253. if (NS_FAILED(rv)) return rv;
  254. }
  255. }
  256. old.swap(*_retval);
  257. return NS_OK;
  258. }
  259. NS_IMETHODIMP
  260. RDFContainerImpl::IndexOf(nsIRDFNode *aElement, int32_t *aIndex)
  261. {
  262. if (!mDataSource || !mContainer)
  263. return NS_ERROR_NOT_INITIALIZED;
  264. return gRDFContainerUtils->IndexOf(mDataSource, mContainer,
  265. aElement, aIndex);
  266. }
  267. ////////////////////////////////////////////////////////////////////////
  268. RDFContainerImpl::RDFContainerImpl()
  269. : mDataSource(nullptr), mContainer(nullptr)
  270. {
  271. }
  272. nsresult
  273. RDFContainerImpl::Init()
  274. {
  275. if (gRefCnt++ == 0) {
  276. nsresult rv;
  277. NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
  278. rv = CallGetService(kRDFServiceCID, &gRDFService);
  279. if (NS_FAILED(rv)) {
  280. NS_ERROR("unable to get RDF service");
  281. return rv;
  282. }
  283. rv = gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "nextVal"),
  284. &kRDF_nextVal);
  285. if (NS_FAILED(rv)) return rv;
  286. NS_DEFINE_CID(kRDFContainerUtilsCID, NS_RDFCONTAINERUTILS_CID);
  287. rv = CallGetService(kRDFContainerUtilsCID, &gRDFContainerUtils);
  288. if (NS_FAILED(rv)) {
  289. NS_ERROR("unable to get RDF container utils service");
  290. return rv;
  291. }
  292. }
  293. return NS_OK;
  294. }
  295. RDFContainerImpl::~RDFContainerImpl()
  296. {
  297. #ifdef DEBUG_REFS
  298. --gInstanceCount;
  299. fprintf(stdout, "%d - RDF: RDFContainerImpl\n", gInstanceCount);
  300. #endif
  301. NS_IF_RELEASE(mContainer);
  302. NS_IF_RELEASE(mDataSource);
  303. if (--gRefCnt == 0) {
  304. NS_IF_RELEASE(gRDFContainerUtils);
  305. NS_IF_RELEASE(gRDFService);
  306. NS_IF_RELEASE(kRDF_nextVal);
  307. }
  308. }
  309. nsresult
  310. NS_NewRDFContainer(nsIRDFContainer** aResult)
  311. {
  312. RDFContainerImpl* result = new RDFContainerImpl();
  313. if (! result)
  314. return NS_ERROR_OUT_OF_MEMORY;
  315. nsresult rv;
  316. rv = result->Init();
  317. if (NS_FAILED(rv)) {
  318. delete result;
  319. return rv;
  320. }
  321. NS_ADDREF(result);
  322. *aResult = result;
  323. return NS_OK;
  324. }
  325. nsresult
  326. NS_NewRDFContainer(nsIRDFDataSource* aDataSource,
  327. nsIRDFResource* aResource,
  328. nsIRDFContainer** aResult)
  329. {
  330. nsresult rv;
  331. rv = NS_NewRDFContainer(aResult);
  332. if (NS_FAILED(rv)) return rv;
  333. rv = (*aResult)->Init(aDataSource, aResource);
  334. if (NS_FAILED(rv)) {
  335. NS_RELEASE(*aResult);
  336. }
  337. return rv;
  338. }
  339. nsresult
  340. RDFContainerImpl::Renumber(int32_t aStartIndex, int32_t aIncrement)
  341. {
  342. if (!mDataSource || !mContainer)
  343. return NS_ERROR_NOT_INITIALIZED;
  344. // Renumber the elements in the container starting with
  345. // aStartIndex, updating each element's index by aIncrement. For
  346. // example,
  347. //
  348. // (1:a 2:b 3:c)
  349. // Renumber(2, +1);
  350. // (1:a 3:b 4:c)
  351. // Renumber(3, -1);
  352. // (1:a 2:b 3:c)
  353. //
  354. nsresult rv;
  355. if (! aIncrement)
  356. return NS_OK;
  357. int32_t count;
  358. rv = GetCount(&count);
  359. if (NS_FAILED(rv)) return rv;
  360. if (aIncrement > 0) {
  361. // Update the container's nextVal to reflect the
  362. // renumbering. We do this now if aIncrement > 0 because we'll
  363. // want to be able to acknowledge that new elements are in the
  364. // container.
  365. rv = SetNextValue(count + aIncrement + 1);
  366. if (NS_FAILED(rv)) return rv;
  367. }
  368. int32_t i;
  369. if (aIncrement < 0) {
  370. i = aStartIndex;
  371. }
  372. else {
  373. i = count; // we're one-indexed.
  374. }
  375. // Note: once we disable notifications, don't exit this method until
  376. // enabling notifications
  377. nsCOMPtr<nsIRDFPropagatableDataSource> propagatable =
  378. do_QueryInterface(mDataSource);
  379. if (propagatable) {
  380. propagatable->SetPropagateChanges(false);
  381. }
  382. bool err = false;
  383. while (!err && ((aIncrement < 0) ? (i <= count) : (i >= aStartIndex)))
  384. {
  385. nsCOMPtr<nsIRDFResource> oldOrdinal;
  386. rv = gRDFContainerUtils->IndexToOrdinalResource(i, getter_AddRefs(oldOrdinal));
  387. if (NS_FAILED(rv))
  388. {
  389. err = true;
  390. continue;
  391. }
  392. nsCOMPtr<nsIRDFResource> newOrdinal;
  393. rv = gRDFContainerUtils->IndexToOrdinalResource(i + aIncrement, getter_AddRefs(newOrdinal));
  394. if (NS_FAILED(rv))
  395. {
  396. err = true;
  397. continue;
  398. }
  399. // Because of aggregation, we need to be paranoid about the
  400. // possibility that >1 element may be present per ordinal. If
  401. // there _is_ in fact more than one element, they'll all get
  402. // assigned to the same new ordinal; i.e., we don't make any
  403. // attempt to "clean up" the duplicate numbering. (Doing so
  404. // would require two passes.)
  405. nsCOMPtr<nsISimpleEnumerator> targets;
  406. rv = mDataSource->GetTargets(mContainer, oldOrdinal, true, getter_AddRefs(targets));
  407. if (NS_FAILED(rv))
  408. {
  409. err = true;
  410. continue;
  411. }
  412. while (1) {
  413. bool hasMore;
  414. rv = targets->HasMoreElements(&hasMore);
  415. if (NS_FAILED(rv))
  416. {
  417. err = true;
  418. break;
  419. }
  420. if (! hasMore)
  421. break;
  422. nsCOMPtr<nsISupports> isupports;
  423. rv = targets->GetNext(getter_AddRefs(isupports));
  424. if (NS_FAILED(rv))
  425. {
  426. err = true;
  427. break;
  428. }
  429. nsCOMPtr<nsIRDFNode> element( do_QueryInterface(isupports) );
  430. NS_ASSERTION(element != nullptr, "something funky in the enumerator");
  431. if (! element)
  432. {
  433. err = true;
  434. rv = NS_ERROR_UNEXPECTED;
  435. break;
  436. }
  437. rv = mDataSource->Unassert(mContainer, oldOrdinal, element);
  438. if (NS_FAILED(rv))
  439. {
  440. err = true;
  441. break;
  442. }
  443. rv = mDataSource->Assert(mContainer, newOrdinal, element, true);
  444. if (NS_FAILED(rv))
  445. {
  446. err = true;
  447. break;
  448. }
  449. }
  450. i -= aIncrement;
  451. }
  452. if (!err && (aIncrement < 0))
  453. {
  454. // Update the container's nextVal to reflect the
  455. // renumbering. We do this now if aIncrement < 0 because, up
  456. // until this point, we'll want people to be able to find
  457. // things that are still "at the end".
  458. rv = SetNextValue(count + aIncrement + 1);
  459. if (NS_FAILED(rv))
  460. {
  461. err = true;
  462. }
  463. }
  464. // Note: MUST enable notifications before exiting this method
  465. if (propagatable) {
  466. propagatable->SetPropagateChanges(true);
  467. }
  468. if (err) return(rv);
  469. return NS_OK;
  470. }
  471. nsresult
  472. RDFContainerImpl::SetNextValue(int32_t aIndex)
  473. {
  474. if (!mDataSource || !mContainer)
  475. return NS_ERROR_NOT_INITIALIZED;
  476. nsresult rv;
  477. // Remove the current value of nextVal, if there is one.
  478. nsCOMPtr<nsIRDFNode> nextValNode;
  479. if (NS_SUCCEEDED(rv = mDataSource->GetTarget(mContainer,
  480. kRDF_nextVal,
  481. true,
  482. getter_AddRefs(nextValNode)))) {
  483. if (NS_FAILED(rv = mDataSource->Unassert(mContainer, kRDF_nextVal, nextValNode))) {
  484. NS_ERROR("unable to update nextVal");
  485. return rv;
  486. }
  487. }
  488. nsAutoString s;
  489. s.AppendInt(aIndex, 10);
  490. nsCOMPtr<nsIRDFLiteral> nextVal;
  491. if (NS_FAILED(rv = gRDFService->GetLiteral(s.get(), getter_AddRefs(nextVal)))) {
  492. NS_ERROR("unable to get nextVal literal");
  493. return rv;
  494. }
  495. rv = mDataSource->Assert(mContainer, kRDF_nextVal, nextVal, true);
  496. if (rv != NS_RDF_ASSERTION_ACCEPTED) {
  497. NS_ERROR("unable to update nextVal");
  498. return NS_ERROR_FAILURE;
  499. }
  500. return NS_OK;
  501. }
  502. nsresult
  503. RDFContainerImpl::GetNextValue(nsIRDFResource** aResult)
  504. {
  505. if (!mDataSource || !mContainer)
  506. return NS_ERROR_NOT_INITIALIZED;
  507. nsresult rv;
  508. // Get the next value, which hangs off of the bag via the
  509. // RDF:nextVal property.
  510. nsCOMPtr<nsIRDFNode> nextValNode;
  511. rv = mDataSource->GetTarget(mContainer, kRDF_nextVal, true, getter_AddRefs(nextValNode));
  512. if (NS_FAILED(rv)) return rv;
  513. if (rv == NS_RDF_NO_VALUE)
  514. return NS_ERROR_UNEXPECTED;
  515. nsCOMPtr<nsIRDFLiteral> nextValLiteral;
  516. rv = nextValNode->QueryInterface(NS_GET_IID(nsIRDFLiteral), getter_AddRefs(nextValLiteral));
  517. if (NS_FAILED(rv)) return rv;
  518. const char16_t* s;
  519. rv = nextValLiteral->GetValueConst(&s);
  520. if (NS_FAILED(rv)) return rv;
  521. int32_t nextVal = 0;
  522. {
  523. for (const char16_t* p = s; *p != 0; ++p) {
  524. NS_ASSERTION(*p >= '0' && *p <= '9', "not a digit");
  525. if (*p < '0' || *p > '9')
  526. break;
  527. nextVal *= 10;
  528. nextVal += *p - '0';
  529. }
  530. }
  531. static const char kRDFNameSpaceURI[] = RDF_NAMESPACE_URI;
  532. char buf[sizeof(kRDFNameSpaceURI) + 16];
  533. nsFixedCString nextValStr(buf, sizeof(buf), 0);
  534. nextValStr = kRDFNameSpaceURI;
  535. nextValStr.Append('_');
  536. nextValStr.AppendInt(nextVal, 10);
  537. rv = gRDFService->GetResource(nextValStr, aResult);
  538. if (NS_FAILED(rv)) return rv;
  539. // Now increment the RDF:nextVal property.
  540. rv = mDataSource->Unassert(mContainer, kRDF_nextVal, nextValLiteral);
  541. if (NS_FAILED(rv)) return rv;
  542. ++nextVal;
  543. nextValStr.Truncate();
  544. nextValStr.AppendInt(nextVal, 10);
  545. rv = gRDFService->GetLiteral(NS_ConvertASCIItoUTF16(nextValStr).get(), getter_AddRefs(nextValLiteral));
  546. if (NS_FAILED(rv)) return rv;
  547. rv = mDataSource->Assert(mContainer, kRDF_nextVal, nextValLiteral, true);
  548. if (NS_FAILED(rv)) return rv;
  549. if (RDF_SEQ_LIST_LIMIT == nextVal)
  550. {
  551. // focal point for RDF container mutation;
  552. // basically, provide a hint to allow for fast access
  553. nsCOMPtr<nsIRDFInMemoryDataSource> inMem = do_QueryInterface(mDataSource);
  554. if (inMem)
  555. {
  556. // ignore error; failure just means slower access
  557. (void)inMem->EnsureFastContainment(mContainer);
  558. }
  559. }
  560. return NS_OK;
  561. }