A packed sheet is a way of storing multiple Georges sheets in a binary format. What a packed sheet does is load all of the sheets/forms into a single binary file that can be serialized by a loader that can automatically populate the proper data. It also will update the packed sheet (if informed to) to either create a new packed sheet (if one does not already exist) or add new entries to a packed sheet.
For packed sheets, you must declare a class that will be used by the form packer:
struct TMyLoader
{
/**
* \brief Here you read in the form if necessary, storing it in memebers of the TMyLoader class
*/
void readGeorges (const NLMISC::CSmartPtr<NLGEORGES::UForm> &form, const NLMISC::CSheetId &sheetId);
/**
* \brief Here you write a standard NeL serial for all the member of TMyLoader that need to be packed.
*/
void serial(NLMISC::IStream &f);
/**
* \brief This methed returns the version of the packed sheet.
* The coder needs to increment the number each time the packed sheet changes and the serial method
* is updated so the code will discard old packed sheets.
*
* \return uint This must always return an integer. Unsigned is probably best.
*/
static uint getVersion();
/**
* \brief Here you can write custom code for when the packed sheet loader needs to remove an old sheet.
* \note This is rarely used.
*/
void removed();
};
Now that you have your class that conforms to the requirements of the packer and loader you have to create a container for the form loader to populate with sheets. This must always be like a map similar to the one below.
std::map<CSheetId, TMyLoader> MySheets;
Usually Nevrax declares this globally but there is no constraint about that. It is used for a single call to loadForm (which is described below) and not for all sheets in an application. This method loads all of the sheets into the container.
loadForm( "my_extension", "packed_sheet_file_name.packed_sheets", MySheets, true);
Essentially what loadForm does is if told to go through the files with my_extension for an extension and check if there are newer ones than in the packed sheet, new ones period, or if some have been removed and marks these files appropriately in memory. It then loads all of the forms and puts them into cached lists and removes any files it found missing from the packed sheet. If it changed the container at all (added new files, updated changed files, or removed old files) it saves the file back out as the file passed in the parameter, which is packed_sheet_file_name.packed_sheets in the above example. In the process your map will be populated either via serialization (unchanged sheets) or by the readGeorges method (added or updated sheets.)
void loadForm (const std::vector< std::string > &sheetFilters, const std::string &packedFilename, std::map< NLMISC::CSheetId, T > &container, bool updatePackedSheet=true, bool errorIfPackedSheetNotGood=true)
As you have defined you own class to hold packed data, and as you declared you own container to hold them (in fact, the container MUST be a std::map<CSheetId, you_class> ), then it's easy to access the container with a valid sheet id to retreive your data
There is no progress callback for during packing - only a debug log every 10 seconds. But when you only load a packed sheet (without updating it with current sheets data) the loading time is very short.
CSheetId and sheet_id.bin file is a manner to uniquely identify sheet file with a 32 bit integer.
There is a (private) tool that builds the sheet_id.bin from a collection of files. The sheet_id.bin is always apended, never are old sheets removed. This ensures persistent data storage to be efficient and stable.
There is also a tool in the public CVS for retrieving information on sheets called ''disp_sheet_id''.
So, when you program starts, you can init the sheet id system by loading the sheet_id.bin file, than CSheetId instance can be created from file name or from 32 interger and converted to/from the int or filename.
It has to be in your search path, then you call the init method in CSheetId (or somethink near that)
CSheetId::init(false);