PageRenderTime 154ms CodeModel.GetById 18ms app.highlight 125ms RepoModel.GetById 1ms app.codeStats 1ms

/indra/llinventory/llinventory.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1649 lines | 1324 code | 156 blank | 169 comment | 240 complexity | 2a0917dc0f04177a368db9d3e6fae210 MD5 | raw file
   1/** 
   2 * @file llinventory.cpp
   3 * @brief Implementation of the inventory system.
   4 *
   5 * $LicenseInfo:firstyear=2001&license=viewerlgpl$
   6 * Second Life Viewer Source Code
   7 * Copyright (C) 2010, Linden Research, Inc.
   8 * 
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation;
  12 * version 2.1 of the License only.
  13 * 
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 * 
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  22 * 
  23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  24 * $/LicenseInfo$
  25 */
  26
  27#include "linden_common.h"
  28#include "llinventory.h"
  29
  30#include "lldbstrings.h"
  31#include "llinventorydefines.h"
  32#include "llxorcipher.h"
  33#include "llsd.h"
  34#include "message.h"
  35#include <boost/tokenizer.hpp>
  36
  37#include "llsdutil.h"
  38
  39///----------------------------------------------------------------------------
  40/// Exported functions
  41///----------------------------------------------------------------------------
  42static const std::string INV_ITEM_ID_LABEL("item_id");
  43static const std::string INV_FOLDER_ID_LABEL("folder_id");
  44static const std::string INV_PARENT_ID_LABEL("parent_id");
  45static const std::string INV_ASSET_TYPE_LABEL("type");
  46static const std::string INV_PREFERRED_TYPE_LABEL("preferred_type");
  47static const std::string INV_INVENTORY_TYPE_LABEL("inv_type");
  48static const std::string INV_NAME_LABEL("name");
  49static const std::string INV_DESC_LABEL("desc");
  50static const std::string INV_PERMISSIONS_LABEL("permissions");
  51static const std::string INV_SHADOW_ID_LABEL("shadow_id");
  52static const std::string INV_ASSET_ID_LABEL("asset_id");
  53static const std::string INV_SALE_INFO_LABEL("sale_info");
  54static const std::string INV_FLAGS_LABEL("flags");
  55static const std::string INV_CREATION_DATE_LABEL("created_at");
  56
  57// key used by agent-inventory-service
  58static const std::string INV_ASSET_TYPE_LABEL_WS("type_default");
  59static const std::string INV_FOLDER_ID_LABEL_WS("category_id");
  60
  61///----------------------------------------------------------------------------
  62/// Local function declarations, constants, enums, and typedefs
  63///----------------------------------------------------------------------------
  64
  65const LLUUID MAGIC_ID("3c115e51-04f4-523c-9fa6-98aff1034730");	
  66
  67///----------------------------------------------------------------------------
  68/// Class LLInventoryObject
  69///----------------------------------------------------------------------------
  70
  71LLInventoryObject::LLInventoryObject(const LLUUID& uuid,
  72									 const LLUUID& parent_uuid,
  73									 LLAssetType::EType type,
  74									 const std::string& name) :
  75	mUUID(uuid),
  76	mParentUUID(parent_uuid),
  77	mType(type),
  78	mName(name)
  79{
  80	correctInventoryName(mName);
  81}
  82
  83LLInventoryObject::LLInventoryObject() :
  84	mType(LLAssetType::AT_NONE)
  85{
  86}
  87
  88LLInventoryObject::~LLInventoryObject()
  89{
  90}
  91
  92void LLInventoryObject::copyObject(const LLInventoryObject* other)
  93{
  94	mUUID = other->mUUID;
  95	mParentUUID = other->mParentUUID;
  96	mType = other->mType;
  97	mName = other->mName;
  98}
  99
 100const LLUUID& LLInventoryObject::getUUID() const
 101{
 102	return mUUID;
 103}
 104
 105const LLUUID& LLInventoryObject::getParentUUID() const
 106{
 107	return mParentUUID;
 108}
 109
 110const std::string& LLInventoryObject::getName() const
 111{
 112	return mName;
 113}
 114
 115// To bypass linked items, since llviewerinventory's getType
 116// will return the linked-to item's type instead of this object's type.
 117LLAssetType::EType LLInventoryObject::getActualType() const
 118{
 119	return mType;
 120}
 121
 122BOOL LLInventoryObject::getIsLinkType() const
 123{
 124	return LLAssetType::lookupIsLinkType(mType);
 125}
 126
 127// See LLInventoryItem override.
 128// virtual
 129const LLUUID& LLInventoryObject::getLinkedUUID() const
 130{
 131	return mUUID;
 132}
 133
 134LLAssetType::EType LLInventoryObject::getType() const
 135{
 136	return mType;
 137}
 138
 139void LLInventoryObject::setUUID(const LLUUID& new_uuid)
 140{
 141	mUUID = new_uuid;
 142}
 143
 144void LLInventoryObject::rename(const std::string& n)
 145{
 146	std::string new_name(n);
 147	correctInventoryName(new_name);
 148	if( !new_name.empty() && new_name != mName )
 149	{
 150		mName = new_name;
 151	}
 152}
 153
 154void LLInventoryObject::setParent(const LLUUID& new_parent)
 155{
 156	mParentUUID = new_parent;
 157}
 158
 159void LLInventoryObject::setType(LLAssetType::EType type)
 160{
 161	mType = type;
 162}
 163
 164
 165// virtual
 166BOOL LLInventoryObject::importLegacyStream(std::istream& input_stream)
 167{
 168	// *NOTE: Changing the buffer size will require changing the scanf
 169	// calls below.
 170	char buffer[MAX_STRING];	/* Flawfinder: ignore */
 171	char keyword[MAX_STRING];	/* Flawfinder: ignore */
 172	char valuestr[MAX_STRING];	/* Flawfinder: ignore */
 173
 174	keyword[0] = '\0';
 175	valuestr[0] = '\0';
 176	while(input_stream.good())
 177	{
 178		input_stream.getline(buffer, MAX_STRING);
 179		sscanf(buffer, " %254s %254s", keyword, valuestr);	/* Flawfinder: ignore */
 180		if(0 == strcmp("{",keyword))
 181		{
 182			continue;
 183		}
 184		if(0 == strcmp("}", keyword))
 185		{
 186			break;
 187		}
 188		else if(0 == strcmp("obj_id", keyword))
 189		{
 190			mUUID.set(valuestr);
 191		}
 192		else if(0 == strcmp("parent_id", keyword))
 193		{
 194			mParentUUID.set(valuestr);
 195		}
 196		else if(0 == strcmp("type", keyword))
 197		{
 198			mType = LLAssetType::lookup(valuestr);
 199		}
 200		else if(0 == strcmp("name", keyword))
 201		{
 202			//strcpy(valuestr, buffer + strlen(keyword) + 3);
 203			// *NOTE: Not ANSI C, but widely supported.
 204			sscanf(	/* Flawfinder: ignore */
 205				buffer,
 206				" %254s %254[^|]",
 207				keyword, valuestr);
 208			mName.assign(valuestr);
 209			correctInventoryName(mName);
 210		}
 211		else
 212		{
 213			llwarns << "unknown keyword '" << keyword
 214					<< "' in LLInventoryObject::importLegacyStream() for object " << mUUID << llendl;
 215		}
 216	}
 217	return TRUE;
 218}
 219
 220// exportFile should be replaced with exportLegacyStream
 221// not sure whether exportLegacyStream(llofstream(fp)) would work, fp may need to get icramented...
 222BOOL LLInventoryObject::exportFile(LLFILE* fp, BOOL) const
 223{
 224	std::string uuid_str;
 225	fprintf(fp, "\tinv_object\t0\n\t{\n");
 226	mUUID.toString(uuid_str);
 227	fprintf(fp, "\t\tobj_id\t%s\n", uuid_str.c_str());
 228	mParentUUID.toString(uuid_str);
 229	fprintf(fp, "\t\tparent_id\t%s\n", uuid_str.c_str());
 230	fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType));
 231	fprintf(fp, "\t\tname\t%s|\n", mName.c_str());
 232	fprintf(fp,"\t}\n");
 233	return TRUE;
 234}
 235
 236BOOL LLInventoryObject::exportLegacyStream(std::ostream& output_stream, BOOL) const
 237{
 238	std::string uuid_str;
 239	output_stream <<  "\tinv_object\t0\n\t{\n";
 240	mUUID.toString(uuid_str);
 241	output_stream << "\t\tobj_id\t" << uuid_str << "\n";
 242	mParentUUID.toString(uuid_str);
 243	output_stream << "\t\tparent_id\t" << uuid_str << "\n";
 244	output_stream << "\t\ttype\t" << LLAssetType::lookup(mType) << "\n";
 245	output_stream << "\t\tname\t" << mName.c_str() << "|\n";
 246	output_stream << "\t}\n";
 247	return TRUE;
 248}
 249
 250
 251void LLInventoryObject::removeFromServer()
 252{
 253	// don't do nothin'
 254	llwarns << "LLInventoryObject::removeFromServer() called.  Doesn't do anything." << llendl;
 255}
 256
 257void LLInventoryObject::updateParentOnServer(BOOL) const
 258{
 259	// don't do nothin'
 260	llwarns << "LLInventoryObject::updateParentOnServer() called.  Doesn't do anything." << llendl;
 261}
 262
 263void LLInventoryObject::updateServer(BOOL) const
 264{
 265	// don't do nothin'
 266	llwarns << "LLInventoryObject::updateServer() called.  Doesn't do anything." << llendl;
 267}
 268
 269inline
 270void LLInventoryObject::correctInventoryName(std::string& name)
 271{
 272	LLStringUtil::replaceNonstandardASCII(name, ' ');
 273	LLStringUtil::replaceChar(name, '|', ' ');
 274	LLStringUtil::trim(name);
 275	LLStringUtil::truncate(name, DB_INV_ITEM_NAME_STR_LEN);
 276}
 277
 278
 279///----------------------------------------------------------------------------
 280/// Class LLInventoryItem
 281///----------------------------------------------------------------------------
 282
 283LLInventoryItem::LLInventoryItem(const LLUUID& uuid,
 284								 const LLUUID& parent_uuid,
 285								 const LLPermissions& permissions,
 286								 const LLUUID& asset_uuid,
 287								 LLAssetType::EType type,
 288								 LLInventoryType::EType inv_type,
 289								 const std::string& name, 
 290								 const std::string& desc,
 291								 const LLSaleInfo& sale_info,
 292								 U32 flags,
 293								 S32 creation_date_utc) :
 294	LLInventoryObject(uuid, parent_uuid, type, name),
 295	mPermissions(permissions),
 296	mAssetUUID(asset_uuid),
 297	mDescription(desc),
 298	mSaleInfo(sale_info),
 299	mInventoryType(inv_type),
 300	mFlags(flags),
 301	mCreationDate(creation_date_utc)
 302{
 303	LLStringUtil::replaceNonstandardASCII(mDescription, ' ');
 304	LLStringUtil::replaceChar(mDescription, '|', ' ');
 305	mPermissions.initMasks(inv_type);
 306}
 307
 308LLInventoryItem::LLInventoryItem() :
 309	LLInventoryObject(),
 310	mPermissions(),
 311	mAssetUUID(),
 312	mDescription(),
 313	mSaleInfo(),
 314	mInventoryType(LLInventoryType::IT_NONE),
 315	mFlags(0),
 316	mCreationDate(0)
 317{
 318}
 319
 320LLInventoryItem::LLInventoryItem(const LLInventoryItem* other) :
 321	LLInventoryObject()
 322{
 323	copyItem(other);
 324}
 325
 326LLInventoryItem::~LLInventoryItem()
 327{
 328}
 329
 330// virtual
 331void LLInventoryItem::copyItem(const LLInventoryItem* other)
 332{
 333	copyObject(other);
 334	mPermissions = other->mPermissions;
 335	mAssetUUID = other->mAssetUUID;
 336	mDescription = other->mDescription;
 337	mSaleInfo = other->mSaleInfo;
 338	mInventoryType = other->mInventoryType;
 339	mFlags = other->mFlags;
 340	mCreationDate = other->mCreationDate;
 341}
 342
 343// If this is a linked item, then the UUID of the base object is
 344// this item's assetID.
 345// virtual
 346const LLUUID& LLInventoryItem::getLinkedUUID() const
 347{
 348	if (LLAssetType::lookupIsLinkType(getActualType()))
 349	{
 350		return mAssetUUID;
 351	}
 352
 353	return LLInventoryObject::getLinkedUUID();
 354}
 355
 356const LLPermissions& LLInventoryItem::getPermissions() const
 357{
 358	return mPermissions;
 359}
 360
 361const LLUUID& LLInventoryItem::getCreatorUUID() const
 362{
 363	return mPermissions.getCreator();
 364}
 365
 366const LLUUID& LLInventoryItem::getAssetUUID() const
 367{
 368	return mAssetUUID;
 369}
 370
 371void LLInventoryItem::setAssetUUID(const LLUUID& asset_id)
 372{
 373	mAssetUUID = asset_id;
 374}
 375
 376
 377const std::string& LLInventoryItem::getDescription() const
 378{
 379	return mDescription;
 380}
 381
 382time_t LLInventoryItem::getCreationDate() const
 383{
 384	return mCreationDate;
 385}
 386
 387U32 LLInventoryItem::getCRC32() const
 388{
 389	// *FIX: Not a real crc - more of a checksum.
 390	// *NOTE: We currently do not validate the name or description,
 391	// but if they change in transit, it's no big deal.
 392	U32 crc = mUUID.getCRC32();
 393	//lldebugs << "1 crc: " << std::hex << crc << std::dec << llendl;
 394	crc += mParentUUID.getCRC32();
 395	//lldebugs << "2 crc: " << std::hex << crc << std::dec << llendl;
 396	crc += mPermissions.getCRC32();
 397	//lldebugs << "3 crc: " << std::hex << crc << std::dec << llendl;
 398	crc += mAssetUUID.getCRC32();
 399	//lldebugs << "4 crc: " << std::hex << crc << std::dec << llendl;
 400	crc += mType;
 401	//lldebugs << "5 crc: " << std::hex << crc << std::dec << llendl;
 402	crc += mInventoryType;
 403	//lldebugs << "6 crc: " << std::hex << crc << std::dec << llendl;
 404	crc += mFlags;
 405	//lldebugs << "7 crc: " << std::hex << crc << std::dec << llendl;
 406	crc += mSaleInfo.getCRC32();
 407	//lldebugs << "8 crc: " << std::hex << crc << std::dec << llendl;
 408	crc += mCreationDate;
 409	//lldebugs << "9 crc: " << std::hex << crc << std::dec << llendl;
 410	return crc;
 411}
 412
 413
 414void LLInventoryItem::setDescription(const std::string& d)
 415{
 416	std::string new_desc(d);
 417	LLStringUtil::replaceNonstandardASCII(new_desc, ' ');
 418	LLStringUtil::replaceChar(new_desc, '|', ' ');
 419	if( new_desc != mDescription )
 420	{
 421		mDescription = new_desc;
 422	}
 423}
 424
 425void LLInventoryItem::setPermissions(const LLPermissions& perm)
 426{
 427	mPermissions = perm;
 428
 429	// Override permissions to unrestricted if this is a landmark
 430	mPermissions.initMasks(mInventoryType);
 431}
 432
 433void LLInventoryItem::setInventoryType(LLInventoryType::EType inv_type)
 434{
 435	mInventoryType = inv_type;
 436}
 437
 438void LLInventoryItem::setFlags(U32 flags)
 439{
 440	mFlags = flags;
 441}
 442
 443void LLInventoryItem::setCreationDate(time_t creation_date_utc)
 444{
 445	mCreationDate = creation_date_utc;
 446}
 447
 448// Currently only used in the Viewer to handle calling cards
 449// where the creator is actually used to store the target.
 450void LLInventoryItem::setCreator(const LLUUID& creator)
 451{ 
 452	mPermissions.setCreator(creator); 
 453}
 454
 455void LLInventoryItem::accumulatePermissionSlamBits(const LLInventoryItem& old_item)
 456{
 457	// Remove any pre-existing II_FLAGS_PERM_OVERWRITE_MASK flags 
 458	// because we now detect when they should be set.
 459	setFlags( old_item.getFlags() | (getFlags() & ~(LLInventoryItemFlags::II_FLAGS_PERM_OVERWRITE_MASK)) );
 460
 461	// Enforce the PERM_OVERWRITE flags for any masks that are different
 462	// but only for AT_OBJECT's since that is the only asset type that can 
 463	// exist in-world (instead of only in-inventory or in-object-contents).
 464	if (LLAssetType::AT_OBJECT == getType())
 465	{
 466		LLPermissions old_permissions = old_item.getPermissions();
 467		U32 flags_to_be_set = 0;
 468		if(old_permissions.getMaskNextOwner() != getPermissions().getMaskNextOwner())
 469		{
 470			flags_to_be_set |= LLInventoryItemFlags::II_FLAGS_OBJECT_SLAM_PERM;
 471		}
 472		if(old_permissions.getMaskEveryone() != getPermissions().getMaskEveryone())
 473		{
 474			flags_to_be_set |= LLInventoryItemFlags::II_FLAGS_OBJECT_PERM_OVERWRITE_EVERYONE;
 475		}
 476		if(old_permissions.getMaskGroup() != getPermissions().getMaskGroup())
 477		{
 478			flags_to_be_set |= LLInventoryItemFlags::II_FLAGS_OBJECT_PERM_OVERWRITE_GROUP;
 479		}
 480		LLSaleInfo old_sale_info = old_item.getSaleInfo();
 481		if(old_sale_info != getSaleInfo())
 482		{
 483			flags_to_be_set |= LLInventoryItemFlags::II_FLAGS_OBJECT_SLAM_SALE;
 484		}
 485		setFlags(getFlags() | flags_to_be_set);
 486	}
 487}
 488
 489const LLSaleInfo& LLInventoryItem::getSaleInfo() const
 490{
 491	return mSaleInfo;
 492}
 493
 494void LLInventoryItem::setSaleInfo(const LLSaleInfo& sale_info)
 495{
 496	mSaleInfo = sale_info;
 497}
 498
 499LLInventoryType::EType LLInventoryItem::getInventoryType() const
 500{
 501	return mInventoryType;
 502}
 503
 504U32 LLInventoryItem::getFlags() const
 505{
 506	return mFlags;
 507}
 508
 509// virtual
 510void LLInventoryItem::packMessage(LLMessageSystem* msg) const
 511{
 512	msg->addUUIDFast(_PREHASH_ItemID, mUUID);
 513	msg->addUUIDFast(_PREHASH_FolderID, mParentUUID);
 514	mPermissions.packMessage(msg);
 515	msg->addUUIDFast(_PREHASH_AssetID, mAssetUUID);
 516	S8 type = static_cast<S8>(mType);
 517	msg->addS8Fast(_PREHASH_Type, type);
 518	type = static_cast<S8>(mInventoryType);
 519	msg->addS8Fast(_PREHASH_InvType, type);
 520	msg->addU32Fast(_PREHASH_Flags, mFlags);
 521	mSaleInfo.packMessage(msg);
 522	msg->addStringFast(_PREHASH_Name, mName);
 523	msg->addStringFast(_PREHASH_Description, mDescription);
 524	msg->addS32Fast(_PREHASH_CreationDate, mCreationDate);
 525	U32 crc = getCRC32();
 526	msg->addU32Fast(_PREHASH_CRC, crc);
 527}
 528
 529// virtual
 530BOOL LLInventoryItem::unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num)
 531{
 532	msg->getUUIDFast(block, _PREHASH_ItemID, mUUID, block_num);
 533	msg->getUUIDFast(block, _PREHASH_FolderID, mParentUUID, block_num);
 534	mPermissions.unpackMessage(msg, block, block_num);
 535	msg->getUUIDFast(block, _PREHASH_AssetID, mAssetUUID, block_num);
 536
 537	S8 type;
 538	msg->getS8Fast(block, _PREHASH_Type, type, block_num);
 539	mType = static_cast<LLAssetType::EType>(type);
 540	msg->getS8(block, "InvType", type, block_num);
 541	mInventoryType = static_cast<LLInventoryType::EType>(type);
 542	mPermissions.initMasks(mInventoryType);
 543
 544	msg->getU32Fast(block, _PREHASH_Flags, mFlags, block_num);
 545
 546	mSaleInfo.unpackMultiMessage(msg, block, block_num);
 547
 548	msg->getStringFast(block, _PREHASH_Name, mName, block_num);
 549	LLStringUtil::replaceNonstandardASCII(mName, ' ');
 550
 551	msg->getStringFast(block, _PREHASH_Description, mDescription, block_num);
 552	LLStringUtil::replaceNonstandardASCII(mDescription, ' ');
 553
 554	S32 date;
 555	msg->getS32(block, "CreationDate", date, block_num);
 556	mCreationDate = date;
 557
 558	U32 local_crc = getCRC32();
 559	U32 remote_crc = 0;
 560	msg->getU32(block, "CRC", remote_crc, block_num);
 561//#define CRC_CHECK
 562#ifdef CRC_CHECK
 563	if(local_crc == remote_crc)
 564	{
 565		lldebugs << "crc matches" << llendl;
 566		return TRUE;
 567	}
 568	else
 569	{
 570		llwarns << "inventory crc mismatch: local=" << std::hex << local_crc
 571				<< " remote=" << remote_crc << std::dec << llendl;
 572		return FALSE;
 573	}
 574#else
 575	return (local_crc == remote_crc);
 576#endif
 577}
 578
 579// virtual
 580BOOL LLInventoryItem::importFile(LLFILE* fp)
 581{
 582	// *NOTE: Changing the buffer size will require changing the scanf
 583	// calls below.
 584	char buffer[MAX_STRING];	/* Flawfinder: ignore */
 585	char keyword[MAX_STRING];	/* Flawfinder: ignore */	
 586	char valuestr[MAX_STRING];	/* Flawfinder: ignore */
 587	char junk[MAX_STRING];	/* Flawfinder: ignore */
 588	BOOL success = TRUE;
 589
 590	keyword[0] = '\0';
 591	valuestr[0] = '\0';
 592
 593	mInventoryType = LLInventoryType::IT_NONE;
 594	mAssetUUID.setNull();
 595	while(success && (!feof(fp)))
 596	{
 597		if (fgets(buffer, MAX_STRING, fp) == NULL)
 598		{
 599			buffer[0] = '\0';
 600		}
 601		
 602		sscanf(buffer, " %254s %254s", keyword, valuestr);	/* Flawfinder: ignore */
 603		if(0 == strcmp("{",keyword))
 604		{
 605			continue;
 606		}
 607		if(0 == strcmp("}", keyword))
 608		{
 609			break;
 610		}
 611		else if(0 == strcmp("item_id", keyword))
 612		{
 613			mUUID.set(valuestr);
 614		}
 615		else if(0 == strcmp("parent_id", keyword))
 616		{
 617			mParentUUID.set(valuestr);
 618		}
 619		else if(0 == strcmp("permissions", keyword))
 620		{
 621			success = mPermissions.importFile(fp);
 622		}
 623		else if(0 == strcmp("sale_info", keyword))
 624		{
 625			// Sale info used to contain next owner perm. It is now in
 626			// the permissions. Thus, we read that out, and fix legacy
 627			// objects. It's possible this op would fail, but it
 628			// should pick up the vast majority of the tasks.
 629			BOOL has_perm_mask = FALSE;
 630			U32 perm_mask = 0;
 631			success = mSaleInfo.importFile(fp, has_perm_mask, perm_mask);
 632			if(has_perm_mask)
 633			{
 634				if(perm_mask == PERM_NONE)
 635				{
 636					perm_mask = mPermissions.getMaskOwner();
 637				}
 638				// fair use fix.
 639				if(!(perm_mask & PERM_COPY))
 640				{
 641					perm_mask |= PERM_TRANSFER;
 642				}
 643				mPermissions.setMaskNext(perm_mask);
 644			}
 645		}
 646		else if(0 == strcmp("shadow_id", keyword))
 647		{
 648			mAssetUUID.set(valuestr);
 649			LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
 650			cipher.decrypt(mAssetUUID.mData, UUID_BYTES);
 651		}
 652		else if(0 == strcmp("asset_id", keyword))
 653		{
 654			mAssetUUID.set(valuestr);
 655		}
 656		else if(0 == strcmp("type", keyword))
 657		{
 658			mType = LLAssetType::lookup(valuestr);
 659		}
 660		else if(0 == strcmp("inv_type", keyword))
 661		{
 662			mInventoryType = LLInventoryType::lookup(std::string(valuestr));
 663		}
 664		else if(0 == strcmp("flags", keyword))
 665		{
 666			sscanf(valuestr, "%x", &mFlags);
 667		}
 668		else if(0 == strcmp("name", keyword))
 669		{
 670			//strcpy(valuestr, buffer + strlen(keyword) + 3);
 671			// *NOTE: Not ANSI C, but widely supported.
 672			sscanf(	/* Flawfinder: ignore */
 673				buffer,
 674				" %254s%254[\t]%254[^|]",
 675				keyword, junk, valuestr);
 676
 677			// IW: sscanf chokes and puts | in valuestr if there's no name
 678			if (valuestr[0] == '|')
 679			{
 680				valuestr[0] = '\000';
 681			}
 682
 683			mName.assign(valuestr);
 684			LLStringUtil::replaceNonstandardASCII(mName, ' ');
 685			LLStringUtil::replaceChar(mName, '|', ' ');
 686		}
 687		else if(0 == strcmp("desc", keyword))
 688		{
 689			//strcpy(valuestr, buffer + strlen(keyword) + 3);
 690			// *NOTE: Not ANSI C, but widely supported.
 691			sscanf(	/* Flawfinder: ignore */
 692				buffer,
 693				" %254s%254[\t]%254[^|]",
 694				keyword, junk, valuestr);
 695
 696			if (valuestr[0] == '|')
 697			{
 698				valuestr[0] = '\000';
 699			}
 700
 701			mDescription.assign(valuestr);
 702			LLStringUtil::replaceNonstandardASCII(mDescription, ' ');
 703			/* TODO -- ask Ian about this code
 704			const char *donkey = mDescription.c_str();
 705			if (donkey[0] == '|')
 706			{
 707				llerrs << "Donkey" << llendl;
 708			}
 709			*/
 710		}
 711		else if(0 == strcmp("creation_date", keyword))
 712		{
 713			S32 date;
 714			sscanf(valuestr, "%d", &date);
 715			mCreationDate = date;
 716		}
 717		else
 718		{
 719			llwarns << "unknown keyword '" << keyword
 720					<< "' in inventory import of item " << mUUID << llendl;
 721		}
 722	}
 723
 724	// Need to convert 1.0 simstate files to a useful inventory type
 725	// and potentially deal with bad inventory tyes eg, a landmark
 726	// marked as a texture.
 727	if((LLInventoryType::IT_NONE == mInventoryType)
 728	   || !inventory_and_asset_types_match(mInventoryType, mType))
 729	{
 730		lldebugs << "Resetting inventory type for " << mUUID << llendl;
 731		mInventoryType = LLInventoryType::defaultForAssetType(mType);
 732	}
 733
 734	mPermissions.initMasks(mInventoryType);
 735
 736	return success;
 737}
 738
 739BOOL LLInventoryItem::exportFile(LLFILE* fp, BOOL include_asset_key) const
 740{
 741	std::string uuid_str;
 742	fprintf(fp, "\tinv_item\t0\n\t{\n");
 743	mUUID.toString(uuid_str);
 744	fprintf(fp, "\t\titem_id\t%s\n", uuid_str.c_str());
 745	mParentUUID.toString(uuid_str);
 746	fprintf(fp, "\t\tparent_id\t%s\n", uuid_str.c_str());
 747	mPermissions.exportFile(fp);
 748
 749	// Check for permissions to see the asset id, and if so write it
 750	// out as an asset id. Otherwise, apply our cheesy encryption.
 751	if(include_asset_key)
 752	{
 753		U32 mask = mPermissions.getMaskBase();
 754		if(((mask & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED)
 755		   || (mAssetUUID.isNull()))
 756		{
 757			mAssetUUID.toString(uuid_str);
 758			fprintf(fp, "\t\tasset_id\t%s\n", uuid_str.c_str());
 759		}
 760		else
 761		{
 762			LLUUID shadow_id(mAssetUUID);
 763			LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
 764			cipher.encrypt(shadow_id.mData, UUID_BYTES);
 765			shadow_id.toString(uuid_str);
 766			fprintf(fp, "\t\tshadow_id\t%s\n", uuid_str.c_str());
 767		}
 768	}
 769	else
 770	{
 771		LLUUID::null.toString(uuid_str);
 772		fprintf(fp, "\t\tasset_id\t%s\n", uuid_str.c_str());
 773	}
 774	fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType));
 775	const std::string inv_type_str = LLInventoryType::lookup(mInventoryType);
 776	if(!inv_type_str.empty()) fprintf(fp, "\t\tinv_type\t%s\n", inv_type_str.c_str());
 777	fprintf(fp, "\t\tflags\t%08x\n", mFlags);
 778	mSaleInfo.exportFile(fp);
 779	fprintf(fp, "\t\tname\t%s|\n", mName.c_str());
 780	fprintf(fp, "\t\tdesc\t%s|\n", mDescription.c_str());
 781	fprintf(fp, "\t\tcreation_date\t%d\n", (S32) mCreationDate);
 782	fprintf(fp,"\t}\n");
 783	return TRUE;
 784}
 785
 786// virtual
 787BOOL LLInventoryItem::importLegacyStream(std::istream& input_stream)
 788{
 789	// *NOTE: Changing the buffer size will require changing the scanf
 790	// calls below.
 791	char buffer[MAX_STRING];	/* Flawfinder: ignore */
 792	char keyword[MAX_STRING];	/* Flawfinder: ignore */
 793	char valuestr[MAX_STRING];	/* Flawfinder: ignore */
 794	char junk[MAX_STRING];	/* Flawfinder: ignore */
 795	BOOL success = TRUE;
 796
 797	keyword[0] = '\0';
 798	valuestr[0] = '\0';
 799
 800	mInventoryType = LLInventoryType::IT_NONE;
 801	mAssetUUID.setNull();
 802	while(success && input_stream.good())
 803	{
 804		input_stream.getline(buffer, MAX_STRING);
 805		sscanf(	/* Flawfinder: ignore */
 806			buffer,
 807			" %254s %254s",
 808			keyword, valuestr);
 809		if(0 == strcmp("{",keyword))
 810		{
 811			continue;
 812		}
 813		if(0 == strcmp("}", keyword))
 814		{
 815			break;
 816		}
 817		else if(0 == strcmp("item_id", keyword))
 818		{
 819			mUUID.set(valuestr);
 820		}
 821		else if(0 == strcmp("parent_id", keyword))
 822		{
 823			mParentUUID.set(valuestr);
 824		}
 825		else if(0 == strcmp("permissions", keyword))
 826		{
 827			success = mPermissions.importLegacyStream(input_stream);
 828		}
 829		else if(0 == strcmp("sale_info", keyword))
 830		{
 831			// Sale info used to contain next owner perm. It is now in
 832			// the permissions. Thus, we read that out, and fix legacy
 833			// objects. It's possible this op would fail, but it
 834			// should pick up the vast majority of the tasks.
 835			BOOL has_perm_mask = FALSE;
 836			U32 perm_mask = 0;
 837			success = mSaleInfo.importLegacyStream(input_stream, has_perm_mask, perm_mask);
 838			if(has_perm_mask)
 839			{
 840				if(perm_mask == PERM_NONE)
 841				{
 842					perm_mask = mPermissions.getMaskOwner();
 843				}
 844				// fair use fix.
 845				if(!(perm_mask & PERM_COPY))
 846				{
 847					perm_mask |= PERM_TRANSFER;
 848				}
 849				mPermissions.setMaskNext(perm_mask);
 850			}
 851		}
 852		else if(0 == strcmp("shadow_id", keyword))
 853		{
 854			mAssetUUID.set(valuestr);
 855			LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
 856			cipher.decrypt(mAssetUUID.mData, UUID_BYTES);
 857		}
 858		else if(0 == strcmp("asset_id", keyword))
 859		{
 860			mAssetUUID.set(valuestr);
 861		}
 862		else if(0 == strcmp("type", keyword))
 863		{
 864			mType = LLAssetType::lookup(valuestr);
 865		}
 866		else if(0 == strcmp("inv_type", keyword))
 867		{
 868			mInventoryType = LLInventoryType::lookup(std::string(valuestr));
 869		}
 870		else if(0 == strcmp("flags", keyword))
 871		{
 872			sscanf(valuestr, "%x", &mFlags);
 873		}
 874		else if(0 == strcmp("name", keyword))
 875		{
 876			//strcpy(valuestr, buffer + strlen(keyword) + 3);
 877			// *NOTE: Not ANSI C, but widely supported.
 878			sscanf(	/* Flawfinder: ignore */
 879				buffer,
 880				" %254s%254[\t]%254[^|]",
 881				keyword, junk, valuestr);
 882
 883			// IW: sscanf chokes and puts | in valuestr if there's no name
 884			if (valuestr[0] == '|')
 885			{
 886				valuestr[0] = '\000';
 887			}
 888
 889			mName.assign(valuestr);
 890			LLStringUtil::replaceNonstandardASCII(mName, ' ');
 891			LLStringUtil::replaceChar(mName, '|', ' ');
 892		}
 893		else if(0 == strcmp("desc", keyword))
 894		{
 895			//strcpy(valuestr, buffer + strlen(keyword) + 3);
 896			// *NOTE: Not ANSI C, but widely supported.
 897			sscanf(	/* Flawfinder: ignore */
 898				buffer,
 899				" %254s%254[\t]%254[^|]",
 900				keyword, junk, valuestr);
 901
 902			if (valuestr[0] == '|')
 903			{
 904				valuestr[0] = '\000';
 905			}
 906
 907			mDescription.assign(valuestr);
 908			LLStringUtil::replaceNonstandardASCII(mDescription, ' ');
 909			/* TODO -- ask Ian about this code
 910			const char *donkey = mDescription.c_str();
 911			if (donkey[0] == '|')
 912			{
 913				llerrs << "Donkey" << llendl;
 914			}
 915			*/
 916		}
 917		else if(0 == strcmp("creation_date", keyword))
 918		{
 919			S32 date;
 920			sscanf(valuestr, "%d", &date);
 921			mCreationDate = date;
 922		}
 923		else
 924		{
 925			llwarns << "unknown keyword '" << keyword
 926					<< "' in inventory import of item " << mUUID << llendl;
 927		}
 928	}
 929
 930	// Need to convert 1.0 simstate files to a useful inventory type
 931	// and potentially deal with bad inventory tyes eg, a landmark
 932	// marked as a texture.
 933	if((LLInventoryType::IT_NONE == mInventoryType)
 934	   || !inventory_and_asset_types_match(mInventoryType, mType))
 935	{
 936		lldebugs << "Resetting inventory type for " << mUUID << llendl;
 937		mInventoryType = LLInventoryType::defaultForAssetType(mType);
 938	}
 939
 940	mPermissions.initMasks(mInventoryType);
 941
 942	return success;
 943}
 944
 945BOOL LLInventoryItem::exportLegacyStream(std::ostream& output_stream, BOOL include_asset_key) const
 946{
 947	std::string uuid_str;
 948	output_stream << "\tinv_item\t0\n\t{\n";
 949	mUUID.toString(uuid_str);
 950	output_stream << "\t\titem_id\t" << uuid_str << "\n";
 951	mParentUUID.toString(uuid_str);
 952	output_stream << "\t\tparent_id\t" << uuid_str << "\n";
 953	mPermissions.exportLegacyStream(output_stream);
 954
 955	// Check for permissions to see the asset id, and if so write it
 956	// out as an asset id. Otherwise, apply our cheesy encryption.
 957	if(include_asset_key)
 958	{
 959		U32 mask = mPermissions.getMaskBase();
 960		if(((mask & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED)
 961		   || (mAssetUUID.isNull()))
 962		{
 963			mAssetUUID.toString(uuid_str);
 964			output_stream << "\t\tasset_id\t" << uuid_str << "\n";
 965		}
 966		else
 967		{
 968			LLUUID shadow_id(mAssetUUID);
 969			LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
 970			cipher.encrypt(shadow_id.mData, UUID_BYTES);
 971			shadow_id.toString(uuid_str);
 972			output_stream << "\t\tshadow_id\t" << uuid_str << "\n";
 973		}
 974	}
 975	else
 976	{
 977		LLUUID::null.toString(uuid_str);
 978		output_stream << "\t\tasset_id\t" << uuid_str << "\n";
 979	}
 980	output_stream << "\t\ttype\t" << LLAssetType::lookup(mType) << "\n";
 981	const std::string inv_type_str = LLInventoryType::lookup(mInventoryType);
 982	if(!inv_type_str.empty()) 
 983		output_stream << "\t\tinv_type\t" << inv_type_str << "\n";
 984	std::string buffer;
 985	buffer = llformat( "\t\tflags\t%08x\n", mFlags);
 986	output_stream << buffer;
 987	mSaleInfo.exportLegacyStream(output_stream);
 988	output_stream << "\t\tname\t" << mName.c_str() << "|\n";
 989	output_stream << "\t\tdesc\t" << mDescription.c_str() << "|\n";
 990	output_stream << "\t\tcreation_date\t" << mCreationDate << "\n";
 991	output_stream << "\t}\n";
 992	return TRUE;
 993}
 994
 995LLSD LLInventoryItem::asLLSD() const
 996{
 997	LLSD sd = LLSD();
 998	asLLSD(sd);
 999	return sd;
1000}
1001
1002void LLInventoryItem::asLLSD( LLSD& sd ) const
1003{
1004	sd[INV_ITEM_ID_LABEL] = mUUID;
1005	sd[INV_PARENT_ID_LABEL] = mParentUUID;
1006	sd[INV_PERMISSIONS_LABEL] = ll_create_sd_from_permissions(mPermissions);
1007
1008	U32 mask = mPermissions.getMaskBase();
1009	if(((mask & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED)
1010		|| (mAssetUUID.isNull()))
1011	{
1012		sd[INV_ASSET_ID_LABEL] = mAssetUUID;
1013	}
1014	else
1015	{
1016		// *TODO: get rid of this. Phoenix 2008-01-30
1017		LLUUID shadow_id(mAssetUUID);
1018		LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
1019		cipher.encrypt(shadow_id.mData, UUID_BYTES);
1020		sd[INV_SHADOW_ID_LABEL] = shadow_id;
1021	}
1022	sd[INV_ASSET_TYPE_LABEL] = LLAssetType::lookup(mType);
1023	sd[INV_INVENTORY_TYPE_LABEL] = mInventoryType;
1024	const std::string inv_type_str = LLInventoryType::lookup(mInventoryType);
1025	if(!inv_type_str.empty())
1026	{
1027		sd[INV_INVENTORY_TYPE_LABEL] = inv_type_str;
1028	}
1029	//sd[INV_FLAGS_LABEL] = (S32)mFlags;
1030	sd[INV_FLAGS_LABEL] = ll_sd_from_U32(mFlags);
1031	sd[INV_SALE_INFO_LABEL] = mSaleInfo;
1032	sd[INV_NAME_LABEL] = mName;
1033	sd[INV_DESC_LABEL] = mDescription;
1034	sd[INV_CREATION_DATE_LABEL] = (S32) mCreationDate;
1035}
1036
1037LLFastTimer::DeclareTimer FTM_INVENTORY_SD_DESERIALIZE("Inventory SD Deserialize");
1038
1039bool LLInventoryItem::fromLLSD(const LLSD& sd)
1040{
1041	LLFastTimer _(FTM_INVENTORY_SD_DESERIALIZE);
1042	mInventoryType = LLInventoryType::IT_NONE;
1043	mAssetUUID.setNull();
1044	std::string w;
1045
1046	w = INV_ITEM_ID_LABEL;
1047	if (sd.has(w))
1048	{
1049		mUUID = sd[w];
1050	}
1051	w = INV_PARENT_ID_LABEL;
1052	if (sd.has(w))
1053	{
1054		mParentUUID = sd[w];
1055	}
1056	w = INV_PERMISSIONS_LABEL;
1057	if (sd.has(w))
1058	{
1059		mPermissions = ll_permissions_from_sd(sd[w]);
1060	}
1061	w = INV_SALE_INFO_LABEL;
1062	if (sd.has(w))
1063	{
1064		// Sale info used to contain next owner perm. It is now in
1065		// the permissions. Thus, we read that out, and fix legacy
1066		// objects. It's possible this op would fail, but it
1067		// should pick up the vast majority of the tasks.
1068		BOOL has_perm_mask = FALSE;
1069		U32 perm_mask = 0;
1070		if (!mSaleInfo.fromLLSD(sd[w], has_perm_mask, perm_mask))
1071		{
1072			goto fail;
1073		}
1074		if (has_perm_mask)
1075		{
1076			if(perm_mask == PERM_NONE)
1077			{
1078				perm_mask = mPermissions.getMaskOwner();
1079			}
1080			// fair use fix.
1081			if(!(perm_mask & PERM_COPY))
1082			{
1083				perm_mask |= PERM_TRANSFER;
1084			}
1085			mPermissions.setMaskNext(perm_mask);
1086		}
1087	}
1088	w = INV_SHADOW_ID_LABEL;
1089	if (sd.has(w))
1090	{
1091		mAssetUUID = sd[w];
1092		LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
1093		cipher.decrypt(mAssetUUID.mData, UUID_BYTES);
1094	}
1095	w = INV_ASSET_ID_LABEL;
1096	if (sd.has(w))
1097	{
1098		mAssetUUID = sd[w];
1099	}
1100	w = INV_ASSET_TYPE_LABEL;
1101	if (sd.has(w))
1102	{
1103		if (sd[w].isString())
1104		{
1105			mType = LLAssetType::lookup(sd[w].asString().c_str());
1106		}
1107		else if (sd[w].isInteger())
1108		{
1109			S8 type = (U8)sd[w].asInteger();
1110			mType = static_cast<LLAssetType::EType>(type);
1111		}
1112	}
1113	w = INV_INVENTORY_TYPE_LABEL;
1114	if (sd.has(w))
1115	{
1116		if (sd[w].isString())
1117		{
1118			mInventoryType = LLInventoryType::lookup(sd[w].asString().c_str());
1119		}
1120		else if (sd[w].isInteger())
1121		{
1122			S8 type = (U8)sd[w].asInteger();
1123			mInventoryType = static_cast<LLInventoryType::EType>(type);
1124		}
1125	}
1126	w = INV_FLAGS_LABEL;
1127	if (sd.has(w))
1128	{
1129		if (sd[w].isBinary())
1130		{
1131			mFlags = ll_U32_from_sd(sd[w]);
1132		}
1133		else if(sd[w].isInteger())
1134		{
1135			mFlags = sd[w].asInteger();
1136		}
1137	}
1138	w = INV_NAME_LABEL;
1139	if (sd.has(w))
1140	{
1141		mName = sd[w].asString();
1142		LLStringUtil::replaceNonstandardASCII(mName, ' ');
1143		LLStringUtil::replaceChar(mName, '|', ' ');
1144	}
1145	w = INV_DESC_LABEL;
1146	if (sd.has(w))
1147	{
1148		mDescription = sd[w].asString();
1149		LLStringUtil::replaceNonstandardASCII(mDescription, ' ');
1150	}
1151	w = INV_CREATION_DATE_LABEL;
1152	if (sd.has(w))
1153	{
1154		mCreationDate = sd[w].asInteger();
1155	}
1156
1157	// Need to convert 1.0 simstate files to a useful inventory type
1158	// and potentially deal with bad inventory tyes eg, a landmark
1159	// marked as a texture.
1160	if((LLInventoryType::IT_NONE == mInventoryType)
1161	   || !inventory_and_asset_types_match(mInventoryType, mType))
1162	{
1163		lldebugs << "Resetting inventory type for " << mUUID << llendl;
1164		mInventoryType = LLInventoryType::defaultForAssetType(mType);
1165	}
1166
1167	mPermissions.initMasks(mInventoryType);
1168
1169	return true;
1170fail:
1171	return false;
1172
1173}
1174
1175// Deleted LLInventoryItem::exportFileXML() and LLInventoryItem::importXML()
1176// because I can't find any non-test code references to it. 2009-05-04 JC
1177
1178S32 LLInventoryItem::packBinaryBucket(U8* bin_bucket, LLPermissions* perm_override) const
1179{
1180	// Figure out which permissions to use.
1181	LLPermissions perm;
1182	if (perm_override)
1183	{
1184		// Use the permissions override.
1185		perm = *perm_override;
1186	}
1187	else
1188	{
1189		// Use the current permissions.
1190		perm = getPermissions();
1191	}
1192
1193	// describe the inventory item
1194	char* buffer = (char*) bin_bucket;
1195	std::string creator_id_str;
1196
1197	perm.getCreator().toString(creator_id_str);
1198	std::string owner_id_str;
1199	perm.getOwner().toString(owner_id_str);
1200	std::string last_owner_id_str;
1201	perm.getLastOwner().toString(last_owner_id_str);
1202	std::string group_id_str;
1203	perm.getGroup().toString(group_id_str);
1204	std::string asset_id_str;
1205	getAssetUUID().toString(asset_id_str);
1206	S32 size = sprintf(buffer,	/* Flawfinder: ignore */
1207					   "%d|%d|%s|%s|%s|%s|%s|%x|%x|%x|%x|%x|%s|%s|%d|%d|%x",
1208					   getType(),
1209					   getInventoryType(),
1210					   getName().c_str(),
1211					   creator_id_str.c_str(),
1212					   owner_id_str.c_str(),
1213					   last_owner_id_str.c_str(),
1214					   group_id_str.c_str(),
1215					   perm.getMaskBase(),
1216					   perm.getMaskOwner(),
1217					   perm.getMaskGroup(),
1218					   perm.getMaskEveryone(),
1219					   perm.getMaskNextOwner(),
1220					   asset_id_str.c_str(),
1221					   getDescription().c_str(),
1222					   getSaleInfo().getSaleType(),
1223					   getSaleInfo().getSalePrice(),
1224					   getFlags()) + 1;
1225
1226	return size;
1227}
1228
1229void LLInventoryItem::unpackBinaryBucket(U8* bin_bucket, S32 bin_bucket_size)
1230{	
1231	// Early exit on an empty binary bucket.
1232	if (bin_bucket_size <= 1) return;
1233
1234	if (NULL == bin_bucket)
1235	{
1236		llerrs << "unpackBinaryBucket failed.  bin_bucket is NULL." << llendl;
1237		return;
1238	}
1239
1240	// Convert the bin_bucket into a string.
1241	std::vector<char> item_buffer(bin_bucket_size+1);
1242	memcpy(&item_buffer[0], bin_bucket, bin_bucket_size);	/* Flawfinder: ignore */
1243	item_buffer[bin_bucket_size] = '\0';
1244	std::string str(&item_buffer[0]);
1245
1246	lldebugs << "item buffer: " << str << llendl;
1247
1248	// Tokenize the string.
1249	typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
1250	boost::char_separator<char> sep("|", "", boost::keep_empty_tokens);
1251	tokenizer tokens(str, sep);
1252	tokenizer::iterator iter = tokens.begin();
1253
1254	// Extract all values.
1255	LLUUID item_id;
1256	item_id.generate();
1257	setUUID(item_id);
1258
1259	LLAssetType::EType type;
1260	type = (LLAssetType::EType)(atoi((*(iter++)).c_str()));
1261	setType( type );
1262	
1263	LLInventoryType::EType inv_type;
1264	inv_type = (LLInventoryType::EType)(atoi((*(iter++)).c_str()));
1265	setInventoryType( inv_type );
1266
1267	std::string name((*(iter++)).c_str());
1268	rename( name );
1269	
1270	LLUUID creator_id((*(iter++)).c_str());
1271	LLUUID owner_id((*(iter++)).c_str());
1272	LLUUID last_owner_id((*(iter++)).c_str());
1273	LLUUID group_id((*(iter++)).c_str());
1274	PermissionMask mask_base = strtoul((*(iter++)).c_str(), NULL, 16);
1275	PermissionMask mask_owner = strtoul((*(iter++)).c_str(), NULL, 16);
1276	PermissionMask mask_group = strtoul((*(iter++)).c_str(), NULL, 16);
1277	PermissionMask mask_every = strtoul((*(iter++)).c_str(), NULL, 16);
1278	PermissionMask mask_next = strtoul((*(iter++)).c_str(), NULL, 16);
1279	LLPermissions perm;
1280	perm.init(creator_id, owner_id, last_owner_id, group_id);
1281	perm.initMasks(mask_base, mask_owner, mask_group, mask_every, mask_next);
1282	setPermissions(perm);
1283	//lldebugs << "perm: " << perm << llendl;
1284
1285	LLUUID asset_id((*(iter++)).c_str());
1286	setAssetUUID(asset_id);
1287
1288	std::string desc((*(iter++)).c_str());
1289	setDescription(desc);
1290	
1291	LLSaleInfo::EForSale sale_type;
1292	sale_type = (LLSaleInfo::EForSale)(atoi((*(iter++)).c_str()));
1293	S32 price = atoi((*(iter++)).c_str());
1294	LLSaleInfo sale_info(sale_type, price);
1295	setSaleInfo(sale_info);
1296	
1297	U32 flags = strtoul((*(iter++)).c_str(), NULL, 16);
1298	setFlags(flags);
1299
1300	time_t now = time(NULL);
1301	setCreationDate(now);
1302}
1303
1304///----------------------------------------------------------------------------
1305/// Class LLInventoryCategory
1306///----------------------------------------------------------------------------
1307
1308LLInventoryCategory::LLInventoryCategory(const LLUUID& uuid,
1309										 const LLUUID& parent_uuid,
1310										 LLFolderType::EType preferred_type,
1311										 const std::string& name) :
1312	LLInventoryObject(uuid, parent_uuid, LLAssetType::AT_CATEGORY, name),
1313	mPreferredType(preferred_type)
1314{
1315}
1316
1317LLInventoryCategory::LLInventoryCategory() :
1318	mPreferredType(LLFolderType::FT_NONE)
1319{
1320	mType = LLAssetType::AT_CATEGORY;
1321}
1322
1323LLInventoryCategory::LLInventoryCategory(const LLInventoryCategory* other) :
1324	LLInventoryObject()
1325{
1326	copyCategory(other);
1327}
1328
1329LLInventoryCategory::~LLInventoryCategory()
1330{
1331}
1332
1333// virtual
1334void LLInventoryCategory::copyCategory(const LLInventoryCategory* other)
1335{
1336	copyObject(other);
1337	mPreferredType = other->mPreferredType;
1338}
1339
1340LLFolderType::EType LLInventoryCategory::getPreferredType() const
1341{
1342	return mPreferredType;
1343}
1344
1345void LLInventoryCategory::setPreferredType(LLFolderType::EType type)
1346{
1347	mPreferredType = type;
1348}
1349
1350LLSD LLInventoryCategory::asLLSD() const
1351{
1352    LLSD sd = LLSD();
1353    sd["item_id"] = mUUID;
1354    sd["parent_id"] = mParentUUID;
1355    S8 type = static_cast<S8>(mPreferredType);
1356    sd["type"]      = type;
1357    sd["name"] = mName;
1358
1359    return sd;
1360}
1361
1362
1363// virtual
1364void LLInventoryCategory::packMessage(LLMessageSystem* msg) const
1365{
1366	msg->addUUIDFast(_PREHASH_FolderID, mUUID);
1367	msg->addUUIDFast(_PREHASH_ParentID, mParentUUID);
1368	S8 type = static_cast<S8>(mPreferredType);
1369	msg->addS8Fast(_PREHASH_Type, type);
1370	msg->addStringFast(_PREHASH_Name, mName);
1371}
1372
1373bool LLInventoryCategory::fromLLSD(const LLSD& sd)
1374{
1375    std::string w;
1376
1377    w = INV_FOLDER_ID_LABEL_WS;
1378    if (sd.has(w))
1379    {
1380        mUUID = sd[w];
1381    }
1382    w = INV_PARENT_ID_LABEL;
1383    if (sd.has(w))
1384    {
1385        mParentUUID = sd[w];
1386    }
1387    w = INV_ASSET_TYPE_LABEL;
1388    if (sd.has(w))
1389    {
1390        S8 type = (U8)sd[w].asInteger();
1391        mPreferredType = static_cast<LLFolderType::EType>(type);
1392    }
1393	w = INV_ASSET_TYPE_LABEL_WS;
1394	if (sd.has(w))
1395	{
1396		S8 type = (U8)sd[w].asInteger();
1397        mPreferredType = static_cast<LLFolderType::EType>(type);
1398	}
1399
1400    w = INV_NAME_LABEL;
1401    if (sd.has(w))
1402    {
1403        mName = sd[w].asString();
1404        LLStringUtil::replaceNonstandardASCII(mName, ' ');
1405        LLStringUtil::replaceChar(mName, '|', ' ');
1406    }
1407    return true;
1408}
1409
1410// virtual
1411void LLInventoryCategory::unpackMessage(LLMessageSystem* msg,
1412										const char* block,
1413										S32 block_num)
1414{
1415	msg->getUUIDFast(block, _PREHASH_FolderID, mUUID, block_num);
1416	msg->getUUIDFast(block, _PREHASH_ParentID, mParentUUID, block_num);
1417	S8 type;
1418	msg->getS8Fast(block, _PREHASH_Type, type, block_num);
1419	mPreferredType = static_cast<LLFolderType::EType>(type);
1420	msg->getStringFast(block, _PREHASH_Name, mName, block_num);
1421	LLStringUtil::replaceNonstandardASCII(mName, ' ');
1422}
1423	
1424// virtual
1425BOOL LLInventoryCategory::importFile(LLFILE* fp)
1426{
1427	// *NOTE: Changing the buffer size will require changing the scanf
1428	// calls below.
1429	char buffer[MAX_STRING];	/* Flawfinder: ignore */
1430	char keyword[MAX_STRING];	/* Flawfinder: ignore */
1431	char valuestr[MAX_STRING];	/* Flawfinder: ignore */
1432
1433	keyword[0] = '\0';
1434	valuestr[0] = '\0';
1435	while(!feof(fp))
1436	{
1437		if (fgets(buffer, MAX_STRING, fp) == NULL)
1438		{
1439			buffer[0] = '\0';
1440		}
1441		
1442		sscanf(	/* Flawfinder: ignore */
1443			buffer,
1444			" %254s %254s",
1445			keyword, valuestr);
1446		if(0 == strcmp("{",keyword))
1447		{
1448			continue;
1449		}
1450		if(0 == strcmp("}", keyword))
1451		{
1452			break;
1453		}
1454		else if(0 == strcmp("cat_id", keyword))
1455		{
1456			mUUID.set(valuestr);
1457		}
1458		else if(0 == strcmp("parent_id", keyword))
1459		{
1460			mParentUUID.set(valuestr);
1461		}
1462		else if(0 == strcmp("type", keyword))
1463		{
1464			mType = LLAssetType::lookup(valuestr);
1465		}
1466		else if(0 == strcmp("pref_type", keyword))
1467		{
1468			mPreferredType = LLFolderType::lookup(valuestr);
1469		}
1470		else if(0 == strcmp("name", keyword))
1471		{
1472			//strcpy(valuestr, buffer + strlen(keyword) + 3);
1473			// *NOTE: Not ANSI C, but widely supported.
1474			sscanf(	/* Flawfinder: ignore */
1475				buffer,
1476				" %254s %254[^|]",
1477				keyword, valuestr);
1478			mName.assign(valuestr);
1479			LLStringUtil::replaceNonstandardASCII(mName, ' ');
1480			LLStringUtil::replaceChar(mName, '|', ' ');
1481		}
1482		else
1483		{
1484			llwarns << "unknown keyword '" << keyword
1485					<< "' in inventory import category "  << mUUID << llendl;
1486		}
1487	}
1488	return TRUE;
1489}
1490
1491BOOL LLInventoryCategory::exportFile(LLFILE* fp, BOOL) const
1492{
1493	std::string uuid_str;
1494	fprintf(fp, "\tinv_category\t0\n\t{\n");
1495	mUUID.toString(uuid_str);
1496	fprintf(fp, "\t\tcat_id\t%s\n", uuid_str.c_str());
1497	mParentUUID.toString(uuid_str);
1498	fprintf(fp, "\t\tparent_id\t%s\n", uuid_str.c_str());
1499	fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType));
1500	fprintf(fp, "\t\tpref_type\t%s\n", LLFolderType::lookup(mPreferredType).c_str());
1501	fprintf(fp, "\t\tname\t%s|\n", mName.c_str());
1502	fprintf(fp,"\t}\n");
1503	return TRUE;
1504}
1505
1506	
1507// virtual
1508BOOL LLInventoryCategory::importLegacyStream(std::istream& input_stream)
1509{
1510	// *NOTE: Changing the buffer size will require changing the scanf
1511	// calls below.
1512	char buffer[MAX_STRING];	/* Flawfinder: ignore */
1513	char keyword[MAX_STRING];	/* Flawfinder: ignore */
1514	char valuestr[MAX_STRING];	/* Flawfinder: ignore */
1515
1516	keyword[0] = '\0';
1517	valuestr[0] = '\0';
1518	while(input_stream.good())
1519	{
1520		input_stream.getline(buffer, MAX_STRING);
1521		sscanf(	/* Flawfinder: ignore */
1522			buffer,
1523			" %254s %254s",
1524			keyword, valuestr);
1525		if(0 == strcmp("{",keyword))
1526		{
1527			continue;
1528		}
1529		if(0 == strcmp("}", keyword))
1530		{
1531			break;
1532		}
1533		else if(0 == strcmp("cat_id", keyword))
1534		{
1535			mUUID.set(valuestr);
1536		}
1537		else if(0 == strcmp("parent_id", keyword))
1538		{
1539			mParentUUID.set(valuestr);
1540		}
1541		else if(0 == strcmp("type", keyword))
1542		{
1543			mType = LLAssetType::lookup(valuestr);
1544		}
1545		else if(0 == strcmp("pref_type", keyword))
1546		{
1547			mPreferredType = LLFolderType::lookup(valuestr);
1548		}
1549		else if(0 == strcmp("name", keyword))
1550		{
1551			//strcpy(valuestr, buffer + strlen(keyword) + 3);
1552			// *NOTE: Not ANSI C, but widely supported.
1553			sscanf(	/* Flawfinder: ignore */
1554				buffer,
1555				" %254s %254[^|]",
1556				keyword, valuestr);
1557			mName.assign(valuestr);
1558			LLStringUtil::replaceNonstandardASCII(mName, ' ');
1559			LLStringUtil::replaceChar(mName, '|', ' ');
1560		}
1561		else
1562		{
1563			llwarns << "unknown keyword '" << keyword
1564					<< "' in inventory import category "  << mUUID << llendl;
1565		}
1566	}
1567	return TRUE;
1568}
1569
1570BOOL LLInventoryCategory::exportLegacyStream(std::ostream& output_stream, BOOL) const
1571{
1572	std::string uuid_str;
1573	output_stream << "\tinv_category\t0\n\t{\n";
1574	mUUID.toString(uuid_str);
1575	output_stream << "\t\tcat_id\t" << uuid_str << "\n";
1576	mParentUUID.toString(uuid_str);
1577	output_stream << "\t\tparent_id\t" << uuid_str << "\n";
1578	output_stream << "\t\ttype\t" << LLAssetType::lookup(mType) << "\n";
1579	output_stream << "\t\tpref_type\t" << LLFolderType::lookup(mPreferredType) << "\n";
1580	output_stream << "\t\tname\t" << mName.c_str() << "|\n";
1581	output_stream << "\t}\n";
1582	return TRUE;
1583}
1584
1585///----------------------------------------------------------------------------
1586/// Local function definitions
1587///----------------------------------------------------------------------------
1588
1589LLSD ll_create_sd_from_inventory_item(LLPointer<LLInventoryItem> item)
1590{
1591	LLSD rv;
1592	if(item.isNull()) return rv;
1593	if (item->getType() == LLAssetType::AT_NONE)
1594	{
1595		llwarns << "ll_create_sd_from_inventory_item() for item with AT_NONE"
1596			<< llendl;
1597		return rv;
1598	}
1599	rv[INV_ITEM_ID_LABEL] =  item->getUUID();
1600	rv[INV_PARENT_ID_LABEL] = item->getParentUUID();
1601	rv[INV_NAME_LABEL] = item->getName();
1602	rv[INV_ASSET_TYPE_LABEL] = LLAssetType::lookup(item->getType());
1603	rv[INV_ASSET_ID_LABEL] = item->getAssetUUID();
1604	rv[INV_DESC_LABEL] = item->getDescription();
1605	rv[INV_SALE_INFO_LABEL] = ll_create_sd_from_sale_info(item->getSaleInfo());
1606	rv[INV_PERMISSIONS_LABEL] =
1607		ll_create_sd_from_permissions(item->getPermissions());
1608	rv[INV_INVENTORY_TYPE_LABEL] =
1609		LLInventoryType::lookup(item->getInventoryType());
1610	rv[INV_FLAGS_LABEL] = (S32)item->getFlags();
1611	rv[INV_CREATION_DATE_LABEL] = (S32)item->getCreationDate();
1612	return rv;
1613}
1614
1615LLSD ll_create_sd_from_inventory_category(LLPointer<LLInventoryCategory> cat)
1616{
1617	LLSD rv;
1618	if(cat.isNull()) return rv;
1619	if (cat->getType() == LLAssetType::AT_NONE)
1620	{
1621		llwarns << "ll_create_sd_from_inventory_category() for cat with AT_NONE"
1622			<< llendl;
1623		return rv;
1624	}
1625	rv[INV_FOLDER_ID_LABEL] = cat->getUUID();
1626	rv[INV_PARENT_ID_LABEL] = cat->getParentUUID();
1627	rv[INV_NAME_LABEL] = cat->getName();
1628	rv[INV_ASSET_TYPE_LABEL] = LLAssetType::lookup(cat->getType());
1629	if(LLFolderType::lookupIsProtectedType(cat->getPreferredType()))
1630	{
1631		rv[INV_PREFERRED_TYPE_LABEL] =
1632			LLFolderType::lookup(cat->getPreferredType()).c_str();
1633	}
1634	return rv;
1635}
1636
1637LLPointer<LLInventoryCategory> ll_create_category_from_sd(const LLSD& sd_cat)
1638{
1639	LLPointer<LLInventoryCategory> rv = new LLInventoryCategory;
1640	rv->setUUID(sd_cat[INV_FOLDER_ID_LABEL].asUUID());
1641	rv->setParent(sd_cat[INV_PARENT_ID_LABEL].asUUID());
1642	rv->rename(sd_cat[INV_NAME_LABEL].asString());
1643	rv->setType(
1644		LLAssetType::lookup(sd_cat[INV_ASSET_TYPE_LABEL].asString()));
1645	rv->setPreferredType(
1646			LLFolderType::lookup(
1647				sd_cat[INV_PREFERRED_TYPE_LABEL].asString()));
1648	return rv;
1649}