/// <summary> /// Add new FBQE. Returns FBQE index /// </summary> /// <param name="address"></param> /// <param name="length"></param> /// <param name="left"></param> /// <param name="right"></param> public void AddFBQE(long address, long length, int left, int right) { FBQE f, fu; // Get free element int n = FIRST_Q; f = GetFBQE(n); // Update free queue FIRST_Q = f.NEXT; FBQE f1 = GetFBQE(f.NEXT); f1.PREV = -1; SerializeFBQE(f1); // Update FBQE f.SG = DEFS.FBQE_SIGNATURE; f.ADDRESS_START = address; f.ADDRESS_END = address + length; f.LENGTH = length; f.PREV = left; f.NEXT = right; f.index = n; SerializeFBQE(f); //Add to BTrees BT_FBQE_Address.Insert(address, (long)f.index); BT_FBQE_Size.Insert(length, (long)f.index); // Update chain if (left < 0) { FIRST = n; } else { fu = GetFBQE(left); fu.NEXT = n; SerializeFBQE(fu); } if (right < 0) { LAST = n; } else { fu = GetFBQE(right); fu.PREV = n; SerializeFBQE(fu); } FREE -= 1; }
/// <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(); } }