From 357edecd9b938f2b83a6db0237c6343de7a18fcf Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Tue, 4 Aug 2020 15:30:20 +0300
Subject: SL-13669 Change inventory cache to use a standard LLSD format

---
 indra/newview/llinventorymodel.cpp  | 114 ++++++++++++-------------
 indra/newview/llviewerinventory.cpp | 164 +++++++++++-------------------------
 indra/newview/llviewerinventory.h   |  13 +--
 3 files changed, 108 insertions(+), 183 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index e7093eac02..c86a9a40d3 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -56,6 +56,7 @@
 #include "llcallbacklist.h"
 #include "llvoavatarself.h"
 #include "llgesturemgr.h"
+#include "llsdserialize.h"
 #include "llsdutil.h"
 #include "bufferarray.h"
 #include "bufferstream.h"
@@ -76,8 +77,8 @@ BOOL LLInventoryModel::sFirstTimeInViewer2 = TRUE;
 ///----------------------------------------------------------------------------
 
 //BOOL decompress_file(const char* src_filename, const char* dst_filename);
-static const char PRODUCTION_CACHE_FORMAT_STRING[] = "%s.inv";
-static const char GRID_CACHE_FORMAT_STRING[] = "%s.%s.inv";
+static const char PRODUCTION_CACHE_FORMAT_STRING[] = "%s.inv.llsd";
+static const char GRID_CACHE_FORMAT_STRING[] = "%s.%s.inv.llsd";
 static const char * const LOG_INV("Inventory");
 
 struct InventoryIDPtrLess
