Author Topic: Read AllAttributes column (image type) in UCS db?  (Read 9191 times)

Offline Rutger

  • Newbie
  • *
  • Posts: 23
  • Karma: 0
Re: Read AllAttributes column (image type) in UCS db?
« Reply #15 on: October 26, 2016, 12:21:19 PM »
You can decode it using the following, example, ruby script:

[code]

data = event['InteractionAllAttributes'];

# Filepointer - could be two bytes and two bytes for number of segments, not sure
sizeBytes = 3;
fp = 0;

# 16 bit big endian
length = data[fp, sizeBytes].unpack('n')[0];

segmentCountBytes = 1;
fp += sizeBytes;

segmentCount = data[fp, segmentCountBytes].unpack('C')[0];


# Skip 0x00, not sure about this - could be it is 16 bit int
fp += 1;

segmentSizeBytes = 2;
segmentIdx = 0;

event['InteractionAttributes'] = {};

while (fp < length)

# Skip 0x00 - todo, is part of header?
  fp += 1;

  # Key - Value structure
  segmentLength = data[fp, segmentSizeBytes].unpack('n')[0];
  fp += segmentSizeBytes;
  key = data[fp, segmentLength];
  fp += segmentLength;

  segmentLength = data[fp, segmentSizeBytes].unpack('n')[0];
  fp += segmentSizeBytes;
  # Show non readable characters as .
  value = data[fp, segmentLength].gsub(/[^[:print:]]/,'.');
  fp += segmentLength;

  event['InteractionAttributes'][key] = value.to_s;

end;


[/code]

Offline roman.smirnov

  • Newbie
  • *
  • Posts: 14
  • Karma: 0
Re: Read AllAttributes column (image type) in UCS db?
« Reply #16 on: January 31, 2025, 04:57:36 AM »
If somebody is still interested in this topic, here is a draft C# implementation of a KVC conversion, based on post by Rutger.
Types handling have to be improved. Right now it works for strings, sub-kvc and ints. For other types I don't have examples on my system right now.

[code=csharp]
        private Dictionary<string, object> ReadKeyValueCollection(byte[] buffer, int offset = 0)
        {
            var kvc = new Dictionary<string, object>();
            int fp = offset;

            int length = BinaryPrimitives.ReverseEndianness(BitConverter.ToInt16(buffer, fp));
            fp += 2;
           
            int pairs = BinaryPrimitives.ReverseEndianness(BitConverter.ToInt16(buffer, fp));
            fp += 2;

            while (fp - offset < length)
            {
                int type = BitConverter.ToChar(buffer, fp);
                fp += 1;

                int keyLength = BinaryPrimitives.ReverseEndianness(BitConverter.ToInt16(buffer, fp));
                fp += 2;

                var key = ASCIIEncoding.Default.GetString(buffer, fp, keyLength);
                fp += keyLength;

                int valueLength = BinaryPrimitives.ReverseEndianness(BitConverter.ToInt16(buffer, fp));
                fp += 2;

                kvc[key] = ReadValue(type, buffer, fp, valueLength);
                fp += valueLength;
            }

            return kvc;
        }

        private object ReadValue(int type, byte[] buffer, int offset, int length)
        {
            // 0 - str, 1 - int, 2 - utf16???, 3 - lst
            switch (type)
            {
                case 1: return ReadInt(buffer, offset, length);
                case 3: return ReadKeyValueCollection(buffer, offset);
                default: return ASCIIEncoding.Default.GetString(buffer, offset, length);
            }
        }

        private object ReadInt(byte[] buffer, int offset, int length)
        {
            switch (length)
            {
                case 1: return BitConverter.ToChar(buffer, offset);
                case 2: return BinaryPrimitives.ReverseEndianness(BitConverter.ToInt16(buffer, offset));
                case 4: return BinaryPrimitives.ReverseEndianness(BitConverter.ToInt32(buffer, offset));
                case 8: return BinaryPrimitives.ReverseEndianness(BitConverter.ToInt64(buffer, offset));
                default: return BinaryPrimitives.ReverseEndianness(BitConverter.ToInt16(buffer, offset));
            }
        }
[/code]