You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
339 lines
13 KiB
339 lines
13 KiB
//
|
|
// Property.cs
|
|
//
|
|
// Author: Kees van Spelde <sicos2002@hotmail.com>
|
|
//
|
|
// Copyright (c) 2013-2018 Magic-Sessions. (www.magic-sessions.com)
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
// THE SOFTWARE.
|
|
//
|
|
|
|
using System;
|
|
using System.IO;
|
|
using System.Text;
|
|
using MsgReader.Exceptions;
|
|
// ReSharper disable InconsistentNaming
|
|
|
|
namespace MsgReader.Outlook
|
|
{
|
|
/// <summary>
|
|
/// Pointer to a variable of type SPropValue that specifies the property value array describing the properties
|
|
/// for the recipient. The rgPropVals member can be NULL.
|
|
/// </summary>
|
|
public class Property
|
|
{
|
|
#region Properties
|
|
/// <summary>
|
|
/// The id of the property
|
|
/// </summary>
|
|
internal ushort Id { get; }
|
|
|
|
/// <summary>
|
|
/// Returns the Property as a readable string without the streamprefix and type
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public string ShortName => Id.ToString("X4");
|
|
|
|
/// <summary>
|
|
/// Returns the Property as a readable string
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public string Name => MapiTags.SubStorageStreamPrefix + Id.ToString("X4") + ((ushort)Type).ToString("X4");
|
|
|
|
/// <summary>
|
|
/// The <see cref="MsgReader.Outlook.PropertyType" />
|
|
/// </summary>
|
|
internal PropertyType Type { get; }
|
|
|
|
/// <summary>
|
|
/// Returns <c>true</c> when this property is part of a multivalue property
|
|
/// </summary>
|
|
internal bool MultiValue { get; }
|
|
|
|
/// <summary>
|
|
/// The property data
|
|
/// </summary>
|
|
internal byte[] Data { get; }
|
|
|
|
/// <summary>
|
|
/// Returns <see cref="Data" /> as an integer when <see cref="Type" /> is set to
|
|
/// <see cref="MsgReader.Outlook.PropertyType.PT_SHORT" />,
|
|
/// <see cref="MsgReader.Outlook.PropertyType.PT_LONG" /> or <see cref="MsgReader.Outlook.PropertyType.PT_ERROR" />
|
|
/// </summary>
|
|
/// <exception cref="MRInvalidProperty">Raised when the <see cref="Type"/> is not <see cref="MsgReader.Outlook.PropertyType.PT_SHORT"/> or
|
|
/// <see cref="MsgReader.Outlook.PropertyType.PT_LONG"/></exception>
|
|
internal int ToInt
|
|
{
|
|
get
|
|
{
|
|
switch (Type)
|
|
{
|
|
case PropertyType.PT_SHORT:
|
|
return BitConverter.ToInt16(Data, 0);
|
|
|
|
case PropertyType.PT_LONG:
|
|
return BitConverter.ToInt32(Data, 0);
|
|
|
|
default:
|
|
throw new MRInvalidProperty("Type is not PT_SHORT or PT_LONG");
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns <see cref="Data" /> as a single when <see cref="Type" /> is set to
|
|
/// <see cref="MsgReader.Outlook.PropertyType.PT_FLOAT" />
|
|
/// </summary>
|
|
/// <exception cref="MRInvalidProperty">Raised when the <see cref="Type"/> is not <see cref="MsgReader.Outlook.PropertyType.PT_FLOAT"/></exception>
|
|
internal float ToSingle
|
|
{
|
|
get
|
|
{
|
|
switch (Type)
|
|
{
|
|
case PropertyType.PT_FLOAT:
|
|
return BitConverter.ToSingle(Data, 0);
|
|
|
|
default:
|
|
throw new MRInvalidProperty("Type is not PT_FLOAT");
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns <see cref="Data" /> as a single when <see cref="Type" /> is set to
|
|
/// <see cref="MsgReader.Outlook.PropertyType.PT_DOUBLE" />
|
|
/// </summary>
|
|
/// <exception cref="MRInvalidProperty">Raised when the <see cref="Type"/> is not <see cref="MsgReader.Outlook.PropertyType.PT_DOUBLE"/></exception>
|
|
internal double ToDouble
|
|
{
|
|
get
|
|
{
|
|
switch (Type)
|
|
{
|
|
case PropertyType.PT_DOUBLE:
|
|
return BitConverter.ToDouble(Data, 0);
|
|
|
|
default:
|
|
throw new MRInvalidProperty("Type is not PT_DOUBLE");
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns <see cref="Data" /> as a decimal when <see cref="Type" /> is set to
|
|
/// <see cref="MsgReader.Outlook.PropertyType.PT_FLOAT" />
|
|
/// </summary>
|
|
/// <exception cref="MRInvalidProperty">Raised when the <see cref="Type"/> is not <see cref="MsgReader.Outlook.PropertyType.PT_FLOAT"/></exception>
|
|
internal decimal ToDecimal
|
|
{
|
|
get
|
|
{
|
|
switch (Type)
|
|
{
|
|
case PropertyType.PT_FLOAT:
|
|
return ByteArrayToDecimal(Data, 0);
|
|
|
|
default:
|
|
throw new MRInvalidProperty("Type is not PT_FLOAT");
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns <see cref="Data" /> as a datetime when <see cref="Type" /> is set to
|
|
/// <see cref="MsgReader.Outlook.PropertyType.PT_APPTIME" />
|
|
/// or <see cref="MsgReader.Outlook.PropertyType.PT_SYSTIME" />
|
|
/// </summary>
|
|
/// <exception cref="MRInvalidProperty">Raised when the <see cref="Type"/> is not set to <see cref="MsgReader.Outlook.PropertyType.PT_APPTIME"/> or
|
|
/// <see cref="MsgReader.Outlook.PropertyType.PT_SYSTIME"/></exception>
|
|
internal DateTime ToDateTime
|
|
{
|
|
get
|
|
{
|
|
switch (Type)
|
|
{
|
|
case PropertyType.PT_APPTIME:
|
|
var oaDate = BitConverter.ToDouble(Data, 0);
|
|
return DateTime.FromOADate(oaDate);
|
|
|
|
case PropertyType.PT_SYSTIME:
|
|
var fileTime = BitConverter.ToInt64(Data, 0);
|
|
return DateTime.FromFileTime(fileTime);
|
|
|
|
default:
|
|
throw new MRInvalidProperty("Type is not PT_APPTIME or PT_SYSTIME");
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns <see cref="Data" /> as a boolean when <see cref="Type" /> is set to <see cref="MsgReader.Outlook.PropertyType.PT_BOOLEAN" />
|
|
/// </summary>
|
|
/// <exception cref="MRInvalidProperty">Raised when the <see cref="Type"/> is not set to <see cref="MsgReader.Outlook.PropertyType.PT_BOOLEAN"/></exception>
|
|
internal bool ToBool
|
|
{
|
|
get
|
|
{
|
|
switch (Type)
|
|
{
|
|
case PropertyType.PT_BOOLEAN:
|
|
return BitConverter.ToBoolean(Data, 0);
|
|
|
|
default:
|
|
throw new MRInvalidProperty("Type is not PT_BOOLEAN");
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns <see cref="Data" /> as a boolean when <see cref="Type" /> is set to
|
|
/// <see cref="MsgReader.Outlook.PropertyType.PT_LONGLONG" />
|
|
/// </summary>
|
|
/// <exception cref="MRInvalidProperty">Raised when the <see cref="Type"/> is not set to <see cref="MsgReader.Outlook.PropertyType.PT_LONGLONG"/></exception>
|
|
internal long ToLong
|
|
{
|
|
get
|
|
{
|
|
switch (Type)
|
|
{
|
|
case PropertyType.PT_LONG:
|
|
case PropertyType.PT_LONGLONG:
|
|
return BitConverter.ToInt64(Data, 0);
|
|
|
|
default:
|
|
throw new MRInvalidProperty("Type is not PtypInteger64");
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns <see cref="Data" /> as a string when <see cref="Type" /> is set to <see cref="MsgReader.Outlook.PropertyType.PT_UNICODE" />
|
|
/// or <see cref="MsgReader.Outlook.PropertyType.PT_STRING8" />
|
|
/// </summary>
|
|
/// <exception cref="MRInvalidProperty">Raised when the <see cref="Type"/> is not set to <see cref="MsgReader.Outlook.PropertyType.PT_UNICODE"/>
|
|
/// or <see cref="MsgReader.Outlook.PropertyType.PT_STRING8" /></exception>
|
|
public new string ToString
|
|
{
|
|
get
|
|
{
|
|
switch (Type)
|
|
{
|
|
case PropertyType.PT_UNICODE:
|
|
case PropertyType.PT_STRING8:
|
|
var encoding = Type == PropertyType.PT_STRING8 ? Encoding.Default : Encoding.Unicode;
|
|
using (var memoryStream = new MemoryStream(Data))
|
|
using (var streamReader = new StreamReader(memoryStream, encoding))
|
|
{
|
|
var streamContent = streamReader.ReadToEnd();
|
|
return streamContent.TrimEnd('\0');
|
|
}
|
|
|
|
default:
|
|
var encoding2 = Type == PropertyType.PT_STRING8 ? Encoding.Default : Encoding.Unicode;
|
|
using (var memoryStream = new MemoryStream(Data))
|
|
using (var streamReader = new StreamReader(memoryStream, encoding2))
|
|
{
|
|
var streamContent = streamReader.ReadToEnd();
|
|
return streamContent.TrimEnd('\0');
|
|
}
|
|
//throw new MRInvalidProperty("Type is not PT_UNICODE or PT_STRING8");
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns <see cref="Data" /> as a byte[] when <see cref="Type" /> is set to <see cref="MsgReader.Outlook.PropertyType.PT_BINARY" />
|
|
/// <see cref="MsgReader.Outlook.PropertyType.PT_OBJECT" />
|
|
/// </summary>
|
|
/// <exception cref="MRInvalidProperty">Raised when the <see cref="Type"/> is not set to <see cref="MsgReader.Outlook.PropertyType.PT_BINARY"/></exception>
|
|
public byte[] ToBinary
|
|
{
|
|
get
|
|
{
|
|
switch (Type)
|
|
{
|
|
case PropertyType.PT_BINARY:
|
|
return Data;
|
|
|
|
default:
|
|
throw new MRInvalidProperty("Type is not PT_BINARY");
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns <see cref="Data" /> as a Guid when <see cref="Type" /> is set to <see cref="MsgReader.Outlook.PropertyType.PT_CLSID" />
|
|
/// <see cref="MsgReader.Outlook.PropertyType.PT_OBJECT" />
|
|
/// </summary>
|
|
/// <exception cref="MRInvalidProperty">Raised when the <see cref="Type"/> is not set to <see cref="MsgReader.Outlook.PropertyType.PT_BINARY"/></exception>
|
|
public Guid ToGuid
|
|
{
|
|
get
|
|
{
|
|
switch (Type)
|
|
{
|
|
case PropertyType.PT_CLSID:
|
|
return new Guid(Data);
|
|
|
|
default:
|
|
throw new MRInvalidProperty("Type is not PT_CLSID");
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region ByteArrayToDecimal
|
|
/// <summary>
|
|
/// Converts a byte array to a decimal
|
|
/// </summary>
|
|
/// <param name="source">The byte array</param>
|
|
/// <param name="offset">The offset to start reading</param>
|
|
/// <returns></returns>
|
|
private static decimal ByteArrayToDecimal(byte[] source, int offset)
|
|
{
|
|
var i1 = BitConverter.ToInt32(source, offset);
|
|
var i2 = BitConverter.ToInt32(source, offset + 4);
|
|
var i3 = BitConverter.ToInt32(source, offset + 8);
|
|
var i4 = BitConverter.ToInt32(source, offset + 12);
|
|
|
|
return new decimal(new[] { i1, i2, i3, i4 });
|
|
}
|
|
#endregion
|
|
|
|
#region Constructor
|
|
/// <summary>
|
|
/// Creates this object and sets all its propertues
|
|
/// </summary>
|
|
/// <param name="id">The id of the property</param>
|
|
/// <param name="type">The <see cref="MsgReader.Outlook.PropertyType" /></param>
|
|
/// <param name="data">The property data</param>
|
|
/// <param name="multiValue">Set to <c>true</c> to indicate that this property is part of a
|
|
/// multivalue property</param>
|
|
public Property(ushort id, PropertyType type, byte[] data, bool multiValue = false)
|
|
{
|
|
Id = id;
|
|
Type = type;
|
|
Data = data;
|
|
MultiValue = multiValue;
|
|
}
|
|
#endregion
|
|
}
|
|
}
|