===========================================
Versioning and Storing Additional User Data
===========================================

Versioning
==========

As discussed in the previous section, one way for you to check if the file contains custom HSF objects that you know/care about is to always use custom opcode handlers, which then check during the reading process to see if there is user data. However, there is one deliberate flaw to the example approach and its corresponding sample code. If the code sees a custom chunk of data following the default ``HTK_Shell`` object (by noticing a ``#TKE_Start_User_Data`` opcode), it simply goes ahead and reads the data, assuming that it was data written out by our custom shell handler. However, what if the file was written out by a custom handler that was not ours?! In this case, we wouldn't understand the information and don't care about it. However, the sample code does not properly check if the data is something that we know or care about. Because it is assuming a specific amount of user data, and this is an unsafe assumption, the code is flawed.

One potential solution is to add another stage during the writing process: after writing out the ``#TKE_Start_User_Data`` opcode and the number of bytes of custom data, we could also write out some special value which 'marks' the custom data as 'our' custom data. Then, during reading, we would check that special value to confirm if it was our data. However, this solution is a bit cumbersome since it means that our custom logic would always need to be executed, and to properly handle the case, we'd also have to either A) peek at the data up through the special value and then return from the function (so that the default toolkit will skip the custom data) or B) manually skip through the custom data ourselves by utilizing the 'number of bytes' information.

A better solution would be to store some type of additional versioning information in the beginning of the file which could be checked once, and then we would create and register our custom HSF object handlers only if the file was verified to be a custom version that we created with our custom toolkit. Recalling that the first opcode in an HSF file is always a ``#TKE_Comment`` opcode (with contents that are specifically formatted to denote file version information), you could export another ``#TKE_Comment`` opcode immediately after the first one with contents that contain additional version information. For example:

.. code-block:: none

	<TKE_Comment> standard version information; contents:  HSF V11.00 
	<TKE_Comment> custom version information; contents:  SuperCAD V2.10 
	<data opcode> 
		  . 
		  .  
		  . 
	<data opcode> 
	<TKE_Termination>  

The following section details how additional information could be added at the beginning of the file (prior to default HSF objects) as well as at the end of the file.


Storing Additional User Data
============================

In addition to providing support for attaching/retrieving user data to/from default HSF objects (by enabling overloading of the Write and Read methods of opcode handlers), the HOOPS/Stream Toolkit also provides general support for exporting user data via the ``TK_XML``, ``TK_User_Data`` and ``TK_URL`` opcode handlers, which export the ``#TKE_XML``, ``#TKE_Start_User_Data``, and ``#TKE_URL`` opcodes, respectively. This gives developers the ability to store discrete chunks of user data that may (or may not) be associated with the HSF objects. The ``TK_XML`` opcode handler would be used to store or retreive XML data, and the ``TK_User_Data`` opcode handler would be used to store or retrieve custom binary data. The ``TK_URL`` opcode handler provides informational links corresponding to data (as opposed to ``#TKE_External_Reference`` which provides additional content).

When writing out user data within the ``Write`` method of your custom ``TK_User_Data`` object, be sure to review the process of :doc:`formatting user data </prog_guide/3dgs_stream/user_data>`.

To handle import/export of user data, you will need to register a custom opcode handler for the ``#TKE_Start_User_Data`` opcode. This is because the toolkit's default handler (``TK_User_Data``) simply skips over the user data that is read in. (Remember that custom opcode handlers such as ``My_HTK_Shell`` described in the previous section typically only handle user data that is *appended* to a default HSF object. If you are adding discrete chunks of user data to the file, then you must read or write that data with an entirely new ``TK_User_Data`` handler) The following steps are involved::
     
**1. Define a new class derived from ``TK_User_Data``(which we'll call ``TK_My_User_Data``) that overloads the ``Write`` and ``Read`` methods to process the extra user data.** Example:

.. code-block:: cpp

	#include "object.h"          

	class TK_My_User_Data : public TK_User_Data 
	{            
		protected:   
			   
			int    my_stage; // denotes the current processing stage          
		 
		
		public:  
				
			TK_My_User_Data(unsigned char opcode) : TK_User_Data(opcode) {}  
					
			// Within Read(), we may need to verify that the user data is 'our'
			// user data.  As previously noted, one approach is to write out 
			// versioning information at the beginning of the file. 
			// If it is not our custom version of the file, we would NOT 
			// even register this custom user data opcode handler; instead 
			// we would allow the default TK_User_Data handler to take care of
			// the TKE_Start_User_Data opcode by simply skipping over any user data
			virtual TK_Status   Read (HStreamFileToolkit & tk) alter;  
					
			virtual TK_Status   Write (HStreamFileToolkit & tk) alter;             
	};           

**2. Instruct the toolkit to use our custom user data opcode handler in place of the default handler by calling ``SetOpcodeHandler``. We specify the type of opcode that we want to replace, and pass in a pointer to the new opcode handler object.**

	tk->SetOpcodeHandler (TKE_Start_User_Data, new TK_My_User_Data(TKE_Start_User_Data));

This will also cause the toolkit to delete it's default handler object for the ``#TKE_Start_User_Data`` opcode. **Note:** As the HOOPS/Stream Reference Manual points out, all opcode handler objects stored in the HStreamFileToolkit object will be deleted when the ``HStreamFileTookit`` object is deleted. Therefore, we would not delete the ``TK_My_User_Data`` object created in the above example.

Custom handling of the ``#TKE_XML`` opcode would be similar to the above, but you would instead register a custom opcode handler for the XML opcode that is derived from ``TK_XML``. 
  
  
Using Prewalk and Postwalk Handers
==================================

The 3dGS-specific classes allow the developer to setup special opcode handlers, called prewalk and postwalk handlers. A prewalk handler will be called prior to the traversal of the HOOPS/3dGS scene-graph, while a postwalk handler will be called after the traversal of the scene-graph is complete. This allows the developer to add chunks of custom data at the beginning or end of the file. These handlers are set by calling ``BStreamFileToolkit::SetPrewalkHandler`` and ``BStreamFileToolkit::SetPostwalkHandler``. Multiple pre/post-walk handlers can be set by calling these functions multiple times. (The order that the handlers will be called is depending on the order in which the functions were called, or FIFE for 'first-invoked, first executed'

It may be desirable to export the ``#TKE_View`` opcode prior to the scene-graph information, so that reading applications know the extents of the scene in advance. This can therefore be achieved by setting the prewalk handler to be a custom opcode-handler that is registered to handle the ``#TKE_View`` opcode::

	tk->SetPrewalkHandler(new TK_My_Initial_View); 

If we want our application to handle the ``#TKE_View`` opcode during reading, then we'd also register our custom opcode handler to handle the ``#TKE_View`` opcode::

	tk->SetOpcodeHandler(TKE_View, new TK_My_Initial_View);
  
The sample definition of ``TK_My_Inital_View`` is contained in `HTK_My_View.h <examples/HTK_My_View.h>`_, and the implementation is located in `HTK_My_View.cpp <examples/HTK_My_View.cpp>`_. Note that it is actually a custom ``HTK_Camera`` class that has been registered to handle the ``#TKE_View`` opcode. (Per the opcode registration list that was previously discussed in the previous page, the ``HTK_Camera`` class is the class designated to handle the ``#TKE_View`` opcode.)