@@ -2690,29 +2691,37 @@ bool LLInventoryModel::loadFromFile(const std::string& filename,
 {
 	if(filename.empty())
 	{
-		LL_ERRS(LOG_INV) << "Filename is Null!" << LL_ENDL;
+		LL_ERRS(LOG_INV) << "filename is Null!" << LL_ENDL;
 		return false;
 	}
-	LL_INFOS(LOG_INV) << "LLInventoryModel::loadFromFile(" << filename << ")" << LL_ENDL;
-	LLFILE* file = LLFile::fopen(filename, "rb");		/*Flawfinder: ignore*/
-	if(!file)
+	LL_INFOS(LOG_INV) << "loading inventory from: (" << filename << ")" << LL_ENDL;
+
+	llifstream file(filename.c_str());
+
+	if (!file.is_open())
 	{
 		LL_INFOS(LOG_INV) << "unable to load inventory from: " << filename << LL_ENDL;
 		return false;
 	}
-	// *NOTE: This buffer size is hard coded into scanf() below.
-	char buffer[MAX_STRING];		/*Flawfinder: ignore*/
-	char keyword[MAX_STRING];		/*Flawfinder: ignore*/
-	char value[MAX_STRING];			/*Flawfinder: ignore*/
-	is_cache_obsolete = true;  		// Obsolete until proven current
-	while(!feof(file) && fgets(buffer, MAX_STRING, file)) 
+
+	is_cache_obsolete = true; // Obsolete until proven current
+
+	std::string line;
+	LLPointer<LLSDParser> parser = new LLSDNotationParser();
+	while (std::getline(file, line)) 
 	{
-		sscanf(buffer, " %126s %126s", keyword, value);	/* Flawfinder: ignore */
-		if(0 == strcmp("inv_cache_version", keyword))
+		LLSD s_item;
+		std::istringstream iss(line);
+		if (parser->parse(iss, s_item, line.length()) == LLSDParser::PARSE_FAILURE)
+		{
+			LL_INFOS(LOG_INV)<< "Parsing inventory cache failed" << LL_ENDL;
+			break;
+		}
+
+		if (s_item.has("inv_cache_version"))
 		{
-			S32 version;
-			int succ = sscanf(value,"%d",&version);
-			if ((1 == succ) && (version == sCurrentInvCacheVersion))
+			S32 version = s_item["inv_cache_version"].asInteger();
+			if (version == sCurrentInvCacheVersion)
 			{
 				// Cache is up to date
 				is_cache_obsolete = false;
@@ -2720,43 +2729,33 @@ bool LLInventoryModel::loadFromFile(const std::string& filename,
 			}
 			else
 			{
-				// Cache is out of date
+				LL_INFOS(LOG_INV)<< "Inventory cache is out of date" << LL_ENDL;
 				break;
 			}
 		}
-		else if(0 == strcmp("inv_category", keyword))
+		else if (s_item.has("cat_id"))
 		{
 			if (is_cache_obsolete)
 				break;
-			
+
 			LLPointer<LLViewerInventoryCategory> inv_cat = new LLViewerInventoryCategory(LLUUID::null);
-			if(inv_cat->importFileLocal(file))
+			if(inv_cat->importLLSD(s_item))
 			{
 				categories.push_back(inv_cat);
 			}
-			else
-			{
-				LL_WARNS(LOG_INV) << "loadInventoryFromFile().  Ignoring invalid inventory category: " << inv_cat->getName() << LL_ENDL;
-				//delete inv_cat; // automatic when inv_cat is reassigned or destroyed
-			}
 		}
-		else if(0 == strcmp("inv_item", keyword))
+		else if (s_item.has("item_id"))
 		{
 			if (is_cache_obsolete)
 				break;
 
 			LLPointer<LLViewerInventoryItem> inv_item = new LLViewerInventoryItem;
-			if( inv_item->importFileLocal(file) )
+			if( inv_item->fromLLSD(s_item) )
 			{
-				// *FIX: Need a better solution, this prevents the
-				// application from freezing, but breaks inventory
-				// caching.
 				if(inv_item->getUUID().isNull())
 				{
-					//delete inv_item; // automatic when inv_cat is reassigned or destroyed
 					LL_WARNS(LOG_INV) << "Ignoring inventory with null item id: "
-									  << inv_item->getName() << LL_ENDL;
-						
+						<< inv_item->getName() << LL_ENDL;
 				}
 				else
 				{
@@ -2769,44 +2768,40 @@ bool LLInventoryModel::loadFromFile(const std::string& filename,
 						items.push_back(inv_item);
 					}
 				}
-			}
-			else
-			{
-				LL_WARNS(LOG_INV) << "loadInventoryFromFile().  Ignoring invalid inventory item: " << inv_item->getName() << LL_ENDL;
-				//delete inv_item; // automatic when inv_cat is reassigned or destroyed
-			}
-		}
-		else
-		{
-			LL_WARNS(LOG_INV) << "Unknown token in inventory file '" << keyword << "'"
-							  << LL_ENDL;
+			}	
 		}
 	}
-	fclose(file);
-	if (is_cache_obsolete)
-		return false;
-	return true;
+
+	file.close();
+
+	return !is_cache_obsolete;	
 }
 
 // static
 bool LLInventoryModel::saveToFile(const std::string& filename,
-								  const cat_array_t& categories,
-								  const item_array_t& items)
+	const cat_array_t& categories,
+	const item_array_t& items)
 {
-	if(filename.empty())
+	if (filename.empty())
 	{
 		LL_ERRS(LOG_INV) << "Filename is Null!" << LL_ENDL;
 		return false;
 	}
-	LL_INFOS(LOG_INV) << "LLInventoryModel::saveToFile(" << filename << ")" << LL_ENDL;
-	LLFILE* file = LLFile::fopen(filename, "wb");		/*Flawfinder: ignore*/
-	if(!file)
+
+	LL_INFOS(LOG_INV) << "saving inventory to: (" << filename << ")" << LL_ENDL;
+
+	llofstream fileXML(filename.c_str());
+	if (!fileXML.is_open())
 	{
 		LL_WARNS(LOG_INV) << "unable to save inventory to: " << filename << LL_ENDL;
 		return false;
 	}
 
-	fprintf(file, "\tinv_cache_version\t%d\n",sCurrentInvCacheVersion);
+	LLSD cache_ver;
+	cache_ver["inv_cache_version"] = sCurrentInvCacheVersion;
+
+	fileXML << LLSDOStreamer<LLSDNotationFormatter>(cache_ver) << std::endl;
+
 	S32 count = categories.size();
 	S32 i;
 	for(i = 0; i < count; ++i)
@@ -2814,17 +2809,18 @@ bool LLInventoryModel::saveToFile(const std::string& filename,
 		LLViewerInventoryCategory* cat = categories[i];
 		if(cat->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN)
 		{
-			cat->exportFileLocal(file);
+			fileXML << LLSDOStreamer<LLSDNotationFormatter>(cat->exportLLSD()) << std::endl;
 		}
 	}
 
 	count = items.size();
 	for(i = 0; i < count; ++i)
 	{
-		items[i]->exportFile(file);
+		fileXML << LLSDOStreamer<LLSDNotationFormatter>(items[i]->asLLSD()) << std::endl;
 	}
 
-	fclose(file);
+	fileXML.close();
+
 	return true;
 }
 
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index d0cbd1181b..6c61c34075 100644
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -81,6 +81,14 @@ static const char * const LOG_INV("Inventory");
 static const char * const LOG_LOCAL("InventoryLocalize");
 static const char * const LOG_NOTECARD("copy_inventory_from_notecard");
 
