/// <summary> /// Gets an entry from the stream represented by the PropertyEntry /// </summary> /// <param name="entry">A property entry</param> /// <param name="storage">The storage to read from</param> /// <returns>An object representing the variable-length property</returns> internal object GetVariableLengthProperty(PropertyEntry entry, string storage = null) { object obj; CFStream stream; //Get the value of the property. string name = string.Format("__substg1.0_{0:X4}{1:X4}", entry.PropertyTag.ID, (short)entry.PropertyTag.Type); if (storage == null) stream = _compoundFile.RootStorage.GetStream(name); else stream = _compoundFile.RootStorage.GetStorage(storage).GetStream(name); switch (entry.PropertyTag.Type) { case PropertyType.PtypString: obj = Encoding.Unicode.GetString(stream.GetData()); break; case PropertyType.PtypString8: obj = Encoding.Default.GetString(stream.GetData()); break; case PropertyType.PtypBinary: obj = stream.GetData(); //binary data. Just return as-is. May be in the following format: https://msdn.microsoft.com/en-us/library/dd947045(v=office.12).aspx break; case PropertyType.PtypGuid: obj = new Guid(stream.GetData()); break; case PropertyType.PtypObject: //See https://msdn.microsoft.com/en-us/library/ee200950(v=exchg.80).aspx //Drink lots! default: obj = null; break; } return obj; }
internal NamedProperty MapProperty(PropertyEntry entry) { int entryStreamIndex = GetEntryStreamIndex(entry.PropertyTag.ID); //find the index into the entry stream var propEntry = _propParser.Entries[entryStreamIndex]; //grab the relevent entry int guidIndex = GetGuidStreamIndex(propEntry.GUIDIndex); //find the index into the guid stream Guid guid = _propParser.Guids[guidIndex]; NamedProperty namedProperty = new NamedProperty() { GUID = guid, Entry = entry, ID = propEntry.NameIdentifier }; if (propEntry.IsString) { string name = _propParser.ReadStringStream(propEntry.NameIdentifier); namedProperty.Name = name; } return namedProperty; }
internal static object ParseEntry(PropertyEntry entry) { object obj = null; if (IsFixedLength(entry.PropertyTag.Type)) { switch (entry.PropertyTag.Type) { //ints case PropertyType.PtypInteger16: obj = BitConverter.ToInt16(entry.Value, 0); break; case PropertyType.PtypInteger32: case PropertyType.PtypErrorCode: obj = BitConverter.ToInt32(entry.Value, 0); break; case PropertyType.PtypInteger64: case PropertyType.PtypCurrency: obj = BitConverter.ToInt64(entry.Value, 0); break; //floats case PropertyType.PtypFloating32: obj = BitConverter.ToSingle(entry.Value, 0); break; case PropertyType.PtypFloating64: //case PropertyType.PtypFloatingTime: obj = BitConverter.ToDouble(entry.Value, 0); break; //other case PropertyType.PtypBoolean: obj = BitConverter.ToBoolean(entry.Value, 0); break; //PtypTime - 8 bytes; a 64-bit integer representing the number of 100-nanosecond intervals since January 1, 1601 case PropertyType.PtypTime: DateTime dt = new DateTime(1601, 1, 1, 0, 0, 0, DateTimeKind.Utc); obj = dt.AddTicks(BitConverter.ToInt64(entry.Value, 0)); break; default: return null; } } return obj; }
/// <summary> /// This will read an entry from the property stream /// </summary> /// <param name="entry">An array of bytes representing an entry</param> /// <returns>A parsed PropertyEntry structure</returns> private PropertyEntry ReadPropertyEntry(byte[] entry) { PropertyEntry propEntry; PropertyTag tag = new PropertyTag(); tag.Type = (PropertyType)BitConverter.ToInt16(entry, 0); tag.ID = BitConverter.ToUInt16(entry, 2); if (TypeMapper.IsFixedLength(tag.Type)) { propEntry = new PropertyEntry(); } else { propEntry = new VariableLengthPropertyEntry(); } propEntry.PropertyTag = tag; propEntry.Flags = BitConverter.ToInt32(entry, 4); propEntry.Value = entry.Skip(8).ToArray(); return propEntry; }