llinventory.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188
  1. /**
  2. * @file llinventory.cpp
  3. * @brief Implementation of the inventory system.
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewergpl$
  6. *
  7. * Copyright (c) 2001-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "linden_common.h"
  33. #include <sstream>
  34. #include "boost/tokenizer.hpp"
  35. #include "llinventory.h"
  36. #include "lldbstrings.h"
  37. #include "llmessage.h"
  38. #include "llsdutil.h"
  39. #include "llsdserialize.h"
  40. #include "llxorcipher.h"
  41. #include "hbxxh.h"
  42. static const LLUUID MAGIC_ID("3c115e51-04f4-523c-9fa6-98aff1034730");
  43. // Keys used by agent-inventory-service
  44. static const std::string INV_ITEM_ID_LABEL("item_id");
  45. static const std::string INV_PARENT_ID_LABEL("parent_id");
  46. static const std::string INV_THUMBNAIL_LABEL("thumbnail");
  47. static const std::string INV_THUMBNAIL_ID_LABEL("thumbnail_id");
  48. static const std::string INV_ASSET_TYPE_LABEL("type");
  49. static const std::string INV_INVENTORY_TYPE_LABEL("inv_type");
  50. static const std::string INV_NAME_LABEL("name");
  51. static const std::string INV_DESC_LABEL("desc");
  52. static const std::string INV_PERMISSIONS_LABEL("permissions");
  53. static const std::string INV_SHADOW_ID_LABEL("shadow_id");
  54. static const std::string INV_ASSET_ID_LABEL("asset_id");
  55. static const std::string INV_LINKED_ID_LABEL("linked_id");
  56. static const std::string INV_SALE_INFO_LABEL("sale_info");
  57. static const std::string INV_FLAGS_LABEL("flags");
  58. static const std::string INV_CREATION_DATE_LABEL("created_at");
  59. static const std::string INV_ASSET_TYPE_LABEL_WS("type_default");
  60. static const std::string INV_FOLDER_ID_LABEL_WS("category_id");
  61. ///----------------------------------------------------------------------------
  62. /// Class LLInventoryObject
  63. ///----------------------------------------------------------------------------
  64. LLInventoryObject::LLInventoryObject(const LLUUID& uuid,
  65. const LLUUID& parent_uuid,
  66. LLAssetType::EType type,
  67. const std::string& name)
  68. : mUUID(uuid),
  69. mParentUUID(parent_uuid),
  70. mType(type),
  71. mName(name),
  72. mCreationDate(0)
  73. {
  74. correctInventoryName(mName);
  75. }
  76. LLInventoryObject::LLInventoryObject()
  77. : mType(LLAssetType::AT_NONE),
  78. mCreationDate(0)
  79. {
  80. }
  81. void LLInventoryObject::copyObject(const LLInventoryObject* otherp)
  82. {
  83. mUUID = otherp->mUUID;
  84. mParentUUID = otherp->mParentUUID;
  85. mThumbnailUUID = otherp->mThumbnailUUID;
  86. mType = otherp->mType;
  87. mName = otherp->mName;
  88. }
  89. void LLInventoryObject::rename(const std::string& n)
  90. {
  91. std::string new_name(n);
  92. correctInventoryName(new_name);
  93. if (!new_name.empty() && new_name != mName)
  94. {
  95. mName = new_name;
  96. }
  97. }
  98. //virtual
  99. bool LLInventoryObject::importLegacyStream(std::istream& input_stream)
  100. {
  101. // *NOTE: Changing the buffer size will require changing the scanf
  102. // calls below.
  103. char buffer[MAX_STRING];
  104. char keyword[MAX_STRING];
  105. char valuestr[MAX_STRING];
  106. keyword[0] = '\0';
  107. valuestr[0] = '\0';
  108. while (input_stream.good())
  109. {
  110. input_stream.getline(buffer, MAX_STRING);
  111. // This happens a lot... And it does not matter. HB
  112. if (!strcmp("|", buffer))
  113. {
  114. continue;
  115. }
  116. if (sscanf(buffer, " %254s %254s", keyword, valuestr) < 1)
  117. {
  118. continue;
  119. }
  120. if (!strcmp("{", keyword))
  121. {
  122. continue;
  123. }
  124. if (!strcmp("}", keyword))
  125. {
  126. break;
  127. }
  128. else if (!strcmp("obj_id", keyword))
  129. {
  130. mUUID.set(valuestr);
  131. }
  132. else if (!strcmp("parent_id", keyword))
  133. {
  134. mParentUUID.set(valuestr);
  135. }
  136. else if (!strcmp("type", keyword))
  137. {
  138. mType = LLAssetType::lookup(valuestr);
  139. }
  140. else if (!strcmp("name", keyword))
  141. {
  142. //strcpy(valuestr, buffer + strlen(keyword) + 3);
  143. // *NOTE: Not ANSI C, but widely supported.
  144. sscanf(buffer, " %254s %254[^|]", keyword, valuestr);
  145. mName.assign(valuestr);
  146. correctInventoryName(mName);
  147. }
  148. else if (!strcmp("metadata", keyword))
  149. {
  150. LLSD metadata;
  151. #if 0
  152. if (!strncmp("<llsd>", valuestr, 6))
  153. {
  154. std::istringstream stream(valuestr);
  155. LLSDSerialize::fromXML(metadata, stream);
  156. }
  157. else
  158. #endif
  159. {
  160. metadata = LLSD(valuestr);
  161. }
  162. if (metadata.has("thumbnail"))
  163. {
  164. const LLSD& thumbnail = metadata["thumbnail"];
  165. if (thumbnail.has("asset_id"))
  166. {
  167. setThumbnailUUID(thumbnail["asset_id"].asUUID());
  168. }
  169. }
  170. }
  171. else
  172. {
  173. llwarns << "Unknown keyword '" << keyword << "' for object "
  174. << mUUID << ". Buffer contents: " << buffer << llendl;
  175. }
  176. }
  177. return true;
  178. }
  179. //virtual
  180. bool LLInventoryObject::exportLegacyStream(std::ostream& output_stream,
  181. bool) const
  182. {
  183. std::string uuid_str;
  184. output_stream << "\tinv_object\t0\n\t{\n";
  185. mUUID.toString(uuid_str);
  186. output_stream << "\t\tobj_id\t" << uuid_str << "\n";
  187. mParentUUID.toString(uuid_str);
  188. output_stream << "\t\tparent_id\t" << uuid_str << "\n";
  189. output_stream << "\t\ttype\t" << LLAssetType::lookup(mType) << "\n";
  190. output_stream << "\t\tname\t" << mName.c_str() << "|\n";
  191. if (mThumbnailUUID.notNull())
  192. {
  193. // Max length is 255 chars, will have to export differently if it gets
  194. // more data (e.g. use newline and toNotation (uses {}) for unlimited
  195. // size).
  196. LLSD metadata;
  197. metadata["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID);
  198. #if 0
  199. output_stream << "\t\tmetadata\t";
  200. LLSDSerialize::toXML(metadata, output_stream);
  201. output_stream << "|\n";
  202. #else
  203. output_stream << "\t\tmetadata\t" << metadata << "|\n";
  204. #endif
  205. }
  206. output_stream << "\t}\n";
  207. return true;
  208. }
  209. void LLInventoryObject::updateParentOnServer(bool) const
  210. {
  211. // Do not do anything
  212. llwarns << "No-operation call. This method should be overridden !"
  213. << llendl;
  214. }
  215. void LLInventoryObject::updateServer(bool) const
  216. {
  217. // Do not do anything
  218. llwarns << "No-operation call. This method should be overridden !"
  219. << llendl;
  220. }
  221. //static
  222. void LLInventoryObject::correctInventoryName(std::string& name)
  223. {
  224. LLStringUtil::replaceNonstandardASCII(name, ' ');
  225. LLStringUtil::replaceChar(name, '|', ' ');
  226. LLStringUtil::trim(name);
  227. LLStringUtil::truncate(name, DB_INV_ITEM_NAME_STR_LEN);
  228. }
  229. ///----------------------------------------------------------------------------
  230. /// Class LLInventoryItem
  231. ///----------------------------------------------------------------------------
  232. LLInventoryItem::LLInventoryItem(const LLUUID& uuid,
  233. const LLUUID& parent_uuid,
  234. const LLPermissions& permissions,
  235. const LLUUID& asset_uuid,
  236. LLAssetType::EType type,
  237. LLInventoryType::EType inv_type,
  238. const std::string& name,
  239. const std::string& desc,
  240. const LLSaleInfo& sale_info,
  241. U32 flags,
  242. S32 creation_date_utc)
  243. : LLInventoryObject(uuid, parent_uuid, type, name),
  244. mPermissions(permissions),
  245. mAssetUUID(asset_uuid),
  246. mDescription(desc),
  247. mSaleInfo(sale_info),
  248. mInventoryType(inv_type),
  249. mFlags(flags)
  250. {
  251. mCreationDate = creation_date_utc;
  252. LLStringUtil::replaceNonstandardASCII(mDescription, ' ');
  253. LLStringUtil::replaceChar(mDescription, '|', ' ');
  254. mPermissions.initMasks(inv_type);
  255. }
  256. LLInventoryItem::LLInventoryItem()
  257. : LLInventoryObject(),
  258. mPermissions(),
  259. mAssetUUID(),
  260. mDescription(),
  261. mSaleInfo(),
  262. mInventoryType(LLInventoryType::IT_NONE),
  263. mFlags(0)
  264. {
  265. mCreationDate = 0;
  266. }
  267. LLInventoryItem::LLInventoryItem(const LLInventoryItem* otherp)
  268. : LLInventoryObject()
  269. {
  270. copyItem(otherp);
  271. }
  272. //virtual
  273. void LLInventoryItem::copyItem(const LLInventoryItem* otherp)
  274. {
  275. copyObject(otherp);
  276. mPermissions = otherp->mPermissions;
  277. mAssetUUID = otherp->mAssetUUID;
  278. mDescription = otherp->mDescription;
  279. mSaleInfo = otherp->mSaleInfo;
  280. mInventoryType = otherp->mInventoryType;
  281. mFlags = otherp->mFlags;
  282. mCreationDate = otherp->mCreationDate;
  283. }
  284. // Note: this method is used to identify a newly created copy of an inventory
  285. // item, and avoid considering it a newly received item by inventory observers.
  286. // We therefore only care about part of the data (e.g. we do not care about the
  287. // parent, since the item may be copied into another folder, neither about the
  288. // sale info which is irrelevant to copy-ok items) and discard from the hash
  289. // any data that changes during the copy action (e.g. the last owner UUID which
  290. // gets reset, or the thumbnail UUID which is currently not copied since the
  291. // copy command still uses the legacy UDP messaging and not yet AISv3). HB
  292. LLUUID LLInventoryItem::hashContents() const
  293. {
  294. HBXXH128 hash;
  295. hash.update(mName);
  296. hash.update(mDescription);
  297. hash.update((void*)mAssetUUID.mData, UUID_BYTES);
  298. U32 buffer[3];
  299. buffer[0] = (U32)mInventoryType;
  300. buffer[1] = mFlags;
  301. buffer[2] = mPermissions.getCRC32(true); // true = skip last owner UUID
  302. hash.update((void*)&buffer, 3 * sizeof(U32));
  303. return hash.digest();
  304. }
  305. // If this is a linked item, then the UUID of the base object is
  306. // this item's assetID.
  307. //virtual
  308. const LLUUID& LLInventoryItem::getLinkedUUID() const
  309. {
  310. if (LLAssetType::lookupIsLinkType(getActualType()))
  311. {
  312. return mAssetUUID;
  313. }
  314. return LLInventoryObject::getLinkedUUID();
  315. }
  316. U32 LLInventoryItem::getCRC32() const
  317. {
  318. // *FIX: Not a real crc - more of a checksum.
  319. // *NOTE: We currently do not validate the name or description, but if they
  320. // change in transit, it's no big deal.
  321. U32 crc = mUUID.getCRC32();
  322. crc += mParentUUID.getCRC32();
  323. crc += mPermissions.getCRC32();
  324. crc += mAssetUUID.getCRC32();
  325. crc += mType;
  326. crc += mInventoryType;
  327. crc += mFlags;
  328. crc += mSaleInfo.getCRC32();
  329. crc += mCreationDate;
  330. crc += mThumbnailUUID.getCRC32();
  331. return crc;
  332. }
  333. //static
  334. void LLInventoryItem::correctInventoryDescription(std::string& desc)
  335. {
  336. LLStringUtil::replaceNonstandardASCII(desc, ' ');
  337. LLStringUtil::replaceChar(desc, '|', ' ');
  338. }
  339. void LLInventoryItem::setDescription(const std::string& d)
  340. {
  341. std::string new_desc(d);
  342. LLInventoryItem::correctInventoryDescription(new_desc);
  343. if (new_desc != mDescription)
  344. {
  345. mDescription = new_desc;
  346. }
  347. }
  348. void LLInventoryItem::setPermissions(const LLPermissions& perm)
  349. {
  350. mPermissions = perm;
  351. // Override permissions to unrestricted if this is a landmark
  352. mPermissions.initMasks(mInventoryType);
  353. }
  354. void LLInventoryItem::accumulatePermissionSlamBits(const LLInventoryItem& old_item)
  355. {
  356. // Remove any pre-existing II_FLAGS_PERM_OVERWRITE_MASK flags
  357. // because we now detect when they should be set.
  358. setFlags(old_item.getFlags() | (getFlags() & ~II_FLAGS_PERM_OVERWRITE_MASK));
  359. // Enforce the PERM_OVERWRITE flags for any masks that are different
  360. // but only for AT_OBJECT's since that is the only asset type that can
  361. // exist in-world (instead of only in-inventory or in-object-contents).
  362. if (LLAssetType::AT_OBJECT == getType())
  363. {
  364. LLPermissions old_permissions = old_item.getPermissions();
  365. U32 flags_to_be_set = 0;
  366. if (old_permissions.getMaskNextOwner() != getPermissions().getMaskNextOwner())
  367. {
  368. flags_to_be_set |= II_FLAGS_OBJECT_SLAM_PERM;
  369. }
  370. if (old_permissions.getMaskEveryone() != getPermissions().getMaskEveryone())
  371. {
  372. flags_to_be_set |= II_FLAGS_OBJECT_PERM_OVERWRITE_EVERYONE;
  373. }
  374. if (old_permissions.getMaskGroup() != getPermissions().getMaskGroup())
  375. {
  376. flags_to_be_set |= II_FLAGS_OBJECT_PERM_OVERWRITE_GROUP;
  377. }
  378. LLSaleInfo old_sale_info = old_item.getSaleInfo();
  379. if (old_sale_info != getSaleInfo())
  380. {
  381. flags_to_be_set |= II_FLAGS_OBJECT_SLAM_SALE;
  382. }
  383. setFlags(getFlags() | flags_to_be_set);
  384. }
  385. }
  386. //virtual
  387. void LLInventoryItem::packMessage(LLMessageSystem* msg) const
  388. {
  389. msg->addUUIDFast(_PREHASH_ItemID, mUUID);
  390. msg->addUUIDFast(_PREHASH_FolderID, mParentUUID);
  391. mPermissions.packMessage(msg);
  392. msg->addUUIDFast(_PREHASH_AssetID, mAssetUUID);
  393. msg->addS8Fast(_PREHASH_Type, (S8)mType);
  394. msg->addS8Fast(_PREHASH_InvType, (S8)mInventoryType);
  395. msg->addU32Fast(_PREHASH_Flags, mFlags);
  396. mSaleInfo.packMessage(msg);
  397. msg->addStringFast(_PREHASH_Name, mName);
  398. msg->addStringFast(_PREHASH_Description, mDescription);
  399. msg->addS32Fast(_PREHASH_CreationDate, mCreationDate);
  400. U32 crc = getCRC32();
  401. msg->addU32Fast(_PREHASH_CRC, crc);
  402. }
  403. #undef CRC_CHECK
  404. //virtual
  405. bool LLInventoryItem::unpackMessage(LLMessageSystem* msg, const char* block,
  406. S32 block_num)
  407. {
  408. msg->getUUIDFast(block, _PREHASH_ItemID, mUUID, block_num);
  409. msg->getUUIDFast(block, _PREHASH_FolderID, mParentUUID, block_num);
  410. mPermissions.unpackMessage(msg, block, block_num);
  411. msg->getUUIDFast(block, _PREHASH_AssetID, mAssetUUID, block_num);
  412. S8 type;
  413. msg->getS8Fast(block, _PREHASH_Type, type, block_num);
  414. mType = (LLAssetType::EType)type;
  415. msg->getS8(block, "InvType", type, block_num);
  416. mInventoryType = (LLInventoryType::EType)type;
  417. mPermissions.initMasks(mInventoryType);
  418. msg->getU32Fast(block, _PREHASH_Flags, mFlags, block_num);
  419. mSaleInfo.unpackMultiMessage(msg, block, block_num);
  420. msg->getStringFast(block, _PREHASH_Name, mName, block_num);
  421. LLStringUtil::replaceNonstandardASCII(mName, ' ');
  422. msg->getStringFast(block, _PREHASH_Description, mDescription, block_num);
  423. LLStringUtil::replaceNonstandardASCII(mDescription, ' ');
  424. S32 date;
  425. msg->getS32(block, "CreationDate", date, block_num);
  426. mCreationDate = date;
  427. U32 local_crc = getCRC32();
  428. U32 remote_crc = 0;
  429. msg->getU32(block, "CRC", remote_crc, block_num);
  430. #ifdef CRC_CHECK
  431. if (local_crc == remote_crc)
  432. {
  433. LL_DEBUGS("Inventory") << "CRC matches" << LL_ENDL;
  434. return true;
  435. }
  436. else
  437. {
  438. llwarns << "Inventory CRC mismatch: local=" << std::hex << local_crc
  439. << " - remote=" << remote_crc << std::dec << llendl;
  440. return false;
  441. }
  442. #else
  443. return local_crc == remote_crc;
  444. #endif
  445. }
  446. //virtual
  447. bool LLInventoryItem::importLegacyStream(std::istream& input_stream)
  448. {
  449. // NOTE: changing the buffer size requires changing the scanf calls below.
  450. char buffer[MAX_STRING];
  451. char keyword[MAX_STRING];
  452. char valuestr[MAX_STRING];
  453. char junk[MAX_STRING];
  454. bool success = true;
  455. keyword[0] = '\0';
  456. valuestr[0] = '\0';
  457. mInventoryType = LLInventoryType::IT_NONE;
  458. mAssetUUID.setNull();
  459. while (success && input_stream.good())
  460. {
  461. input_stream.getline(buffer, MAX_STRING);
  462. // This happens a lot... And it does not matter. HB
  463. if (!strcmp("|", buffer))
  464. {
  465. continue;
  466. }
  467. if (sscanf(buffer, " %254s %254s", keyword, valuestr) < 1)
  468. {
  469. continue;
  470. }
  471. if (!strcmp("{", keyword))
  472. {
  473. continue;
  474. }
  475. if (!strcmp("}", keyword))
  476. {
  477. break;
  478. }
  479. if (!strcmp("item_id", keyword))
  480. {
  481. mUUID.set(valuestr);
  482. }
  483. else if (!strcmp("parent_id", keyword))
  484. {
  485. mParentUUID.set(valuestr);
  486. }
  487. else if (!strcmp("permissions", keyword))
  488. {
  489. success = mPermissions.importLegacyStream(input_stream);
  490. }
  491. else if (!strcmp("sale_info", keyword))
  492. {
  493. // Sale info used to contain next owner perm. It is now in
  494. // the permissions. Thus, we read that out, and fix legacy
  495. // objects. It's possible this op would fail, but it
  496. // should pick up the vast majority of the tasks.
  497. bool has_perm_mask = false;
  498. U32 perm_mask = 0;
  499. success = mSaleInfo.importLegacyStream(input_stream, has_perm_mask,
  500. perm_mask);
  501. if (has_perm_mask)
  502. {
  503. if (perm_mask == PERM_NONE)
  504. {
  505. perm_mask = mPermissions.getMaskOwner();
  506. }
  507. // fair use fix.
  508. if (!(perm_mask & PERM_COPY))
  509. {
  510. perm_mask |= PERM_TRANSFER;
  511. }
  512. mPermissions.setMaskNext(perm_mask);
  513. }
  514. }
  515. else if (!strcmp("shadow_id", keyword))
  516. {
  517. mAssetUUID.set(valuestr);
  518. LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
  519. cipher.decrypt(mAssetUUID.mData, UUID_BYTES);
  520. }
  521. else if (!strcmp("asset_id", keyword))
  522. {
  523. mAssetUUID.set(valuestr);
  524. }
  525. else if (!strcmp("type", keyword))
  526. {
  527. mType = LLAssetType::lookup(valuestr);
  528. }
  529. else if (!strcmp("inv_type", keyword))
  530. {
  531. mInventoryType = LLInventoryType::lookup(std::string(valuestr));
  532. }
  533. else if (!strcmp("flags", keyword))
  534. {
  535. sscanf(valuestr, "%x", &mFlags);
  536. }
  537. else if (!strcmp("name", keyword))
  538. {
  539. sscanf(buffer, " %254s%254[\t]%254[^|]", keyword, junk, valuestr);
  540. // IW: sscanf chokes and puts | in valuestr if there's no name
  541. if (valuestr[0] == '|')
  542. {
  543. valuestr[0] = '\000';
  544. }
  545. mName.assign(valuestr);
  546. LLStringUtil::replaceNonstandardASCII(mName, ' ');
  547. LLStringUtil::replaceChar(mName, '|', ' ');
  548. }
  549. else if (!strcmp("desc", keyword))
  550. {
  551. //strcpy(valuestr, buffer + strlen(keyword) + 3);
  552. // *NOTE: Not ANSI C, but widely supported.
  553. sscanf(buffer, " %254s%254[\t]%254[^|]", keyword, junk, valuestr);
  554. if (valuestr[0] == '|')
  555. {
  556. valuestr[0] = '\000';
  557. }
  558. mDescription.assign(valuestr);
  559. LLStringUtil::replaceNonstandardASCII(mDescription, ' ');
  560. }
  561. else if (!strcmp("creation_date", keyword))
  562. {
  563. S32 date;
  564. sscanf(valuestr, "%d", &date);
  565. mCreationDate = date;
  566. }
  567. else if (!strcmp("metadata", keyword))
  568. {
  569. LLSD metadata;
  570. #if 0
  571. if (!strncmp("<llsd>", valuestr, 6))
  572. {
  573. std::istringstream stream(valuestr);
  574. LLSDSerialize::fromXML(metadata, stream);
  575. }
  576. else
  577. #endif
  578. {
  579. metadata = LLSD(valuestr);
  580. }
  581. if (metadata.has("thumbnail"))
  582. {
  583. const LLSD& thumbnail = metadata["thumbnail"];
  584. if (thumbnail.has("asset_id"))
  585. {
  586. setThumbnailUUID(thumbnail["asset_id"].asUUID());
  587. }
  588. }
  589. }
  590. else
  591. {
  592. llwarns << "Unknown keyword '" << keyword
  593. << "' in inventory import of item " << mUUID
  594. << ". Buffer contents: " << buffer << llendl;
  595. }
  596. }
  597. // Need to convert 1.0 simstate files to a useful inventory type and
  598. // potentially deal with bad inventory tyes eg, a landmark marked as a
  599. // texture.
  600. if (mInventoryType == LLInventoryType::IT_NONE ||
  601. !inventory_and_asset_types_match(mInventoryType, mType))
  602. {
  603. LL_DEBUGS("Inventory") << "Resetting inventory type for " << mUUID
  604. << LL_ENDL;
  605. mInventoryType = LLInventoryType::defaultForAssetType(mType);
  606. }
  607. mPermissions.initMasks(mInventoryType);
  608. return success;
  609. }
  610. //virtual
  611. bool LLInventoryItem::exportLegacyStream(std::ostream& output_stream,
  612. bool include_asset_key) const
  613. {
  614. std::string uuid_str;
  615. output_stream << "\tinv_item\t0\n\t{\n";
  616. mUUID.toString(uuid_str);
  617. output_stream << "\t\titem_id\t" << uuid_str << "\n";
  618. mParentUUID.toString(uuid_str);
  619. output_stream << "\t\tparent_id\t" << uuid_str << "\n";
  620. mPermissions.exportLegacyStream(output_stream);
  621. if (mThumbnailUUID.notNull())
  622. {
  623. // Max length is 255 chars, will have to export differently if it gets
  624. // more data (e.g. use newline and toNotation (uses {}) for unlimited
  625. // size).
  626. LLSD metadata;
  627. metadata["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID);
  628. #if 0
  629. output_stream << "\t\tmetadata\t";
  630. LLSDSerialize::toXML(metadata, output_stream);
  631. output_stream << "|\n";
  632. #else
  633. output_stream << "\t\tmetadata\t" << metadata << "|\n";
  634. #endif
  635. }
  636. // Check for permissions to see the asset id, and if so write it out as an
  637. // asset id. Otherwise, apply our cheesy encryption.
  638. if (include_asset_key)
  639. {
  640. if (mPermissions.unrestricted() || mAssetUUID.isNull())
  641. {
  642. mAssetUUID.toString(uuid_str);
  643. output_stream << "\t\tasset_id\t" << uuid_str << "\n";
  644. }
  645. else
  646. {
  647. LLUUID shadow_id(mAssetUUID);
  648. LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
  649. cipher.encrypt(shadow_id.mData, UUID_BYTES);
  650. shadow_id.toString(uuid_str);
  651. output_stream << "\t\tshadow_id\t" << uuid_str << "\n";
  652. }
  653. }
  654. else
  655. {
  656. LLUUID::null.toString(uuid_str);
  657. output_stream << "\t\tasset_id\t" << uuid_str << "\n";
  658. }
  659. output_stream << "\t\ttype\t" << LLAssetType::lookup(mType) << "\n";
  660. const std::string& inv_type_str = LLInventoryType::lookup(mInventoryType);
  661. if (!inv_type_str.empty())
  662. {
  663. output_stream << "\t\tinv_type\t" << inv_type_str << "\n";
  664. }
  665. std::string buffer;
  666. buffer = llformat( "\t\tflags\t%08x\n", mFlags);
  667. output_stream << buffer;
  668. mSaleInfo.exportLegacyStream(output_stream);
  669. output_stream << "\t\tname\t" << mName.c_str() << "|\n";
  670. output_stream << "\t\tdesc\t" << mDescription.c_str() << "|\n";
  671. output_stream << "\t\tcreation_date\t" << mCreationDate << "\n";
  672. output_stream << "\t}\n";
  673. return true;
  674. }
  675. LLSD LLInventoryItem::asLLSD() const
  676. {
  677. LLSD sd = LLSD();
  678. asLLSD(sd);
  679. return sd;
  680. }
  681. void LLInventoryItem::asLLSD(LLSD& sd) const
  682. {
  683. sd[INV_ITEM_ID_LABEL] = mUUID;
  684. sd[INV_PARENT_ID_LABEL] = mParentUUID;
  685. sd[INV_PERMISSIONS_LABEL] = ll_create_sd_from_permissions(mPermissions);
  686. if (mThumbnailUUID.notNull())
  687. {
  688. sd[INV_THUMBNAIL_LABEL] =
  689. LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID);
  690. }
  691. if (mPermissions.unrestricted() || mAssetUUID.isNull())
  692. {
  693. sd[INV_ASSET_ID_LABEL] = mAssetUUID;
  694. }
  695. else
  696. {
  697. // *TODO: get rid of this. Phoenix 2008-01-30
  698. LLUUID shadow_id(mAssetUUID);
  699. LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
  700. cipher.encrypt(shadow_id.mData, UUID_BYTES);
  701. sd[INV_SHADOW_ID_LABEL] = shadow_id;
  702. }
  703. sd[INV_ASSET_TYPE_LABEL] = LLAssetType::lookup(mType);
  704. sd[INV_INVENTORY_TYPE_LABEL] = mInventoryType;
  705. const std::string& inv_type_str = LLInventoryType::lookup(mInventoryType);
  706. if (!inv_type_str.empty())
  707. {
  708. sd[INV_INVENTORY_TYPE_LABEL] = inv_type_str;
  709. }
  710. //sd[INV_FLAGS_LABEL] = (S32)mFlags;
  711. sd[INV_FLAGS_LABEL] = ll_sd_from_U32(mFlags);
  712. sd[INV_SALE_INFO_LABEL] = mSaleInfo;
  713. sd[INV_NAME_LABEL] = mName;
  714. sd[INV_DESC_LABEL] = mDescription;
  715. sd[INV_CREATION_DATE_LABEL] = (S32) mCreationDate;
  716. }
  717. bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
  718. {
  719. if (is_new)
  720. {
  721. // If we are adding LLSD to an existing object, need avoid clobbering
  722. // these fields.
  723. mInventoryType = LLInventoryType::IT_NONE;
  724. mAssetUUID.setNull();
  725. }
  726. for (LLSD::map_const_iterator it = sd.beginMap(), end = sd.endMap();
  727. it != end; ++it)
  728. {
  729. const LLSD::String& key = it->first;
  730. const LLSD& value = it->second;
  731. if (key == INV_ITEM_ID_LABEL)
  732. {
  733. mUUID = value;
  734. continue;
  735. }
  736. if (key == INV_PARENT_ID_LABEL)
  737. {
  738. mParentUUID = value;
  739. continue;
  740. }
  741. if (key == INV_THUMBNAIL_LABEL)
  742. {
  743. if (value.has(INV_ASSET_ID_LABEL))
  744. {
  745. mThumbnailUUID = value[INV_ASSET_ID_LABEL];
  746. }
  747. continue;
  748. }
  749. if (key == INV_THUMBNAIL_ID_LABEL)
  750. {
  751. mThumbnailUUID = value;
  752. continue;
  753. }
  754. if (key == INV_PERMISSIONS_LABEL)
  755. {
  756. mPermissions = ll_permissions_from_sd(value);
  757. continue;
  758. }
  759. if (key == INV_SALE_INFO_LABEL)
  760. {
  761. // Sale info used to contain next owner perm. It is now in the
  762. // permissions. Thus, we read that out, and fix legacy objects. It
  763. // is possible this op would fail, but it should pick up the vast
  764. // majority of the tasks.
  765. bool has_perm_mask = false;
  766. U32 perm_mask = 0;
  767. if (!mSaleInfo.fromLLSD(value, has_perm_mask, perm_mask))
  768. {
  769. return false;
  770. }
  771. if (has_perm_mask)
  772. {
  773. if (perm_mask == PERM_NONE)
  774. {
  775. perm_mask = mPermissions.getMaskOwner();
  776. }
  777. // Fair use fix.
  778. if (!(perm_mask & PERM_COPY))
  779. {
  780. perm_mask |= PERM_TRANSFER;
  781. }
  782. mPermissions.setMaskNext(perm_mask);
  783. }
  784. continue;
  785. }
  786. if (key == INV_SHADOW_ID_LABEL)
  787. {
  788. mAssetUUID = value;
  789. LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
  790. cipher.decrypt(mAssetUUID.mData, UUID_BYTES);
  791. continue;
  792. }
  793. if (key == INV_ASSET_ID_LABEL || key == INV_LINKED_ID_LABEL)
  794. {
  795. mAssetUUID = value;
  796. continue;
  797. }
  798. if (key == INV_ASSET_TYPE_LABEL)
  799. {
  800. if (value.isString())
  801. {
  802. mType = LLAssetType::lookup(value.asString());
  803. }
  804. else if (value.isInteger())
  805. {
  806. S8 type = (U8)value.asInteger();
  807. mType = (LLAssetType::EType)type;
  808. }
  809. continue;
  810. }
  811. if (key == INV_INVENTORY_TYPE_LABEL)
  812. {
  813. if (value.isString())
  814. {
  815. mInventoryType =
  816. LLInventoryType::lookup(value.asString().c_str());
  817. }
  818. else if (value.isInteger())
  819. {
  820. S8 type = (U8)value.asInteger();
  821. mInventoryType = (LLInventoryType::EType)type;
  822. }
  823. continue;
  824. }
  825. if (key == INV_FLAGS_LABEL)
  826. {
  827. if (value.isBinary())
  828. {
  829. mFlags = ll_U32_from_sd(value);
  830. }
  831. else if (value.isInteger())
  832. {
  833. mFlags = value.asInteger();
  834. }
  835. continue;
  836. }
  837. if (key == INV_NAME_LABEL)
  838. {
  839. mName = value.asString();
  840. LLStringUtil::replaceNonstandardASCII(mName, ' ');
  841. LLStringUtil::replaceChar(mName, '|', ' ');
  842. continue;
  843. }
  844. if (key == INV_DESC_LABEL)
  845. {
  846. mDescription = value.asString();
  847. LLStringUtil::replaceNonstandardASCII(mDescription, ' ');
  848. continue;
  849. }
  850. if (key == INV_CREATION_DATE_LABEL)
  851. {
  852. mCreationDate = value.asInteger();
  853. }
  854. }
  855. // Need to convert 1.0 simstate files to a useful inventory type and
  856. // potentially deal with bad inventory tyes eg, a landmark marked as a
  857. // texture.
  858. if (mInventoryType == LLInventoryType::IT_NONE ||
  859. !inventory_and_asset_types_match(mInventoryType, mType))
  860. {
  861. LL_DEBUGS("Inventory") << "Resetting inventory type for " << mUUID
  862. << LL_ENDL;
  863. mInventoryType = LLInventoryType::defaultForAssetType(mType);
  864. }
  865. mPermissions.initMasks(mInventoryType);
  866. return true;
  867. }
  868. ///----------------------------------------------------------------------------
  869. /// Class LLInventoryCategory
  870. ///----------------------------------------------------------------------------
  871. LLInventoryCategory::LLInventoryCategory(const LLUUID& uuid,
  872. const LLUUID& parent_uuid,
  873. LLFolderType::EType preferred_type,
  874. const std::string& name)
  875. : LLInventoryObject(uuid, parent_uuid, LLAssetType::AT_CATEGORY, name),
  876. mPreferredType(preferred_type)
  877. {
  878. }
  879. LLInventoryCategory::LLInventoryCategory()
  880. : mPreferredType(LLFolderType::FT_NONE)
  881. {
  882. mType = LLAssetType::AT_CATEGORY;
  883. }
  884. LLInventoryCategory::LLInventoryCategory(const LLInventoryCategory* otherp)
  885. : LLInventoryObject()
  886. {
  887. copyCategory(otherp);
  888. }
  889. //virtual
  890. void LLInventoryCategory::copyCategory(const LLInventoryCategory* otherp)
  891. {
  892. copyObject(otherp);
  893. mPreferredType = otherp->mPreferredType;
  894. }
  895. LLSD LLInventoryCategory::asLLSD() const
  896. {
  897. LLSD sd = LLSD();
  898. sd[INV_ITEM_ID_LABEL] = mUUID;
  899. sd[INV_PARENT_ID_LABEL] = mParentUUID;
  900. sd[INV_ASSET_TYPE_LABEL] = (S8)mPreferredType;
  901. sd[INV_NAME_LABEL] = mName;
  902. if (mThumbnailUUID.notNull())
  903. {
  904. sd[INV_THUMBNAIL_LABEL] =
  905. LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID);
  906. }
  907. return sd;
  908. }
  909. LLSD LLInventoryCategory::asAISCreateCatLLSD() const
  910. {
  911. LLSD sd = LLSD();
  912. sd[INV_FOLDER_ID_LABEL_WS] = mUUID;
  913. sd[INV_PARENT_ID_LABEL] = mParentUUID;
  914. sd[INV_ASSET_TYPE_LABEL_WS] = (S8)mPreferredType;
  915. sd[INV_NAME_LABEL] = mName;
  916. if (mThumbnailUUID.notNull())
  917. {
  918. sd[INV_THUMBNAIL_LABEL] =
  919. LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID);
  920. }
  921. return sd;
  922. }
  923. bool LLInventoryCategory::fromLLSD(const LLSD& sd)
  924. {
  925. for (LLSD::map_const_iterator it = sd.beginMap(), end = sd.endMap();
  926. it != end; ++it)
  927. {
  928. const LLSD::String& key = it->first;
  929. const LLSD& value = it->second;
  930. if (key == INV_FOLDER_ID_LABEL_WS)
  931. {
  932. mUUID = value;
  933. continue;
  934. }
  935. if (key == INV_PARENT_ID_LABEL)
  936. {
  937. mParentUUID = value;
  938. continue;
  939. }
  940. if (key == INV_THUMBNAIL_LABEL)
  941. {
  942. if (value.has(INV_ASSET_ID_LABEL))
  943. {
  944. mThumbnailUUID = value[INV_ASSET_ID_LABEL];
  945. }
  946. continue;
  947. }
  948. if (key == INV_THUMBNAIL_ID_LABEL)
  949. {
  950. mThumbnailUUID = value;
  951. continue;
  952. }
  953. if (key == INV_ASSET_TYPE_LABEL || key == INV_ASSET_TYPE_LABEL_WS)
  954. {
  955. S8 type = (U8)value.asInteger();
  956. mPreferredType = (LLFolderType::EType)type;
  957. continue;
  958. }
  959. if (key == INV_NAME_LABEL)
  960. {
  961. mName = value.asString();
  962. LLStringUtil::replaceNonstandardASCII(mName, ' ');
  963. LLStringUtil::replaceChar(mName, '|', ' ');
  964. }
  965. }
  966. return true;
  967. }
  968. //virtual
  969. void LLInventoryCategory::packMessage(LLMessageSystem* msg) const
  970. {
  971. msg->addUUIDFast(_PREHASH_FolderID, mUUID);
  972. msg->addUUIDFast(_PREHASH_ParentID, mParentUUID);
  973. msg->addS8Fast(_PREHASH_Type, (S8)mPreferredType);
  974. msg->addStringFast(_PREHASH_Name, mName);
  975. }
  976. //virtual
  977. void LLInventoryCategory::unpackMessage(LLMessageSystem* msg,
  978. const char* block, S32 block_num)
  979. {
  980. msg->getUUIDFast(block, _PREHASH_FolderID, mUUID, block_num);
  981. msg->getUUIDFast(block, _PREHASH_ParentID, mParentUUID, block_num);
  982. S8 type;
  983. msg->getS8Fast(block, _PREHASH_Type, type, block_num);
  984. mPreferredType = (LLFolderType::EType)type;
  985. msg->getStringFast(block, _PREHASH_Name, mName, block_num);
  986. LLStringUtil::replaceNonstandardASCII(mName, ' ');
  987. }
  988. //virtual
  989. bool LLInventoryCategory::importLegacyStream(std::istream& input_stream)
  990. {
  991. // *NOTE: Changing the buffer size will require changing the scanf
  992. // calls below.
  993. char buffer[MAX_STRING];
  994. char keyword[MAX_STRING];
  995. char valuestr[MAX_STRING];
  996. keyword[0] = '\0';
  997. valuestr[0] = '\0';
  998. while (input_stream.good())
  999. {
  1000. input_stream.getline(buffer, MAX_STRING);
  1001. // This happens a lot... And it does not matter. HB
  1002. if (!strcmp("|", buffer))
  1003. {
  1004. continue;
  1005. }
  1006. if (sscanf(buffer, " %254s %254s", keyword, valuestr) < 1)
  1007. {
  1008. continue;
  1009. }
  1010. if (!strcmp("{", keyword))
  1011. {
  1012. continue;
  1013. }
  1014. if (!strcmp("}", keyword))
  1015. {
  1016. break;
  1017. }
  1018. else if (!strcmp("cat_id", keyword))
  1019. {
  1020. mUUID.set(valuestr);
  1021. }
  1022. else if (!strcmp("parent_id", keyword))
  1023. {
  1024. mParentUUID.set(valuestr);
  1025. }
  1026. else if (!strcmp("type", keyword))
  1027. {
  1028. mType = LLAssetType::lookup(valuestr);
  1029. }
  1030. else if (!strcmp("pref_type", keyword))
  1031. {
  1032. mPreferredType = LLFolderType::lookup(valuestr);
  1033. }
  1034. else if (!strcmp("name", keyword))
  1035. {
  1036. //strcpy(valuestr, buffer + strlen(keyword) + 3);
  1037. // *NOTE: Not ANSI C, but widely supported.
  1038. sscanf(buffer, " %254s %254[^|]", keyword, valuestr);
  1039. mName.assign(valuestr);
  1040. LLStringUtil::replaceNonstandardASCII(mName, ' ');
  1041. LLStringUtil::replaceChar(mName, '|', ' ');
  1042. }
  1043. else if (!strcmp("metadata", keyword))
  1044. {
  1045. LLSD metadata;
  1046. #if 0
  1047. if (!strncmp("<llsd>", valuestr, 6))
  1048. {
  1049. std::istringstream stream(valuestr);
  1050. LLSDSerialize::fromXML(metadata, stream);
  1051. }
  1052. else
  1053. #endif
  1054. {
  1055. metadata = LLSD(valuestr);
  1056. }
  1057. if (metadata.has("thumbnail"))
  1058. {
  1059. const LLSD& thumbnail = metadata["thumbnail"];
  1060. if (thumbnail.has("asset_id"))
  1061. {
  1062. setThumbnailUUID(thumbnail["asset_id"].asUUID());
  1063. }
  1064. }
  1065. }
  1066. else
  1067. {
  1068. llwarns << "Unknown keyword '" << keyword
  1069. << "' in inventory import category " << mUUID
  1070. << ". Buffer contents: " << buffer << llendl;
  1071. }
  1072. }
  1073. return true;
  1074. }
  1075. //virtual
  1076. bool LLInventoryCategory::exportLegacyStream(std::ostream& output_stream,
  1077. bool) const
  1078. {
  1079. std::string uuid_str;
  1080. output_stream << "\tinv_category\t0\n\t{\n";
  1081. mUUID.toString(uuid_str);
  1082. output_stream << "\t\tcat_id\t" << uuid_str << "\n";
  1083. mParentUUID.toString(uuid_str);
  1084. output_stream << "\t\tparent_id\t" << uuid_str << "\n";
  1085. output_stream << "\t\ttype\t" << LLAssetType::lookup(mType) << "\n";
  1086. output_stream << "\t\tpref_type\t" << LLFolderType::lookup(mPreferredType)
  1087. << "\n";
  1088. output_stream << "\t\tname\t" << mName.c_str() << "|\n";
  1089. if (mThumbnailUUID.notNull())
  1090. {
  1091. // Max length is 255 chars, will have to export differently if it gets
  1092. // more data (e.g. use newline and toNotation (uses {}) for unlimited
  1093. // size).
  1094. LLSD metadata;
  1095. metadata["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID);
  1096. #if 0
  1097. output_stream << "\t\tmetadata\t";
  1098. LLSDSerialize::toXML(metadata, output_stream);
  1099. output_stream << "|\n";
  1100. #else
  1101. output_stream << "\t\tmetadata\t" << metadata << "|\n";
  1102. #endif
  1103. }
  1104. output_stream << "\t}\n";
  1105. return true;
  1106. }