+static const std::string INV_CAT_ID("cat_id");
+static const std::string INV_PARENT_ID("parent_id");
+static const std::string INV_ASSET_TYPE("type");
+static const std::string INV_PREFERRED_TYPE("pref_type");
+static const std::string INV_NAME("name");
+static const std::string INV_OWNER_ID("owner_id");
+static const std::string INV_VERSION("version");
+
 #if 1
 // *TODO$: LLInventoryCallback should be deprecated to conform to the new boost::bind/coroutine model.
 // temp code in transition
@@ -518,14 +526,6 @@ void LLViewerInventoryItem::packMessage(LLMessageSystem* msg) const
 	msg->addU32Fast(_PREHASH_CRC, crc);
 }
 
-// virtual
-BOOL LLViewerInventoryItem::importFile(LLFILE* fp)
-{
-	BOOL rv = LLInventoryItem::importFile(fp);
-	mIsComplete = TRUE;
-	return rv;
-}
-
 // virtual
 BOOL LLViewerInventoryItem::importLegacyStream(std::istream& input_stream)
 {
@@ -534,32 +534,6 @@ BOOL LLViewerInventoryItem::importLegacyStream(std::istream& input_stream)
 	return rv;
 }
 
-bool LLViewerInventoryItem::importFileLocal(LLFILE* fp)
-{
-	// TODO: convert all functions that return BOOL to return bool
-	bool rv = (LLInventoryItem::importFile(fp) ? true : false);
-	mIsComplete = false;
-	return rv;
-}
-
-bool LLViewerInventoryItem::exportFileLocal(LLFILE* fp) const
-{
-	std::string uuid_str;
-	fprintf(fp, "\tinv_item\t0\n\t{\n");
-	mUUID.toString(uuid_str);
-	fprintf(fp, "\t\titem_id\t%s\n", uuid_str.c_str());
-	mParentUUID.toString(uuid_str);
-	fprintf(fp, "\t\tparent_id\t%s\n", uuid_str.c_str());
-	mPermissions.exportFile(fp);
-	fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType));
-	const std::string inv_type_str = LLInventoryType::lookup(mInventoryType);
-	if(!inv_type_str.empty()) fprintf(fp, "\t\tinv_type\t%s\n", inv_type_str.c_str());
-	fprintf(fp, "\t\tname\t%s|\n", mName.c_str());
-	fprintf(fp, "\t\tcreation_date\t%d\n", (S32) mCreationDate);
-	fprintf(fp,"\t}\n");
-	return true;
-}
-
 void LLViewerInventoryItem::updateParentOnServer(BOOL restamp) const
 {
 	LLMessageSystem* msg = gMessageSystem;
@@ -720,90 +694,52 @@ S32 LLViewerInventoryCategory::getViewerDescendentCount() const
 	return descendents_actual;
 }
 
-bool LLViewerInventoryCategory::importFileLocal(LLFILE* fp)
+LLSD LLViewerInventoryCategory::exportLLSD() const
 {
-	// *NOTE: This buffer size is hard coded into scanf() below.
-	char buffer[MAX_STRING];		/* Flawfinder: ignore */
-	char keyword[MAX_STRING];		/* Flawfinder: ignore */
-	char valuestr[MAX_STRING];		/* Flawfinder: ignore */
+	LLSD cat_data;
+	cat_data[INV_CAT_ID] = mUUID;
+	cat_data[INV_PARENT_ID] = mParentUUID;
+	cat_data[INV_ASSET_TYPE] = LLAssetType::lookup(mType);
+	cat_data[INV_PREFERRED_TYPE] = LLFolderType::lookup(mPreferredType);
+	cat_data[INV_NAME] = mName;
+	cat_data[INV_OWNER_ID] = mOwnerID;
+	cat_data[INV_VERSION] = mVersion;
 
-	keyword[0] = '\0';
-	valuestr[0] = '\0';
-	while(!feof(fp))
-	{
-		if (fgets(buffer, MAX_STRING, fp) == NULL)
-		{
-			buffer[0] = '\0';
-		}
-		
-		sscanf(	/* Flawfinder: ignore */
-			buffer, " %254s %254s", keyword, valuestr); 
-		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 = LLFolderType::lookup(valuestr);
-		}
-		else if(0 == strcmp("name", keyword))
-		{
-			//strcpy(valuestr, buffer + strlen(keyword) + 3);
-			// *NOTE: Not ANSI C, but widely supported.
-			sscanf(	/* Flawfinder: ignore */
-				buffer, " %254s %254[^|]", keyword, valuestr);
-			mName.assign(valuestr);
-			LLStringUtil::replaceNonstandardASCII(mName, ' ');
-			LLStringUtil::replaceChar(mName, '|', ' ');
-		}
-		else if(0 == strcmp("owner_id", keyword))
-		{
-			mOwnerID.set(valuestr);
-		}
-		else if(0 == strcmp("version", keyword))
-		{
-			sscanf(valuestr, "%d", &mVersion);
-		}
-		else
-		{
-			LL_WARNS(LOG_INV) << "unknown keyword '" << keyword
-							  << "' in inventory import category "  << mUUID << LL_ENDL;
-		}
-	}
-	return true;
+	return cat_data;
 }
 
