LVClass Data Storage Format
What does an LVClass look like when we flatten it? The string has four parts:
1. "NumLevels" The first 4 bytes represent a uInt32. This tells us how many levels of the hierarchy are recorded herein. If NumLevels is zero, absolutely nothing else follows. Zero indicates that this is an instance of LabVIEW Object, the ancestor of all classes which has no fields, no methods and inherits ex nihilo.
2. "ClassName". The next several bytes represent a PStr (aka Pascal String, which is a single byte that is the length of the string followed by the text of the string). This tells us the name of the class that flattened this data. This is the fully qualified name of the class, using the colon : as the delimiter character. Note that there are enough pad bytes after the PStr to get the length of the string to be a multiple of four.
3. "VersionList". The next series of uInt16s that represent a list of version numbers. Each version number is 4 uInt16s, usually written in the format W.X.Y.Z, where W, X, Y and Z are each a uInt16. There are NumLevels of version numbers. The first version number is the version of ClassName class, followed by the version number for ClassName's parent, and so on to the version of the oldest ancestor (not including LabVIEW Object).
SPECIAL CASE: If NumLevels == 1 and the version == 0.0.0.0, then this is the default data of the class. Skip section 4 -- no further data follows in this special case. If version is zero for any other value of NumLevels, the string is considered corrupt and the unflatten functions will return an error.
4. "ClusterData" -- This is a series of flattened clusters, one for each level of the hierarchy. The first cluster is the oldest ancestor class. Pay attention: The version numbers start at the descendant class and go up the hierarchy. The cluster data starts at the oldest ancestor and goes down the hierarchy. Each block of data starts with 4 bytes interpreted as an int32. This int32 represents the number of bytes in the data that follows. If this number is zero, then we use the default default data for this level of the hierarchy. If this number is non-zero then this is the standard flat data representation for the cluster at this level of the inheritance hierarchy. After each cluster there are enough pad bytes to get the length of the string back to a multiple of four.
Here, for example, is a flattened class object (I put the string into slash notation to make this "easier" to parse):
and here is the exact same string in hex because slashcodes can be confusing:
0000 0002 1210 4261 6374 6572 6961 2E6C 7663 6C61 7373 0000 0005 0006 0007 0008 0001 0000 0000 0009 0000 0000 0000 000C 0000 0004 6162 6364 0000 0000
The first 4 bytes are NumLevels. NumLevels in this case is 2. So we have a class that has one ancestor between it and LabVIEW Object.
Next is the PStr that is the name of the class: Bacteria.lvclass. After that are 2 NULL pad bytes to get the length back to a multiple of four.
Next is the first version number: 220.127.116.11. That's the version number for Bacteria.lvclass. Next is the second version number: 18.104.22.168. That's the version number for Bacteria's parent class. We'd have to have Bacteria in memory to ask it "Hey, who was your parent class back when you were version 22.214.171.124?"
Next come the data blocks. The first data block has data size 0. That means that we'll just assume that the parent cluster was the default default value. The second data block has data size 15. So the next 15 bytes are a flattened cluster of the cluster of Bacteria when it was version 126.96.36.199. Remember that the Bacteria.lvclass currently in memory might be a much later version of the class -- LabVIEW will automatically handle the conversion for you (which you can read all about on NI.com). In this case, it looks like those 15 bytes of data contain a string ("abcd") and a couple other cluster elements.
IMPORTANT NOTE: The flattened form of LV data is portable to any endian platform. We always flatten int32s, uInt32s and other data types into big endian order. If you are on a little endian machine (any Mac, Windows or Linux box is little endian), make sure that your custom write/write functions take care of reversing the bytes.