aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llinventory/llinventory.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llinventory/llinventory.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to '')
-rw-r--r--linden/indra/llinventory/llinventory.cpp1792
1 files changed, 1792 insertions, 0 deletions
diff --git a/linden/indra/llinventory/llinventory.cpp b/linden/indra/llinventory/llinventory.cpp
new file mode 100644
index 0000000..1f7efb3
--- /dev/null
+++ b/linden/indra/llinventory/llinventory.cpp
@@ -0,0 +1,1792 @@
1/**
2 * @file llinventory.cpp
3 * @brief Implementation of the inventory system.
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29
30#include <time.h>
31
32#include "llinventory.h"
33
34#include "lldbstrings.h"
35#include "llcrypto.h"
36#include "llsd.h"
37#include "message.h"
38#include <boost/tokenizer.hpp>
39
40#include "llsdutil.h"
41
42#include "llsdutil.h"
43
44///----------------------------------------------------------------------------
45/// Local function declarations, constants, enums, and typedefs
46///----------------------------------------------------------------------------
47
48const U8 TASK_INVENTORY_ITEM_KEY = 0;
49const U8 TASK_INVENTORY_ASSET_KEY = 1;
50
51const LLUUID MAGIC_ID("3c115e51-04f4-523c-9fa6-98aff1034730");
52
53// helper function which returns true if inventory type and asset type
54// are potentially compatible. For example, an attachment must be an
55// object, but a wearable can be a bodypart or clothing asset.
56bool inventory_and_asset_types_match(
57 LLInventoryType::EType inventory_type,
58 LLAssetType::EType asset_type);
59
60
61///----------------------------------------------------------------------------
62/// Class LLInventoryType
63///----------------------------------------------------------------------------
64
65// Unlike asset type names, not limited to 8 characters.
66// Need not match asset type names.
67static const char* INVENTORY_TYPE_NAMES[LLInventoryType::IT_COUNT] =
68{
69 "texture", // 0
70 "sound",
71 "callcard",
72 "landmark",
73 NULL,
74 NULL, // 5
75 "object",
76 "notecard",
77 "category",
78 "root",
79 "script", // 10
80 NULL,
81 NULL,
82 NULL,
83 NULL,
84 "snapshot", // 15
85 NULL,
86 "attach",
87 "wearable",
88 "animation",
89 "gesture", // 20
90};
91
92// This table is meant for decoding to human readable form. Put any
93// and as many printable characters you want in each one.
94// See also LLAssetType::mAssetTypeHumanNames
95static const char* INVENTORY_TYPE_HUMAN_NAMES[LLInventoryType::IT_COUNT] =
96{
97 "texture", // 0
98 "sound",
99 "calling card",
100 "landmark",
101 NULL,
102 NULL, // 5
103 "object",
104 "note card",
105 "folder",
106 "root",
107 "script", // 10
108 NULL,
109 NULL,
110 NULL,
111 NULL,
112 "snapshot", // 15
113 NULL,
114 "attachment",
115 "wearable",
116 "animation",
117 "gesture", // 20
118};
119
120// Maps asset types to the default inventory type for that kind of asset.
121// Thus, "Lost and Found" is a "Category"
122static const LLInventoryType::EType
123DEFAULT_ASSET_FOR_INV_TYPE[LLAssetType::AT_COUNT] =
124{
125 LLInventoryType::IT_TEXTURE, // AT_TEXTURE
126 LLInventoryType::IT_SOUND, // AT_SOUND
127 LLInventoryType::IT_CALLINGCARD, // AT_CALLINGCARD
128 LLInventoryType::IT_LANDMARK, // AT_LANDMARK
129 LLInventoryType::IT_LSL, // AT_SCRIPT
130 LLInventoryType::IT_WEARABLE, // AT_CLOTHING
131 LLInventoryType::IT_OBJECT, // AT_OBJECT
132 LLInventoryType::IT_NOTECARD, // AT_NOTECARD
133 LLInventoryType::IT_CATEGORY, // AT_CATEGORY
134 LLInventoryType::IT_ROOT_CATEGORY, // AT_ROOT_CATEGORY
135 LLInventoryType::IT_LSL, // AT_LSL_TEXT
136 LLInventoryType::IT_LSL, // AT_LSL_BYTECODE
137 LLInventoryType::IT_TEXTURE, // AT_TEXTURE_TGA
138 LLInventoryType::IT_WEARABLE, // AT_BODYPART
139 LLInventoryType::IT_CATEGORY, // AT_TRASH
140 LLInventoryType::IT_CATEGORY, // AT_SNAPSHOT_CATEGORY
141 LLInventoryType::IT_CATEGORY, // AT_LOST_AND_FOUND
142 LLInventoryType::IT_SOUND, // AT_SOUND_WAV
143 LLInventoryType::IT_NONE, // AT_IMAGE_TGA
144 LLInventoryType::IT_NONE, // AT_IMAGE_JPEG
145 LLInventoryType::IT_ANIMATION, // AT_ANIMATION
146 LLInventoryType::IT_GESTURE, // AT_GESTURE
147};
148
149static const int MAX_POSSIBLE_ASSET_TYPES = 2;
150static const LLAssetType::EType
151INVENTORY_TO_ASSET_TYPE[LLInventoryType::IT_COUNT][MAX_POSSIBLE_ASSET_TYPES] =
152{
153 { LLAssetType::AT_TEXTURE, LLAssetType::AT_NONE }, // IT_TEXTURE
154 { LLAssetType::AT_SOUND, LLAssetType::AT_NONE }, // IT_SOUND
155 { LLAssetType::AT_CALLINGCARD, LLAssetType::AT_NONE }, // IT_CALLINGCARD
156 { LLAssetType::AT_LANDMARK, LLAssetType::AT_NONE }, // IT_LANDMARK
157 { LLAssetType::AT_NONE, LLAssetType::AT_NONE },
158 { LLAssetType::AT_NONE, LLAssetType::AT_NONE },
159 { LLAssetType::AT_OBJECT, LLAssetType::AT_NONE }, // IT_OBJECT
160 { LLAssetType::AT_NOTECARD, LLAssetType::AT_NONE }, // IT_NOTECARD
161 { LLAssetType::AT_NONE, LLAssetType::AT_NONE }, // IT_CATEGORY
162 { LLAssetType::AT_NONE, LLAssetType::AT_NONE }, // IT_ROOT_CATEGORY
163 { LLAssetType::AT_LSL_TEXT, LLAssetType::AT_LSL_BYTECODE }, // IT_LSL
164 { LLAssetType::AT_NONE, LLAssetType::AT_NONE },
165 { LLAssetType::AT_NONE, LLAssetType::AT_NONE },
166 { LLAssetType::AT_NONE, LLAssetType::AT_NONE },
167 { LLAssetType::AT_NONE, LLAssetType::AT_NONE },
168 { LLAssetType::AT_TEXTURE, LLAssetType::AT_NONE }, // IT_SNAPSHOT
169 { LLAssetType::AT_NONE, LLAssetType::AT_NONE },
170 { LLAssetType::AT_OBJECT, LLAssetType::AT_NONE }, // IT_ATTACHMENT
171 { LLAssetType::AT_CLOTHING, LLAssetType::AT_BODYPART }, // IT_WEARABLE
172 { LLAssetType::AT_ANIMATION, LLAssetType::AT_NONE }, // IT_ANIMATION
173 { LLAssetType::AT_GESTURE, LLAssetType::AT_NONE }, // IT_GESTURE
174};
175
176// static
177const char* LLInventoryType::lookup(EType type)
178{
179 if((type >= 0) && (type < IT_COUNT))
180 {
181 return INVENTORY_TYPE_NAMES[S32(type)];
182 }
183 else
184 {
185 return NULL;
186 }
187}
188
189// static
190LLInventoryType::EType LLInventoryType::lookup(const char* name)
191{
192 for(S32 i = 0; i < IT_COUNT; ++i)
193 {
194 if((INVENTORY_TYPE_NAMES[i])
195 && (0 == strcmp(name, INVENTORY_TYPE_NAMES[i])))
196 {
197 // match
198 return (EType)i;
199 }
200 }
201 return IT_NONE;
202}
203
204// XUI:translate
205// translation from a type to a human readable form.
206// static
207const char* LLInventoryType::lookupHumanReadable(EType type)
208{
209 if((type >= 0) && (type < IT_COUNT))
210 {
211 return INVENTORY_TYPE_HUMAN_NAMES[S32(type)];
212 }
213 else
214 {
215 return NULL;
216 }
217}
218
219// return the default inventory for the given asset type.
220// static
221LLInventoryType::EType LLInventoryType::defaultForAssetType(LLAssetType::EType asset_type)
222{
223 if((asset_type >= 0) && (asset_type < LLAssetType::AT_COUNT))
224 {
225 return DEFAULT_ASSET_FOR_INV_TYPE[S32(asset_type)];
226 }
227 else
228 {
229 return IT_NONE;
230 }
231}
232
233///----------------------------------------------------------------------------
234/// Class LLInventoryObject
235///----------------------------------------------------------------------------
236
237LLInventoryObject::LLInventoryObject(
238 const LLUUID& uuid,
239 const LLUUID& parent_uuid,
240 LLAssetType::EType type,
241 const LLString& name) :
242 mUUID(uuid),
243 mParentUUID(parent_uuid),
244 mType(type),
245 mName(name)
246{
247 LLString::replaceNonstandardASCII(mName, ' ');
248 LLString::replaceChar(mName, '|', ' ');
249 LLString::trim(mName);
250 LLString::truncate(mName, DB_INV_ITEM_NAME_STR_LEN);
251}
252
253LLInventoryObject::LLInventoryObject() :
254 mType(LLAssetType::AT_NONE)
255{
256}
257
258LLInventoryObject::~LLInventoryObject( void )
259{
260}
261
262void LLInventoryObject::copy(const LLInventoryObject* other)
263{
264 mUUID = other->mUUID;
265 mParentUUID = other->mParentUUID;
266 mType = other->mType;
267 mName = other->mName;
268}
269
270const LLUUID& LLInventoryObject::getUUID() const
271{
272 return mUUID;
273}
274
275const LLUUID& LLInventoryObject::getParentUUID() const
276{
277 return mParentUUID;
278}
279
280const LLString& LLInventoryObject::getName() const
281{
282 return mName;
283}
284
285LLAssetType::EType LLInventoryObject::getType() const
286{
287 return mType;
288}
289
290void LLInventoryObject::setUUID(const LLUUID& new_uuid)
291{
292 mUUID = new_uuid;
293}
294
295void LLInventoryObject::rename(const LLString& n)
296{
297 LLString new_name(n);
298 LLString::replaceNonstandardASCII(new_name, ' ');
299 LLString::replaceChar(new_name, '|', ' ');
300 LLString::trim(new_name);
301 LLString::truncate(new_name, DB_INV_ITEM_NAME_STR_LEN);
302
303 if( new_name != mName )
304 {
305 mName = new_name;
306 }
307}
308
309void LLInventoryObject::setParent(const LLUUID& new_parent)
310{
311 mParentUUID = new_parent;
312}
313
314void LLInventoryObject::setType(LLAssetType::EType type)
315{
316 mType = type;
317}
318
319
320// virtual
321BOOL LLInventoryObject::importLegacyStream(std::istream& input_stream)
322{
323 char buffer[MAX_STRING];
324 char keyword[MAX_STRING];
325 char valuestr[MAX_STRING];
326
327 keyword[0] = '\0';
328 valuestr[0] = '\0';
329 while(input_stream.good())
330 {
331 input_stream.getline(buffer, MAX_STRING);
332 sscanf(buffer, " %254s %254s", keyword, valuestr);
333 if(!keyword)
334 {
335 continue;
336 }
337 if(0 == strcmp("{",keyword))
338 {
339 continue;
340 }
341 if(0 == strcmp("}", keyword))
342 {
343 break;
344 }
345 else if(0 == strcmp("obj_id", keyword))
346 {
347 mUUID.set(valuestr);
348 }
349 else if(0 == strcmp("parent_id", keyword))
350 {
351 mParentUUID.set(valuestr);
352 }
353 else if(0 == strcmp("type", keyword))
354 {
355 mType = LLAssetType::lookup(valuestr);
356 }
357 else if(0 == strcmp("name", keyword))
358 {
359 //strcpy(valuestr, buffer + strlen(keyword) + 3);
360 // *NOTE: Not ANSI C, but widely supported.
361 sscanf(buffer, " %254s %[^|]", keyword, valuestr);
362 mName.assign(valuestr);
363 LLString::replaceNonstandardASCII(mName, ' ');
364 LLString::replaceChar(mName, '|', ' ');
365 LLString::trim(mName);
366 LLString::truncate(mName, DB_INV_ITEM_NAME_STR_LEN);
367 }
368 else
369 {
370 llwarns << "unknown keyword '" << keyword
371 << "' in LLInventoryObject::importLegacyStream() for object " << mUUID << llendl;
372 }
373 }
374 return TRUE;
375}
376
377// exportFile should be replaced with exportLegacyStream
378// not sure whether exportLegacyStream(llofstream(fp)) would work, fp may need to get icramented...
379BOOL LLInventoryObject::exportFile(FILE* fp, BOOL) const
380{
381 char uuid_str[UUID_STR_LENGTH];
382 fprintf(fp, "\tinv_object\t0\n\t{\n");
383 mUUID.toString(uuid_str);
384 fprintf(fp, "\t\tobj_id\t%s\n", uuid_str);
385 mParentUUID.toString(uuid_str);
386 fprintf(fp, "\t\tparent_id\t%s\n", uuid_str);
387 fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType));
388 fprintf(fp, "\t\tname\t%s|\n", mName.c_str());
389 fprintf(fp,"\t}\n");
390 return TRUE;
391}
392
393BOOL LLInventoryObject::exportLegacyStream(std::ostream& output_stream, BOOL) const
394{
395 char uuid_str[UUID_STR_LENGTH];
396 output_stream << "\tinv_object\t0\n\t{\n";
397 mUUID.toString(uuid_str);
398 output_stream << "\t\tobj_id\t" << uuid_str << "\n";
399 mParentUUID.toString(uuid_str);
400 output_stream << "\t\tparent_id\t" << uuid_str << "\n";
401 output_stream << "\t\ttype\t" << LLAssetType::lookup(mType) << "\n";
402 output_stream << "\t\tname\t" << mName.c_str() << "|\n";
403 output_stream << "\t}\n";
404 return TRUE;
405}
406
407
408void LLInventoryObject::removeFromServer()
409{
410 // don't do nothin'
411 llwarns << "LLInventoryObject::removeFromServer() called. Doesn't do anything." << llendl;
412}
413
414void LLInventoryObject::updateParentOnServer(BOOL) const
415{
416 // don't do nothin'
417 llwarns << "LLInventoryObject::updateParentOnServer() called. Doesn't do anything." << llendl;
418}
419
420void LLInventoryObject::updateServer(BOOL) const
421{
422 // don't do nothin'
423 llwarns << "LLInventoryObject::updateServer() called. Doesn't do anything." << llendl;
424}
425
426
427///----------------------------------------------------------------------------
428/// Class LLInventoryItem
429///----------------------------------------------------------------------------
430
431LLInventoryItem::LLInventoryItem(
432 const LLUUID& uuid,
433 const LLUUID& parent_uuid,
434 const LLPermissions& permissions,
435 const LLUUID& asset_uuid,
436 LLAssetType::EType type,
437 LLInventoryType::EType inv_type,
438 const LLString& name,
439 const LLString& desc,
440 const LLSaleInfo& sale_info,
441 U32 flags,
442 S32 creation_date_utc) :
443 LLInventoryObject(uuid, parent_uuid, type, name),
444 mPermissions(permissions),
445 mAssetUUID(asset_uuid),
446 mDescription(desc),
447 mSaleInfo(sale_info),
448 mInventoryType(inv_type),
449 mFlags(flags),
450 mCreationDate(creation_date_utc)
451{
452 LLString::replaceNonstandardASCII(mDescription, ' ');
453 LLString::replaceChar(mDescription, '|', ' ');
454}
455
456LLInventoryItem::LLInventoryItem() :
457 LLInventoryObject(),
458 mPermissions(),
459 mAssetUUID(),
460 mDescription(),
461 mSaleInfo(),
462 mInventoryType(LLInventoryType::IT_NONE),
463 mFlags(0),
464 mCreationDate(0)
465{
466}
467
468LLInventoryItem::LLInventoryItem(const LLInventoryItem* other) :
469 LLInventoryObject()
470{
471 copy(other);
472}
473
474LLInventoryItem::~LLInventoryItem()
475{
476}
477
478// virtual
479void LLInventoryItem::copy(const LLInventoryItem* other)
480{
481 LLInventoryObject::copy(other);
482 mPermissions = other->mPermissions;
483 mAssetUUID = other->mAssetUUID;
484 mDescription = other->mDescription;
485 mSaleInfo = other->mSaleInfo;
486 mInventoryType = other->mInventoryType;
487 mFlags = other->mFlags;
488 mCreationDate = other->mCreationDate;
489}
490
491// As a constructor alternative, the clone() method works like a
492// copy constructor, but gens a new UUID.
493void LLInventoryItem::clone(LLPointer<LLInventoryItem>& newitem) const
494{
495 newitem = new LLInventoryItem;
496 newitem->copy(this);
497 newitem->mUUID.generate();
498}
499
500const LLPermissions& LLInventoryItem::getPermissions() const
501{
502 return mPermissions;
503}
504
505const LLUUID& LLInventoryItem::getCreatorUUID() const
506{
507 return mPermissions.getCreator();
508}
509
510const LLUUID& LLInventoryItem::getAssetUUID() const
511{
512 return mAssetUUID;
513}
514
515void LLInventoryItem::setAssetUUID(const LLUUID& asset_id)
516{
517 mAssetUUID = asset_id;
518}
519
520
521const LLString& LLInventoryItem::getDescription() const
522{
523 return mDescription;
524}
525
526S32 LLInventoryItem::getCreationDate() const
527{
528 return mCreationDate;
529}
530
531U32 LLInventoryItem::getCRC32() const
532{
533 // *FIX: Not a real crc - more of a checksum.
534 // *NOTE: We currently do not validate the name or description,
535 // but if they change in transit, it's no big deal.
536 U32 crc = mUUID.getCRC32();
537 //lldebugs << "1 crc: " << std::hex << crc << std::dec << llendl;
538 crc += mParentUUID.getCRC32();
539 //lldebugs << "2 crc: " << std::hex << crc << std::dec << llendl;
540 crc += mPermissions.getCRC32();
541 //lldebugs << "3 crc: " << std::hex << crc << std::dec << llendl;
542 crc += mAssetUUID.getCRC32();
543 //lldebugs << "4 crc: " << std::hex << crc << std::dec << llendl;
544 crc += mType;
545 //lldebugs << "5 crc: " << std::hex << crc << std::dec << llendl;
546 crc += mInventoryType;
547 //lldebugs << "6 crc: " << std::hex << crc << std::dec << llendl;
548 crc += mFlags;
549 //lldebugs << "7 crc: " << std::hex << crc << std::dec << llendl;
550 crc += mSaleInfo.getCRC32();
551 //lldebugs << "8 crc: " << std::hex << crc << std::dec << llendl;
552 crc += mCreationDate;
553 //lldebugs << "9 crc: " << std::hex << crc << std::dec << llendl;
554 return crc;
555}
556
557
558void LLInventoryItem::setDescription(const LLString& d)
559{
560 LLString new_desc(d);
561 LLString::replaceNonstandardASCII(new_desc, ' ');
562 LLString::replaceChar(new_desc, '|', ' ');
563 if( new_desc != mDescription )
564 {
565 mDescription = new_desc;
566 }
567}
568
569void LLInventoryItem::setPermissions(const LLPermissions& perm)
570{
571 mPermissions = perm;
572}
573
574void LLInventoryItem::setInventoryType(LLInventoryType::EType inv_type)
575{
576 mInventoryType = inv_type;
577}
578
579void LLInventoryItem::setFlags(U32 flags)
580{
581 mFlags = flags;
582}
583
584void LLInventoryItem::setCreationDate(S32 creation_date_utc)
585{
586 mCreationDate = creation_date_utc;
587}
588
589
590const LLSaleInfo& LLInventoryItem::getSaleInfo() const
591{
592 return mSaleInfo;
593}
594
595void LLInventoryItem::setSaleInfo(const LLSaleInfo& sale_info)
596{
597 mSaleInfo = sale_info;
598}
599
600LLInventoryType::EType LLInventoryItem::getInventoryType() const
601{
602 return mInventoryType;
603}
604
605U32 LLInventoryItem::getFlags() const
606{
607 return mFlags;
608}
609
610// virtual
611void LLInventoryItem::packMessage(LLMessageSystem* msg) const
612{
613 msg->addUUIDFast(_PREHASH_ItemID, mUUID);
614 msg->addUUIDFast(_PREHASH_FolderID, mParentUUID);
615 mPermissions.packMessage(msg);
616 msg->addUUIDFast(_PREHASH_AssetID, mAssetUUID);
617 S8 type = static_cast<S8>(mType);
618 msg->addS8Fast(_PREHASH_Type, type);
619 type = static_cast<S8>(mInventoryType);
620 msg->addS8Fast(_PREHASH_InvType, type);
621 msg->addU32Fast(_PREHASH_Flags, mFlags);
622 mSaleInfo.packMessage(msg);
623 msg->addStringFast(_PREHASH_Name, mName);
624 msg->addStringFast(_PREHASH_Description, mDescription);
625 msg->addS32Fast(_PREHASH_CreationDate, mCreationDate);
626 U32 crc = getCRC32();
627 msg->addU32Fast(_PREHASH_CRC, crc);
628}
629
630// virtual
631BOOL LLInventoryItem::unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num)
632{
633 msg->getUUIDFast(block, _PREHASH_ItemID, mUUID, block_num);
634 msg->getUUIDFast(block, _PREHASH_FolderID, mParentUUID, block_num);
635 mPermissions.unpackMessage(msg, block, block_num);
636 msg->getUUIDFast(block, _PREHASH_AssetID, mAssetUUID, block_num);
637
638 S8 type;
639 msg->getS8Fast(block, _PREHASH_Type, type, block_num);
640 mType = static_cast<LLAssetType::EType>(type);
641 msg->getS8(block, "InvType", type, block_num);
642 mInventoryType = static_cast<LLInventoryType::EType>(type);
643
644 msg->getU32Fast(block, _PREHASH_Flags, mFlags, block_num);
645
646 mSaleInfo.unpackMultiMessage(msg, block, block_num);
647
648 char name[DB_INV_ITEM_NAME_BUF_SIZE];
649 msg->getStringFast(block, _PREHASH_Name, DB_INV_ITEM_NAME_BUF_SIZE, name, block_num);
650 mName.assign(name);
651 LLString::replaceNonstandardASCII(mName, ' ');
652
653 char desc[DB_INV_ITEM_DESC_BUF_SIZE];
654 msg->getStringFast(block, _PREHASH_Description, DB_INV_ITEM_DESC_BUF_SIZE, desc, block_num);
655 mDescription.assign(desc);
656 LLString::replaceNonstandardASCII(mDescription, ' ');
657
658 msg->getS32(block, "CreationDate", mCreationDate, block_num);
659
660 U32 local_crc = getCRC32();
661 U32 remote_crc = 0;
662 msg->getU32(block, "CRC", remote_crc, block_num);
663//#define CRC_CHECK
664#ifdef CRC_CHECK
665 if(local_crc == remote_crc)
666 {
667 lldebugs << "crc matches" << llendl;
668 return TRUE;
669 }
670 else
671 {
672 llwarns << "inventory crc mismatch: local=" << std::hex << local_crc
673 << " remote=" << remote_crc << std::dec << llendl;
674 return FALSE;
675 }
676#else
677 return (local_crc == remote_crc);
678#endif
679}
680
681// virtual
682BOOL LLInventoryItem::importFile(FILE* fp)
683{
684 char buffer[MAX_STRING];
685 char keyword[MAX_STRING];
686 char valuestr[MAX_STRING];
687 char junk[MAX_STRING];
688 BOOL success = TRUE;
689
690 keyword[0] = '\0';
691 valuestr[0] = '\0';
692
693 mInventoryType = LLInventoryType::IT_NONE;
694 mAssetUUID.setNull();
695 while(success && (!feof(fp)))
696 {
697 fgets(buffer, MAX_STRING, fp);
698 sscanf(buffer, " %254s %254s", keyword, valuestr);
699 if(!keyword)
700 {
701 continue;
702 }
703 if(0 == strcmp("{",keyword))
704 {
705 continue;
706 }
707 if(0 == strcmp("}", keyword))
708 {
709 break;
710 }
711 else if(0 == strcmp("item_id", keyword))
712 {
713 mUUID.set(valuestr);
714 }
715 else if(0 == strcmp("parent_id", keyword))
716 {
717 mParentUUID.set(valuestr);
718 }
719 else if(0 == strcmp("permissions", keyword))
720 {
721 success = mPermissions.importFile(fp);
722 }
723 else if(0 == strcmp("sale_info", keyword))
724 {
725 // Sale info used to contain next owner perm. It is now in
726 // the permissions. Thus, we read that out, and fix legacy
727 // objects. It's possible this op would fail, but it
728 // should pick up the vast majority of the tasks.
729 BOOL has_perm_mask = FALSE;
730 U32 perm_mask = 0;
731 success = mSaleInfo.importFile(fp, has_perm_mask, perm_mask);
732 if(has_perm_mask)
733 {
734 if(perm_mask == PERM_NONE)
735 {
736 perm_mask = mPermissions.getMaskOwner();
737 }
738 // fair use fix.
739 if(!(perm_mask & PERM_COPY))
740 {
741 perm_mask |= PERM_TRANSFER;
742 }
743 mPermissions.setMaskNext(perm_mask);
744 }
745 }
746 else if(0 == strcmp("shadow_id", keyword))
747 {
748 mAssetUUID.set(valuestr);
749 LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
750 cipher.decrypt(mAssetUUID.mData, UUID_BYTES);
751 }
752 else if(0 == strcmp("asset_id", keyword))
753 {
754 mAssetUUID.set(valuestr);
755 }
756 else if(0 == strcmp("type", keyword))
757 {
758 mType = LLAssetType::lookup(valuestr);
759 }
760 else if(0 == strcmp("inv_type", keyword))
761 {
762 mInventoryType = LLInventoryType::lookup(valuestr);
763 }
764 else if(0 == strcmp("flags", keyword))
765 {
766 sscanf(valuestr, "%x", &mFlags);
767 }
768 else if(0 == strcmp("name", keyword))
769 {
770 //strcpy(valuestr, buffer + strlen(keyword) + 3);
771 // *NOTE: Not ANSI C, but widely supported.
772 sscanf(buffer, " %254s%[\t]%[^|]", keyword, junk, valuestr);
773
774 // IW: sscanf chokes and puts | in valuestr if there's no name
775 if (valuestr[0] == '|')
776 {
777 valuestr[0] = '\000';
778 }
779
780 mName.assign(valuestr);
781 LLString::replaceNonstandardASCII(mName, ' ');
782 LLString::replaceChar(mName, '|', ' ');
783 }
784 else if(0 == strcmp("desc", keyword))
785 {
786 //strcpy(valuestr, buffer + strlen(keyword) + 3);
787 // *NOTE: Not ANSI C, but widely supported.
788 sscanf(buffer, " %s%[\t]%[^|]", keyword, junk, valuestr);
789
790 if (valuestr[0] == '|')
791 {
792 valuestr[0] = '\000';
793 }
794
795 mDescription.assign(valuestr);
796 LLString::replaceNonstandardASCII(mDescription, ' ');
797 /* TODO -- ask Ian about this code
798 const char *donkey = mDescription.c_str();
799 if (donkey[0] == '|')
800 {
801 llerrs << "Donkey" << llendl;
802 }
803 */
804 }
805 else if(0 == strcmp("creation_date", keyword))
806 {
807 sscanf(valuestr, "%d", &mCreationDate);
808 }
809 else
810 {
811 llwarns << "unknown keyword '" << keyword
812 << "' in inventory import of item " << mUUID << llendl;
813 }
814 }
815
816 // Need to convert 1.0 simstate files to a useful inventory type
817 // and potentially deal with bad inventory tyes eg, a landmark
818 // marked as a texture.
819 if((LLInventoryType::IT_NONE == mInventoryType)
820 || !inventory_and_asset_types_match(mInventoryType, mType))
821 {
822 lldebugs << "Resetting inventory type for " << mUUID << llendl;
823 mInventoryType = LLInventoryType::defaultForAssetType(mType);
824 }
825 return success;
826}
827
828BOOL LLInventoryItem::exportFile(FILE* fp, BOOL include_asset_key) const
829{
830 char uuid_str[UUID_STR_LENGTH];
831 fprintf(fp, "\tinv_item\t0\n\t{\n");
832 mUUID.toString(uuid_str);
833 fprintf(fp, "\t\titem_id\t%s\n", uuid_str);
834 mParentUUID.toString(uuid_str);
835 fprintf(fp, "\t\tparent_id\t%s\n", uuid_str);
836 mPermissions.exportFile(fp);
837
838 // Check for permissions to see the asset id, and if so write it
839 // out as an asset id. Otherwise, apply our cheesy encryption.
840 if(include_asset_key)
841 {
842 U32 mask = mPermissions.getMaskBase();
843 if(((mask & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED)
844 || (mAssetUUID.isNull()))
845 {
846 mAssetUUID.toString(uuid_str);
847 fprintf(fp, "\t\tasset_id\t%s\n", uuid_str);
848 }
849 else
850 {
851 LLUUID shadow_id(mAssetUUID);
852 LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
853 cipher.encrypt(shadow_id.mData, UUID_BYTES);
854 shadow_id.toString(uuid_str);
855 fprintf(fp, "\t\tshadow_id\t%s\n", uuid_str);
856 }
857 }
858 else
859 {
860 LLUUID::null.toString(uuid_str);
861 fprintf(fp, "\t\tasset_id\t%s\n", uuid_str);
862 }
863 fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType));
864 const char* inv_type_str = LLInventoryType::lookup(mInventoryType);
865 if(inv_type_str) fprintf(fp, "\t\tinv_type\t%s\n", inv_type_str);
866 fprintf(fp, "\t\tflags\t%08x\n", mFlags);
867 mSaleInfo.exportFile(fp);
868 fprintf(fp, "\t\tname\t%s|\n", mName.c_str());
869 fprintf(fp, "\t\tdesc\t%s|\n", mDescription.c_str());
870 fprintf(fp, "\t\tcreation_date\t%d\n", mCreationDate);
871 fprintf(fp,"\t}\n");
872 return TRUE;
873}
874
875// virtual
876BOOL LLInventoryItem::importLegacyStream(std::istream& input_stream)
877{
878 char buffer[MAX_STRING];
879 char keyword[MAX_STRING];
880 char valuestr[MAX_STRING];
881 char junk[MAX_STRING];
882 BOOL success = TRUE;
883
884 keyword[0] = '\0';
885 valuestr[0] = '\0';
886
887 mInventoryType = LLInventoryType::IT_NONE;
888 mAssetUUID.setNull();
889 while(success && input_stream.good())
890 {
891 input_stream.getline(buffer, MAX_STRING);
892 sscanf(buffer, " %s %s", keyword, valuestr);
893 if(!keyword)
894 {
895 continue;
896 }
897 if(0 == strcmp("{",keyword))
898 {
899 continue;
900 }
901 if(0 == strcmp("}", keyword))
902 {
903 break;
904 }
905 else if(0 == strcmp("item_id", keyword))
906 {
907 mUUID.set(valuestr);
908 }
909 else if(0 == strcmp("parent_id", keyword))
910 {
911 mParentUUID.set(valuestr);
912 }
913 else if(0 == strcmp("permissions", keyword))
914 {
915 success = mPermissions.importLegacyStream(input_stream);
916 }
917 else if(0 == strcmp("sale_info", keyword))
918 {
919 // Sale info used to contain next owner perm. It is now in
920 // the permissions. Thus, we read that out, and fix legacy
921 // objects. It's possible this op would fail, but it
922 // should pick up the vast majority of the tasks.
923 BOOL has_perm_mask = FALSE;
924 U32 perm_mask = 0;
925 success = mSaleInfo.importLegacyStream(input_stream, has_perm_mask, perm_mask);
926 if(has_perm_mask)
927 {
928 if(perm_mask == PERM_NONE)
929 {
930 perm_mask = mPermissions.getMaskOwner();
931 }
932 // fair use fix.
933 if(!(perm_mask & PERM_COPY))
934 {
935 perm_mask |= PERM_TRANSFER;
936 }
937 mPermissions.setMaskNext(perm_mask);
938 }
939 }
940 else if(0 == strcmp("shadow_id", keyword))
941 {
942 mAssetUUID.set(valuestr);
943 LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
944 cipher.decrypt(mAssetUUID.mData, UUID_BYTES);
945 }
946 else if(0 == strcmp("asset_id", keyword))
947 {
948 mAssetUUID.set(valuestr);
949 }
950 else if(0 == strcmp("type", keyword))
951 {
952 mType = LLAssetType::lookup(valuestr);
953 }
954 else if(0 == strcmp("inv_type", keyword))
955 {
956 mInventoryType = LLInventoryType::lookup(valuestr);
957 }
958 else if(0 == strcmp("flags", keyword))
959 {
960 sscanf(valuestr, "%x", &mFlags);
961 }
962 else if(0 == strcmp("name", keyword))
963 {
964 //strcpy(valuestr, buffer + strlen(keyword) + 3);
965 // *NOTE: Not ANSI C, but widely supported.
966 sscanf(buffer, " %s%[\t]%[^|]", keyword, junk, valuestr);
967
968 // IW: sscanf chokes and puts | in valuestr if there's no name
969 if (valuestr[0] == '|')
970 {
971 valuestr[0] = '\000';
972 }
973
974 mName.assign(valuestr);
975 LLString::replaceNonstandardASCII(mName, ' ');
976 LLString::replaceChar(mName, '|', ' ');
977 }
978 else if(0 == strcmp("desc", keyword))
979 {
980 //strcpy(valuestr, buffer + strlen(keyword) + 3);
981 // *NOTE: Not ANSI C, but widely supported.
982 sscanf(buffer, " %s%[\t]%[^|]", keyword, junk, valuestr);
983
984 if (valuestr[0] == '|')
985 {
986 valuestr[0] = '\000';
987 }
988
989 mDescription.assign(valuestr);
990 LLString::replaceNonstandardASCII(mDescription, ' ');
991 /* TODO -- ask Ian about this code
992 const char *donkey = mDescription.c_str();
993 if (donkey[0] == '|')
994 {
995 llerrs << "Donkey" << llendl;
996 }
997 */
998 }
999 else if(0 == strcmp("creation_date", keyword))
1000 {
1001 sscanf(valuestr, "%d", &mCreationDate);
1002 }
1003 else
1004 {
1005 llwarns << "unknown keyword '" << keyword
1006 << "' in inventory import of item " << mUUID << llendl;
1007 }
1008 }
1009
1010 // Need to convert 1.0 simstate files to a useful inventory type
1011 // and potentially deal with bad inventory tyes eg, a landmark
1012 // marked as a texture.
1013 if((LLInventoryType::IT_NONE == mInventoryType)
1014 || !inventory_and_asset_types_match(mInventoryType, mType))
1015 {
1016 lldebugs << "Resetting inventory type for " << mUUID << llendl;
1017 mInventoryType = LLInventoryType::defaultForAssetType(mType);
1018 }
1019 return success;
1020}
1021
1022BOOL LLInventoryItem::exportLegacyStream(std::ostream& output_stream, BOOL include_asset_key) const
1023{
1024 char uuid_str[UUID_STR_LENGTH];
1025 output_stream << "\tinv_item\t0\n\t{\n";
1026 mUUID.toString(uuid_str);
1027 output_stream << "\t\titem_id\t" << uuid_str << "\n";
1028 mParentUUID.toString(uuid_str);
1029 output_stream << "\t\tparent_id\t" << uuid_str << "\n";
1030 mPermissions.exportLegacyStream(output_stream);
1031
1032 // Check for permissions to see the asset id, and if so write it
1033 // out as an asset id. Otherwise, apply our cheesy encryption.
1034 if(include_asset_key)
1035 {
1036 U32 mask = mPermissions.getMaskBase();
1037 if(((mask & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED)
1038 || (mAssetUUID.isNull()))
1039 {
1040 mAssetUUID.toString(uuid_str);
1041 output_stream << "\t\tasset_id\t" << uuid_str << "\n";
1042 }
1043 else
1044 {
1045 LLUUID shadow_id(mAssetUUID);
1046 LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
1047 cipher.encrypt(shadow_id.mData, UUID_BYTES);
1048 shadow_id.toString(uuid_str);
1049 output_stream << "\t\tshadow_id\t" << uuid_str << "\n";
1050 }
1051 }
1052 else
1053 {
1054 LLUUID::null.toString(uuid_str);
1055 output_stream << "\t\tasset_id\t" << uuid_str << "\n";
1056 }
1057 output_stream << "\t\ttype\t" << LLAssetType::lookup(mType) << "\n";
1058 const char* inv_type_str = LLInventoryType::lookup(mInventoryType);
1059 if(inv_type_str)
1060 output_stream << "\t\tinv_type\t" << inv_type_str << "\n";
1061 char buffer[32];
1062 sprintf(buffer, "\t\tflags\t%08x\n", mFlags);
1063 output_stream << buffer;
1064 mSaleInfo.exportLegacyStream(output_stream);
1065 output_stream << "\t\tname\t" << mName.c_str() << "|\n";
1066 output_stream << "\t\tdesc\t" << mDescription.c_str() << "|\n";
1067 output_stream << "\t\tcreation_date\t" << mCreationDate << "\n";
1068 output_stream << "\t}\n";
1069 return TRUE;
1070}
1071
1072LLSD LLInventoryItem::asLLSD() const
1073{
1074 LLSD sd = LLSD();
1075 sd["item_id"] = mUUID;
1076 sd["parent_id"] = mParentUUID;
1077 sd["permissions"] = ll_create_sd_from_permissions(mPermissions);
1078
1079 U32 mask = mPermissions.getMaskBase();
1080 if(((mask & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED)
1081 || (mAssetUUID.isNull()))
1082 {
1083 sd["asset_id"] = mAssetUUID;
1084 }
1085 else
1086 {
1087 LLUUID shadow_id(mAssetUUID);
1088 LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
1089 cipher.encrypt(shadow_id.mData, UUID_BYTES);
1090 sd["shadow_id"] = shadow_id;
1091 }
1092 sd["type"] = LLAssetType::lookup(mType);
1093 const char* inv_type_str = LLInventoryType::lookup(mInventoryType);
1094 if(inv_type_str)
1095 {
1096 sd["inv_type"] = inv_type_str;
1097 }
1098 sd["flags"] = ll_sd_from_U32(mFlags);
1099 sd["sale_info"] = mSaleInfo;
1100 sd["name"] = mName;
1101 sd["desc"] = mDescription;
1102 sd["creation_date"] = mCreationDate;
1103
1104 return sd;
1105}
1106
1107bool LLInventoryItem::fromLLSD(LLSD& sd)
1108{
1109 mInventoryType = LLInventoryType::IT_NONE;
1110 mAssetUUID.setNull();
1111 const char *w;
1112
1113 w = "item_id";
1114 if (sd.has(w))
1115 {
1116 mUUID = sd[w];
1117 }
1118 w = "parent_id";
1119 if (sd.has(w))
1120 {
1121 mParentUUID = sd[w];
1122 }
1123 w = "permissions";
1124 if (sd.has(w))
1125 {
1126 mPermissions = ll_permissions_from_sd(sd[w]);
1127 }
1128 w = "sale_info";
1129 if (sd.has(w))
1130 {
1131 // Sale info used to contain next owner perm. It is now in
1132 // the permissions. Thus, we read that out, and fix legacy
1133 // objects. It's possible this op would fail, but it
1134 // should pick up the vast majority of the tasks.
1135 BOOL has_perm_mask = FALSE;
1136 U32 perm_mask = 0;
1137 if (!mSaleInfo.fromLLSD(sd[w], has_perm_mask, perm_mask))
1138 {
1139 goto fail;
1140 }
1141 if (has_perm_mask)
1142 {
1143 if(perm_mask == PERM_NONE)
1144 {
1145 perm_mask = mPermissions.getMaskOwner();
1146 }
1147 // fair use fix.
1148 if(!(perm_mask & PERM_COPY))
1149 {
1150 perm_mask |= PERM_TRANSFER;
1151 }
1152 mPermissions.setMaskNext(perm_mask);
1153 }
1154 }
1155 w = "shadow_id";
1156 if (sd.has(w))
1157 {
1158 mAssetUUID = sd[w];
1159 LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
1160 cipher.decrypt(mAssetUUID.mData, UUID_BYTES);
1161 }
1162 w = "asset_id";
1163 if (sd.has(w))
1164 {
1165 mAssetUUID = sd[w];
1166 }
1167 w = "type";
1168 if (sd.has(w))
1169 {
1170 mType = LLAssetType::lookup(sd[w].asString().c_str());
1171 }
1172 w = "inv_type";
1173 if (sd.has(w))
1174 {
1175 mInventoryType = LLInventoryType::lookup(sd[w].asString().c_str());
1176 }
1177 w = "flags";
1178 if (sd.has(w))
1179 {
1180 mFlags = ll_U32_from_sd(sd[w]);
1181 }
1182 w = "name";
1183 if (sd.has(w))
1184 {
1185 mName = sd[w].asString();
1186 LLString::replaceNonstandardASCII(mName, ' ');
1187 LLString::replaceChar(mName, '|', ' ');
1188 }
1189 w = "desc";
1190 if (sd.has(w))
1191 {
1192 mDescription = sd[w].asString();
1193 LLString::replaceNonstandardASCII(mDescription, ' ');
1194 }
1195 w = "creation_date";
1196 if (sd.has(w))
1197 {
1198 mCreationDate = sd[w];
1199 }
1200
1201 // Need to convert 1.0 simstate files to a useful inventory type
1202 // and potentially deal with bad inventory tyes eg, a landmark
1203 // marked as a texture.
1204 if((LLInventoryType::IT_NONE == mInventoryType)
1205 || !inventory_and_asset_types_match(mInventoryType, mType))
1206 {
1207 lldebugs << "Resetting inventory type for " << mUUID << llendl;
1208 mInventoryType = LLInventoryType::defaultForAssetType(mType);
1209 }
1210
1211 return true;
1212fail:
1213 return false;
1214
1215}
1216
1217LLXMLNode *LLInventoryItem::exportFileXML(BOOL include_asset_key) const
1218{
1219 LLMemType m1(LLMemType::MTYPE_INVENTORY);
1220 LLXMLNode *ret = new LLXMLNode("item", FALSE);
1221
1222 ret->createChild("uuid", TRUE)->setUUIDValue(1, &mUUID);
1223 ret->createChild("parent_uuid", TRUE)->setUUIDValue(1, &mParentUUID);
1224
1225 mPermissions.exportFileXML()->setParent(ret);
1226
1227 // Check for permissions to see the asset id, and if so write it
1228 // out as an asset id. Otherwise, apply our cheesy encryption.
1229 if(include_asset_key)
1230 {
1231 U32 mask = mPermissions.getMaskBase();
1232 if(((mask & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED)
1233 || (mAssetUUID.isNull()))
1234 {
1235 ret->createChild("asset_id", FALSE)->setUUIDValue(1, &mAssetUUID);
1236 }
1237 else
1238 {
1239 LLUUID shadow_id(mAssetUUID);
1240 LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
1241 cipher.encrypt(shadow_id.mData, UUID_BYTES);
1242
1243 ret->createChild("shadow_id", FALSE)->setUUIDValue(1, &shadow_id);
1244 }
1245 }
1246
1247 LLString type_str = LLAssetType::lookup(mType);
1248 LLString inv_type_str = LLInventoryType::lookup(mInventoryType);
1249
1250 ret->createChild("asset_type", FALSE)->setStringValue(1, &type_str);
1251 ret->createChild("inventory_type", FALSE)->setStringValue(1, &inv_type_str);
1252 S32 tmp_flags = (S32) mFlags;
1253 ret->createChild("flags", FALSE)->setByteValue(4, (U8*)(&tmp_flags), LLXMLNode::ENCODING_HEX);
1254
1255 mSaleInfo.exportFileXML()->setParent(ret);
1256
1257 LLString temp;
1258 temp.assign(mName);
1259 ret->createChild("name", FALSE)->setStringValue(1, &temp);
1260 temp.assign(mDescription);
1261 ret->createChild("description", FALSE)->setStringValue(1, &temp);
1262 ret->createChild("creation_date", FALSE)->setIntValue(1, &mCreationDate);
1263
1264 return ret;
1265}
1266
1267BOOL LLInventoryItem::importXML(LLXMLNode* node)
1268{
1269 BOOL success = FALSE;
1270 if (node)
1271 {
1272 success = TRUE;
1273 LLXMLNodePtr sub_node;
1274 if (node->getChild("uuid", sub_node))
1275 success = (1 == sub_node->getUUIDValue(1, &mUUID));
1276 if (node->getChild("parent_uuid", sub_node))
1277 success = success && (1 == sub_node->getUUIDValue(1, &mParentUUID));
1278 if (node->getChild("permissions", sub_node))
1279 success = success && mPermissions.importXML(sub_node);
1280 if (node->getChild("asset_id", sub_node))
1281 success = success && (1 == sub_node->getUUIDValue(1, &mAssetUUID));
1282 if (node->getChild("shadow_id", sub_node))
1283 {
1284 success = success && (1 == sub_node->getUUIDValue(1, &mAssetUUID));
1285 LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
1286 cipher.decrypt(mAssetUUID.mData, UUID_BYTES);
1287 }
1288 if (node->getChild("asset_type", sub_node))
1289 mType = LLAssetType::lookup(sub_node->getValue().c_str());
1290 if (node->getChild("inventory_type", sub_node))
1291 mInventoryType = LLInventoryType::lookup(sub_node->getValue().c_str());
1292 if (node->getChild("flags", sub_node))
1293 {
1294 S32 tmp_flags = 0;
1295 success = success && (1 == sub_node->getIntValue(1, &tmp_flags));
1296 mFlags = (U32) tmp_flags;
1297 }
1298 if (node->getChild("sale_info", sub_node))
1299 success = success && mSaleInfo.importXML(sub_node);
1300 if (node->getChild("name", sub_node))
1301 mName = sub_node->getValue();
1302 if (node->getChild("description", sub_node))
1303 mDescription = sub_node->getValue();
1304 if (node->getChild("creation_date", sub_node))
1305 success = success && (1 == sub_node->getIntValue(1, &mCreationDate));
1306 if (!success)
1307 {
1308 lldebugs << "LLInventory::importXML() failed for node named '"
1309 << node->getName() << "'" << llendl;
1310 }
1311 }
1312 return success;
1313}
1314
1315S32 LLInventoryItem::packBinaryBucket(U8* bin_bucket, LLPermissions* perm_override) const
1316{
1317 // Figure out which permissions to use.
1318 LLPermissions perm;
1319 if (perm_override)
1320 {
1321 // Use the permissions override.
1322 perm = *perm_override;
1323 }
1324 else
1325 {
1326 // Use the current permissions.
1327 perm = getPermissions();
1328 }
1329
1330 // describe the inventory item
1331 char* buffer = (char*) bin_bucket;
1332 char creator_id_str[UUID_STR_LENGTH];
1333
1334 perm.getCreator().toString(creator_id_str);
1335 char owner_id_str[UUID_STR_LENGTH];
1336 perm.getOwner().toString(owner_id_str);
1337 char last_owner_id_str[UUID_STR_LENGTH];
1338 perm.getLastOwner().toString(last_owner_id_str);
1339 char group_id_str[UUID_STR_LENGTH];
1340 perm.getGroup().toString(group_id_str);
1341 char asset_id_str[UUID_STR_LENGTH];
1342 getAssetUUID().toString(asset_id_str);
1343 S32 size = sprintf(buffer,
1344 "%d|%d|%s|%s|%s|%s|%s|%x|%x|%x|%x|%x|%s|%s|%d|%d|%x",
1345 getType(),
1346 getInventoryType(),
1347 getName().c_str(),
1348 creator_id_str,
1349 owner_id_str,
1350 last_owner_id_str,
1351 group_id_str,
1352 perm.getMaskBase(),
1353 perm.getMaskOwner(),
1354 perm.getMaskGroup(),
1355 perm.getMaskEveryone(),
1356 perm.getMaskNextOwner(),
1357 asset_id_str,
1358 getDescription().c_str(),
1359 getSaleInfo().getSaleType(),
1360 getSaleInfo().getSalePrice(),
1361 getFlags()) + 1;
1362
1363 return size;
1364}
1365
1366void LLInventoryItem::unpackBinaryBucket(U8* bin_bucket, S32 bin_bucket_size)
1367{
1368 // Early exit on an empty binary bucket.
1369 if (bin_bucket_size <= 1) return;
1370
1371 // Convert the bin_bucket into a string.
1372 char* item_buffer = new char[bin_bucket_size+1];
1373 memcpy(item_buffer, bin_bucket, bin_bucket_size);
1374 item_buffer[bin_bucket_size] = '\0';
1375 std::string str(item_buffer);
1376
1377 lldebugs << "item buffer: " << item_buffer << llendl;
1378 delete[] item_buffer;
1379
1380 // Tokenize the string.
1381 typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
1382 boost::char_separator<char> sep("|", "", boost::keep_empty_tokens);
1383 tokenizer tokens(str, sep);
1384 tokenizer::iterator iter = tokens.begin();
1385
1386 // Extract all values.
1387 LLUUID item_id;
1388 item_id.generate();
1389 setUUID(item_id);
1390
1391 LLAssetType::EType type;
1392 type = (LLAssetType::EType)(atoi((*(iter++)).c_str()));
1393 setType( type );
1394
1395 LLInventoryType::EType inv_type;
1396 inv_type = (LLInventoryType::EType)(atoi((*(iter++)).c_str()));
1397 setInventoryType( inv_type );
1398
1399 LLString name((*(iter++)).c_str());
1400 rename( name );
1401
1402 LLUUID creator_id((*(iter++)).c_str());
1403 LLUUID owner_id((*(iter++)).c_str());
1404 LLUUID last_owner_id((*(iter++)).c_str());
1405 LLUUID group_id((*(iter++)).c_str());
1406 PermissionMask mask_base = strtoul((*(iter++)).c_str(), NULL, 16);
1407 PermissionMask mask_owner = strtoul((*(iter++)).c_str(), NULL, 16);
1408 PermissionMask mask_group = strtoul((*(iter++)).c_str(), NULL, 16);
1409 PermissionMask mask_every = strtoul((*(iter++)).c_str(), NULL, 16);
1410 PermissionMask mask_next = strtoul((*(iter++)).c_str(), NULL, 16);
1411 LLPermissions perm;
1412 perm.init(creator_id, owner_id, last_owner_id, group_id);
1413 perm.initMasks(mask_base, mask_owner, mask_group, mask_every, mask_next);
1414 setPermissions(perm);
1415 //lldebugs << "perm: " << perm << llendl;
1416
1417 LLUUID asset_id((*(iter++)).c_str());
1418 setAssetUUID(asset_id);
1419
1420 LLString desc((*(iter++)).c_str());
1421 setDescription(desc);
1422
1423 LLSaleInfo::EForSale sale_type;
1424 sale_type = (LLSaleInfo::EForSale)(atoi((*(iter++)).c_str()));
1425 S32 price = atoi((*(iter++)).c_str());
1426 LLSaleInfo sale_info(sale_type, price);
1427 setSaleInfo(sale_info);
1428
1429 U32 flags = strtoul((*(iter++)).c_str(), NULL, 16);
1430 setFlags(flags);
1431
1432 time_t now = time(NULL);
1433 setCreationDate(now);
1434}
1435
1436// returns TRUE if a should appear before b
1437BOOL item_dictionary_sort( LLInventoryItem* a, LLInventoryItem* b )
1438{
1439 return (LLString::compareDict( a->getName().c_str(), b->getName().c_str() ) < 0);
1440}
1441
1442// returns TRUE if a should appear before b
1443BOOL item_date_sort( LLInventoryItem* a, LLInventoryItem* b )
1444{
1445 return a->getCreationDate() < b->getCreationDate();
1446}
1447
1448
1449///----------------------------------------------------------------------------
1450/// Class LLInventoryCategory
1451///----------------------------------------------------------------------------
1452
1453LLInventoryCategory::LLInventoryCategory(
1454 const LLUUID& uuid,
1455 const LLUUID& parent_uuid,
1456 LLAssetType::EType preferred_type,
1457 const LLString& name) :
1458 LLInventoryObject(uuid, parent_uuid, LLAssetType::AT_CATEGORY, name),
1459 mPreferredType(preferred_type)
1460{
1461}
1462
1463LLInventoryCategory::LLInventoryCategory() :
1464 mPreferredType(LLAssetType::AT_NONE)
1465{
1466 mType = LLAssetType::AT_CATEGORY;
1467}
1468
1469LLInventoryCategory::LLInventoryCategory(const LLInventoryCategory* other) :
1470 LLInventoryObject()
1471{
1472 copy(other);
1473}
1474
1475LLInventoryCategory::~LLInventoryCategory()
1476{
1477}
1478
1479// virtual
1480void LLInventoryCategory::copy(const LLInventoryCategory* other)
1481{
1482 LLInventoryObject::copy(other);
1483 mPreferredType = other->mPreferredType;
1484}
1485
1486LLAssetType::EType LLInventoryCategory::getPreferredType() const
1487{
1488 return mPreferredType;
1489}
1490
1491void LLInventoryCategory::setPreferredType(LLAssetType::EType type)
1492{
1493 mPreferredType = type;
1494}
1495
1496// virtual
1497void LLInventoryCategory::packMessage(LLMessageSystem* msg) const
1498{
1499 msg->addUUIDFast(_PREHASH_FolderID, mUUID);
1500 msg->addUUIDFast(_PREHASH_ParentID, mParentUUID);
1501 S8 type = static_cast<S8>(mPreferredType);
1502 msg->addS8Fast(_PREHASH_Type, type);
1503 msg->addStringFast(_PREHASH_Name, mName);
1504}
1505
1506// virtual
1507void LLInventoryCategory::unpackMessage(LLMessageSystem* msg,
1508 const char* block,
1509 S32 block_num)
1510{
1511 msg->getUUIDFast(block, _PREHASH_FolderID, mUUID, block_num);
1512 msg->getUUIDFast(block, _PREHASH_ParentID, mParentUUID, block_num);
1513 S8 type;
1514 msg->getS8Fast(block, _PREHASH_Type, type, block_num);
1515 mPreferredType = static_cast<LLAssetType::EType>(type);
1516 char name[DB_INV_ITEM_NAME_BUF_SIZE];
1517 msg->getStringFast(block, _PREHASH_Name, DB_INV_ITEM_NAME_BUF_SIZE, name, block_num);
1518 mName.assign(name);
1519 LLString::replaceNonstandardASCII(mName, ' ');
1520}
1521
1522// virtual
1523BOOL LLInventoryCategory::importFile(FILE* fp)
1524{
1525 char buffer[MAX_STRING];
1526 char keyword[MAX_STRING];
1527 char valuestr[MAX_STRING];
1528
1529 keyword[0] = '\0';
1530 valuestr[0] = '\0';
1531 while(!feof(fp))
1532 {
1533 fgets(buffer, MAX_STRING, fp);
1534 sscanf(buffer, " %s %s", keyword, valuestr);
1535 if(!keyword)
1536 {
1537 continue;
1538 }
1539 if(0 == strcmp("{",keyword))
1540 {
1541 continue;
1542 }
1543 if(0 == strcmp("}", keyword))
1544 {
1545 break;
1546 }
1547 else if(0 == strcmp("cat_id", keyword))
1548 {
1549 mUUID.set(valuestr);
1550 }
1551 else if(0 == strcmp("parent_id", keyword))
1552 {
1553 mParentUUID.set(valuestr);
1554 }
1555 else if(0 == strcmp("type", keyword))
1556 {
1557 mType = LLAssetType::lookup(valuestr);
1558 }
1559 else if(0 == strcmp("pref_type", keyword))
1560 {
1561 mPreferredType = LLAssetType::lookup(valuestr);
1562 }
1563 else if(0 == strcmp("name", keyword))
1564 {
1565 //strcpy(valuestr, buffer + strlen(keyword) + 3);
1566 // *NOTE: Not ANSI C, but widely supported.
1567 sscanf(buffer, " %s %[^|]", keyword, valuestr);
1568 mName.assign(valuestr);
1569 LLString::replaceNonstandardASCII(mName, ' ');
1570 LLString::replaceChar(mName, '|', ' ');
1571 }
1572 else
1573 {
1574 llwarns << "unknown keyword '" << keyword
1575 << "' in inventory import category " << mUUID << llendl;
1576 }
1577 }
1578 return TRUE;
1579}
1580
1581BOOL LLInventoryCategory::exportFile(FILE* fp, BOOL) const
1582{
1583 char uuid_str[UUID_STR_LENGTH];
1584 fprintf(fp, "\tinv_category\t0\n\t{\n");
1585 mUUID.toString(uuid_str);
1586 fprintf(fp, "\t\tcat_id\t%s\n", uuid_str);
1587 mParentUUID.toString(uuid_str);
1588 fprintf(fp, "\t\tparent_id\t%s\n", uuid_str);
1589 fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType));
1590 fprintf(fp, "\t\tpref_type\t%s\n", LLAssetType::lookup(mPreferredType));
1591 fprintf(fp, "\t\tname\t%s|\n", mName.c_str());
1592 fprintf(fp,"\t}\n");
1593 return TRUE;
1594}
1595
1596
1597// virtual
1598BOOL LLInventoryCategory::importLegacyStream(std::istream& input_stream)
1599{
1600 char buffer[MAX_STRING];
1601 char keyword[MAX_STRING];
1602 char valuestr[MAX_STRING];
1603
1604 keyword[0] = '\0';
1605 valuestr[0] = '\0';
1606 while(input_stream.good())
1607 {
1608 input_stream.getline(buffer, MAX_STRING);
1609 sscanf(buffer, " %s %s", keyword, valuestr);
1610 if(!keyword)
1611 {
1612 continue;
1613 }
1614 if(0 == strcmp("{",keyword))
1615 {
1616 continue;
1617 }
1618 if(0 == strcmp("}", keyword))
1619 {
1620 break;
1621 }
1622 else if(0 == strcmp("cat_id", keyword))
1623 {
1624 mUUID.set(valuestr);
1625 }
1626 else if(0 == strcmp("parent_id", keyword))
1627 {
1628 mParentUUID.set(valuestr);
1629 }
1630 else if(0 == strcmp("type", keyword))
1631 {
1632 mType = LLAssetType::lookup(valuestr);
1633 }
1634 else if(0 == strcmp("pref_type", keyword))
1635 {
1636 mPreferredType = LLAssetType::lookup(valuestr);
1637 }
1638 else if(0 == strcmp("name", keyword))
1639 {
1640 //strcpy(valuestr, buffer + strlen(keyword) + 3);
1641 // *NOTE: Not ANSI C, but widely supported.
1642 sscanf(buffer, " %s %[^|]", keyword, valuestr);
1643 mName.assign(valuestr);
1644 LLString::replaceNonstandardASCII(mName, ' ');
1645 LLString::replaceChar(mName, '|', ' ');
1646 }
1647 else
1648 {
1649 llwarns << "unknown keyword '" << keyword
1650 << "' in inventory import category " << mUUID << llendl;
1651 }
1652 }
1653 return TRUE;
1654}
1655
1656BOOL LLInventoryCategory::exportLegacyStream(std::ostream& output_stream, BOOL) const
1657{
1658 char uuid_str[UUID_STR_LENGTH];
1659 output_stream << "\tinv_category\t0\n\t{\n";
1660 mUUID.toString(uuid_str);
1661 output_stream << "\t\tcat_id\t" << uuid_str << "\n";
1662 mParentUUID.toString(uuid_str);
1663 output_stream << "\t\tparent_id\t" << uuid_str << "\n";
1664 output_stream << "\t\ttype\t" << LLAssetType::lookup(mType) << "\n";
1665 output_stream << "\t\tpref_type\t" << LLAssetType::lookup(mPreferredType) << "\n";
1666 output_stream << "\t\tname\t" << mName.c_str() << "|\n";
1667 output_stream << "\t}\n";
1668 return TRUE;
1669}
1670
1671///----------------------------------------------------------------------------
1672/// Local function definitions
1673///----------------------------------------------------------------------------
1674
1675bool inventory_and_asset_types_match(
1676 LLInventoryType::EType inventory_type,
1677 LLAssetType::EType asset_type)
1678{
1679 bool rv = false;
1680 if((inventory_type >= 0) && (inventory_type < LLInventoryType::IT_COUNT))
1681 {
1682 for(S32 i = 0; i < MAX_POSSIBLE_ASSET_TYPES; ++i)
1683 {
1684 if(INVENTORY_TO_ASSET_TYPE[inventory_type][i] == asset_type)
1685 {
1686 rv = true;
1687 break;
1688 }
1689 }
1690 }
1691 return rv;
1692}
1693
1694///----------------------------------------------------------------------------
1695/// exported functions
1696///----------------------------------------------------------------------------
1697
1698static const std::string INV_ITEM_ID_LABEL("item_id");
1699static const std::string INV_FOLDER_ID_LABEL("folder_id");
1700static const std::string INV_PARENT_ID_LABEL("parent_id");
1701static const std::string INV_ASSET_TYPE_LABEL("asset_type");
1702static const std::string INV_PREFERRED_TYPE_LABEL("preferred_type");
1703static const std::string INV_INVENTORY_TYPE_LABEL("inv_type");
1704static const std::string INV_NAME_LABEL("name");
1705static const std::string INV_DESC_LABEL("description");
1706static const std::string INV_PERMISSIONS_LABEL("permissions");
1707static const std::string INV_ASSET_ID_LABEL("asset_id");
1708static const std::string INV_SALE_INFO_LABEL("sale_info");
1709static const std::string INV_FLAGS_LABEL("flags");
1710static const std::string INV_CREATION_DATE_LABEL("created_at");
1711
1712LLSD ll_create_sd_from_inventory_item(LLPointer<LLInventoryItem> item)
1713{
1714 LLSD rv;
1715 if(item.isNull()) return rv;
1716 if (item->getType() == LLAssetType::AT_NONE)
1717 {
1718 llwarns << "ll_create_sd_from_inventory_item() for item with AT_NONE"
1719 << llendl;
1720 return rv;
1721 }
1722 rv[INV_ITEM_ID_LABEL] = item->getUUID();
1723 rv[INV_PARENT_ID_LABEL] = item->getParentUUID();
1724 rv[INV_NAME_LABEL] = item->getName();
1725 rv[INV_ASSET_TYPE_LABEL] = LLAssetType::lookup(item->getType());
1726 rv[INV_ASSET_ID_LABEL] = item->getAssetUUID();
1727 rv[INV_DESC_LABEL] = item->getDescription();
1728 rv[INV_SALE_INFO_LABEL] = ll_create_sd_from_sale_info(item->getSaleInfo());
1729 rv[INV_PERMISSIONS_LABEL] =
1730 ll_create_sd_from_permissions(item->getPermissions());
1731 rv[INV_INVENTORY_TYPE_LABEL] =
1732 LLInventoryType::lookup(item->getInventoryType());
1733 rv[INV_FLAGS_LABEL] = (S32)item->getFlags();
1734 rv[INV_CREATION_DATE_LABEL] = item->getCreationDate();
1735 return rv;
1736}
1737
1738LLPointer<LLInventoryItem> ll_create_item_from_sd(const LLSD& sd_item)
1739{
1740 LLPointer<LLInventoryItem> rv = new LLInventoryItem;
1741 rv->setUUID(sd_item[INV_ITEM_ID_LABEL].asUUID());
1742 rv->setParent(sd_item[INV_PARENT_ID_LABEL].asUUID());
1743 rv->rename(sd_item[INV_NAME_LABEL].asString());
1744 rv->setType(
1745 LLAssetType::lookup(sd_item[INV_ASSET_TYPE_LABEL].asString().c_str()));
1746 rv->setAssetUUID(sd_item[INV_ASSET_ID_LABEL].asUUID());
1747 rv->setDescription(sd_item[INV_DESC_LABEL].asString());
1748 rv->setSaleInfo(ll_sale_info_from_sd(sd_item[INV_SALE_INFO_LABEL]));
1749 rv->setPermissions(ll_permissions_from_sd(sd_item[INV_PERMISSIONS_LABEL]));
1750 rv->setInventoryType(
1751 LLInventoryType::lookup(
1752 sd_item[INV_INVENTORY_TYPE_LABEL].asString().c_str()));
1753 rv->setFlags((U32)(sd_item[INV_FLAGS_LABEL].asInteger()));
1754 rv->setCreationDate(sd_item[INV_CREATION_DATE_LABEL].asInteger());
1755 return rv;
1756}
1757
1758LLSD ll_create_sd_from_inventory_category(LLPointer<LLInventoryCategory> cat)
1759{
1760 LLSD rv;
1761 if(cat.isNull()) return rv;
1762 if (cat->getType() == LLAssetType::AT_NONE)
1763 {
1764 llwarns << "ll_create_sd_from_inventory_category() for cat with AT_NONE"
1765 << llendl;
1766 return rv;
1767 }
1768 rv[INV_FOLDER_ID_LABEL] = cat->getUUID();
1769 rv[INV_PARENT_ID_LABEL] = cat->getParentUUID();
1770 rv[INV_NAME_LABEL] = cat->getName();
1771 rv[INV_ASSET_TYPE_LABEL] = LLAssetType::lookup(cat->getType());
1772 if(LLAssetType::AT_NONE != cat->getPreferredType())
1773 {
1774 rv[INV_PREFERRED_TYPE_LABEL] =
1775 LLAssetType::lookup(cat->getPreferredType());
1776 }
1777 return rv;
1778}
1779
1780LLPointer<LLInventoryCategory> ll_create_category_from_sd(const LLSD& sd_cat)
1781{
1782 LLPointer<LLInventoryCategory> rv = new LLInventoryCategory;
1783 rv->setUUID(sd_cat[INV_FOLDER_ID_LABEL].asUUID());
1784 rv->setParent(sd_cat[INV_PARENT_ID_LABEL].asUUID());
1785 rv->rename(sd_cat[INV_NAME_LABEL].asString());
1786 rv->setType(
1787 LLAssetType::lookup(sd_cat[INV_ASSET_TYPE_LABEL].asString().c_str()));
1788 rv->setPreferredType(
1789 LLAssetType::lookup(
1790 sd_cat[INV_PREFERRED_TYPE_LABEL].asString().c_str()));
1791 return rv;
1792}