summaryrefslogtreecommitdiff
path: root/indra/llinventory/llinventory.cpp
diff options
context:
space:
mode:
authorJames Cook <james@lindenlab.com>2007-01-02 08:33:20 +0000
committerJames Cook <james@lindenlab.com>2007-01-02 08:33:20 +0000
commit420b91db29485df39fd6e724e782c449158811cb (patch)
treeb471a94563af914d3ed3edd3e856d21cb1b69945 /indra/llinventory/llinventory.cpp
Print done when done.
Diffstat (limited to 'indra/llinventory/llinventory.cpp')
-rw-r--r--indra/llinventory/llinventory.cpp1773
1 files changed, 1773 insertions, 0 deletions
diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp
new file mode 100644
index 0000000000..bffc4df281
--- /dev/null
+++ b/indra/llinventory/llinventory.cpp
@@ -0,0 +1,1773 @@
+/**
+ * @file llinventory.cpp
+ * @brief Implementation of the inventory system.
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "linden_common.h"
+
+#include <time.h>
+
+#include "llinventory.h"
+
+#include "lldbstrings.h"
+#include "llcrypto.h"
+#include "llsd.h"
+#include "message.h"
+#include <boost/tokenizer.hpp>
+
+#include "llsdutil.h"
+
+#include "llsdutil.h"
+
+///----------------------------------------------------------------------------
+/// Local function declarations, constants, enums, and typedefs
+///----------------------------------------------------------------------------
+
+const U8 TASK_INVENTORY_ITEM_KEY = 0;
+const U8 TASK_INVENTORY_ASSET_KEY = 1;
+
+const LLUUID MAGIC_ID("3c115e51-04f4-523c-9fa6-98aff1034730");
+
+// helper function which returns true if inventory type and asset type
+// are potentially compatible. For example, an attachment must be an
+// object, but a wearable can be a bodypart or clothing asset.
+bool inventory_and_asset_types_match(
+ LLInventoryType::EType inventory_type,
+ LLAssetType::EType asset_type);
+
+
+///----------------------------------------------------------------------------
+/// Class LLInventoryType
+///----------------------------------------------------------------------------
+
+// Unlike asset type names, not limited to 8 characters.
+// Need not match asset type names.
+static const char* INVENTORY_TYPE_NAMES[LLInventoryType::IT_COUNT] =
+{
+ "texture", // 0
+ "sound",
+ "callcard",
+ "landmark",
+ NULL,
+ NULL, // 5
+ "object",
+ "notecard",
+ "category",
+ "root",
+ "script", // 10
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "snapshot", // 15
+ NULL,
+ "attach",
+ "wearable",
+ "animation",
+ "gesture", // 20
+};
+
+// This table is meant for decoding to human readable form. Put any
+// and as many printable characters you want in each one.
+// See also LLAssetType::mAssetTypeHumanNames
+static const char* INVENTORY_TYPE_HUMAN_NAMES[LLInventoryType::IT_COUNT] =
+{
+ "texture", // 0
+ "sound",
+ "calling card",
+ "landmark",
+ NULL,
+ NULL, // 5
+ "object",
+ "note card",
+ "folder",
+ "root",
+ "script", // 10
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "snapshot", // 15
+ NULL,
+ "attachment",
+ "wearable",
+ "animation",
+ "gesture", // 20
+};
+
+// Maps asset types to the default inventory type for that kind of asset.
+// Thus, "Lost and Found" is a "Category"
+static const LLInventoryType::EType
+DEFAULT_ASSET_FOR_INV_TYPE[LLAssetType::AT_COUNT] =
+{
+ LLInventoryType::IT_TEXTURE, // AT_TEXTURE
+ LLInventoryType::IT_SOUND, // AT_SOUND
+ LLInventoryType::IT_CALLINGCARD, // AT_CALLINGCARD
+ LLInventoryType::IT_LANDMARK, // AT_LANDMARK
+ LLInventoryType::IT_LSL, // AT_SCRIPT
+ LLInventoryType::IT_WEARABLE, // AT_CLOTHING
+ LLInventoryType::IT_OBJECT, // AT_OBJECT
+ LLInventoryType::IT_NOTECARD, // AT_NOTECARD
+ LLInventoryType::IT_CATEGORY, // AT_CATEGORY
+ LLInventoryType::IT_ROOT_CATEGORY, // AT_ROOT_CATEGORY
+ LLInventoryType::IT_LSL, // AT_LSL_TEXT
+ LLInventoryType::IT_LSL, // AT_LSL_BYTECODE
+ LLInventoryType::IT_TEXTURE, // AT_TEXTURE_TGA
+ LLInventoryType::IT_WEARABLE, // AT_BODYPART
+ LLInventoryType::IT_CATEGORY, // AT_TRASH
+ LLInventoryType::IT_CATEGORY, // AT_SNAPSHOT_CATEGORY
+ LLInventoryType::IT_CATEGORY, // AT_LOST_AND_FOUND
+ LLInventoryType::IT_SOUND, // AT_SOUND_WAV
+ LLInventoryType::IT_NONE, // AT_IMAGE_TGA
+ LLInventoryType::IT_NONE, // AT_IMAGE_JPEG
+ LLInventoryType::IT_ANIMATION, // AT_ANIMATION
+ LLInventoryType::IT_GESTURE, // AT_GESTURE
+};
+
+static const int MAX_POSSIBLE_ASSET_TYPES = 2;
+static const LLAssetType::EType
+INVENTORY_TO_ASSET_TYPE[LLInventoryType::IT_COUNT][MAX_POSSIBLE_ASSET_TYPES] =
+{
+ { LLAssetType::AT_TEXTURE, LLAssetType::AT_NONE }, // IT_TEXTURE
+ { LLAssetType::AT_SOUND, LLAssetType::AT_NONE }, // IT_SOUND
+ { LLAssetType::AT_CALLINGCARD, LLAssetType::AT_NONE }, // IT_CALLINGCARD
+ { LLAssetType::AT_LANDMARK, LLAssetType::AT_NONE }, // IT_LANDMARK
+ { LLAssetType::AT_NONE, LLAssetType::AT_NONE },
+ { LLAssetType::AT_NONE, LLAssetType::AT_NONE },
+ { LLAssetType::AT_OBJECT, LLAssetType::AT_NONE }, // IT_OBJECT
+ { LLAssetType::AT_NOTECARD, LLAssetType::AT_NONE }, // IT_NOTECARD
+ { LLAssetType::AT_NONE, LLAssetType::AT_NONE }, // IT_CATEGORY
+ { LLAssetType::AT_NONE, LLAssetType::AT_NONE }, // IT_ROOT_CATEGORY
+ { LLAssetType::AT_LSL_TEXT, LLAssetType::AT_LSL_BYTECODE }, // IT_LSL
+ { LLAssetType::AT_NONE, LLAssetType::AT_NONE },
+ { LLAssetType::AT_NONE, LLAssetType::AT_NONE },
+ { LLAssetType::AT_NONE, LLAssetType::AT_NONE },
+ { LLAssetType::AT_NONE, LLAssetType::AT_NONE },
+ { LLAssetType::AT_TEXTURE, LLAssetType::AT_NONE }, // IT_SNAPSHOT
+ { LLAssetType::AT_NONE, LLAssetType::AT_NONE },
+ { LLAssetType::AT_OBJECT, LLAssetType::AT_NONE }, // IT_ATTACHMENT
+ { LLAssetType::AT_CLOTHING, LLAssetType::AT_BODYPART }, // IT_WEARABLE
+ { LLAssetType::AT_ANIMATION, LLAssetType::AT_NONE }, // IT_ANIMATION
+ { LLAssetType::AT_GESTURE, LLAssetType::AT_NONE }, // IT_GESTURE
+};
+
+// static
+const char* LLInventoryType::lookup(EType type)
+{
+ if((type >= 0) && (type < IT_COUNT))
+ {
+ return INVENTORY_TYPE_NAMES[S32(type)];
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+// static
+LLInventoryType::EType LLInventoryType::lookup(const char* name)
+{
+ for(S32 i = 0; i < IT_COUNT; ++i)
+ {
+ if((INVENTORY_TYPE_NAMES[i])
+ && (0 == strcmp(name, INVENTORY_TYPE_NAMES[i])))
+ {
+ // match
+ return (EType)i;
+ }
+ }
+ return IT_NONE;
+}
+
+// XUI:translate
+// translation from a type to a human readable form.
+// static
+const char* LLInventoryType::lookupHumanReadable(EType type)
+{
+ if((type >= 0) && (type < IT_COUNT))
+ {
+ return INVENTORY_TYPE_HUMAN_NAMES[S32(type)];
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+// return the default inventory for the given asset type.
+// static
+LLInventoryType::EType LLInventoryType::defaultForAssetType(LLAssetType::EType asset_type)
+{
+ if((asset_type >= 0) && (asset_type < LLAssetType::AT_COUNT))
+ {
+ return DEFAULT_ASSET_FOR_INV_TYPE[S32(asset_type)];
+ }
+ else
+ {
+ return IT_NONE;
+ }
+}
+
+///----------------------------------------------------------------------------
+/// Class LLInventoryObject
+///----------------------------------------------------------------------------
+
+LLInventoryObject::LLInventoryObject(
+ const LLUUID& uuid,
+ const LLUUID& parent_uuid,
+ LLAssetType::EType type,
+ const LLString& name) :
+ mUUID(uuid),
+ mParentUUID(parent_uuid),
+ mType(type),
+ mName(name)
+{
+ LLString::replaceNonstandardASCII(mName, ' ');
+ LLString::replaceChar(mName, '|', ' ');
+ LLString::trim(mName);
+ LLString::truncate(mName, DB_INV_ITEM_NAME_STR_LEN);
+}
+
+LLInventoryObject::LLInventoryObject() :
+ mType(LLAssetType::AT_NONE)
+{
+}
+
+LLInventoryObject::~LLInventoryObject( void )
+{
+}
+
+void LLInventoryObject::copy(const LLInventoryObject* other)
+{
+ mUUID = other->mUUID;
+ mParentUUID = other->mParentUUID;
+ mType = other->mType;
+ mName = other->mName;
+}
+
+const LLUUID& LLInventoryObject::getUUID() const
+{
+ return mUUID;
+}
+
+const LLUUID& LLInventoryObject::getParentUUID() const
+{
+ return mParentUUID;
+}
+
+const LLString& LLInventoryObject::getName() const
+{
+ return mName;
+}
+
+LLAssetType::EType LLInventoryObject::getType() const
+{
+ return mType;
+}
+
+void LLInventoryObject::setUUID(const LLUUID& new_uuid)
+{
+ mUUID = new_uuid;
+}
+
+void LLInventoryObject::rename(const LLString& n)
+{
+ LLString new_name(n);
+ LLString::replaceNonstandardASCII(new_name, ' ');
+ LLString::replaceChar(new_name, '|', ' ');
+ LLString::trim(new_name);
+ LLString::truncate(new_name, DB_INV_ITEM_NAME_STR_LEN);
+
+ if( new_name != mName )
+ {
+ mName = new_name;
+ }
+}
+
+void LLInventoryObject::setParent(const LLUUID& new_parent)
+{
+ mParentUUID = new_parent;
+}
+
+void LLInventoryObject::setType(LLAssetType::EType type)
+{
+ mType = type;
+}
+
+
+// virtual
+BOOL LLInventoryObject::importLegacyStream(std::istream& input_stream)
+{
+ char buffer[MAX_STRING];
+ char keyword[MAX_STRING];
+ char valuestr[MAX_STRING];
+
+ keyword[0] = '\0';
+ valuestr[0] = '\0';
+ while(input_stream.good())
+ {
+ input_stream.getline(buffer, MAX_STRING);
+ sscanf(buffer, " %254s %254s", keyword, valuestr);
+ if(!keyword)
+ {
+ continue;
+ }
+ if(0 == strcmp("{",keyword))
+ {
+ continue;
+ }
+ if(0 == strcmp("}", keyword))
+ {
+ break;
+ }
+ else if(0 == strcmp("obj_id", keyword))
+ {
+ mUUID.set(valuestr);
+ }
+ else if(0 == strcmp("parent_id", keyword))
+ {
+ mParentUUID.set(valuestr);
+ }
+ else if(0 == strcmp("type", keyword))
+ {
+ mType = LLAssetType::lookup(valuestr);
+ }
+ else if(0 == strcmp("name", keyword))
+ {
+ //strcpy(valuestr, buffer + strlen(keyword) + 3);
+ // *NOTE: Not ANSI C, but widely supported.
+ sscanf(buffer, " %254s %[^|]", keyword, valuestr);
+ mName.assign(valuestr);
+ LLString::replaceNonstandardASCII(mName, ' ');
+ LLString::replaceChar(mName, '|', ' ');
+ LLString::trim(mName);
+ LLString::truncate(mName, DB_INV_ITEM_NAME_STR_LEN);
+ }
+ else
+ {
+ llwarns << "unknown keyword '" << keyword
+ << "' in LLInventoryObject::importLegacyStream() for object " << mUUID << llendl;
+ }
+ }
+ return TRUE;
+}
+
+// exportFile should be replaced with exportLegacyStream
+// not sure whether exportLegacyStream(llofstream(fp)) would work, fp may need to get icramented...
+BOOL LLInventoryObject::exportFile(FILE* fp, BOOL) const
+{
+ char uuid_str[UUID_STR_LENGTH];
+ fprintf(fp, "\tinv_object\t0\n\t{\n");
+ mUUID.toString(uuid_str);
+ fprintf(fp, "\t\tobj_id\t%s\n", uuid_str);
+ mParentUUID.toString(uuid_str);
+ fprintf(fp, "\t\tparent_id\t%s\n", uuid_str);
+ fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType));
+ fprintf(fp, "\t\tname\t%s|\n", mName.c_str());
+ fprintf(fp,"\t}\n");
+ return TRUE;
+}
+
+BOOL LLInventoryObject::exportLegacyStream(std::ostream& output_stream, BOOL) const
+{
+ char uuid_str[UUID_STR_LENGTH];
+ output_stream << "\tinv_object\t0\n\t{\n";
+ mUUID.toString(uuid_str);
+ output_stream << "\t\tobj_id\t" << uuid_str << "\n";
+ mParentUUID.toString(uuid_str);
+ output_stream << "\t\tparent_id\t" << uuid_str << "\n";
+ output_stream << "\t\ttype\t" << LLAssetType::lookup(mType) << "\n";
+ output_stream << "\t\tname\t" << mName.c_str() << "|\n";
+ output_stream << "\t}\n";
+ return TRUE;
+}
+
+
+void LLInventoryObject::removeFromServer()
+{
+ // don't do nothin'
+ llwarns << "LLInventoryObject::removeFromServer() called. Doesn't do anything." << llendl;
+}
+
+void LLInventoryObject::updateParentOnServer(BOOL) const
+{
+ // don't do nothin'
+ llwarns << "LLInventoryObject::updateParentOnServer() called. Doesn't do anything." << llendl;
+}
+
+void LLInventoryObject::updateServer(BOOL) const
+{
+ // don't do nothin'
+ llwarns << "LLInventoryObject::updateServer() called. Doesn't do anything." << llendl;
+}
+
+
+///----------------------------------------------------------------------------
+/// Class LLInventoryItem
+///----------------------------------------------------------------------------
+
+LLInventoryItem::LLInventoryItem(
+ const LLUUID& uuid,
+ const LLUUID& parent_uuid,
+ const LLPermissions& permissions,
+ const LLUUID& asset_uuid,
+ LLAssetType::EType type,
+ LLInventoryType::EType inv_type,
+ const LLString& name,
+ const LLString& desc,
+ const LLSaleInfo& sale_info,
+ U32 flags,
+ S32 creation_date_utc) :
+ LLInventoryObject(uuid, parent_uuid, type, name),
+ mPermissions(permissions),
+ mAssetUUID(asset_uuid),
+ mDescription(desc),
+ mSaleInfo(sale_info),
+ mInventoryType(inv_type),
+ mFlags(flags),
+ mCreationDate(creation_date_utc)
+{
+ LLString::replaceNonstandardASCII(mDescription, ' ');
+ LLString::replaceChar(mDescription, '|', ' ');
+}
+
+LLInventoryItem::LLInventoryItem() :
+ LLInventoryObject(),
+ mPermissions(),
+ mAssetUUID(),
+ mDescription(),
+ mSaleInfo(),
+ mInventoryType(LLInventoryType::IT_NONE),
+ mFlags(0),
+ mCreationDate(0)
+{
+}
+
+LLInventoryItem::LLInventoryItem(const LLInventoryItem* other) :
+ LLInventoryObject()
+{
+ copy(other);
+}
+
+LLInventoryItem::~LLInventoryItem()
+{
+}
+
+// virtual
+void LLInventoryItem::copy(const LLInventoryItem* other)
+{
+ LLInventoryObject::copy(other);
+ mPermissions = other->mPermissions;
+ mAssetUUID = other->mAssetUUID;
+ mDescription = other->mDescription;
+ mSaleInfo = other->mSaleInfo;
+ mInventoryType = other->mInventoryType;
+ mFlags = other->mFlags;
+ mCreationDate = other->mCreationDate;
+}
+
+// As a constructor alternative, the clone() method works like a
+// copy constructor, but gens a new UUID.
+void LLInventoryItem::clone(LLPointer<LLInventoryItem>& newitem) const
+{
+ newitem = new LLInventoryItem;
+ newitem->copy(this);
+ newitem->mUUID.generate();
+}
+
+const LLPermissions& LLInventoryItem::getPermissions() const
+{
+ return mPermissions;
+}
+
+const LLUUID& LLInventoryItem::getCreatorUUID() const
+{
+ return mPermissions.getCreator();
+}
+
+const LLUUID& LLInventoryItem::getAssetUUID() const
+{
+ return mAssetUUID;
+}
+
+void LLInventoryItem::setAssetUUID(const LLUUID& asset_id)
+{
+ mAssetUUID = asset_id;
+}
+
+
+const LLString& LLInventoryItem::getDescription() const
+{
+ return mDescription;
+}
+
+S32 LLInventoryItem::getCreationDate() const
+{
+ return mCreationDate;
+}
+
+U32 LLInventoryItem::getCRC32() const
+{
+ // *FIX: Not a real crc - more of a checksum.
+ // *NOTE: We currently do not validate the name or description,
+ // but if they change in transit, it's no big deal.
+ U32 crc = mUUID.getCRC32();
+ //lldebugs << "1 crc: " << std::hex << crc << std::dec << llendl;
+ crc += mParentUUID.getCRC32();
+ //lldebugs << "2 crc: " << std::hex << crc << std::dec << llendl;
+ crc += mPermissions.getCRC32();
+ //lldebugs << "3 crc: " << std::hex << crc << std::dec << llendl;
+ crc += mAssetUUID.getCRC32();
+ //lldebugs << "4 crc: " << std::hex << crc << std::dec << llendl;
+ crc += mType;
+ //lldebugs << "5 crc: " << std::hex << crc << std::dec << llendl;
+ crc += mInventoryType;
+ //lldebugs << "6 crc: " << std::hex << crc << std::dec << llendl;
+ crc += mFlags;
+ //lldebugs << "7 crc: " << std::hex << crc << std::dec << llendl;
+ crc += mSaleInfo.getCRC32();
+ //lldebugs << "8 crc: " << std::hex << crc << std::dec << llendl;
+ crc += mCreationDate;
+ //lldebugs << "9 crc: " << std::hex << crc << std::dec << llendl;
+ return crc;
+}
+
+
+void LLInventoryItem::setDescription(const LLString& d)
+{
+ LLString new_desc(d);
+ LLString::replaceNonstandardASCII(new_desc, ' ');
+ LLString::replaceChar(new_desc, '|', ' ');
+ if( new_desc != mDescription )
+ {
+ mDescription = new_desc;
+ }
+}
+
+void LLInventoryItem::setPermissions(const LLPermissions& perm)
+{
+ mPermissions = perm;
+}
+
+void LLInventoryItem::setInventoryType(LLInventoryType::EType inv_type)
+{
+ mInventoryType = inv_type;
+}
+
+void LLInventoryItem::setFlags(U32 flags)
+{
+ mFlags = flags;
+}
+
+void LLInventoryItem::setCreationDate(S32 creation_date_utc)
+{
+ mCreationDate = creation_date_utc;
+}
+
+
+const LLSaleInfo& LLInventoryItem::getSaleInfo() const
+{
+ return mSaleInfo;
+}
+
+void LLInventoryItem::setSaleInfo(const LLSaleInfo& sale_info)
+{
+ mSaleInfo = sale_info;
+}
+
+LLInventoryType::EType LLInventoryItem::getInventoryType() const
+{
+ return mInventoryType;
+}
+
+U32 LLInventoryItem::getFlags() const
+{
+ return mFlags;
+}
+
+// virtual
+void LLInventoryItem::packMessage(LLMessageSystem* msg) const
+{
+ msg->addUUIDFast(_PREHASH_ItemID, mUUID);
+ msg->addUUIDFast(_PREHASH_FolderID, mParentUUID);
+ mPermissions.packMessage(msg);
+ msg->addUUIDFast(_PREHASH_AssetID, mAssetUUID);
+ S8 type = static_cast<S8>(mType);
+ msg->addS8Fast(_PREHASH_Type, type);
+ type = static_cast<S8>(mInventoryType);
+ msg->addS8Fast(_PREHASH_InvType, type);
+ msg->addU32Fast(_PREHASH_Flags, mFlags);
+ mSaleInfo.packMessage(msg);
+ msg->addStringFast(_PREHASH_Name, mName);
+ msg->addStringFast(_PREHASH_Description, mDescription);
+ msg->addS32Fast(_PREHASH_CreationDate, mCreationDate);
+ U32 crc = getCRC32();
+ msg->addU32Fast(_PREHASH_CRC, crc);
+}
+
+// virtual
+BOOL LLInventoryItem::unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num)
+{
+ msg->getUUIDFast(block, _PREHASH_ItemID, mUUID, block_num);
+ msg->getUUIDFast(block, _PREHASH_FolderID, mParentUUID, block_num);
+ mPermissions.unpackMessage(msg, block, block_num);
+ msg->getUUIDFast(block, _PREHASH_AssetID, mAssetUUID, block_num);
+
+ S8 type;
+ msg->getS8Fast(block, _PREHASH_Type, type, block_num);
+ mType = static_cast<LLAssetType::EType>(type);
+ msg->getS8(block, "InvType", type, block_num);
+ mInventoryType = static_cast<LLInventoryType::EType>(type);
+
+ msg->getU32Fast(block, _PREHASH_Flags, mFlags, block_num);
+
+ mSaleInfo.unpackMultiMessage(msg, block, block_num);
+
+ char name[DB_INV_ITEM_NAME_BUF_SIZE];
+ msg->getStringFast(block, _PREHASH_Name, DB_INV_ITEM_NAME_BUF_SIZE, name, block_num);
+ mName.assign(name);
+ LLString::replaceNonstandardASCII(mName, ' ');
+
+ char desc[DB_INV_ITEM_DESC_BUF_SIZE];
+ msg->getStringFast(block, _PREHASH_Description, DB_INV_ITEM_DESC_BUF_SIZE, desc, block_num);
+ mDescription.assign(desc);
+ LLString::replaceNonstandardASCII(mDescription, ' ');
+
+ msg->getS32(block, "CreationDate", mCreationDate, block_num);
+
+ U32 local_crc = getCRC32();
+ U32 remote_crc = 0;
+ msg->getU32(block, "CRC", remote_crc, block_num);
+//#define CRC_CHECK
+#ifdef CRC_CHECK
+ if(local_crc == remote_crc)
+ {
+ lldebugs << "crc matches" << llendl;
+ return TRUE;
+ }
+ else
+ {
+ llwarns << "inventory crc mismatch: local=" << std::hex << local_crc
+ << " remote=" << remote_crc << std::dec << llendl;
+ return FALSE;
+ }
+#else
+ return (local_crc == remote_crc);
+#endif
+}
+
+// virtual
+BOOL LLInventoryItem::importFile(FILE* fp)
+{
+ char buffer[MAX_STRING];
+ char keyword[MAX_STRING];
+ char valuestr[MAX_STRING];
+ char junk[MAX_STRING];
+ BOOL success = TRUE;
+
+ keyword[0] = '\0';
+ valuestr[0] = '\0';
+
+ mInventoryType = LLInventoryType::IT_NONE;
+ mAssetUUID.setNull();
+ while(success && (!feof(fp)))
+ {
+ fgets(buffer, MAX_STRING, fp);
+ sscanf(buffer, " %254s %254s", keyword, valuestr);
+ if(!keyword)
+ {
+ continue;
+ }
+ if(0 == strcmp("{",keyword))
+ {
+ continue;
+ }
+ if(0 == strcmp("}", keyword))
+ {
+ break;
+ }
+ else if(0 == strcmp("item_id", keyword))
+ {
+ mUUID.set(valuestr);
+ }
+ else if(0 == strcmp("parent_id", keyword))
+ {
+ mParentUUID.set(valuestr);
+ }
+ else if(0 == strcmp("permissions", keyword))
+ {
+ success = mPermissions.importFile(fp);
+ }
+ else if(0 == strcmp("sale_info", keyword))
+ {
+ // Sale info used to contain next owner perm. It is now in
+ // the permissions. Thus, we read that out, and fix legacy
+ // objects. It's possible this op would fail, but it
+ // should pick up the vast majority of the tasks.
+ BOOL has_perm_mask = FALSE;
+ U32 perm_mask = 0;
+ success = mSaleInfo.importFile(fp, has_perm_mask, perm_mask);
+ if(has_perm_mask)
+ {
+ if(perm_mask == PERM_NONE)
+ {
+ perm_mask = mPermissions.getMaskOwner();
+ }
+ // fair use fix.
+ if(!(perm_mask & PERM_COPY))
+ {
+ perm_mask |= PERM_TRANSFER;
+ }
+ mPermissions.setMaskNext(perm_mask);
+ }
+ }
+ else if(0 == strcmp("shadow_id", keyword))
+ {
+ mAssetUUID.set(valuestr);
+ LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
+ cipher.decrypt(mAssetUUID.mData, UUID_BYTES);
+ }
+ else if(0 == strcmp("asset_id", keyword))
+ {
+ mAssetUUID.set(valuestr);
+ }
+ else if(0 == strcmp("type", keyword))
+ {
+ mType = LLAssetType::lookup(valuestr);
+ }
+ else if(0 == strcmp("inv_type", keyword))
+ {
+ mInventoryType = LLInventoryType::lookup(valuestr);
+ }
+ else if(0 == strcmp("flags", keyword))
+ {
+ sscanf(valuestr, "%x", &mFlags);
+ }
+ else if(0 == strcmp("name", keyword))
+ {
+ //strcpy(valuestr, buffer + strlen(keyword) + 3);
+ // *NOTE: Not ANSI C, but widely supported.
+ sscanf(buffer, " %254s%[\t]%[^|]", keyword, junk, valuestr);
+
+ // IW: sscanf chokes and puts | in valuestr if there's no name
+ if (valuestr[0] == '|')
+ {
+ valuestr[0] = '\000';
+ }
+
+ mName.assign(valuestr);
+ LLString::replaceNonstandardASCII(mName, ' ');
+ LLString::replaceChar(mName, '|', ' ');
+ }
+ else if(0 == strcmp("desc", keyword))
+ {
+ //strcpy(valuestr, buffer + strlen(keyword) + 3);
+ // *NOTE: Not ANSI C, but widely supported.
+ sscanf(buffer, " %s%[\t]%[^|]", keyword, junk, valuestr);
+
+ if (valuestr[0] == '|')
+ {
+ valuestr[0] = '\000';
+ }
+
+ mDescription.assign(valuestr);
+ LLString::replaceNonstandardASCII(mDescription, ' ');
+ /* TODO -- ask Ian about this code
+ const char *donkey = mDescription.c_str();
+ if (donkey[0] == '|')
+ {
+ llerrs << "Donkey" << llendl;
+ }
+ */
+ }
+ else if(0 == strcmp("creation_date", keyword))
+ {
+ sscanf(valuestr, "%d", &mCreationDate);
+ }
+ else
+ {
+ llwarns << "unknown keyword '" << keyword
+ << "' in inventory import of item " << mUUID << llendl;
+ }
+ }
+
+ // Need to convert 1.0 simstate files to a useful inventory type
+ // and potentially deal with bad inventory tyes eg, a landmark
+ // marked as a texture.
+ if((LLInventoryType::IT_NONE == mInventoryType)
+ || !inventory_and_asset_types_match(mInventoryType, mType))
+ {
+ lldebugs << "Resetting inventory type for " << mUUID << llendl;
+ mInventoryType = LLInventoryType::defaultForAssetType(mType);
+ }
+ return success;
+}
+
+BOOL LLInventoryItem::exportFile(FILE* fp, BOOL include_asset_key) const
+{
+ char uuid_str[UUID_STR_LENGTH];
+ fprintf(fp, "\tinv_item\t0\n\t{\n");
+ mUUID.toString(uuid_str);
+ fprintf(fp, "\t\titem_id\t%s\n", uuid_str);
+ mParentUUID.toString(uuid_str);
+ fprintf(fp, "\t\tparent_id\t%s\n", uuid_str);
+ mPermissions.exportFile(fp);
+
+ // Check for permissions to see the asset id, and if so write it
+ // out as an asset id. Otherwise, apply our cheesy encryption.
+ if(include_asset_key)
+ {
+ U32 mask = mPermissions.getMaskBase();
+ if(((mask & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED)
+ || (mAssetUUID.isNull()))
+ {
+ mAssetUUID.toString(uuid_str);
+ fprintf(fp, "\t\tasset_id\t%s\n", uuid_str);
+ }
+ else
+ {
+ LLUUID shadow_id(mAssetUUID);
+ LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
+ cipher.encrypt(shadow_id.mData, UUID_BYTES);
+ shadow_id.toString(uuid_str);
+ fprintf(fp, "\t\tshadow_id\t%s\n", uuid_str);
+ }
+ }
+ else
+ {
+ LLUUID::null.toString(uuid_str);
+ fprintf(fp, "\t\tasset_id\t%s\n", uuid_str);
+ }
+ fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType));
+ const char* inv_type_str = LLInventoryType::lookup(mInventoryType);
+ if(inv_type_str) fprintf(fp, "\t\tinv_type\t%s\n", inv_type_str);
+ fprintf(fp, "\t\tflags\t%08x\n", mFlags);
+ mSaleInfo.exportFile(fp);
+ fprintf(fp, "\t\tname\t%s|\n", mName.c_str());
+ fprintf(fp, "\t\tdesc\t%s|\n", mDescription.c_str());
+ fprintf(fp, "\t\tcreation_date\t%d\n", mCreationDate);
+ fprintf(fp,"\t}\n");
+ return TRUE;
+}
+
+// virtual
+BOOL LLInventoryItem::importLegacyStream(std::istream& input_stream)
+{
+ char buffer[MAX_STRING];
+ char keyword[MAX_STRING];
+ char valuestr[MAX_STRING];
+ char junk[MAX_STRING];
+ BOOL success = TRUE;
+
+ keyword[0] = '\0';
+ valuestr[0] = '\0';
+
+ mInventoryType = LLInventoryType::IT_NONE;
+ mAssetUUID.setNull();
+ while(success && input_stream.good())
+ {
+ input_stream.getline(buffer, MAX_STRING);
+ sscanf(buffer, " %s %s", keyword, valuestr);
+ if(!keyword)
+ {
+ continue;
+ }
+ if(0 == strcmp("{",keyword))
+ {
+ continue;
+ }
+ if(0 == strcmp("}", keyword))
+ {
+ break;
+ }
+ else if(0 == strcmp("item_id", keyword))
+ {
+ mUUID.set(valuestr);
+ }
+ else if(0 == strcmp("parent_id", keyword))
+ {
+ mParentUUID.set(valuestr);
+ }
+ else if(0 == strcmp("permissions", keyword))
+ {
+ success = mPermissions.importLegacyStream(input_stream);
+ }
+ else if(0 == strcmp("sale_info", keyword))
+ {
+ // Sale info used to contain next owner perm. It is now in
+ // the permissions. Thus, we read that out, and fix legacy
+ // objects. It's possible this op would fail, but it
+ // should pick up the vast majority of the tasks.
+ BOOL has_perm_mask = FALSE;
+ U32 perm_mask = 0;
+ success = mSaleInfo.importLegacyStream(input_stream, has_perm_mask, perm_mask);
+ if(has_perm_mask)
+ {
+ if(perm_mask == PERM_NONE)
+ {
+ perm_mask = mPermissions.getMaskOwner();
+ }
+ // fair use fix.
+ if(!(perm_mask & PERM_COPY))
+ {
+ perm_mask |= PERM_TRANSFER;
+ }
+ mPermissions.setMaskNext(perm_mask);
+ }
+ }
+ else if(0 == strcmp("shadow_id", keyword))
+ {
+ mAssetUUID.set(valuestr);
+ LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
+ cipher.decrypt(mAssetUUID.mData, UUID_BYTES);
+ }
+ else if(0 == strcmp("asset_id", keyword))
+ {
+ mAssetUUID.set(valuestr);
+ }
+ else if(0 == strcmp("type", keyword))
+ {
+ mType = LLAssetType::lookup(valuestr);
+ }
+ else if(0 == strcmp("inv_type", keyword))
+ {
+ mInventoryType = LLInventoryType::lookup(valuestr);
+ }
+ else if(0 == strcmp("flags", keyword))
+ {
+ sscanf(valuestr, "%x", &mFlags);
+ }
+ else if(0 == strcmp("name", keyword))
+ {
+ //strcpy(valuestr, buffer + strlen(keyword) + 3);
+ // *NOTE: Not ANSI C, but widely supported.
+ sscanf(buffer, " %s%[\t]%[^|]", keyword, junk, valuestr);
+
+ // IW: sscanf chokes and puts | in valuestr if there's no name
+ if (valuestr[0] == '|')
+ {
+ valuestr[0] = '\000';
+ }
+
+ mName.assign(valuestr);
+ LLString::replaceNonstandardASCII(mName, ' ');
+ LLString::replaceChar(mName, '|', ' ');
+ }
+ else if(0 == strcmp("desc", keyword))
+ {
+ //strcpy(valuestr, buffer + strlen(keyword) + 3);
+ // *NOTE: Not ANSI C, but widely supported.
+ sscanf(buffer, " %s%[\t]%[^|]", keyword, junk, valuestr);
+
+ if (valuestr[0] == '|')
+ {
+ valuestr[0] = '\000';
+ }
+
+ mDescription.assign(valuestr);
+ LLString::replaceNonstandardASCII(mDescription, ' ');
+ /* TODO -- ask Ian about this code
+ const char *donkey = mDescription.c_str();
+ if (donkey[0] == '|')
+ {
+ llerrs << "Donkey" << llendl;
+ }
+ */
+ }
+ else if(0 == strcmp("creation_date", keyword))
+ {
+ sscanf(valuestr, "%d", &mCreationDate);
+ }
+ else
+ {
+ llwarns << "unknown keyword '" << keyword
+ << "' in inventory import of item " << mUUID << llendl;
+ }
+ }
+
+ // Need to convert 1.0 simstate files to a useful inventory type
+ // and potentially deal with bad inventory tyes eg, a landmark
+ // marked as a texture.
+ if((LLInventoryType::IT_NONE == mInventoryType)
+ || !inventory_and_asset_types_match(mInventoryType, mType))
+ {
+ lldebugs << "Resetting inventory type for " << mUUID << llendl;
+ mInventoryType = LLInventoryType::defaultForAssetType(mType);
+ }
+ return success;
+}
+
+BOOL LLInventoryItem::exportLegacyStream(std::ostream& output_stream, BOOL include_asset_key) const
+{
+ char uuid_str[UUID_STR_LENGTH];
+ output_stream << "\tinv_item\t0\n\t{\n";
+ mUUID.toString(uuid_str);
+ output_stream << "\t\titem_id\t" << uuid_str << "\n";
+ mParentUUID.toString(uuid_str);
+ output_stream << "\t\tparent_id\t" << uuid_str << "\n";
+ mPermissions.exportLegacyStream(output_stream);
+
+ // Check for permissions to see the asset id, and if so write it
+ // out as an asset id. Otherwise, apply our cheesy encryption.
+ if(include_asset_key)
+ {
+ U32 mask = mPermissions.getMaskBase();
+ if(((mask & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED)
+ || (mAssetUUID.isNull()))
+ {
+ mAssetUUID.toString(uuid_str);
+ output_stream << "\t\tasset_id\t" << uuid_str << "\n";
+ }
+ else
+ {
+ LLUUID shadow_id(mAssetUUID);
+ LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
+ cipher.encrypt(shadow_id.mData, UUID_BYTES);
+ shadow_id.toString(uuid_str);
+ output_stream << "\t\tshadow_id\t" << uuid_str << "\n";
+ }
+ }
+ else
+ {
+ LLUUID::null.toString(uuid_str);
+ output_stream << "\t\tasset_id\t" << uuid_str << "\n";
+ }
+ output_stream << "\t\ttype\t" << LLAssetType::lookup(mType) << "\n";
+ const char* inv_type_str = LLInventoryType::lookup(mInventoryType);
+ if(inv_type_str)
+ output_stream << "\t\tinv_type\t" << inv_type_str << "\n";
+ char buffer[32];
+ sprintf(buffer, "\t\tflags\t%08x\n", mFlags);
+ output_stream << buffer;
+ mSaleInfo.exportLegacyStream(output_stream);
+ output_stream << "\t\tname\t" << mName.c_str() << "|\n";
+ output_stream << "\t\tdesc\t" << mDescription.c_str() << "|\n";
+ output_stream << "\t\tcreation_date\t" << mCreationDate << "\n";
+ output_stream << "\t}\n";
+ return TRUE;
+}
+
+LLSD LLInventoryItem::asLLSD() const
+{
+ LLSD sd = LLSD();
+ sd["item_id"] = mUUID;
+ sd["parent_id"] = mParentUUID;
+ sd["permissions"] = ll_create_sd_from_permissions(mPermissions);
+
+ U32 mask = mPermissions.getMaskBase();
+ if(((mask & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED)
+ || (mAssetUUID.isNull()))
+ {
+ sd["asset_id"] = mAssetUUID;
+ }
+ else
+ {
+ LLUUID shadow_id(mAssetUUID);
+ LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
+ cipher.encrypt(shadow_id.mData, UUID_BYTES);
+ sd["shadow_id"] = shadow_id;
+ }
+ sd["type"] = LLAssetType::lookup(mType);
+ const char* inv_type_str = LLInventoryType::lookup(mInventoryType);
+ if(inv_type_str)
+ {
+ sd["inv_type"] = inv_type_str;
+ }
+ sd["flags"] = ll_sd_from_U32(mFlags);
+ sd["sale_info"] = mSaleInfo;
+ sd["name"] = mName;
+ sd["desc"] = mDescription;
+ sd["creation_date"] = mCreationDate;
+
+ return sd;
+}
+
+bool LLInventoryItem::fromLLSD(LLSD& sd)
+{
+ mInventoryType = LLInventoryType::IT_NONE;
+ mAssetUUID.setNull();
+ const char *w;
+
+ w = "item_id";
+ if (sd.has(w))
+ {
+ mUUID = sd[w];
+ }
+ w = "parent_id";
+ if (sd.has(w))
+ {
+ mParentUUID = sd[w];
+ }
+ w = "permissions";
+ if (sd.has(w))
+ {
+ mPermissions = ll_permissions_from_sd(sd[w]);
+ }
+ w = "sale_info";
+ if (sd.has(w))
+ {
+ // Sale info used to contain next owner perm. It is now in
+ // the permissions. Thus, we read that out, and fix legacy
+ // objects. It's possible this op would fail, but it
+ // should pick up the vast majority of the tasks.
+ BOOL has_perm_mask = FALSE;
+ U32 perm_mask = 0;
+ if (!mSaleInfo.fromLLSD(sd[w], has_perm_mask, perm_mask))
+ {
+ goto fail;
+ }
+ if (has_perm_mask)
+ {
+ if(perm_mask == PERM_NONE)
+ {
+ perm_mask = mPermissions.getMaskOwner();
+ }
+ // fair use fix.
+ if(!(perm_mask & PERM_COPY))
+ {
+ perm_mask |= PERM_TRANSFER;
+ }
+ mPermissions.setMaskNext(perm_mask);
+ }
+ }
+ w = "shadow_id";
+ if (sd.has(w))
+ {
+ mAssetUUID = sd[w];
+ LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
+ cipher.decrypt(mAssetUUID.mData, UUID_BYTES);
+ }
+ w = "asset_id";
+ if (sd.has(w))
+ {
+ mAssetUUID = sd[w];
+ }
+ w = "type";
+ if (sd.has(w))
+ {
+ mType = LLAssetType::lookup(sd[w].asString().c_str());
+ }
+ w = "inv_type";
+ if (sd.has(w))
+ {
+ mInventoryType = LLInventoryType::lookup(sd[w].asString().c_str());
+ }
+ w = "flags";
+ if (sd.has(w))
+ {
+ mFlags = ll_U32_from_sd(sd[w]);
+ }
+ w = "name";
+ if (sd.has(w))
+ {
+ mName = sd[w].asString();
+ LLString::replaceNonstandardASCII(mName, ' ');
+ LLString::replaceChar(mName, '|', ' ');
+ }
+ w = "desc";
+ if (sd.has(w))
+ {
+ mDescription = sd[w].asString();
+ LLString::replaceNonstandardASCII(mDescription, ' ');
+ }
+ w = "creation_date";
+ if (sd.has(w))
+ {
+ mCreationDate = sd[w];
+ }
+
+ // Need to convert 1.0 simstate files to a useful inventory type
+ // and potentially deal with bad inventory tyes eg, a landmark
+ // marked as a texture.
+ if((LLInventoryType::IT_NONE == mInventoryType)
+ || !inventory_and_asset_types_match(mInventoryType, mType))
+ {
+ lldebugs << "Resetting inventory type for " << mUUID << llendl;
+ mInventoryType = LLInventoryType::defaultForAssetType(mType);
+ }
+
+ return true;
+fail:
+ return false;
+
+}
+
+LLXMLNode *LLInventoryItem::exportFileXML(BOOL include_asset_key) const
+{
+ LLMemType m1(LLMemType::MTYPE_INVENTORY);
+ LLXMLNode *ret = new LLXMLNode("item", FALSE);
+
+ ret->createChild("uuid", TRUE)->setUUIDValue(1, &mUUID);
+ ret->createChild("parent_uuid", TRUE)->setUUIDValue(1, &mParentUUID);
+
+ mPermissions.exportFileXML()->setParent(ret);
+
+ // Check for permissions to see the asset id, and if so write it
+ // out as an asset id. Otherwise, apply our cheesy encryption.
+ if(include_asset_key)
+ {
+ U32 mask = mPermissions.getMaskBase();
+ if(((mask & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED)
+ || (mAssetUUID.isNull()))
+ {
+ ret->createChild("asset_id", FALSE)->setUUIDValue(1, &mAssetUUID);
+ }
+ else
+ {
+ LLUUID shadow_id(mAssetUUID);
+ LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
+ cipher.encrypt(shadow_id.mData, UUID_BYTES);
+
+ ret->createChild("shadow_id", FALSE)->setUUIDValue(1, &shadow_id);
+ }
+ }
+
+ LLString type_str = LLAssetType::lookup(mType);
+ LLString inv_type_str = LLInventoryType::lookup(mInventoryType);
+
+ ret->createChild("asset_type", FALSE)->setStringValue(1, &type_str);
+ ret->createChild("inventory_type", FALSE)->setStringValue(1, &inv_type_str);
+ S32 tmp_flags = (S32) mFlags;
+ ret->createChild("flags", FALSE)->setByteValue(4, (U8*)(&tmp_flags), LLXMLNode::ENCODING_HEX);
+
+ mSaleInfo.exportFileXML()->setParent(ret);
+
+ LLString temp;
+ temp.assign(mName);
+ ret->createChild("name", FALSE)->setStringValue(1, &temp);
+ temp.assign(mDescription);
+ ret->createChild("description", FALSE)->setStringValue(1, &temp);
+ ret->createChild("creation_date", FALSE)->setIntValue(1, &mCreationDate);
+
+ return ret;
+}
+
+BOOL LLInventoryItem::importXML(LLXMLNode* node)
+{
+ BOOL success = FALSE;
+ if (node)
+ {
+ success = TRUE;
+ LLXMLNodePtr sub_node;
+ if (node->getChild("uuid", sub_node))
+ success = (1 == sub_node->getUUIDValue(1, &mUUID));
+ if (node->getChild("parent_uuid", sub_node))
+ success = success && (1 == sub_node->getUUIDValue(1, &mParentUUID));
+ if (node->getChild("permissions", sub_node))
+ success = success && mPermissions.importXML(sub_node);
+ if (node->getChild("asset_id", sub_node))
+ success = success && (1 == sub_node->getUUIDValue(1, &mAssetUUID));
+ if (node->getChild("shadow_id", sub_node))
+ {
+ success = success && (1 == sub_node->getUUIDValue(1, &mAssetUUID));
+ LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
+ cipher.decrypt(mAssetUUID.mData, UUID_BYTES);
+ }
+ if (node->getChild("asset_type", sub_node))
+ mType = LLAssetType::lookup(sub_node->getValue().c_str());
+ if (node->getChild("inventory_type", sub_node))
+ mInventoryType = LLInventoryType::lookup(sub_node->getValue().c_str());
+ if (node->getChild("flags", sub_node))
+ {
+ S32 tmp_flags = 0;
+ success = success && (1 == sub_node->getIntValue(1, &tmp_flags));
+ mFlags = (U32) tmp_flags;
+ }
+ if (node->getChild("sale_info", sub_node))
+ success = success && mSaleInfo.importXML(sub_node);
+ if (node->getChild("name", sub_node))
+ mName = sub_node->getValue();
+ if (node->getChild("description", sub_node))
+ mDescription = sub_node->getValue();
+ if (node->getChild("creation_date", sub_node))
+ success = success && (1 == sub_node->getIntValue(1, &mCreationDate));
+ if (!success)
+ {
+ lldebugs << "LLInventory::importXML() failed for node named '"
+ << node->getName() << "'" << llendl;
+ }
+ }
+ return success;
+}
+
+S32 LLInventoryItem::packBinaryBucket(U8* bin_bucket, LLPermissions* perm_override) const
+{
+ // Figure out which permissions to use.
+ LLPermissions perm;
+ if (perm_override)
+ {
+ // Use the permissions override.
+ perm = *perm_override;
+ }
+ else
+ {
+ // Use the current permissions.
+ perm = getPermissions();
+ }
+
+ // describe the inventory item
+ char* buffer = (char*) bin_bucket;
+ char creator_id_str[UUID_STR_LENGTH];
+
+ perm.getCreator().toString(creator_id_str);
+ char owner_id_str[UUID_STR_LENGTH];
+ perm.getOwner().toString(owner_id_str);
+ char last_owner_id_str[UUID_STR_LENGTH];
+ perm.getLastOwner().toString(last_owner_id_str);
+ char group_id_str[UUID_STR_LENGTH];
+ perm.getGroup().toString(group_id_str);
+ char asset_id_str[UUID_STR_LENGTH];
+ getAssetUUID().toString(asset_id_str);
+ S32 size = sprintf(buffer,
+ "%d|%d|%s|%s|%s|%s|%s|%x|%x|%x|%x|%x|%s|%s|%d|%d|%x",
+ getType(),
+ getInventoryType(),
+ getName().c_str(),
+ creator_id_str,
+ owner_id_str,
+ last_owner_id_str,
+ group_id_str,
+ perm.getMaskBase(),
+ perm.getMaskOwner(),
+ perm.getMaskGroup(),
+ perm.getMaskEveryone(),
+ perm.getMaskNextOwner(),
+ asset_id_str,
+ getDescription().c_str(),
+ getSaleInfo().getSaleType(),
+ getSaleInfo().getSalePrice(),
+ getFlags()) + 1;
+
+ return size;
+}
+
+void LLInventoryItem::unpackBinaryBucket(U8* bin_bucket, S32 bin_bucket_size)
+{
+ // Early exit on an empty binary bucket.
+ if (bin_bucket_size <= 1) return;
+
+ // Convert the bin_bucket into a string.
+ char* item_buffer = new char[bin_bucket_size+1];
+ memcpy(item_buffer, bin_bucket, bin_bucket_size);
+ item_buffer[bin_bucket_size] = '\0';
+ std::string str(item_buffer);
+
+ lldebugs << "item buffer: " << item_buffer << llendl;
+ delete[] item_buffer;
+
+ // Tokenize the string.
+ typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+ boost::char_separator<char> sep("|", "", boost::keep_empty_tokens);
+ tokenizer tokens(str, sep);
+ tokenizer::iterator iter = tokens.begin();
+
+ // Extract all values.
+ LLUUID item_id;
+ item_id.generate();
+ setUUID(item_id);
+
+ LLAssetType::EType type;
+ type = (LLAssetType::EType)(atoi((*(iter++)).c_str()));
+ setType( type );
+
+ LLInventoryType::EType inv_type;
+ inv_type = (LLInventoryType::EType)(atoi((*(iter++)).c_str()));
+ setInventoryType( inv_type );
+
+ LLString name((*(iter++)).c_str());
+ rename( name );
+
+ LLUUID creator_id((*(iter++)).c_str());
+ LLUUID owner_id((*(iter++)).c_str());
+ LLUUID last_owner_id((*(iter++)).c_str());
+ LLUUID group_id((*(iter++)).c_str());
+ PermissionMask mask_base = strtoul((*(iter++)).c_str(), NULL, 16);
+ PermissionMask mask_owner = strtoul((*(iter++)).c_str(), NULL, 16);
+ PermissionMask mask_group = strtoul((*(iter++)).c_str(), NULL, 16);
+ PermissionMask mask_every = strtoul((*(iter++)).c_str(), NULL, 16);
+ PermissionMask mask_next = strtoul((*(iter++)).c_str(), NULL, 16);
+ LLPermissions perm;
+ perm.init(creator_id, owner_id, last_owner_id, group_id);
+ perm.initMasks(mask_base, mask_owner, mask_group, mask_every, mask_next);
+ setPermissions(perm);
+ //lldebugs << "perm: " << perm << llendl;
+
+ LLUUID asset_id((*(iter++)).c_str());
+ setAssetUUID(asset_id);
+
+ LLString desc((*(iter++)).c_str());
+ setDescription(desc);
+
+ LLSaleInfo::EForSale sale_type;
+ sale_type = (LLSaleInfo::EForSale)(atoi((*(iter++)).c_str()));
+ S32 price = atoi((*(iter++)).c_str());
+ LLSaleInfo sale_info(sale_type, price);
+ setSaleInfo(sale_info);
+
+ U32 flags = strtoul((*(iter++)).c_str(), NULL, 16);
+ setFlags(flags);
+
+ time_t now = time(NULL);
+ setCreationDate(now);
+}
+
+// returns TRUE if a should appear before b
+BOOL item_dictionary_sort( LLInventoryItem* a, LLInventoryItem* b )
+{
+ return (LLString::compareDict( a->getName().c_str(), b->getName().c_str() ) < 0);
+}
+
+// returns TRUE if a should appear before b
+BOOL item_date_sort( LLInventoryItem* a, LLInventoryItem* b )
+{
+ return a->getCreationDate() < b->getCreationDate();
+}
+
+
+///----------------------------------------------------------------------------
+/// Class LLInventoryCategory
+///----------------------------------------------------------------------------
+
+LLInventoryCategory::LLInventoryCategory(
+ const LLUUID& uuid,
+ const LLUUID& parent_uuid,
+ LLAssetType::EType preferred_type,
+ const LLString& name) :
+ LLInventoryObject(uuid, parent_uuid, LLAssetType::AT_CATEGORY, name),
+ mPreferredType(preferred_type)
+{
+}
+
+LLInventoryCategory::LLInventoryCategory() :
+ mPreferredType(LLAssetType::AT_NONE)
+{
+ mType = LLAssetType::AT_CATEGORY;
+}
+
+LLInventoryCategory::LLInventoryCategory(const LLInventoryCategory* other) :
+ LLInventoryObject()
+{
+ copy(other);
+}
+
+LLInventoryCategory::~LLInventoryCategory()
+{
+}
+
+// virtual
+void LLInventoryCategory::copy(const LLInventoryCategory* other)
+{
+ LLInventoryObject::copy(other);
+ mPreferredType = other->mPreferredType;
+}
+
+LLAssetType::EType LLInventoryCategory::getPreferredType() const
+{
+ return mPreferredType;
+}
+
+void LLInventoryCategory::setPreferredType(LLAssetType::EType type)
+{
+ mPreferredType = type;
+}
+
+// virtual
+void LLInventoryCategory::packMessage(LLMessageSystem* msg) const
+{
+ msg->addUUIDFast(_PREHASH_FolderID, mUUID);
+ msg->addUUIDFast(_PREHASH_ParentID, mParentUUID);
+ S8 type = static_cast<S8>(mPreferredType);
+ msg->addS8Fast(_PREHASH_Type, type);
+ msg->addStringFast(_PREHASH_Name, mName);
+}
+
+// virtual
+void LLInventoryCategory::unpackMessage(LLMessageSystem* msg,
+ const char* block,
+ S32 block_num)
+{
+ msg->getUUIDFast(block, _PREHASH_FolderID, mUUID, block_num);
+ msg->getUUIDFast(block, _PREHASH_ParentID, mParentUUID, block_num);
+ S8 type;
+ msg->getS8Fast(block, _PREHASH_Type, type, block_num);
+ mPreferredType = static_cast<LLAssetType::EType>(type);
+ char name[DB_INV_ITEM_NAME_BUF_SIZE];
+ msg->getStringFast(block, _PREHASH_Name, DB_INV_ITEM_NAME_BUF_SIZE, name, block_num);
+ mName.assign(name);
+ LLString::replaceNonstandardASCII(mName, ' ');
+}
+
+// virtual
+BOOL LLInventoryCategory::importFile(FILE* fp)
+{
+ char buffer[MAX_STRING];
+ char keyword[MAX_STRING];
+ char valuestr[MAX_STRING];
+
+ keyword[0] = '\0';
+ valuestr[0] = '\0';
+ while(!feof(fp))
+ {
+ fgets(buffer, MAX_STRING, fp);
+ sscanf(buffer, " %s %s", keyword, valuestr);
+ if(!keyword)
+ {
+ continue;
+ }
+ if(0 == strcmp("{",keyword))
+ {
+ continue;
+ }
+ if(0 == strcmp("}", keyword))
+ {
+ break;
+ }
+ else if(0 == strcmp("cat_id", keyword))
+ {
+ mUUID.set(valuestr);
+ }
+ else if(0 == strcmp("parent_id", keyword))
+ {
+ mParentUUID.set(valuestr);
+ }
+ else if(0 == strcmp("type", keyword))
+ {
+ mType = LLAssetType::lookup(valuestr);
+ }
+ else if(0 == strcmp("pref_type", keyword))
+ {
+ mPreferredType = LLAssetType::lookup(valuestr);
+ }
+ else if(0 == strcmp("name", keyword))
+ {
+ //strcpy(valuestr, buffer + strlen(keyword) + 3);
+ // *NOTE: Not ANSI C, but widely supported.
+ sscanf(buffer, " %s %[^|]", keyword, valuestr);
+ mName.assign(valuestr);
+ LLString::replaceNonstandardASCII(mName, ' ');
+ LLString::replaceChar(mName, '|', ' ');
+ }
+ else
+ {
+ llwarns << "unknown keyword '" << keyword
+ << "' in inventory import category " << mUUID << llendl;
+ }
+ }
+ return TRUE;
+}
+
+BOOL LLInventoryCategory::exportFile(FILE* fp, BOOL) const
+{
+ char uuid_str[UUID_STR_LENGTH];
+ fprintf(fp, "\tinv_category\t0\n\t{\n");
+ mUUID.toString(uuid_str);
+ fprintf(fp, "\t\tcat_id\t%s\n", uuid_str);
+ mParentUUID.toString(uuid_str);
+ fprintf(fp, "\t\tparent_id\t%s\n", uuid_str);
+ fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType));
+ fprintf(fp, "\t\tpref_type\t%s\n", LLAssetType::lookup(mPreferredType));
+ fprintf(fp, "\t\tname\t%s|\n", mName.c_str());
+ fprintf(fp,"\t}\n");
+ return TRUE;
+}
+
+
+// virtual
+BOOL LLInventoryCategory::importLegacyStream(std::istream& input_stream)
+{
+ char buffer[MAX_STRING];
+ char keyword[MAX_STRING];
+ char valuestr[MAX_STRING];
+
+ keyword[0] = '\0';
+ valuestr[0] = '\0';
+ while(input_stream.good())
+ {
+ input_stream.getline(buffer, MAX_STRING);
+ sscanf(buffer, " %s %s", keyword, valuestr);
+ if(!keyword)
+ {
+ continue;
+ }
+ if(0 == strcmp("{",keyword))
+ {
+ continue;
+ }
+ if(0 == strcmp("}", keyword))
+ {
+ break;
+ }
+ else if(0 == strcmp("cat_id", keyword))
+ {
+ mUUID.set(valuestr);
+ }
+ else if(0 == strcmp("parent_id", keyword))
+ {
+ mParentUUID.set(valuestr);
+ }
+ else if(0 == strcmp("type", keyword))
+ {
+ mType = LLAssetType::lookup(valuestr);
+ }
+ else if(0 == strcmp("pref_type", keyword))
+ {
+ mPreferredType = LLAssetType::lookup(valuestr);
+ }
+ else if(0 == strcmp("name", keyword))
+ {
+ //strcpy(valuestr, buffer + strlen(keyword) + 3);
+ // *NOTE: Not ANSI C, but widely supported.
+ sscanf(buffer, " %s %[^|]", keyword, valuestr);
+ mName.assign(valuestr);
+ LLString::replaceNonstandardASCII(mName, ' ');
+ LLString::replaceChar(mName, '|', ' ');
+ }
+ else
+ {
+ llwarns << "unknown keyword '" << keyword
+ << "' in inventory import category " << mUUID << llendl;
+ }
+ }
+ return TRUE;
+}
+
+BOOL LLInventoryCategory::exportLegacyStream(std::ostream& output_stream, BOOL) const
+{
+ char uuid_str[UUID_STR_LENGTH];
+ output_stream << "\tinv_category\t0\n\t{\n";
+ mUUID.toString(uuid_str);
+ output_stream << "\t\tcat_id\t" << uuid_str << "\n";
+ mParentUUID.toString(uuid_str);
+ output_stream << "\t\tparent_id\t" << uuid_str << "\n";
+ output_stream << "\t\ttype\t" << LLAssetType::lookup(mType) << "\n";
+ output_stream << "\t\tpref_type\t" << LLAssetType::lookup(mPreferredType) << "\n";
+ output_stream << "\t\tname\t" << mName.c_str() << "|\n";
+ output_stream << "\t}\n";
+ return TRUE;
+}
+
+///----------------------------------------------------------------------------
+/// Local function definitions
+///----------------------------------------------------------------------------
+
+bool inventory_and_asset_types_match(
+ LLInventoryType::EType inventory_type,
+ LLAssetType::EType asset_type)
+{
+ bool rv = false;
+ if((inventory_type >= 0) && (inventory_type < LLInventoryType::IT_COUNT))
+ {
+ for(S32 i = 0; i < MAX_POSSIBLE_ASSET_TYPES; ++i)
+ {
+ if(INVENTORY_TO_ASSET_TYPE[inventory_type][i] == asset_type)
+ {
+ rv = true;
+ break;
+ }
+ }
+ }
+ return rv;
+}
+
+///----------------------------------------------------------------------------
+/// exported functions
+///----------------------------------------------------------------------------
+
+static const std::string INV_ITEM_ID_LABEL("item_id");
+static const std::string INV_FOLDER_ID_LABEL("folder_id");
+static const std::string INV_PARENT_ID_LABEL("parent_id");
+static const std::string INV_ASSET_TYPE_LABEL("asset_type");
+static const std::string INV_PREFERRED_TYPE_LABEL("preferred_type");
+static const std::string INV_INVENTORY_TYPE_LABEL("inv_type");
+static const std::string INV_NAME_LABEL("name");
+static const std::string INV_DESC_LABEL("description");
+static const std::string INV_PERMISSIONS_LABEL("permissions");
+static const std::string INV_ASSET_ID_LABEL("asset_id");
+static const std::string INV_SALE_INFO_LABEL("sale_info");
+static const std::string INV_FLAGS_LABEL("flags");
+static const std::string INV_CREATION_DATE_LABEL("created_at");
+
+LLSD ll_create_sd_from_inventory_item(LLPointer<LLInventoryItem> item)
+{
+ LLSD rv;
+ if(item.isNull()) return rv;
+ if (item->getType() == LLAssetType::AT_NONE)
+ {
+ llwarns << "ll_create_sd_from_inventory_item() for item with AT_NONE"
+ << llendl;
+ return rv;
+ }
+ rv[INV_ITEM_ID_LABEL] = item->getUUID();
+ rv[INV_PARENT_ID_LABEL] = item->getParentUUID();
+ rv[INV_NAME_LABEL] = item->getName();
+ rv[INV_ASSET_TYPE_LABEL] = LLAssetType::lookup(item->getType());
+ rv[INV_ASSET_ID_LABEL] = item->getAssetUUID();
+ rv[INV_DESC_LABEL] = item->getDescription();
+ rv[INV_SALE_INFO_LABEL] = ll_create_sd_from_sale_info(item->getSaleInfo());
+ rv[INV_PERMISSIONS_LABEL] =
+ ll_create_sd_from_permissions(item->getPermissions());
+ rv[INV_INVENTORY_TYPE_LABEL] =
+ LLInventoryType::lookup(item->getInventoryType());
+ rv[INV_FLAGS_LABEL] = (S32)item->getFlags();
+ rv[INV_CREATION_DATE_LABEL] = item->getCreationDate();
+ return rv;
+}
+
+LLPointer<LLInventoryItem> ll_create_item_from_sd(const LLSD& sd_item)
+{
+ LLPointer<LLInventoryItem> rv = new LLInventoryItem;
+ rv->setUUID(sd_item[INV_ITEM_ID_LABEL].asUUID());
+ rv->setParent(sd_item[INV_PARENT_ID_LABEL].asUUID());
+ rv->rename(sd_item[INV_NAME_LABEL].asString());
+ rv->setType(
+ LLAssetType::lookup(sd_item[INV_ASSET_TYPE_LABEL].asString().c_str()));
+ rv->setAssetUUID(sd_item[INV_ASSET_ID_LABEL].asUUID());
+ rv->setDescription(sd_item[INV_DESC_LABEL].asString());
+ rv->setSaleInfo(ll_sale_info_from_sd(sd_item[INV_SALE_INFO_LABEL]));
+ rv->setPermissions(ll_permissions_from_sd(sd_item[INV_PERMISSIONS_LABEL]));
+ rv->setInventoryType(
+ LLInventoryType::lookup(
+ sd_item[INV_INVENTORY_TYPE_LABEL].asString().c_str()));
+ rv->setFlags((U32)(sd_item[INV_FLAGS_LABEL].asInteger()));
+ rv->setCreationDate(sd_item[INV_CREATION_DATE_LABEL].asInteger());
+ return rv;
+}
+
+LLSD ll_create_sd_from_inventory_category(LLPointer<LLInventoryCategory> cat)
+{
+ LLSD rv;
+ if(cat.isNull()) return rv;
+ if (cat->getType() == LLAssetType::AT_NONE)
+ {
+ llwarns << "ll_create_sd_from_inventory_category() for cat with AT_NONE"
+ << llendl;
+ return rv;
+ }
+ rv[INV_FOLDER_ID_LABEL] = cat->getUUID();
+ rv[INV_PARENT_ID_LABEL] = cat->getParentUUID();
+ rv[INV_NAME_LABEL] = cat->getName();
+ rv[INV_ASSET_TYPE_LABEL] = LLAssetType::lookup(cat->getType());
+ if(LLAssetType::AT_NONE != cat->getPreferredType())
+ {
+ rv[INV_PREFERRED_TYPE_LABEL] =
+ LLAssetType::lookup(cat->getPreferredType());
+ }
+ return rv;
+}
+
+LLPointer<LLInventoryCategory> ll_create_category_from_sd(const LLSD& sd_cat)
+{
+ LLPointer<LLInventoryCategory> rv = new LLInventoryCategory;
+ rv->setUUID(sd_cat[INV_FOLDER_ID_LABEL].asUUID());
+ rv->setParent(sd_cat[INV_PARENT_ID_LABEL].asUUID());
+ rv->rename(sd_cat[INV_NAME_LABEL].asString());
+ rv->setType(
+ LLAssetType::lookup(sd_cat[INV_ASSET_TYPE_LABEL].asString().c_str()));
+ rv->setPreferredType(
+ LLAssetType::lookup(
+ sd_cat[INV_PREFERRED_TYPE_LABEL].asString().c_str()));
+ return rv;
+}