-bool LLViewerInventoryCategory::exportFileLocal(LLFILE* fp) const
-{
-	std::string uuid_str;
-	fprintf(fp, "\tinv_category\t0\n\t{\n");
-	mUUID.toString(uuid_str);
-	fprintf(fp, "\t\tcat_id\t%s\n", uuid_str.c_str());
-	mParentUUID.toString(uuid_str);
-	fprintf(fp, "\t\tparent_id\t%s\n", uuid_str.c_str());
-	fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType));
-	fprintf(fp, "\t\tpref_type\t%s\n", LLFolderType::lookup(mPreferredType).c_str());
-	fprintf(fp, "\t\tname\t%s|\n", mName.c_str());
-	mOwnerID.toString(uuid_str);
-	fprintf(fp, "\t\towner_id\t%s\n", uuid_str.c_str());
-	fprintf(fp, "\t\tversion\t%d\n", mVersion);
-	fprintf(fp,"\t}\n");
+bool LLViewerInventoryCategory::importLLSD(const LLSD& cat_data)
+{
+	if (cat_data.has(INV_CAT_ID))
+	{
+		setUUID(cat_data[INV_CAT_ID].asUUID());
+	}
+	if (cat_data.has(INV_PARENT_ID))
+	{
+		setParent(cat_data[INV_PARENT_ID].asUUID());
+	}
+	if (cat_data.has(INV_ASSET_TYPE))
+	{
+		setType(LLAssetType::lookup(cat_data[INV_ASSET_TYPE].asString()));
+	}
+	if (cat_data.has(INV_PREFERRED_TYPE))
+	{
+		setPreferredType(LLFolderType::lookup(cat_data[INV_PREFERRED_TYPE].asString()));
+	}
+	if (cat_data.has(INV_NAME))
+	{
+		mName = cat_data[INV_NAME].asString();
+		LLStringUtil::replaceNonstandardASCII(mName, ' ');
+		LLStringUtil::replaceChar(mName, '|', ' ');
+	}
+	if (cat_data.has(INV_OWNER_ID))
+	{
+		mOwnerID = cat_data[INV_OWNER_ID].asUUID();
+	}
+	if (cat_data.has(INV_VERSION))
+	{
+		setVersion(cat_data[INV_VERSION].asInteger());
+	}
 	return true;
 }
 
diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h
index d537b28682..24b632632b 100644
--- a/indra/newview/llviewerinventory.h
+++ b/indra/newview/llviewerinventory.h
@@ -131,14 +131,8 @@ public:
 	virtual void packMessage(LLMessageSystem* msg) const;
 	virtual BOOL unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num = 0);
 	virtual BOOL unpackMessage(const LLSD& item);
-	virtual BOOL importFile(LLFILE* fp);
 	virtual BOOL importLegacyStream(std::istream& input_stream);
 
-	// file handling on the viewer. These are not meant for anything
-	// other than cacheing.
-	bool exportFileLocal(LLFILE* fp) const;
-	bool importFileLocal(LLFILE* fp);
-
 	// new methods
 	BOOL isFinished() const { return mIsComplete; }
 	void setComplete(BOOL complete) { mIsComplete = complete; }
@@ -226,10 +220,9 @@ public:
 	// How many descendents do we currently have information for in the InventoryModel?
 	S32 getViewerDescendentCount() const;
 
-	// file handling on the viewer. These are not meant for anything
-	// other than caching.
-	bool exportFileLocal(LLFILE* fp) const;
-	bool importFileLocal(LLFILE* fp);
+	LLSD exportLLSD() const;
+	bool importLLSD(const LLSD& cat_data);
+
 	void determineFolderType();
 	void changeType(LLFolderType::EType new_folder_type);
 	virtual void unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num = 0);
-- 
cgit v1.2.3