/// <summary> /// Load/renew cache if versions doesnt match /// </summary> private void sync_cache() { if ((CURRENT_ALLOC == base.ALLOC) & (FCache != null)) { return; } else { if (base.ALLOC == ALLOC_TYPE_RAW) { if (FreeSpace >= 0) { FCache.Clear(); FCache = null; FCacheTree = null; FreeSpace = -1; set_alloc(ALLOC_RESET); } } else { deserialize(); // Load and cache new version of the fields } } }
/// <summary> /// Build binary trees for FBQE /// </summary> internal void BuildBTrees() { BT_FBQE_Address = new VSBBTree("ADDR", 0, true); BT_FBQE_Size = new VSBBTree("SIZE", 0, false); int i = this.FIRST; while (i >= 0) { FBQE f = GetFBQE(i); BT_FBQE_Address.Insert(f.ADDRESS_START, (long)f.index); BT_FBQE_Size.Insert(f.LENGTH, (long)f.index); i = f.NEXT; } }
/// <summary> /// Load cahce fields /// </summary> private void deserialize() { CURRENT_ALLOC = base.ALLOC; // Create/cleanup fields cache if (FCache == null) { FCache = new List <FieldCache>(32); } else { FCache.Clear(); } // Create cache binary tree FCacheTree = new VSBBTree(FCT_NAME, 32, true); // Read variable data into the buffer byte[] data = base.ReadBytes(base.FIXED, (long)FIELDS_SIZE); int offset = FIRST_FIELD_OFFSET_REL; // Offset inside buffer (relative, doesn't include fixed part) int n = (int)FIELDS_NUMBER; // Number of fields // Load fields for (int i = 0; i < n; i++) { // Create field FieldCache f = new FieldCache(); f.OFFSET = offset; // Field offset in object f.TYPE = data[offset + FIELD_TYPE_POS]; // Field type byte name_length = data[offset + FIELD_NAME_LENGTH_POS]; // Name length f.NAME = VSLib.ConvertByteToString(VSLib.GetByteArray(data, (int)(offset + FIELD_NAME_POS), (int)name_length)); // Name int value_offset = FIELD_FIXED_LENGTH + name_length; // Value offset // Get value depending on type if ((f.TYPE == FIELD_TYPE_BYTE) | (f.TYPE == FIELD_TYPE_SHORT) | (f.TYPE == FIELD_TYPE_DATETIME)) { f.DATA_OFFSET = value_offset; // Shift to value offset f.LENGTH = FIELD_LENGTHS[f.TYPE]; } else if ((f.TYPE == FIELD_TYPE_INT) | (f.TYPE == FIELD_TYPE_LONG)) { f.DATA_OFFSET = value_offset + 1; // Shift to value offset (+ 1 byte length) f.LENGTH = (int)data[offset + value_offset]; } else if ((f.TYPE == FIELD_TYPE_BYTES) | (f.TYPE == FIELD_TYPE_STRING)) { int l = (int)data[offset + value_offset]; // Read number of length bytes if (l > 0) { byte[] ba = VSLib.GetByteArray(data, (int)(offset + value_offset + 1), (int)l); // Read length f.LENGTH = VSLib.ConvertByteToInt(decompress(ba, FIELD_TYPE_LONG)); } else { f.LENGTH = 0; } f.DATA_OFFSET = value_offset + 1 + l; } else { throw new VSException(DEFS.E0029_INVALID_FIELD_TYPE_CODE, "- " + f.TYPE.ToString()); } f.OLDLENGTH = f.LENGTH; f.STATE = STATE_LOADED; f.FULL_LENGTH = f.DATA_OFFSET + f.LENGTH; if (f.LENGTH > 0) { f.VALUE = VSLib.GetByteArray(data, (int)(offset + f.DATA_OFFSET), (int)f.LENGTH); } else { f.VALUE = new byte[0]; } offset += f.FULL_LENGTH; f.DELETED = false; // Add to cache FCache.Add(f); // Add to the tree FCacheTree.Insert(f.NAME, i); } FreeSpace = (int)(this.Size - base.FIXED - offset); }
/// <summary> /// Generic Set /// </summary> /// <param name="serialize">false = do not write (for multiple values at once)</param> /// <returns></returns> private void set_field(string name, byte type, byte[] data, bool serialize = true) { string nm = name.Trim(); if ((nm.Length < 1) | (nm.Length > 255)) { throw new VSException(DEFS.E0027_FIELD_WRITE_ERROR_CODE, "- " + name + " : name length shall be between 1 and 255"); } FieldCache fc; int index; byte[] compressed_length = null; // Compressed length // Initialize fields structure if (base.ALLOC == ALLOC_TYPE_RAW) { index = -1; set_alloc(ALLOC_INIT); FreeSpace = (int)(this.Size - FIRST_FIELD_OFFSET_ABS); FIELDS_NUMBER = (short)0; FIELDS_SIZE = FIRST_FIELD_OFFSET_REL; // Create cache FCache = new List <FieldCache>(32); // Create cache binary tree FCacheTree = new VSBBTree(FCT_NAME, 32, true); } else { index = find_field(nm, type); } // Field is not found in cache, add new field if (index < 0) { fc = new FieldCache(); fc.STATE = STATE_NEW; // New field fc.OFFSET = -1; fc.NAME = nm; fc.VALUE = compress(data, type); fc.LENGTH = fc.VALUE.Length; fc.OLDLENGTH = fc.VALUE.Length; fc.TYPE = type; fc.DATA_OFFSET = FIELD_NAME_POS + fc.NAME.Length; if ((fc.TYPE == FIELD_TYPE_INT) | (fc.TYPE == FIELD_TYPE_LONG)) { fc.DATA_OFFSET += 1; } else if ((fc.TYPE == FIELD_TYPE_BYTES) | (fc.TYPE == FIELD_TYPE_STRING)) { compressed_length = compress(VSLib.ConvertLongToByte(fc.LENGTH), FIELD_TYPE_LONG); fc.DATA_OFFSET += (compressed_length.Length + 1); } fc.FULL_LENGTH = fc.DATA_OFFSET + fc.LENGTH; // Add to the tree FCacheTree.Insert(fc.NAME, (long)FCache.Count); // Add to the cache FCache.Add(fc); } else { // Field found in cache, update fc = FCache[index]; byte[] b = compress(data, type); if (b.Length == fc.LENGTH) { if (b.Length == 0) { return; } bool eq = true; for (int i = 0; i < b.Length; i++) { if (b[i] != fc.VALUE[i]) { eq = false; break; } } if (eq) { return; // Value not changed } for (int i = 0; i < b.Length; i++) { fc.VALUE[i] = b[i]; } base.Write(base.FIXED + fc.OFFSET + fc.DATA_OFFSET, b, fc.LENGTH); fc.STATE = STATE_LOADED; FCache.RemoveAt(index); FCache.Insert(index, fc); set_alloc(ALLOC_RENEW); return; } fc.VALUE = b; fc.LENGTH = fc.VALUE.Length; fc.DATA_OFFSET = FIELD_NAME_POS + fc.NAME.Length; if ((fc.TYPE == FIELD_TYPE_INT) | (fc.TYPE == FIELD_TYPE_LONG)) { fc.DATA_OFFSET += 1; } else if ((fc.TYPE == FIELD_TYPE_BYTES) | (fc.TYPE == FIELD_TYPE_STRING)) { compressed_length = compress(VSLib.ConvertLongToByte(fc.LENGTH), FIELD_TYPE_LONG); fc.DATA_OFFSET += (compressed_length.Length + 1); } fc.FULL_LENGTH = fc.DATA_OFFSET + fc.LENGTH; // Update full length fc.STATE = STATE_UPDATED; FCache.RemoveAt(index); FCache.Insert(index, fc); } if (serialize) { this.serialize(); } }