Obsolete old migrations and exif code (#13382)

* Obsoleted and deleted internal migrations + Enabled breaking changes checks agains v11.0.0-rc1

* Obsoleted and deleted internal exif stuff

* Added CompatibilitySuppressions.xml

* Change GenerateCompatibilitySuppressionFile
This commit is contained in:
Bjarke Berg
2022-11-14 12:40:06 +01:00
committed by GitHub
parent 0e1095061e
commit 616d092577
139 changed files with 151 additions and 8877 deletions

1
.gitignore vendored
View File

@@ -107,3 +107,4 @@ preserve.belle
/src/Umbraco.Web.UI/appsettings-schema.*.json
/tests/Umbraco.Tests.Integration/appsettings-schema.json
/tests/Umbraco.Tests.Integration/appsettings-schema.*.json
/src/Umbraco.Cms/appsettings-schema.json

View File

@@ -29,9 +29,9 @@
<!-- Package Validation -->
<PropertyGroup>
<GenerateCompatibilitySuppressionFile>false</GenerateCompatibilitySuppressionFile>
<EnablePackageValidation>true</EnablePackageValidation>
<!-- TODO: Change to 11.0.0 and remove all CompatibilitySuppressions.xml files when final version shipped -->
<PackageValidationBaselineVersion>10.2.1</PackageValidationBaselineVersion>
<PackageValidationBaselineVersion>11.0.0-rc1</PackageValidationBaselineVersion>
<EnableStrictModeForCompatibleFrameworksInPackage>true</EnableStrictModeForCompatibleFrameworksInPackage>
<EnableStrictModeForCompatibleTfms>true</EnableStrictModeForCompatibleTfms>
</PropertyGroup>

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Suppression>
<DiagnosticId>PKV006</DiagnosticId>
<Target>net6.0</Target>
</Suppression>
</Suppressions>

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Suppression>
<DiagnosticId>PKV006</DiagnosticId>
<Target>net6.0</Target>
</Suppression>
</Suppressions>

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Suppression>
<DiagnosticId>PKV006</DiagnosticId>
<Target>net6.0</Target>
</Suppression>
</Suppressions>

View File

@@ -1,7 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Suppression>
<DiagnosticId>PKV006</DiagnosticId>
<Target>net6.0</Target>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Umbraco.Cms.Core.Deploy.IDataTypeConfigurationConnector.FromArtifact(Umbraco.Cms.Core.Models.IDataType,System.String,Umbraco.Cms.Core.Deploy.IContextCache)</Target>
<Left>lib/net7.0/Umbraco.Core.dll</Left>
<Right>lib/net7.0/Umbraco.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Umbraco.Cms.Core.Deploy.IDataTypeConfigurationConnector.ToArtifact(Umbraco.Cms.Core.Models.IDataType,System.Collections.Generic.ICollection{Umbraco.Cms.Core.Deploy.ArtifactDependency},Umbraco.Cms.Core.Deploy.IContextCache)</Target>
<Left>lib/net7.0/Umbraco.Core.dll</Left>
<Right>lib/net7.0/Umbraco.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Umbraco.Cms.Core.Deploy.IServiceConnector.GetArtifact(System.Object,Umbraco.Cms.Core.Deploy.IContextCache)</Target>
<Left>lib/net7.0/Umbraco.Core.dll</Left>
<Right>lib/net7.0/Umbraco.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Umbraco.Cms.Core.Deploy.IServiceConnector.GetArtifact(Umbraco.Cms.Core.Udi,Umbraco.Cms.Core.Deploy.IContextCache)</Target>
<Left>lib/net7.0/Umbraco.Core.dll</Left>
<Right>lib/net7.0/Umbraco.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Umbraco.Cms.Core.Deploy.IValueConnector.FromArtifact(System.String,Umbraco.Cms.Core.Models.IPropertyType,System.Object,Umbraco.Cms.Core.Deploy.IContextCache)</Target>
<Left>lib/net7.0/Umbraco.Core.dll</Left>
<Right>lib/net7.0/Umbraco.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Umbraco.Cms.Core.Deploy.IValueConnector.ToArtifact(System.Object,Umbraco.Cms.Core.Models.IPropertyType,System.Collections.Generic.ICollection{Umbraco.Cms.Core.Deploy.ArtifactDependency},Umbraco.Cms.Core.Deploy.IContextCache)</Target>
<Left>lib/net7.0/Umbraco.Core.dll</Left>
<Right>lib/net7.0/Umbraco.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
</Suppressions>

View File

@@ -1,346 +0,0 @@
namespace Umbraco.Cms.Core.Media.Exif;
/// <summary>
/// An endian-aware converter for converting between base data types
/// and an array of bytes.
/// </summary>
internal class BitConverterEx
{
#region Public Enums
/// <summary>
/// Represents the byte order.
/// </summary>
public enum ByteOrder
{
LittleEndian = 1,
BigEndian = 2,
}
#endregion
#region Member Variables
private readonly ByteOrder mFrom;
private readonly ByteOrder mTo;
#endregion
#region Constructors
public BitConverterEx(ByteOrder from, ByteOrder to)
{
mFrom = from;
mTo = to;
}
#endregion
#region Properties
/// <summary>
/// Indicates the byte order in which data is stored in this platform.
/// </summary>
public static ByteOrder SystemByteOrder =>
BitConverter.IsLittleEndian ? ByteOrder.LittleEndian : ByteOrder.BigEndian;
#endregion
#region Predefined Values
/// <summary>
/// Returns a bit converter that converts between little-endian and system byte-order.
/// </summary>
public static BitConverterEx LittleEndian => new BitConverterEx(ByteOrder.LittleEndian, SystemByteOrder);
/// <summary>
/// Returns a bit converter that converts between big-endian and system byte-order.
/// </summary>
public static BitConverterEx BigEndian => new BitConverterEx(ByteOrder.BigEndian, SystemByteOrder);
/// <summary>
/// Returns a bit converter that does not do any byte-order conversion.
/// </summary>
public static BitConverterEx SystemEndian => new BitConverterEx(SystemByteOrder, SystemByteOrder);
#endregion
#region Static Methods
/// <summary>
/// Converts the given array of bytes to a Unicode character.
/// </summary>
public static char ToChar(byte[] value, long startIndex, ByteOrder from, ByteOrder to)
{
var data = CheckData(value, startIndex, 2, from, to);
return BitConverter.ToChar(data, 0);
}
/// <summary>
/// Converts the given array of bytes to a 16-bit unsigned integer.
/// </summary>
public static ushort ToUInt16(byte[] value, long startIndex, ByteOrder from, ByteOrder to)
{
var data = CheckData(value, startIndex, 2, from, to);
return BitConverter.ToUInt16(data, 0);
}
/// <summary>
/// Converts the given array of bytes to a 32-bit unsigned integer.
/// </summary>
public static uint ToUInt32(byte[] value, long startIndex, ByteOrder from, ByteOrder to)
{
var data = CheckData(value, startIndex, 4, from, to);
return BitConverter.ToUInt32(data, 0);
}
/// <summary>
/// Converts the given array of bytes to a 64-bit unsigned integer.
/// </summary>
public static ulong ToUInt64(byte[] value, long startIndex, ByteOrder from, ByteOrder to)
{
var data = CheckData(value, startIndex, 8, from, to);
return BitConverter.ToUInt64(data, 0);
}
/// <summary>
/// Converts the given array of bytes to a 16-bit signed integer.
/// </summary>
public static short ToInt16(byte[] value, long startIndex, ByteOrder from, ByteOrder to)
{
var data = CheckData(value, startIndex, 2, from, to);
return BitConverter.ToInt16(data, 0);
}
/// <summary>
/// Converts the given array of bytes to a 32-bit signed integer.
/// </summary>
public static int ToInt32(byte[] value, long startIndex, ByteOrder from, ByteOrder to)
{
var data = CheckData(value, startIndex, 4, from, to);
return BitConverter.ToInt32(data, 0);
}
/// <summary>
/// Converts the given array of bytes to a 64-bit signed integer.
/// </summary>
public static long ToInt64(byte[] value, long startIndex, ByteOrder from, ByteOrder to)
{
var data = CheckData(value, startIndex, 8, from, to);
return BitConverter.ToInt64(data, 0);
}
/// <summary>
/// Converts the given array of bytes to a single precision floating number.
/// </summary>
public static float ToSingle(byte[] value, long startIndex, ByteOrder from, ByteOrder to)
{
var data = CheckData(value, startIndex, 4, from, to);
return BitConverter.ToSingle(data, 0);
}
/// <summary>
/// Converts the given array of bytes to a double precision floating number.
/// </summary>
public static double ToDouble(byte[] value, long startIndex, ByteOrder from, ByteOrder to)
{
var data = CheckData(value, startIndex, 8, from, to);
return BitConverter.ToDouble(data, 0);
}
/// <summary>
/// Converts the given 16-bit unsigned integer to an array of bytes.
/// </summary>
public static byte[] GetBytes(ushort value, ByteOrder from, ByteOrder to)
{
var data = BitConverter.GetBytes(value);
data = CheckData(data, from, to);
return data;
}
/// <summary>
/// Converts the given 32-bit unsigned integer to an array of bytes.
/// </summary>
public static byte[] GetBytes(uint value, ByteOrder from, ByteOrder to)
{
var data = BitConverter.GetBytes(value);
data = CheckData(data, from, to);
return data;
}
/// <summary>
/// Converts the given 64-bit unsigned integer to an array of bytes.
/// </summary>
public static byte[] GetBytes(ulong value, ByteOrder from, ByteOrder to)
{
var data = BitConverter.GetBytes(value);
data = CheckData(data, from, to);
return data;
}
/// <summary>
/// Converts the given 16-bit signed integer to an array of bytes.
/// </summary>
public static byte[] GetBytes(short value, ByteOrder from, ByteOrder to)
{
var data = BitConverter.GetBytes(value);
data = CheckData(data, from, to);
return data;
}
/// <summary>
/// Converts the given 32-bit signed integer to an array of bytes.
/// </summary>
public static byte[] GetBytes(int value, ByteOrder from, ByteOrder to)
{
var data = BitConverter.GetBytes(value);
data = CheckData(data, from, to);
return data;
}
/// <summary>
/// Converts the given 64-bit signed integer to an array of bytes.
/// </summary>
public static byte[] GetBytes(long value, ByteOrder from, ByteOrder to)
{
var data = BitConverter.GetBytes(value);
data = CheckData(data, from, to);
return data;
}
/// <summary>
/// Converts the given single precision floating-point number to an array of bytes.
/// </summary>
public static byte[] GetBytes(float value, ByteOrder from, ByteOrder to)
{
var data = BitConverter.GetBytes(value);
data = CheckData(data, from, to);
return data;
}
/// <summary>
/// Converts the given double precision floating-point number to an array of bytes.
/// </summary>
public static byte[] GetBytes(double value, ByteOrder from, ByteOrder to)
{
var data = BitConverter.GetBytes(value);
data = CheckData(data, from, to);
return data;
}
#endregion
#region Instance Methods
/// <summary>
/// Converts the given array of bytes to a 16-bit unsigned integer.
/// </summary>
public char ToChar(byte[] value, long startIndex) => ToChar(value, startIndex, mFrom, mTo);
/// <summary>
/// Converts the given array of bytes to a 16-bit unsigned integer.
/// </summary>
public ushort ToUInt16(byte[] value, long startIndex) => ToUInt16(value, startIndex, mFrom, mTo);
/// <summary>
/// Converts the given array of bytes to a 32-bit unsigned integer.
/// </summary>
public uint ToUInt32(byte[] value, long startIndex) => ToUInt32(value, startIndex, mFrom, mTo);
/// <summary>
/// Converts the given array of bytes to a 64-bit unsigned integer.
/// </summary>
public ulong ToUInt64(byte[] value, long startIndex) => ToUInt64(value, startIndex, mFrom, mTo);
/// <summary>
/// Converts the given array of bytes to a 16-bit signed integer.
/// </summary>
public short ToInt16(byte[] value, long startIndex) => ToInt16(value, startIndex, mFrom, mTo);
/// <summary>
/// Converts the given array of bytes to a 32-bit signed integer.
/// </summary>
public int ToInt32(byte[] value, long startIndex) => ToInt32(value, startIndex, mFrom, mTo);
/// <summary>
/// Converts the given array of bytes to a 64-bit signed integer.
/// </summary>
public long ToInt64(byte[] value, long startIndex) => ToInt64(value, startIndex, mFrom, mTo);
/// <summary>
/// Converts the given array of bytes to a single precision floating number.
/// </summary>
public float ToSingle(byte[] value, long startIndex) => ToSingle(value, startIndex, mFrom, mTo);
/// <summary>
/// Converts the given array of bytes to a double precision floating number.
/// </summary>
public double ToDouble(byte[] value, long startIndex) => ToDouble(value, startIndex, mFrom, mTo);
/// <summary>
/// Converts the given 16-bit unsigned integer to an array of bytes.
/// </summary>
public byte[] GetBytes(ushort value) => GetBytes(value, mFrom, mTo);
/// <summary>
/// Converts the given 32-bit unsigned integer to an array of bytes.
/// </summary>
public byte[] GetBytes(uint value) => GetBytes(value, mFrom, mTo);
/// <summary>
/// Converts the given 64-bit unsigned integer to an array of bytes.
/// </summary>
public byte[] GetBytes(ulong value) => GetBytes(value, mFrom, mTo);
/// <summary>
/// Converts the given 16-bit signed integer to an array of bytes.
/// </summary>
public byte[] GetBytes(short value) => GetBytes(value, mFrom, mTo);
/// <summary>
/// Converts the given 32-bit signed integer to an array of bytes.
/// </summary>
public byte[] GetBytes(int value) => GetBytes(value, mFrom, mTo);
/// <summary>
/// Converts the given 64-bit signed integer to an array of bytes.
/// </summary>
public byte[] GetBytes(long value) => GetBytes(value, mFrom, mTo);
/// <summary>
/// Converts the given single precision floating-point number to an array of bytes.
/// </summary>
public byte[] GetBytes(float value) => GetBytes(value, mFrom, mTo);
/// <summary>
/// Converts the given double precision floating-point number to an array of bytes.
/// </summary>
public byte[] GetBytes(double value) => GetBytes(value, mFrom, mTo);
#endregion
#region Private Helpers
/// <summary>
/// Reverse the array of bytes as needed.
/// </summary>
private static byte[] CheckData(byte[] value, long startIndex, long length, ByteOrder from, ByteOrder to)
{
var data = new byte[length];
Array.Copy(value, startIndex, data, 0, length);
if (from != to)
{
Array.Reverse(data);
}
return data;
}
/// <summary>
/// Reverse the array of bytes as needed.
/// </summary>
private static byte[] CheckData(byte[] value, ByteOrder from, ByteOrder to) =>
CheckData(value, 0, value.Length, from, to);
#endregion
}

View File

@@ -1,392 +0,0 @@
using System.Globalization;
using System.Text;
namespace Umbraco.Cms.Core.Media.Exif;
/// <summary>
/// Converts between exif data types and array of bytes.
/// </summary>
internal class ExifBitConverter : BitConverterEx
{
#region Constructors
public ExifBitConverter(ByteOrder from, ByteOrder to)
: base(from, to)
{
}
#endregion
#region Static Methods
/// <summary>
/// Returns an ASCII string converted from the given byte array.
/// </summary>
public static string ToAscii(byte[] data, bool endatfirstnull, Encoding encoding)
{
var len = data.Length;
if (endatfirstnull)
{
len = Array.IndexOf(data, (byte)0);
if (len == -1)
{
len = data.Length;
}
}
return encoding.GetString(data, 0, len);
}
/// <summary>
/// Returns an ASCII string converted from the given byte array.
/// </summary>
public static string ToAscii(byte[] data, Encoding encoding) => ToAscii(data, true, encoding);
/// <summary>
/// Returns a string converted from the given byte array.
/// from the numeric value of each byte.
/// </summary>
public static string ToString(byte[] data)
{
var sb = new StringBuilder();
foreach (var b in data)
{
sb.Append(b);
}
return sb.ToString();
}
/// <summary>
/// Returns a DateTime object converted from the given byte array.
/// </summary>
public static DateTime ToDateTime(byte[] data, bool hastime)
{
var str = ToAscii(data, Encoding.ASCII);
var parts = str.Split(':', ' ');
try
{
if (hastime && parts.Length == 6)
{
// yyyy:MM:dd HH:mm:ss
// This is the expected format though some cameras
// can use single digits. See Issue 21.
return new DateTime(
int.Parse(parts[0], CultureInfo.InvariantCulture),
int.Parse(parts[1], CultureInfo.InvariantCulture),
int.Parse(parts[2], CultureInfo.InvariantCulture),
int.Parse(parts[3], CultureInfo.InvariantCulture),
int.Parse(parts[4], CultureInfo.InvariantCulture),
int.Parse(parts[5], CultureInfo.InvariantCulture));
}
if (!hastime && parts.Length == 3)
{
// yyyy:MM:dd
return new DateTime(
int.Parse(parts[0], CultureInfo.InvariantCulture),
int.Parse(parts[1], CultureInfo.InvariantCulture),
int.Parse(parts[2], CultureInfo.InvariantCulture));
}
return DateTime.MinValue;
}
catch (ArgumentOutOfRangeException)
{
return DateTime.MinValue;
}
catch (ArgumentException)
{
return DateTime.MinValue;
}
}
/// <summary>
/// Returns a DateTime object converted from the given byte array.
/// </summary>
public static DateTime ToDateTime(byte[] data) => ToDateTime(data, true);
/// <summary>
/// Returns an unsigned rational number converted from the first
/// eight bytes of the given byte array. The first four bytes are
/// assumed to be the numerator and the next four bytes are the
/// denominator.
/// Numbers are converted from the given byte-order to platform byte-order.
/// </summary>
public static MathEx.UFraction32 ToURational(byte[] data, ByteOrder frombyteorder)
{
var num = new byte[4];
var den = new byte[4];
Array.Copy(data, 0, num, 0, 4);
Array.Copy(data, 4, den, 0, 4);
return new MathEx.UFraction32(
ToUInt32(num, 0, frombyteorder, SystemByteOrder),
ToUInt32(den, 0, frombyteorder, SystemByteOrder));
}
/// <summary>
/// Returns a signed rational number converted from the first
/// eight bytes of the given byte array. The first four bytes are
/// assumed to be the numerator and the next four bytes are the
/// denominator.
/// Numbers are converted from the given byte-order to platform byte-order.
/// </summary>
public static MathEx.Fraction32 ToSRational(byte[] data, ByteOrder frombyteorder)
{
var num = new byte[4];
var den = new byte[4];
Array.Copy(data, 0, num, 0, 4);
Array.Copy(data, 4, den, 0, 4);
return new MathEx.Fraction32(
ToInt32(num, 0, frombyteorder, SystemByteOrder),
ToInt32(den, 0, frombyteorder, SystemByteOrder));
}
/// <summary>
/// Returns an array of 16-bit unsigned integers converted from
/// the given byte array.
/// Numbers are converted from the given byte-order to platform byte-order.
/// </summary>
public static ushort[] ToUShortArray(byte[] data, int count, ByteOrder frombyteorder)
{
var numbers = new ushort[count];
for (uint i = 0; i < count; i++)
{
var num = new byte[2];
Array.Copy(data, i * 2, num, 0, 2);
numbers[i] = ToUInt16(num, 0, frombyteorder, SystemByteOrder);
}
return numbers;
}
/// <summary>
/// Returns an array of 32-bit unsigned integers converted from
/// the given byte array.
/// Numbers are converted from the given byte-order to platform byte-order.
/// </summary>
public static uint[] ToUIntArray(byte[] data, int count, ByteOrder frombyteorder)
{
var numbers = new uint[count];
for (uint i = 0; i < count; i++)
{
var num = new byte[4];
Array.Copy(data, i * 4, num, 0, 4);
numbers[i] = ToUInt32(num, 0, frombyteorder, SystemByteOrder);
}
return numbers;
}
/// <summary>
/// Returns an array of 32-bit signed integers converted from
/// the given byte array.
/// Numbers are converted from the given byte-order to platform byte-order.
/// </summary>
public static int[] ToSIntArray(byte[] data, int count, ByteOrder byteorder)
{
var numbers = new int[count];
for (uint i = 0; i < count; i++)
{
var num = new byte[4];
Array.Copy(data, i * 4, num, 0, 4);
numbers[i] = ToInt32(num, 0, byteorder, SystemByteOrder);
}
return numbers;
}
/// <summary>
/// Returns an array of unsigned rational numbers converted from
/// the given byte array.
/// Numbers are converted from the given byte-order to platform byte-order.
/// </summary>
public static MathEx.UFraction32[] ToURationalArray(byte[] data, int count, ByteOrder frombyteorder)
{
var numbers = new MathEx.UFraction32[count];
for (uint i = 0; i < count; i++)
{
var num = new byte[4];
var den = new byte[4];
Array.Copy(data, i * 8, num, 0, 4);
Array.Copy(data, (i * 8) + 4, den, 0, 4);
numbers[i].Set(
ToUInt32(num, 0, frombyteorder, SystemByteOrder),
ToUInt32(den, 0, frombyteorder, SystemByteOrder));
}
return numbers;
}
/// <summary>
/// Returns an array of signed rational numbers converted from
/// the given byte array.
/// Numbers are converted from the given byte-order to platform byte-order.
/// </summary>
public static MathEx.Fraction32[] ToSRationalArray(byte[] data, int count, ByteOrder frombyteorder)
{
var numbers = new MathEx.Fraction32[count];
for (uint i = 0; i < count; i++)
{
var num = new byte[4];
var den = new byte[4];
Array.Copy(data, i * 8, num, 0, 4);
Array.Copy(data, (i * 8) + 4, den, 0, 4);
numbers[i].Set(
ToInt32(num, 0, frombyteorder, SystemByteOrder),
ToInt32(den, 0, frombyteorder, SystemByteOrder));
}
return numbers;
}
/// <summary>
/// Converts the given ascii string to an array of bytes optionally adding a null terminator.
/// </summary>
public static byte[] GetBytes(string value, bool addnull, Encoding encoding)
{
if (addnull)
{
value += '\0';
}
return encoding.GetBytes(value);
}
/// <summary>
/// Converts the given ascii string to an array of bytes without adding a null terminator.
/// </summary>
public static byte[] GetBytes(string value, Encoding encoding) => GetBytes(value, false, encoding);
/// <summary>
/// Converts the given datetime to an array of bytes with a null terminator.
/// </summary>
public static byte[] GetBytes(DateTime value, bool hastime)
{
var str = string.Empty;
if (hastime)
{
str = value.ToString("yyyy:MM:dd HH:mm:ss", CultureInfo.InvariantCulture);
}
else
{
str = value.ToString("yyyy:MM:dd", CultureInfo.InvariantCulture);
}
return GetBytes(str, true, Encoding.ASCII);
}
/// <summary>
/// Converts the given unsigned rational number to an array of bytes.
/// Numbers are converted from the platform byte-order to the given byte-order.
/// </summary>
public static byte[] GetBytes(MathEx.UFraction32 value, ByteOrder tobyteorder)
{
var num = GetBytes(value.Numerator, SystemByteOrder, tobyteorder);
var den = GetBytes(value.Denominator, SystemByteOrder, tobyteorder);
var data = new byte[8];
Array.Copy(num, 0, data, 0, 4);
Array.Copy(den, 0, data, 4, 4);
return data;
}
/// <summary>
/// Converts the given signed rational number to an array of bytes.
/// Numbers are converted from the platform byte-order to the given byte-order.
/// </summary>
public static byte[] GetBytes(MathEx.Fraction32 value, ByteOrder tobyteorder)
{
var num = GetBytes(value.Numerator, SystemByteOrder, tobyteorder);
var den = GetBytes(value.Denominator, SystemByteOrder, tobyteorder);
var data = new byte[8];
Array.Copy(num, 0, data, 0, 4);
Array.Copy(den, 0, data, 4, 4);
return data;
}
/// <summary>
/// Converts the given array of 16-bit unsigned integers to an array of bytes.
/// Numbers are converted from the platform byte-order to the given byte-order.
/// </summary>
public static byte[] GetBytes(ushort[] value, ByteOrder tobyteorder)
{
var data = new byte[2 * value.Length];
for (var i = 0; i < value.Length; i++)
{
var num = GetBytes(value[i], SystemByteOrder, tobyteorder);
Array.Copy(num, 0, data, i * 2, 2);
}
return data;
}
/// <summary>
/// Converts the given array of 32-bit unsigned integers to an array of bytes.
/// Numbers are converted from the platform byte-order to the given byte-order.
/// </summary>
public static byte[] GetBytes(uint[] value, ByteOrder tobyteorder)
{
var data = new byte[4 * value.Length];
for (var i = 0; i < value.Length; i++)
{
var num = GetBytes(value[i], SystemByteOrder, tobyteorder);
Array.Copy(num, 0, data, i * 4, 4);
}
return data;
}
/// <summary>
/// Converts the given array of 32-bit signed integers to an array of bytes.
/// Numbers are converted from the platform byte-order to the given byte-order.
/// </summary>
public static byte[] GetBytes(int[] value, ByteOrder tobyteorder)
{
var data = new byte[4 * value.Length];
for (var i = 0; i < value.Length; i++)
{
var num = GetBytes(value[i], SystemByteOrder, tobyteorder);
Array.Copy(num, 0, data, i * 4, 4);
}
return data;
}
/// <summary>
/// Converts the given array of unsigned rationals to an array of bytes.
/// Numbers are converted from the platform byte-order to the given byte-order.
/// </summary>
public static byte[] GetBytes(MathEx.UFraction32[] value, ByteOrder tobyteorder)
{
var data = new byte[8 * value.Length];
for (var i = 0; i < value.Length; i++)
{
var num = GetBytes(value[i].Numerator, SystemByteOrder, tobyteorder);
var den = GetBytes(value[i].Denominator, SystemByteOrder, tobyteorder);
Array.Copy(num, 0, data, i * 8, 4);
Array.Copy(den, 0, data, (i * 8) + 4, 4);
}
return data;
}
/// <summary>
/// Converts the given array of signed rationals to an array of bytes.
/// Numbers are converted from the platform byte-order to the given byte-order.
/// </summary>
public static byte[] GetBytes(MathEx.Fraction32[] value, ByteOrder tobyteorder)
{
var data = new byte[8 * value.Length];
for (var i = 0; i < value.Length; i++)
{
var num = GetBytes(value[i].Numerator, SystemByteOrder, tobyteorder);
var den = GetBytes(value[i].Denominator, SystemByteOrder, tobyteorder);
Array.Copy(num, 0, data, i * 8, 4);
Array.Copy(den, 0, data, (i * 8) + 4, 4);
}
return data;
}
#endregion
}

View File

@@ -1,297 +0,0 @@
namespace Umbraco.Cms.Core.Media.Exif;
internal enum Compression : ushort
{
Uncompressed = 1,
CCITT1D = 2,
Group3Fax = 3,
Group4Fax = 4,
LZW = 5,
JPEG = 6,
PackBits = 32773,
}
internal enum PhotometricInterpretation : ushort
{
WhiteIsZero = 0,
BlackIsZero = 1,
RGB = 2,
RGBPalette = 3,
TransparencyMask = 4,
CMYK = 5,
YCbCr = 6,
CIELab = 8,
}
internal enum Orientation : ushort
{
Normal = 1,
MirroredVertically = 2,
Rotated180 = 3,
MirroredHorizontally = 4,
RotatedLeftAndMirroredVertically = 5,
RotatedRight = 6,
RotatedLeft = 7,
RotatedRightAndMirroredVertically = 8,
}
internal enum PlanarConfiguration : ushort
{
ChunkyFormat = 1,
PlanarFormat = 2,
}
internal enum YCbCrPositioning : ushort
{
Centered = 1,
CoSited = 2,
}
internal enum ResolutionUnit : ushort
{
Inches = 2,
Centimeters = 3,
}
internal enum ColorSpace : ushort
{
SRGB = 1,
Uncalibrated = 0xfff,
}
internal enum ExposureProgram : ushort
{
NotDefined = 0,
Manual = 1,
Normal = 2,
AperturePriority = 3,
ShutterPriority = 4,
/// <summary>
/// Biased toward depth of field.
/// </summary>
Creative = 5,
/// <summary>
/// Biased toward fast shutter speed.
/// </summary>
Action = 6,
/// <summary>
/// For closeup photos with the background out of focus.
/// </summary>
Portrait = 7,
/// <summary>
/// For landscape photos with the background in focus.
/// </summary>
Landscape = 8,
}
internal enum MeteringMode : ushort
{
Unknown = 0,
Average = 1,
CenterWeightedAverage = 2,
Spot = 3,
MultiSpot = 4,
Pattern = 5,
Partial = 6,
Other = 255,
}
internal enum LightSource : ushort
{
Unknown = 0,
Daylight = 1,
Fluorescent = 2,
Tungsten = 3,
Flash = 4,
FineWeather = 9,
CloudyWeather = 10,
Shade = 11,
/// <summary>
/// D 5700 7100K
/// </summary>
DaylightFluorescent = 12,
/// <summary>
/// N 4600 5400K
/// </summary>
DayWhiteFluorescent = 13,
/// <summary>
/// W 3900 4500K
/// </summary>
CoolWhiteFluorescent = 14,
/// <summary>
/// WW 3200 3700K
/// </summary>
WhiteFluorescent = 15,
StandardLightA = 17,
StandardLightB = 18,
StandardLightC = 19,
D55 = 20,
D65 = 21,
D75 = 22,
D50 = 23,
ISOStudioTungsten = 24,
OtherLightSource = 255,
}
[Flags]
internal enum Flash : ushort
{
FlashDidNotFire = 0,
StrobeReturnLightNotDetected = 4,
StrobeReturnLightDetected = 2,
FlashFired = 1,
CompulsoryFlashMode = 8,
AutoMode = 16,
NoFlashFunction = 32,
RedEyeReductionMode = 64,
}
internal enum SensingMethod : ushort
{
NotDefined = 1,
OneChipColorAreaSensor = 2,
TwoChipColorAreaSensor = 3,
ThreeChipColorAreaSensor = 4,
ColorSequentialAreaSensor = 5,
TriLinearSensor = 7,
ColorSequentialLinearSensor = 8,
}
internal enum FileSource : byte // UNDEFINED
{
DSC = 3,
}
internal enum SceneType : byte // UNDEFINED
{
DirectlyPhotographedImage = 1,
}
internal enum CustomRendered : ushort
{
NormalProcess = 0,
CustomProcess = 1,
}
internal enum ExposureMode : ushort
{
Auto = 0,
Manual = 1,
AutoBracket = 2,
}
internal enum WhiteBalance : ushort
{
Auto = 0,
Manual = 1,
}
internal enum SceneCaptureType : ushort
{
Standard = 0,
Landscape = 1,
Portrait = 2,
NightScene = 3,
}
internal enum GainControl : ushort
{
None = 0,
LowGainUp = 1,
HighGainUp = 2,
LowGainDown = 3,
HighGainDown = 4,
}
internal enum Contrast : ushort
{
Normal = 0,
Soft = 1,
Hard = 2,
}
internal enum Saturation : ushort
{
Normal = 0,
Low = 1,
High = 2,
}
internal enum Sharpness : ushort
{
Normal = 0,
Soft = 1,
Hard = 2,
}
internal enum SubjectDistanceRange : ushort
{
Unknown = 0,
Macro = 1,
CloseView = 2,
DistantView = 3,
}
internal enum GPSLatitudeRef : byte // ASCII
{
North = 78, // 'N'
South = 83, // 'S'
}
internal enum GPSLongitudeRef : byte // ASCII
{
West = 87, // 'W'
East = 69, // 'E'
}
internal enum GPSAltitudeRef : byte
{
AboveSeaLevel = 0,
BelowSeaLevel = 1,
}
internal enum GPSStatus : byte // ASCII
{
MeasurementInProgress = 65, // 'A'
MeasurementInteroperability = 86, // 'V'
}
internal enum GPSMeasureMode : byte // ASCII
{
TwoDimensional = 50, // '2'
ThreeDimensional = 51, // '3'
}
internal enum GPSSpeedRef : byte // ASCII
{
KilometersPerHour = 75, // 'K'
MilesPerHour = 77, // 'M'
Knots = 78, // 'N'
}
internal enum GPSDirectionRef : byte // ASCII
{
TrueDirection = 84, // 'T'
MagneticDirection = 77, // 'M'
}
internal enum GPSDistanceRef : byte // ASCII
{
Kilometers = 75, // 'K'
Miles = 77, // 'M'
Knots = 78, // 'N'
}
internal enum GPSDifferential : ushort
{
MeasurementWithoutDifferentialCorrection = 0,
DifferentialCorrectionApplied = 1,
}

View File

@@ -7,6 +7,7 @@ namespace Umbraco.Cms.Core.Media.Exif;
/// </summary>
/// <seealso cref="System.Exception" />
[Serializable]
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class NotValidExifFileException : Exception
{
/// <summary>

View File

@@ -1,487 +0,0 @@
using System.Text;
namespace Umbraco.Cms.Core.Media.Exif;
/// <summary>
/// Represents an enumerated value.
/// </summary>
internal class ExifEnumProperty<T> : ExifProperty
where T : notnull
{
protected bool mIsBitField;
protected T mValue;
public ExifEnumProperty(ExifTag tag, T value, bool isbitfield)
: base(tag)
{
mValue = value;
mIsBitField = isbitfield;
}
public ExifEnumProperty(ExifTag tag, T value)
: this(tag, value, false)
{
}
public new T Value
{
get => mValue;
set => mValue = value;
}
protected override object _Value
{
get => Value;
set => Value = (T)value;
}
public bool IsBitField => mIsBitField;
public override ExifInterOperability Interoperability
{
get
{
var tagid = ExifTagFactory.GetTagID(mTag);
Type type = typeof(T);
Type basetype = Enum.GetUnderlyingType(type);
if (type == typeof(FileSource) || type == typeof(SceneType))
{
// UNDEFINED
return new ExifInterOperability(tagid, 7, 1, new[] { (byte)(object)mValue });
}
if (type == typeof(GPSLatitudeRef) || type == typeof(GPSLongitudeRef) ||
type == typeof(GPSStatus) || type == typeof(GPSMeasureMode) ||
type == typeof(GPSSpeedRef) || type == typeof(GPSDirectionRef) ||
type == typeof(GPSDistanceRef))
{
// ASCII
return new ExifInterOperability(tagid, 2, 2, new byte[] { (byte)(object)mValue, 0 });
}
if (basetype == typeof(byte))
{
// BYTE
return new ExifInterOperability(tagid, 1, 1, new[] { (byte)(object)mValue });
}
if (basetype == typeof(ushort))
{
// SHORT
return new ExifInterOperability(
tagid,
3,
1,
BitConverterEx.GetBytes((ushort)(object)mValue, BitConverterEx.SystemByteOrder, BitConverterEx.SystemByteOrder));
}
throw new InvalidOperationException(
$"An invalid enum type ({basetype.FullName}) was provided for type {type.FullName}");
}
}
public static implicit operator T(ExifEnumProperty<T> obj) => obj.mValue;
public override string? ToString() => mValue.ToString();
}
/// <summary>
/// Represents an ASCII string. (EXIF Specification: UNDEFINED) Used for the UserComment field.
/// </summary>
internal class ExifEncodedString : ExifProperty
{
protected string mValue;
public ExifEncodedString(ExifTag tag, string value, Encoding encoding)
: base(tag)
{
mValue = value;
Encoding = encoding;
}
public new string Value
{
get => mValue;
set => mValue = value;
}
protected override object _Value
{
get => Value;
set => Value = (string)value;
}
public Encoding Encoding { get; set; }
public override ExifInterOperability Interoperability
{
get
{
var enc = string.Empty;
if (Encoding == null)
{
enc = "\0\0\0\0\0\0\0\0";
}
else if (Encoding.EncodingName == "US-ASCII")
{
enc = "ASCII\0\0\0";
}
else if (Encoding.EncodingName == "Japanese (JIS 0208-1990 and 0212-1990)")
{
enc = "JIS\0\0\0\0\0";
}
else if (Encoding.EncodingName == "Unicode")
{
enc = "Unicode\0";
}
else
{
enc = "\0\0\0\0\0\0\0\0";
}
var benc = Encoding.ASCII.GetBytes(enc);
var bstr = Encoding == null ? Encoding.ASCII.GetBytes(mValue) : Encoding.GetBytes(mValue);
var data = new byte[benc.Length + bstr.Length];
Array.Copy(benc, 0, data, 0, benc.Length);
Array.Copy(bstr, 0, data, benc.Length, bstr.Length);
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 7, (uint)data.Length, data);
}
}
public static implicit operator string(ExifEncodedString obj) => obj.mValue;
public override string ToString() => mValue;
}
/// <summary>
/// Represents an ASCII string formatted as DateTime. (EXIF Specification: ASCII) Used for the date time fields.
/// </summary>
internal class ExifDateTime : ExifProperty
{
protected DateTime mValue;
public ExifDateTime(ExifTag tag, DateTime value)
: base(tag) =>
mValue = value;
public new DateTime Value
{
get => mValue;
set => mValue = value;
}
protected override object _Value
{
get => Value;
set => Value = (DateTime)value;
}
public override ExifInterOperability Interoperability =>
new(ExifTagFactory.GetTagID(mTag), 2, 20, ExifBitConverter.GetBytes(mValue, true));
public static implicit operator DateTime(ExifDateTime obj) => obj.mValue;
public override string ToString() => mValue.ToString("yyyy.MM.dd HH:mm:ss");
}
/// <summary>
/// Represents the exif version as a 4 byte ASCII string. (EXIF Specification: UNDEFINED)
/// Used for the ExifVersion, FlashpixVersion, InteroperabilityVersion and GPSVersionID fields.
/// </summary>
internal class ExifVersion : ExifProperty
{
protected string mValue;
public ExifVersion(ExifTag tag, string value)
: base(tag)
{
if (value.Length > 4)
{
mValue = value[..4];
}
else if (value.Length < 4)
{
mValue = value + new string(' ', 4 - value.Length);
}
else
{
mValue = value;
}
}
public new string Value
{
get => mValue;
set => mValue = value[..4];
}
protected override object _Value
{
get => Value;
set => Value = (string)value;
}
public override ExifInterOperability Interoperability
{
get
{
if (mTag == ExifTag.ExifVersion || mTag == ExifTag.FlashpixVersion ||
mTag == ExifTag.InteroperabilityVersion)
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 7, 4, Encoding.ASCII.GetBytes(mValue));
}
var data = new byte[4];
for (var i = 0; i < 4; i++)
{
data[i] = byte.Parse(mValue[0].ToString());
}
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 7, 4, data);
}
}
public override string ToString() => mValue;
}
/// <summary>
/// Represents the location and area of the subject (EXIF Specification: 2xSHORT)
/// The coordinate values, width, and height are expressed in relation to the
/// upper left as origin, prior to rotation processing as per the Rotation tag.
/// </summary>
internal class ExifPointSubjectArea : ExifUShortArray
{
public ExifPointSubjectArea(ExifTag tag, ushort[] value)
: base(tag, value)
{
}
public ExifPointSubjectArea(ExifTag tag, ushort x, ushort y)
: base(tag, new[] { x, y })
{
}
public ushort X
{
get => mValue[0];
set => mValue[0] = value;
}
protected new ushort[] Value
{
get => mValue;
set => mValue = value;
}
public ushort Y
{
get => mValue[1];
set => mValue[1] = value;
}
public override string ToString()
{
var sb = new StringBuilder();
sb.AppendFormat("({0:d}, {1:d})", mValue[0], mValue[1]);
return sb.ToString();
}
}
/// <summary>
/// Represents the location and area of the subject (EXIF Specification: 3xSHORT)
/// The coordinate values, width, and height are expressed in relation to the
/// upper left as origin, prior to rotation processing as per the Rotation tag.
/// </summary>
internal class ExifCircularSubjectArea : ExifPointSubjectArea
{
public ExifCircularSubjectArea(ExifTag tag, ushort[] value)
: base(tag, value)
{
}
public ExifCircularSubjectArea(ExifTag tag, ushort x, ushort y, ushort d)
: base(tag, new[] { x, y, d })
{
}
public ushort Diamater
{
get => mValue[2];
set => mValue[2] = value;
}
public override string ToString()
{
var sb = new StringBuilder();
sb.AppendFormat("({0:d}, {1:d}) {2:d}", mValue[0], mValue[1], mValue[2]);
return sb.ToString();
}
}
/// <summary>
/// Represents the location and area of the subject (EXIF Specification: 4xSHORT)
/// The coordinate values, width, and height are expressed in relation to the
/// upper left as origin, prior to rotation processing as per the Rotation tag.
/// </summary>
internal class ExifRectangularSubjectArea : ExifPointSubjectArea
{
public ExifRectangularSubjectArea(ExifTag tag, ushort[] value)
: base(tag, value)
{
}
public ExifRectangularSubjectArea(ExifTag tag, ushort x, ushort y, ushort w, ushort h)
: base(tag, new[] { x, y, w, h })
{
}
public ushort Width
{
get => mValue[2];
set => mValue[2] = value;
}
public ushort Height
{
get => mValue[3];
set => mValue[3] = value;
}
public override string ToString()
{
var sb = new StringBuilder();
sb.AppendFormat("({0:d}, {1:d}) ({2:d} x {3:d})", mValue[0], mValue[1], mValue[2], mValue[3]);
return sb.ToString();
}
}
/// <summary>
/// Represents GPS latitudes and longitudes (EXIF Specification: 3xRATIONAL)
/// </summary>
internal class GPSLatitudeLongitude : ExifURationalArray
{
public GPSLatitudeLongitude(ExifTag tag, MathEx.UFraction32[] value)
: base(tag, value)
{
}
public GPSLatitudeLongitude(ExifTag tag, float d, float m, float s)
: base(tag, new[] { new(d), new MathEx.UFraction32(m), new MathEx.UFraction32(s) })
{
}
public MathEx.UFraction32 Degrees
{
get => mValue[0];
set => mValue[0] = value;
}
protected new MathEx.UFraction32[] Value
{
get => mValue;
set => mValue = value;
}
public MathEx.UFraction32 Minutes
{
get => mValue[1];
set => mValue[1] = value;
}
public MathEx.UFraction32 Seconds
{
get => mValue[2];
set => mValue[2] = value;
}
public static explicit operator float(GPSLatitudeLongitude obj) => obj.ToFloat();
public float ToFloat() => (float)Degrees + ((float)Minutes / 60.0f) + ((float)Seconds / 3600.0f);
public override string ToString() =>
string.Format("{0:F2}°{1:F2}'{2:F2}\"", (float)Degrees, (float)Minutes, (float)Seconds);
}
/// <summary>
/// Represents a GPS time stamp as UTC (EXIF Specification: 3xRATIONAL)
/// </summary>
internal class GPSTimeStamp : ExifURationalArray
{
public GPSTimeStamp(ExifTag tag, MathEx.UFraction32[] value)
: base(tag, value)
{
}
public GPSTimeStamp(ExifTag tag, float h, float m, float s)
: base(tag, new[] { new(h), new MathEx.UFraction32(m), new MathEx.UFraction32(s) })
{
}
public MathEx.UFraction32 Hour
{
get => mValue[0];
set => mValue[0] = value;
}
protected new MathEx.UFraction32[] Value
{
get => mValue;
set => mValue = value;
}
public MathEx.UFraction32 Minute
{
get => mValue[1];
set => mValue[1] = value;
}
public MathEx.UFraction32 Second
{
get => mValue[2];
set => mValue[2] = value;
}
public override string ToString() =>
string.Format("{0:F2}:{1:F2}:{2:F2}\"", (float)Hour, (float)Minute, (float)Second);
}
/// <summary>
/// Represents an ASCII string. (EXIF Specification: BYTE)
/// Used by Windows XP.
/// </summary>
internal class WindowsByteString : ExifProperty
{
protected string mValue;
public WindowsByteString(ExifTag tag, string value)
: base(tag) =>
mValue = value;
public new string Value
{
get => mValue;
set => mValue = value;
}
protected override object _Value
{
get => Value;
set => Value = (string)value;
}
public override ExifInterOperability Interoperability
{
get
{
var data = Encoding.Unicode.GetBytes(mValue);
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 1, (uint)data.Length, data);
}
}
public static implicit operator string(WindowsByteString obj) => obj.mValue;
public override string ToString() => mValue;
}

View File

@@ -1,108 +0,0 @@
using System.ComponentModel;
namespace Umbraco.Cms.Core.Media.Exif;
/// <summary>
/// Provides a custom type descriptor for an ExifFile instance.
/// </summary>
internal sealed class ExifFileTypeDescriptionProvider : TypeDescriptionProvider
{
public ExifFileTypeDescriptionProvider()
: this(TypeDescriptor.GetProvider(typeof(ImageFile)))
{
}
public ExifFileTypeDescriptionProvider(TypeDescriptionProvider parent)
: base(parent)
{
}
/// <summary>
/// Gets a custom type descriptor for the given type and object.
/// </summary>
/// <param name="objectType">The type of object for which to retrieve the type descriptor.</param>
/// <param name="instance">
/// An instance of the type. Can be null if no instance was passed to the
/// <see cref="T:System.ComponentModel.TypeDescriptor" />.
/// </param>
/// <returns>
/// An <see cref="T:System.ComponentModel.ICustomTypeDescriptor" /> that can provide metadata for the type.
/// </returns>
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object? instance) =>
new ExifFileTypeDescriptor(base.GetTypeDescriptor(objectType, instance), instance);
}
/// <summary>
/// Expands ExifProperty objects contained in an ExifFile as separate properties.
/// </summary>
internal sealed class ExifFileTypeDescriptor : CustomTypeDescriptor
{
private readonly ImageFile? owner;
public ExifFileTypeDescriptor(ICustomTypeDescriptor? parent, object? instance)
: base(parent) =>
owner = (ImageFile?)instance;
public override PropertyDescriptorCollection GetProperties(Attribute[]? attributes) => GetProperties();
/// <summary>
/// Returns a collection of property descriptors for the object represented by this type descriptor.
/// </summary>
/// <returns>
/// A <see cref="T:System.ComponentModel.PropertyDescriptorCollection" /> containing the property descriptions for the
/// object represented by this type descriptor. The default is
/// <see cref="F:System.ComponentModel.PropertyDescriptorCollection.Empty" />.
/// </returns>
public override PropertyDescriptorCollection GetProperties()
{
// Enumerate the original set of properties and create our new set with it
var properties = new List<PropertyDescriptor>();
if (owner is not null)
{
foreach (ExifProperty prop in owner.Properties)
{
var pd = new ExifPropertyDescriptor(prop);
properties.Add(pd);
}
}
// Finally return the list
return new PropertyDescriptorCollection(properties.ToArray(), true);
}
}
internal sealed class ExifPropertyDescriptor : PropertyDescriptor
{
private readonly ExifProperty linkedProperty;
private readonly object originalValue;
public ExifPropertyDescriptor(ExifProperty property)
: base(property.Name, new Attribute[] { new BrowsableAttribute(true) })
{
linkedProperty = property;
originalValue = property.Value;
}
public override Type ComponentType => typeof(JPEGFile);
public override bool IsReadOnly => false;
public override Type PropertyType => linkedProperty.Value.GetType();
public override bool CanResetValue(object component) => true;
public override object GetValue(object? component) => linkedProperty.Value;
public override void ResetValue(object component) => linkedProperty.Value = originalValue;
public override void SetValue(object? component, object? value)
{
if (value is not null)
{
linkedProperty.Value = value;
}
}
public override bool ShouldSerializeValue(object component) => false;
}

View File

@@ -1,55 +0,0 @@
namespace Umbraco.Cms.Core.Media.Exif;
/// <summary>
/// Represents interoperability data for an exif tag in the platform byte order.
/// </summary>
internal struct ExifInterOperability
{
public ExifInterOperability(ushort tagid, ushort typeid, uint count, byte[] data)
{
TagID = tagid;
TypeID = typeid;
Count = count;
Data = data;
}
/// <summary>
/// Gets the tag ID defined in the Exif standard.
/// </summary>
public ushort TagID { get; }
/// <summary>
/// Gets the type code defined in the Exif standard.
/// <list type="bullet">
/// <item>1 = BYTE (byte)</item>
/// <item>2 = ASCII (byte array)</item>
/// <item>3 = SHORT (ushort)</item>
/// <item>4 = LONG (uint)</item>
/// <item>5 = RATIONAL (2 x uint: numerator, denominator)</item>
/// <item>6 = BYTE (sbyte)</item>
/// <item>7 = UNDEFINED (byte array)</item>
/// <item>8 = SSHORT (short)</item>
/// <item>9 = SLONG (int)</item>
/// <item>10 = SRATIONAL (2 x int: numerator, denominator)</item>
/// <item>11 = FLOAT (float)</item>
/// <item>12 = DOUBLE (double)</item>
/// </list>
/// </summary>
public ushort TypeID { get; }
/// <summary>
/// Gets the byte count or number of components.
/// </summary>
public uint Count { get; }
/// <summary>
/// Gets the field value as an array of bytes.
/// </summary>
public byte[] Data { get; }
/// <summary>
/// Returns the string representation of this instance.
/// </summary>
/// <returns></returns>
public override string ToString() => string.Format("Tag: {0}, Type: {1}, Count: {2}, Data Length: {3}", TagID, TypeID, Count, Data.Length);
}

View File

@@ -1,672 +0,0 @@
using System.Text;
namespace Umbraco.Cms.Core.Media.Exif;
/// <summary>
/// Represents the abstract base class for an Exif property.
/// </summary>
internal abstract class ExifProperty
{
protected IFD mIFD;
protected string? mName;
protected ExifTag mTag;
public ExifProperty(ExifTag tag)
{
mTag = tag;
mIFD = ExifTagFactory.GetTagIFD(tag);
}
/// <summary>
/// Gets the Exif tag associated with this property.
/// </summary>
public ExifTag Tag => mTag;
/// <summary>
/// Gets the IFD section containing this property.
/// </summary>
public IFD IFD => mIFD;
/// <summary>
/// Gets or sets the name of this property.
/// </summary>
public string Name
{
get
{
if (string.IsNullOrEmpty(mName))
{
return ExifTagFactory.GetTagName(mTag);
}
return mName;
}
set => mName = value;
}
/// <summary>
/// Gets or sets the value of this property.
/// </summary>
public object Value
{
get => _Value;
set => _Value = value;
}
protected abstract object _Value { get; set; }
/// <summary>
/// Gets interoperability data for this property.
/// </summary>
public abstract ExifInterOperability Interoperability { get; }
}
/// <summary>
/// Represents an 8-bit unsigned integer. (EXIF Specification: BYTE)
/// </summary>
internal class ExifByte : ExifProperty
{
protected byte mValue;
public ExifByte(ExifTag tag, byte value)
: base(tag) =>
mValue = value;
public new byte Value
{
get => mValue;
set => mValue = value;
}
protected override object _Value
{
get => Value;
set => Value = Convert.ToByte(value);
}
public override ExifInterOperability Interoperability =>
new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 1, 1, new[] { mValue });
public static implicit operator byte(ExifByte obj) => obj.mValue;
public override string ToString() => mValue.ToString();
}
/// <summary>
/// Represents an array of 8-bit unsigned integers. (EXIF Specification: BYTE with count > 1)
/// </summary>
internal class ExifByteArray : ExifProperty
{
protected byte[] mValue;
public ExifByteArray(ExifTag tag, byte[] value)
: base(tag) =>
mValue = value;
public new byte[] Value
{
get => mValue;
set => mValue = value;
}
protected override object _Value
{
get => Value;
set => Value = (byte[])value;
}
public override ExifInterOperability Interoperability =>
new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 1, (uint)mValue.Length, mValue);
public static implicit operator byte[](ExifByteArray obj) => obj.mValue;
public override string ToString()
{
var sb = new StringBuilder();
sb.Append('[');
foreach (var b in mValue)
{
sb.Append(b);
sb.Append(' ');
}
sb.Remove(sb.Length - 1, 1);
sb.Append(']');
return sb.ToString();
}
}
/// <summary>
/// Represents an ASCII string. (EXIF Specification: ASCII)
/// </summary>
internal class ExifAscii : ExifProperty
{
protected string mValue;
public ExifAscii(ExifTag tag, string value, Encoding encoding)
: base(tag)
{
mValue = value;
Encoding = encoding;
}
public new string Value
{
get => mValue;
set => mValue = value;
}
protected override object _Value
{
get => Value;
set => Value = (string)value;
}
public Encoding Encoding { get; }
public override ExifInterOperability Interoperability =>
new ExifInterOperability(
ExifTagFactory.GetTagID(mTag),
2,
(uint)mValue.Length + 1,
ExifBitConverter.GetBytes(mValue, true, Encoding));
public static implicit operator string(ExifAscii obj) => obj.mValue;
public override string ToString() => mValue;
}
/// <summary>
/// Represents a 16-bit unsigned integer. (EXIF Specification: SHORT)
/// </summary>
internal class ExifUShort : ExifProperty
{
protected ushort mValue;
public ExifUShort(ExifTag tag, ushort value)
: base(tag) =>
mValue = value;
public new ushort Value
{
get => mValue;
set => mValue = value;
}
protected override object _Value
{
get => Value;
set => Value = Convert.ToUInt16(value);
}
public override ExifInterOperability Interoperability =>
new ExifInterOperability(
ExifTagFactory.GetTagID(mTag),
3,
1,
BitConverterEx.GetBytes(mValue, BitConverterEx.SystemByteOrder, BitConverterEx.SystemByteOrder));
public static implicit operator ushort(ExifUShort obj) => obj.mValue;
public override string ToString() => mValue.ToString();
}
/// <summary>
/// Represents an array of 16-bit unsigned integers.
/// (EXIF Specification: SHORT with count > 1)
/// </summary>
internal class ExifUShortArray : ExifProperty
{
protected ushort[] mValue;
public ExifUShortArray(ExifTag tag, ushort[] value)
: base(tag) =>
mValue = value;
public new ushort[] Value
{
get => mValue;
set => mValue = value;
}
protected override object _Value
{
get => Value;
set => Value = (ushort[])value;
}
public override ExifInterOperability Interoperability =>
new ExifInterOperability(
ExifTagFactory.GetTagID(mTag),
3,
(uint)mValue.Length,
ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder));
public static implicit operator ushort[](ExifUShortArray obj) => obj.mValue;
public override string ToString()
{
var sb = new StringBuilder();
sb.Append('[');
foreach (var b in mValue)
{
sb.Append(b);
sb.Append(' ');
}
sb.Remove(sb.Length - 1, 1);
sb.Append(']');
return sb.ToString();
}
}
/// <summary>
/// Represents a 32-bit unsigned integer. (EXIF Specification: LONG)
/// </summary>
internal class ExifUInt : ExifProperty
{
protected uint mValue;
public ExifUInt(ExifTag tag, uint value)
: base(tag) =>
mValue = value;
public new uint Value
{
get => mValue;
set => mValue = value;
}
protected override object _Value
{
get => Value;
set => Value = Convert.ToUInt32(value);
}
public override ExifInterOperability Interoperability =>
new ExifInterOperability(
ExifTagFactory.GetTagID(mTag),
4,
1,
BitConverterEx.GetBytes(mValue, BitConverterEx.SystemByteOrder, BitConverterEx.SystemByteOrder));
public static implicit operator uint(ExifUInt obj) => obj.mValue;
public override string ToString() => mValue.ToString();
}
/// <summary>
/// Represents an array of 16-bit unsigned integers.
/// (EXIF Specification: LONG with count > 1)
/// </summary>
internal class ExifUIntArray : ExifProperty
{
protected uint[] mValue;
public ExifUIntArray(ExifTag tag, uint[] value)
: base(tag) =>
mValue = value;
public new uint[] Value
{
get => mValue;
set => mValue = value;
}
protected override object _Value
{
get => Value;
set => Value = (uint[])value;
}
public override ExifInterOperability Interoperability => new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 3, (uint)mValue.Length, ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder));
public static implicit operator uint[](ExifUIntArray obj) => obj.mValue;
public override string ToString()
{
var sb = new StringBuilder();
sb.Append('[');
foreach (var b in mValue)
{
sb.Append(b);
sb.Append(' ');
}
sb.Remove(sb.Length - 1, 1);
sb.Append(']');
return sb.ToString();
}
}
/// <summary>
/// Represents a rational number defined with a 32-bit unsigned numerator
/// and denominator. (EXIF Specification: RATIONAL)
/// </summary>
internal class ExifURational : ExifProperty
{
protected MathEx.UFraction32 mValue;
public ExifURational(ExifTag tag, uint numerator, uint denominator)
: base(tag) =>
mValue = new MathEx.UFraction32(numerator, denominator);
public ExifURational(ExifTag tag, MathEx.UFraction32 value)
: base(tag) =>
mValue = value;
public new MathEx.UFraction32 Value
{
get => mValue;
set => mValue = value;
}
protected override object _Value
{
get => Value;
set => Value = (MathEx.UFraction32)value;
}
public override ExifInterOperability Interoperability =>
new ExifInterOperability(
ExifTagFactory.GetTagID(mTag),
5,
1,
ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder));
public static explicit operator float(ExifURational obj) => (float)obj.mValue;
public override string ToString() => mValue.ToString();
public float ToFloat() => (float)mValue;
public uint[] ToArray() => new[] { mValue.Numerator, mValue.Denominator };
}
/// <summary>
/// Represents an array of unsigned rational numbers.
/// (EXIF Specification: RATIONAL with count > 1)
/// </summary>
internal class ExifURationalArray : ExifProperty
{
protected MathEx.UFraction32[] mValue;
public ExifURationalArray(ExifTag tag, MathEx.UFraction32[] value)
: base(tag) =>
mValue = value;
public new MathEx.UFraction32[] Value
{
get => mValue;
set => mValue = value;
}
protected override object _Value
{
get => Value;
set => Value = (MathEx.UFraction32[])value;
}
public override ExifInterOperability Interoperability =>
new ExifInterOperability(
ExifTagFactory.GetTagID(mTag),
5,
(uint)mValue.Length,
ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder));
public static explicit operator float[](ExifURationalArray obj)
{
var result = new float[obj.mValue.Length];
for (var i = 0; i < obj.mValue.Length; i++)
{
result[i] = (float)obj.mValue[i];
}
return result;
}
public override string ToString()
{
var sb = new StringBuilder();
sb.Append('[');
foreach (MathEx.UFraction32 b in mValue)
{
sb.Append(b.ToString());
sb.Append(' ');
}
sb.Remove(sb.Length - 1, 1);
sb.Append(']');
return sb.ToString();
}
}
/// <summary>
/// Represents a byte array that can take any value. (EXIF Specification: UNDEFINED)
/// </summary>
internal class ExifUndefined : ExifProperty
{
protected byte[] mValue;
public ExifUndefined(ExifTag tag, byte[] value)
: base(tag) =>
mValue = value;
public new byte[] Value
{
get => mValue;
set => mValue = value;
}
protected override object _Value
{
get => Value;
set => Value = (byte[])value;
}
public override ExifInterOperability Interoperability =>
new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 7, (uint)mValue.Length, mValue);
public static implicit operator byte[](ExifUndefined obj) => obj.mValue;
public override string ToString()
{
var sb = new StringBuilder();
sb.Append('[');
foreach (var b in mValue)
{
sb.Append(b);
sb.Append(' ');
}
sb.Remove(sb.Length - 1, 1);
sb.Append(']');
return sb.ToString();
}
}
/// <summary>
/// Represents a 32-bit signed integer. (EXIF Specification: SLONG)
/// </summary>
internal class ExifSInt : ExifProperty
{
protected int mValue;
public ExifSInt(ExifTag tag, int value)
: base(tag) =>
mValue = value;
public new int Value
{
get => mValue;
set => mValue = value;
}
protected override object _Value
{
get => Value;
set => Value = Convert.ToInt32(value);
}
public override ExifInterOperability Interoperability =>
new ExifInterOperability(
ExifTagFactory.GetTagID(mTag),
9,
1,
BitConverterEx.GetBytes(mValue, BitConverterEx.SystemByteOrder, BitConverterEx.SystemByteOrder));
public static implicit operator int(ExifSInt obj) => obj.mValue;
public override string ToString() => mValue.ToString();
}
/// <summary>
/// Represents an array of 32-bit signed integers.
/// (EXIF Specification: SLONG with count > 1)
/// </summary>
internal class ExifSIntArray : ExifProperty
{
protected int[] mValue;
public ExifSIntArray(ExifTag tag, int[] value)
: base(tag) =>
mValue = value;
public new int[] Value
{
get => mValue;
set => mValue = value;
}
protected override object _Value
{
get => Value;
set => Value = (int[])value;
}
public override ExifInterOperability Interoperability =>
new ExifInterOperability(
ExifTagFactory.GetTagID(mTag),
9,
(uint)mValue.Length,
ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder));
public static implicit operator int[](ExifSIntArray obj) => obj.mValue;
public override string ToString()
{
var sb = new StringBuilder();
sb.Append('[');
foreach (var b in mValue)
{
sb.Append(b);
sb.Append(' ');
}
sb.Remove(sb.Length - 1, 1);
sb.Append(']');
return sb.ToString();
}
}
/// <summary>
/// Represents a rational number defined with a 32-bit signed numerator
/// and denominator. (EXIF Specification: SRATIONAL)
/// </summary>
internal class ExifSRational : ExifProperty
{
protected MathEx.Fraction32 mValue;
public ExifSRational(ExifTag tag, int numerator, int denominator)
: base(tag) =>
mValue = new MathEx.Fraction32(numerator, denominator);
public ExifSRational(ExifTag tag, MathEx.Fraction32 value)
: base(tag) =>
mValue = value;
public new MathEx.Fraction32 Value
{
get => mValue;
set => mValue = value;
}
protected override object _Value
{
get => Value;
set => Value = (MathEx.Fraction32)value;
}
public override ExifInterOperability Interoperability =>
new ExifInterOperability(
ExifTagFactory.GetTagID(mTag),
10,
1,
ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder));
public static explicit operator float(ExifSRational obj) => (float)obj.mValue;
public override string ToString() => mValue.ToString();
public float ToFloat() => (float)mValue;
public int[] ToArray() => new[] { mValue.Numerator, mValue.Denominator };
}
/// <summary>
/// Represents an array of signed rational numbers.
/// (EXIF Specification: SRATIONAL with count > 1)
/// </summary>
internal class ExifSRationalArray : ExifProperty
{
protected MathEx.Fraction32[] mValue;
public ExifSRationalArray(ExifTag tag, MathEx.Fraction32[] value)
: base(tag) =>
mValue = value;
public new MathEx.Fraction32[] Value
{
get => mValue;
set => mValue = value;
}
protected override object _Value
{
get => Value;
set => Value = (MathEx.Fraction32[])value;
}
public override ExifInterOperability Interoperability =>
new ExifInterOperability(
ExifTagFactory.GetTagID(mTag),
10,
(uint)mValue.Length,
ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder));
public static explicit operator float[](ExifSRationalArray obj)
{
var result = new float[obj.mValue.Length];
for (var i = 0; i < obj.mValue.Length; i++)
{
result[i] = (float)obj.mValue[i];
}
return result;
}
public override string ToString()
{
var sb = new StringBuilder();
sb.Append('[');
foreach (MathEx.Fraction32 b in mValue)
{
sb.Append(b.ToString());
sb.Append(' ');
}
sb.Remove(sb.Length - 1, 1);
sb.Append(']');
return sb.ToString();
}
}

View File

@@ -1,493 +0,0 @@
using System.Collections;
using System.Diagnostics.CodeAnalysis;
using System.Text;
namespace Umbraco.Cms.Core.Media.Exif;
/// <summary>
/// Represents a collection of <see cref="ExifProperty" /> objects.
/// </summary>
internal class ExifPropertyCollection : IDictionary<ExifTag, ExifProperty>
{
#region Constructor
internal ExifPropertyCollection(ImageFile parentFile)
{
parent = parentFile;
items = new Dictionary<ExifTag, ExifProperty>();
}
#endregion
#region Member Variables
private readonly ImageFile parent;
private readonly Dictionary<ExifTag, ExifProperty> items;
#endregion
#region Properties
/// <summary>
/// Gets the number of elements contained in the collection.
/// </summary>
public int Count => items.Count;
/// <summary>
/// Gets a collection containing the keys in this collection.
/// </summary>
public ICollection<ExifTag> Keys => items.Keys;
/// <summary>
/// Gets a collection containing the values in this collection.
/// </summary>
public ICollection<ExifProperty> Values => items.Values;
/// <summary>
/// Gets or sets the <see cref="ExifProperty" /> with the specified key.
/// </summary>
public ExifProperty this[ExifTag key]
{
get => items[key];
set
{
if (items.ContainsKey(key))
{
items.Remove(key);
}
items.Add(key, value);
}
}
#endregion
#region ExifProperty Collection Setters
/// <summary>
/// Sets the <see cref="ExifProperty" /> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="value">The value of tag.</param>
public void Set(ExifTag key, byte value)
{
if (items.ContainsKey(key))
{
items.Remove(key);
}
items.Add(key, new ExifByte(key, value));
}
/// <summary>
/// Sets the <see cref="ExifProperty" /> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="value">The value of tag.</param>
public void Set(ExifTag key, string value)
{
if (items.ContainsKey(key))
{
items.Remove(key);
}
if (key == ExifTag.WindowsTitle || key == ExifTag.WindowsComment || key == ExifTag.WindowsAuthor ||
key == ExifTag.WindowsKeywords || key == ExifTag.WindowsSubject)
{
items.Add(key, new WindowsByteString(key, value));
}
else
{
items.Add(key, new ExifAscii(key, value, parent.Encoding));
}
}
/// <summary>
/// Sets the <see cref="ExifProperty" /> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="value">The value of tag.</param>
public void Set(ExifTag key, ushort value)
{
if (items.ContainsKey(key))
{
items.Remove(key);
}
items.Add(key, new ExifUShort(key, value));
}
/// <summary>
/// Sets the <see cref="ExifProperty" /> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="value">The value of tag.</param>
public void Set(ExifTag key, int value)
{
if (items.ContainsKey(key))
{
items.Remove(key);
}
items.Add(key, new ExifSInt(key, value));
}
/// <summary>
/// Sets the <see cref="ExifProperty" /> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="value">The value of tag.</param>
public void Set(ExifTag key, uint value)
{
if (items.ContainsKey(key))
{
items.Remove(key);
}
items.Add(key, new ExifUInt(key, value));
}
/// <summary>
/// Sets the <see cref="ExifProperty" /> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="value">The value of tag.</param>
public void Set(ExifTag key, float value)
{
if (items.ContainsKey(key))
{
items.Remove(key);
}
items.Add(key, new ExifURational(key, new MathEx.UFraction32(value)));
}
/// <summary>
/// Sets the <see cref="ExifProperty" /> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="value">The value of tag.</param>
public void Set(ExifTag key, double value)
{
if (items.ContainsKey(key))
{
items.Remove(key);
}
items.Add(key, new ExifURational(key, new MathEx.UFraction32(value)));
}
/// <summary>
/// Sets the <see cref="ExifProperty" /> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="value">The value of tag.</param>
public void Set(ExifTag key, object value)
{
Type type = value.GetType();
if (type.IsEnum)
{
Type etype = typeof(ExifEnumProperty<>).MakeGenericType(type);
var prop = Activator.CreateInstance(etype, key, value);
if (items.ContainsKey(key))
{
items.Remove(key);
}
if (prop is ExifProperty exifProperty)
{
items.Add(key, exifProperty);
}
}
else
{
throw new ArgumentException("No exif property exists for this tag.", "value");
}
}
/// <summary>
/// Sets the <see cref="ExifProperty" /> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="value">The value of tag.</param>
/// <param name="encoding">String encoding.</param>
public void Set(ExifTag key, string value, Encoding encoding)
{
if (items.ContainsKey(key))
{
items.Remove(key);
}
items.Add(key, new ExifEncodedString(key, value, encoding));
}
/// <summary>
/// Sets the <see cref="ExifProperty" /> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="value">The value of tag.</param>
public void Set(ExifTag key, DateTime value)
{
if (items.ContainsKey(key))
{
items.Remove(key);
}
items.Add(key, new ExifDateTime(key, value));
}
/// <summary>
/// Sets the <see cref="ExifProperty" /> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="d">Angular degrees (or clock hours for a timestamp).</param>
/// <param name="m">Angular minutes (or clock minutes for a timestamp).</param>
/// <param name="s">Angular seconds (or clock seconds for a timestamp).</param>
public void Set(ExifTag key, float d, float m, float s)
{
if (items.ContainsKey(key))
{
items.Remove(key);
}
items.Add(key, new ExifURationalArray(key, new[] { new(d), new MathEx.UFraction32(m), new MathEx.UFraction32(s) }));
}
#endregion
#region Instance Methods
/// <summary>
/// Adds the specified item to the collection.
/// </summary>
/// <param name="item">The <see cref="ExifProperty" /> to add to the collection.</param>
public void Add(ExifProperty item)
{
ExifProperty? oldItem = null;
if (items.TryGetValue(item.Tag, out oldItem))
{
items[item.Tag] = item;
}
else
{
items.Add(item.Tag, item);
}
}
/// <summary>
/// Removes all items from the collection.
/// </summary>
public void Clear() => items.Clear();
/// <summary>
/// Determines whether the collection contains an element with the specified key.
/// </summary>
/// <param name="key">The key to locate in the collection.</param>
/// <returns>
/// true if the collection contains an element with the key; otherwise, false.
/// </returns>
/// <exception cref="T:System.ArgumentNullException">
/// <paramref name="key" /> is null.
/// </exception>
public bool ContainsKey(ExifTag key) => items.ContainsKey(key);
/// <summary>
/// Removes the element with the specified key from the collection.
/// </summary>
/// <param name="key">The key of the element to remove.</param>
/// <returns>
/// true if the element is successfully removed; otherwise, false. This method also returns false if
/// <paramref name="key" /> was not found in the original collection.
/// </returns>
/// <exception cref="T:System.ArgumentNullException">
/// <paramref name="key" /> is null.
/// </exception>
public bool Remove(ExifTag key) => items.Remove(key);
/// <summary>
/// Removes all items with the given IFD from the collection.
/// </summary>
/// <param name="ifd">The IFD section to remove.</param>
public void Remove(IFD ifd)
{
var toRemove = new List<ExifTag>();
foreach (KeyValuePair<ExifTag, ExifProperty> item in items)
{
if (item.Value.IFD == ifd)
{
toRemove.Add(item.Key);
}
}
foreach (ExifTag tag in toRemove)
{
items.Remove(tag);
}
}
/// <summary>
/// Gets the value associated with the specified key.
/// </summary>
/// <param name="key">The key whose value to get.</param>
/// <param name="value">
/// When this method returns, the value associated with the specified key, if the key is found;
/// otherwise, the default value for the type of the <paramref name="value" /> parameter. This parameter is passed
/// uninitialized.
/// </param>
/// <returns>
/// true if the collection contains an element with the specified key; otherwise, false.
/// </returns>
/// <exception cref="T:System.ArgumentNullException">
/// <paramref name="key" /> is null.
/// </exception>
public bool TryGetValue(ExifTag key, [MaybeNullWhen(false)] out ExifProperty value) =>
items.TryGetValue(key, out value);
/// <summary>
/// Returns an enumerator that iterates through a collection.
/// </summary>
/// <returns>
/// An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.
/// </returns>
public IEnumerator<ExifProperty> GetEnumerator() => Values.GetEnumerator();
#endregion
#region Hidden Interface
/// <summary>
/// Adds an element with the provided key and value to the <see cref="T:System.Collections.Generic.IDictionary`2" />.
/// </summary>
/// <param name="key">The object to use as the key of the element to add.</param>
/// <param name="value">The object to use as the value of the element to add.</param>
/// <exception cref="T:System.ArgumentNullException">
/// <paramref name="key" /> is null.
/// </exception>
/// <exception cref="T:System.ArgumentException">
/// An element with the same key already exists in the
/// <see cref="T:System.Collections.Generic.IDictionary`2" />.
/// </exception>
/// <exception cref="T:System.NotSupportedException">
/// The <see cref="T:System.Collections.Generic.IDictionary`2" /> is
/// read-only.
/// </exception>
void IDictionary<ExifTag, ExifProperty>.Add(ExifTag key, ExifProperty value) => Add(value);
/// <summary>
/// Adds an item to the <see cref="T:System.Collections.Generic.ICollection`1" />.
/// </summary>
/// <param name="item">The object to add to the <see cref="T:System.Collections.Generic.ICollection`1" />.</param>
/// <exception cref="T:System.NotSupportedException">
/// The <see cref="T:System.Collections.Generic.ICollection`1" /> is
/// read-only.
/// </exception>
void ICollection<KeyValuePair<ExifTag, ExifProperty>>.Add(KeyValuePair<ExifTag, ExifProperty> item) =>
Add(item.Value);
bool ICollection<KeyValuePair<ExifTag, ExifProperty>>.Contains(KeyValuePair<ExifTag, ExifProperty> item) =>
throw new NotSupportedException();
/// <summary>
/// Copies the elements of the <see cref="T:System.Collections.Generic.ICollection`1" /> to an
/// <see cref="T:System.Array" />, starting at a particular <see cref="T:System.Array" /> index.
/// </summary>
/// <param name="array">
/// The one-dimensional <see cref="T:System.Array" /> that is the destination of the elements copied
/// from <see cref="T:System.Collections.Generic.ICollection`1" />. The <see cref="T:System.Array" /> must have
/// zero-based indexing.
/// </param>
/// <param name="arrayIndex">The zero-based index in <paramref name="array" /> at which copying begins.</param>
/// <exception cref="T:System.ArgumentNullException">
/// <paramref name="array" /> is null.
/// </exception>
/// <exception cref="T:System.ArgumentOutOfRangeException">
/// <paramref name="arrayIndex" /> is less than 0.
/// </exception>
/// <exception cref="T:System.ArgumentException">
/// <paramref name="array" /> is multidimensional.-or-<paramref name="arrayIndex" /> is equal to or greater than the
/// length of <paramref name="array" />.-or-The number of elements in the source
/// <see cref="T:System.Collections.Generic.ICollection`1" /> is greater than the available space from
/// <paramref name="arrayIndex" /> to the end of the destination <paramref name="array" />.-or-Type
/// <paramref name="T" /> cannot be cast automatically to the type of the destination <paramref name="array" />.
/// </exception>
void ICollection<KeyValuePair<ExifTag, ExifProperty>>.CopyTo(KeyValuePair<ExifTag, ExifProperty>[] array, int arrayIndex)
{
if (array == null)
{
throw new ArgumentNullException("array");
}
if (arrayIndex < 0)
{
throw new ArgumentOutOfRangeException("arrayIndex");
}
if (array.Rank > 1)
{
throw new ArgumentException("Destination array is multidimensional.", "array");
}
if (arrayIndex >= array.Length)
{
throw new ArgumentException("arrayIndex is equal to or greater than the length of destination array", "array");
}
if (arrayIndex + items.Count > array.Length)
{
throw new ArgumentException("There is not enough space in destination array.", "array");
}
var i = 0;
foreach (KeyValuePair<ExifTag, ExifProperty> item in items)
{
if (i >= arrayIndex)
{
array[i] = item;
}
i++;
}
}
/// <summary>
/// Gets a value indicating whether the <see cref="T:System.Collections.Generic.ICollection`1" /> is read-only.
/// </summary>
/// <returns>true if the <see cref="T:System.Collections.Generic.ICollection`1" /> is read-only; otherwise, false.</returns>
bool ICollection<KeyValuePair<ExifTag, ExifProperty>>.IsReadOnly => false;
/// <summary>
/// Removes the first occurrence of a specific object from the
/// <see cref="T:System.Collections.Generic.ICollection`1" />.
/// </summary>
/// <param name="item">The object to remove from the <see cref="T:System.Collections.Generic.ICollection`1" />.</param>
/// <returns>
/// true if <paramref name="item" /> was successfully removed from the
/// <see cref="T:System.Collections.Generic.ICollection`1" />; otherwise, false. This method also returns false if
/// <paramref name="item" /> is not found in the original <see cref="T:System.Collections.Generic.ICollection`1" />.
/// </returns>
/// <exception cref="T:System.NotSupportedException">
/// The <see cref="T:System.Collections.Generic.ICollection`1" /> is
/// read-only.
/// </exception>
bool ICollection<KeyValuePair<ExifTag, ExifProperty>>.Remove(KeyValuePair<ExifTag, ExifProperty> item) =>
throw new NotSupportedException();
/// <summary>
/// Returns an enumerator that iterates through a collection.
/// </summary>
/// <returns>
/// An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.
/// </returns>
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
/// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
/// <returns>
/// A <see cref="T:System.Collections.Generic.IEnumerator`1" /> that can be used to iterate through the collection.
/// </returns>
IEnumerator<KeyValuePair<ExifTag, ExifProperty>> IEnumerable<KeyValuePair<ExifTag, ExifProperty>>.GetEnumerator() =>
items.GetEnumerator();
#endregion
}

View File

@@ -1,598 +0,0 @@
using System.Text;
namespace Umbraco.Cms.Core.Media.Exif;
/// <summary>
/// Creates exif properties from interoperability parameters.
/// </summary>
internal static class ExifPropertyFactory
{
#region Static Methods
/// <summary>
/// Creates an ExifProperty from the given interoperability parameters.
/// </summary>
/// <param name="tag">The tag id of the exif property.</param>
/// <param name="type">The type id of the exif property.</param>
/// <param name="count">Byte or component count.</param>
/// <param name="value">Field data as an array of bytes.</param>
/// <param name="byteOrder">Byte order of value.</param>
/// <param name="ifd">IFD section containing this property.</param>
/// <param name="encoding">The encoding to be used for text metadata when the source encoding is unknown.</param>
/// <returns>an ExifProperty initialized from the interoperability parameters.</returns>
public static ExifProperty Get(ushort tag, ushort type, uint count, byte[] value, BitConverterEx.ByteOrder byteOrder, IFD ifd, Encoding encoding)
{
var conv = new BitConverterEx(byteOrder, BitConverterEx.SystemByteOrder);
// Find the exif tag corresponding to given tag id
ExifTag etag = ExifTagFactory.GetExifTag(ifd, tag);
if (ifd == IFD.Zeroth)
{
// Compression
if (tag == 0x103)
{
return new ExifEnumProperty<Compression>(ExifTag.Compression, (Compression)conv.ToUInt16(value, 0));
}
// PhotometricInterpretation
if (tag == 0x106)
{
return new ExifEnumProperty<PhotometricInterpretation>(
ExifTag.PhotometricInterpretation,
(PhotometricInterpretation)conv.ToUInt16(value, 0));
}
// Orientation
if (tag == 0x112)
{
return new ExifEnumProperty<Orientation>(ExifTag.Orientation, (Orientation)conv.ToUInt16(value, 0));
}
// PlanarConfiguration
if (tag == 0x11c)
{
return new ExifEnumProperty<PlanarConfiguration>(
ExifTag.PlanarConfiguration,
(PlanarConfiguration)conv.ToUInt16(value, 0));
}
// YCbCrPositioning
if (tag == 0x213)
{
return new ExifEnumProperty<YCbCrPositioning>(
ExifTag.YCbCrPositioning,
(YCbCrPositioning)conv.ToUInt16(value, 0));
}
// ResolutionUnit
if (tag == 0x128)
{
return new ExifEnumProperty<ResolutionUnit>(
ExifTag.ResolutionUnit,
(ResolutionUnit)conv.ToUInt16(value, 0));
}
// DateTime
if (tag == 0x132)
{
return new ExifDateTime(ExifTag.DateTime, ExifBitConverter.ToDateTime(value));
}
if (tag == 0x9c9b || tag == 0x9c9c || // Windows tags
tag == 0x9c9d || tag == 0x9c9e || tag == 0x9c9f)
{
return new WindowsByteString(
etag,
Encoding.Unicode.GetString(value).TrimEnd(Constants.CharArrays.NullTerminator));
}
}
else if (ifd == IFD.EXIF)
{
// ExifVersion
if (tag == 0x9000)
{
return new ExifVersion(ExifTag.ExifVersion, ExifBitConverter.ToAscii(value, Encoding.ASCII));
}
// FlashpixVersion
if (tag == 0xa000)
{
return new ExifVersion(ExifTag.FlashpixVersion, ExifBitConverter.ToAscii(value, Encoding.ASCII));
}
// ColorSpace
if (tag == 0xa001)
{
return new ExifEnumProperty<ColorSpace>(ExifTag.ColorSpace, (ColorSpace)conv.ToUInt16(value, 0));
}
// UserComment
if (tag == 0x9286)
{
// Default to ASCII
Encoding enc = Encoding.ASCII;
bool hasenc;
if (value.Length < 8)
{
hasenc = false;
}
else
{
hasenc = true;
var encstr = enc.GetString(value, 0, 8);
if (string.Compare(encstr, "ASCII\0\0\0", StringComparison.OrdinalIgnoreCase) == 0)
{
enc = Encoding.ASCII;
}
else if (string.Compare(encstr, "JIS\0\0\0\0\0", StringComparison.OrdinalIgnoreCase) == 0)
{
enc = Encoding.GetEncoding("Japanese (JIS 0208-1990 and 0212-1990)");
}
else if (string.Compare(encstr, "Unicode\0", StringComparison.OrdinalIgnoreCase) == 0)
{
enc = Encoding.Unicode;
}
else
{
hasenc = false;
}
}
var val = (hasenc ? enc.GetString(value, 8, value.Length - 8) : enc.GetString(value)).Trim(
Constants.CharArrays.NullTerminator);
return new ExifEncodedString(ExifTag.UserComment, val, enc);
}
// DateTimeOriginal
if (tag == 0x9003)
{
return new ExifDateTime(ExifTag.DateTimeOriginal, ExifBitConverter.ToDateTime(value));
}
// DateTimeDigitized
if (tag == 0x9004)
{
return new ExifDateTime(ExifTag.DateTimeDigitized, ExifBitConverter.ToDateTime(value));
}
// ExposureProgram
if (tag == 0x8822)
{
return new ExifEnumProperty<ExposureProgram>(
ExifTag.ExposureProgram,
(ExposureProgram)conv.ToUInt16(value, 0));
}
// MeteringMode
if (tag == 0x9207)
{
return new ExifEnumProperty<MeteringMode>(ExifTag.MeteringMode, (MeteringMode)conv.ToUInt16(value, 0));
}
// LightSource
if (tag == 0x9208)
{
return new ExifEnumProperty<LightSource>(ExifTag.LightSource, (LightSource)conv.ToUInt16(value, 0));
}
// Flash
if (tag == 0x9209)
{
return new ExifEnumProperty<Flash>(ExifTag.Flash, (Flash)conv.ToUInt16(value, 0), true);
}
// SubjectArea
if (tag == 0x9214)
{
if (count == 3)
{
return new ExifCircularSubjectArea(
ExifTag.SubjectArea,
ExifBitConverter.ToUShortArray(value, (int)count, byteOrder));
}
if (count == 4)
{
return new ExifRectangularSubjectArea(
ExifTag.SubjectArea,
ExifBitConverter.ToUShortArray(value, (int)count, byteOrder));
}
return new ExifPointSubjectArea(
ExifTag.SubjectArea,
ExifBitConverter.ToUShortArray(value, (int)count, byteOrder));
}
// FocalPlaneResolutionUnit
if (tag == 0xa210)
{
return new ExifEnumProperty<ResolutionUnit>(
ExifTag.FocalPlaneResolutionUnit,
(ResolutionUnit)conv.ToUInt16(value, 0),
true);
}
// SubjectLocation
if (tag == 0xa214)
{
return new ExifPointSubjectArea(
ExifTag.SubjectLocation,
ExifBitConverter.ToUShortArray(value, (int)count, byteOrder));
}
// SensingMethod
if (tag == 0xa217)
{
return new ExifEnumProperty<SensingMethod>(
ExifTag.SensingMethod,
(SensingMethod)conv.ToUInt16(value, 0),
true);
}
// FileSource
if (tag == 0xa300)
{
return new ExifEnumProperty<FileSource>(ExifTag.FileSource, (FileSource)conv.ToUInt16(value, 0), true);
}
// SceneType
if (tag == 0xa301)
{
return new ExifEnumProperty<SceneType>(ExifTag.SceneType, (SceneType)conv.ToUInt16(value, 0), true);
}
// CustomRendered
if (tag == 0xa401)
{
return new ExifEnumProperty<CustomRendered>(
ExifTag.CustomRendered,
(CustomRendered)conv.ToUInt16(value, 0),
true);
}
// ExposureMode
if (tag == 0xa402)
{
return new ExifEnumProperty<ExposureMode>(ExifTag.ExposureMode, (ExposureMode)conv.ToUInt16(value, 0), true);
}
// WhiteBalance
if (tag == 0xa403)
{
return new ExifEnumProperty<WhiteBalance>(ExifTag.WhiteBalance, (WhiteBalance)conv.ToUInt16(value, 0), true);
}
// SceneCaptureType
if (tag == 0xa406)
{
return new ExifEnumProperty<SceneCaptureType>(
ExifTag.SceneCaptureType,
(SceneCaptureType)conv.ToUInt16(value, 0),
true);
}
// GainControl
if (tag == 0xa407)
{
return new ExifEnumProperty<GainControl>(ExifTag.GainControl, (GainControl)conv.ToUInt16(value, 0), true);
}
// Contrast
if (tag == 0xa408)
{
return new ExifEnumProperty<Contrast>(ExifTag.Contrast, (Contrast)conv.ToUInt16(value, 0), true);
}
// Saturation
if (tag == 0xa409)
{
return new ExifEnumProperty<Saturation>(ExifTag.Saturation, (Saturation)conv.ToUInt16(value, 0), true);
}
// Sharpness
if (tag == 0xa40a)
{
return new ExifEnumProperty<Sharpness>(ExifTag.Sharpness, (Sharpness)conv.ToUInt16(value, 0), true);
}
// SubjectDistanceRange
if (tag == 0xa40c)
{
return new ExifEnumProperty<SubjectDistanceRange>(
ExifTag.SubjectDistanceRange,
(SubjectDistanceRange)conv.ToUInt16(value, 0),
true);
}
}
else if (ifd == IFD.GPS)
{
// GPSVersionID
if (tag == 0)
{
return new ExifVersion(ExifTag.GPSVersionID, ExifBitConverter.ToString(value));
}
// GPSLatitudeRef
if (tag == 1)
{
return new ExifEnumProperty<GPSLatitudeRef>(ExifTag.GPSLatitudeRef, (GPSLatitudeRef)value[0]);
}
// GPSLatitude
if (tag == 2)
{
return new GPSLatitudeLongitude(
ExifTag.GPSLatitude,
ExifBitConverter.ToURationalArray(value, (int)count, byteOrder));
}
// GPSLongitudeRef
if (tag == 3)
{
return new ExifEnumProperty<GPSLongitudeRef>(ExifTag.GPSLongitudeRef, (GPSLongitudeRef)value[0]);
}
// GPSLongitude
if (tag == 4)
{
return new GPSLatitudeLongitude(
ExifTag.GPSLongitude,
ExifBitConverter.ToURationalArray(value, (int)count, byteOrder));
}
// GPSAltitudeRef
if (tag == 5)
{
return new ExifEnumProperty<GPSAltitudeRef>(ExifTag.GPSAltitudeRef, (GPSAltitudeRef)value[0]);
}
// GPSTimeStamp
if (tag == 7)
{
return new GPSTimeStamp(
ExifTag.GPSTimeStamp,
ExifBitConverter.ToURationalArray(value, (int)count, byteOrder));
}
// GPSStatus
if (tag == 9)
{
return new ExifEnumProperty<GPSStatus>(ExifTag.GPSStatus, (GPSStatus)value[0]);
}
// GPSMeasureMode
if (tag == 10)
{
return new ExifEnumProperty<GPSMeasureMode>(ExifTag.GPSMeasureMode, (GPSMeasureMode)value[0]);
}
// GPSSpeedRef
if (tag == 12)
{
return new ExifEnumProperty<GPSSpeedRef>(ExifTag.GPSSpeedRef, (GPSSpeedRef)value[0]);
}
// GPSTrackRef
if (tag == 14)
{
return new ExifEnumProperty<GPSDirectionRef>(ExifTag.GPSTrackRef, (GPSDirectionRef)value[0]);
}
// GPSImgDirectionRef
if (tag == 16)
{
return new ExifEnumProperty<GPSDirectionRef>(ExifTag.GPSImgDirectionRef, (GPSDirectionRef)value[0]);
}
// GPSDestLatitudeRef
if (tag == 19)
{
return new ExifEnumProperty<GPSLatitudeRef>(ExifTag.GPSDestLatitudeRef, (GPSLatitudeRef)value[0]);
}
// GPSDestLatitude
if (tag == 20)
{
return new GPSLatitudeLongitude(
ExifTag.GPSDestLatitude,
ExifBitConverter.ToURationalArray(value, (int)count, byteOrder));
}
// GPSDestLongitudeRef
if (tag == 21)
{
return new ExifEnumProperty<GPSLongitudeRef>(ExifTag.GPSDestLongitudeRef, (GPSLongitudeRef)value[0]);
}
// GPSDestLongitude
if (tag == 22)
{
return new GPSLatitudeLongitude(
ExifTag.GPSDestLongitude,
ExifBitConverter.ToURationalArray(value, (int)count, byteOrder));
}
// GPSDestBearingRef
if (tag == 23)
{
return new ExifEnumProperty<GPSDirectionRef>(ExifTag.GPSDestBearingRef, (GPSDirectionRef)value[0]);
}
// GPSDestDistanceRef
if (tag == 25)
{
return new ExifEnumProperty<GPSDistanceRef>(ExifTag.GPSDestDistanceRef, (GPSDistanceRef)value[0]);
}
// GPSDate
if (tag == 29)
{
return new ExifDateTime(ExifTag.GPSDateStamp, ExifBitConverter.ToDateTime(value, false));
}
// GPSDifferential
if (tag == 30)
{
return new ExifEnumProperty<GPSDifferential>(
ExifTag.GPSDifferential,
(GPSDifferential)conv.ToUInt16(value, 0));
}
}
else if (ifd == IFD.Interop)
{
// InteroperabilityIndex
if (tag == 1)
{
return new ExifAscii(ExifTag.InteroperabilityIndex, ExifBitConverter.ToAscii(value, Encoding.ASCII), Encoding.ASCII);
}
// InteroperabilityVersion
if (tag == 2)
{
return new ExifVersion(
ExifTag.InteroperabilityVersion,
ExifBitConverter.ToAscii(value, Encoding.ASCII));
}
}
else if (ifd == IFD.First)
{
// Compression
if (tag == 0x103)
{
return new ExifEnumProperty<Compression>(
ExifTag.ThumbnailCompression,
(Compression)conv.ToUInt16(value, 0));
}
// PhotometricInterpretation
if (tag == 0x106)
{
return new ExifEnumProperty<PhotometricInterpretation>(
ExifTag.ThumbnailPhotometricInterpretation,
(PhotometricInterpretation)conv.ToUInt16(value, 0));
}
// Orientation
if (tag == 0x112)
{
return new ExifEnumProperty<Orientation>(
ExifTag.ThumbnailOrientation,
(Orientation)conv.ToUInt16(value, 0));
}
// PlanarConfiguration
if (tag == 0x11c)
{
return new ExifEnumProperty<PlanarConfiguration>(
ExifTag.ThumbnailPlanarConfiguration,
(PlanarConfiguration)conv.ToUInt16(value, 0));
}
// YCbCrPositioning
if (tag == 0x213)
{
return new ExifEnumProperty<YCbCrPositioning>(
ExifTag.ThumbnailYCbCrPositioning,
(YCbCrPositioning)conv.ToUInt16(value, 0));
}
// ResolutionUnit
if (tag == 0x128)
{
return new ExifEnumProperty<ResolutionUnit>(
ExifTag.ThumbnailResolutionUnit,
(ResolutionUnit)conv.ToUInt16(value, 0));
}
// DateTime
if (tag == 0x132)
{
return new ExifDateTime(ExifTag.ThumbnailDateTime, ExifBitConverter.ToDateTime(value));
}
}
// 1 = BYTE An 8-bit unsigned integer.
if (type == 1)
{
if (count == 1)
{
return new ExifByte(etag, value[0]);
}
return new ExifByteArray(etag, value);
}
// 2 = ASCII An 8-bit byte containing one 7-bit ASCII code.
if (type == 2)
{
return new ExifAscii(etag, ExifBitConverter.ToAscii(value, encoding), encoding);
}
// 3 = SHORT A 16-bit (2-byte) unsigned integer.
if (type == 3)
{
if (count == 1)
{
return new ExifUShort(etag, conv.ToUInt16(value, 0));
}
return new ExifUShortArray(etag, ExifBitConverter.ToUShortArray(value, (int)count, byteOrder));
}
// 4 = LONG A 32-bit (4-byte) unsigned integer.
if (type == 4)
{
if (count == 1)
{
return new ExifUInt(etag, conv.ToUInt32(value, 0));
}
return new ExifUIntArray(etag, ExifBitConverter.ToUIntArray(value, (int)count, byteOrder));
}
// 5 = RATIONAL Two LONGs. The first LONG is the numerator and the second LONG expresses the denominator.
if (type == 5)
{
if (count == 1)
{
return new ExifURational(etag, ExifBitConverter.ToURational(value, byteOrder));
}
return new ExifURationalArray(etag, ExifBitConverter.ToURationalArray(value, (int)count, byteOrder));
}
// 7 = UNDEFINED An 8-bit byte that can take any value depending on the field definition.
if (type == 7)
{
return new ExifUndefined(etag, value);
}
// 9 = SLONG A 32-bit (4-byte) signed integer (2's complement notation).
if (type == 9)
{
if (count == 1)
{
return new ExifSInt(etag, conv.ToInt32(value, 0));
}
return new ExifSIntArray(etag, ExifBitConverter.ToSIntArray(value, (int)count, byteOrder));
}
// 10 = SRATIONAL Two SLONGs. The first SLONG is the numerator and the second SLONG is the denominator.
if (type == 10)
{
if (count == 1)
{
return new ExifSRational(etag, ExifBitConverter.ToSRational(value, byteOrder));
}
return new ExifSRationalArray(etag, ExifBitConverter.ToSRationalArray(value, (int)count, byteOrder));
}
throw new ArgumentException("Unknown property type.");
}
#endregion
}

View File

@@ -1,310 +0,0 @@
namespace Umbraco.Cms.Core.Media.Exif;
/// <summary>
/// Represents the tags associated with exif fields.
/// </summary>
internal enum ExifTag
{
// ****************************
// Zeroth IFD
// ****************************
NewSubfileType = IFD.Zeroth + 254,
SubfileType = IFD.Zeroth + 255,
ImageWidth = IFD.Zeroth + 256,
ImageLength = IFD.Zeroth + 257,
BitsPerSample = IFD.Zeroth + 258,
Compression = IFD.Zeroth + 259,
PhotometricInterpretation = IFD.Zeroth + 262,
Threshholding = IFD.Zeroth + 263,
CellWidth = IFD.Zeroth + 264,
CellLength = IFD.Zeroth + 265,
FillOrder = IFD.Zeroth + 266,
DocumentName = IFD.Zeroth + 269,
ImageDescription = IFD.Zeroth + 270,
Make = IFD.Zeroth + 271,
Model = IFD.Zeroth + 272,
StripOffsets = IFD.Zeroth + 273,
Orientation = IFD.Zeroth + 274,
SamplesPerPixel = IFD.Zeroth + 277,
RowsPerStrip = IFD.Zeroth + 278,
StripByteCounts = IFD.Zeroth + 279,
MinSampleValue = IFD.Zeroth + 280,
MaxSampleValue = IFD.Zeroth + 281,
XResolution = IFD.Zeroth + 282,
YResolution = IFD.Zeroth + 283,
PlanarConfiguration = IFD.Zeroth + 284,
PageName = IFD.Zeroth + 285,
XPosition = IFD.Zeroth + 286,
YPosition = IFD.Zeroth + 287,
FreeOffsets = IFD.Zeroth + 288,
FreeByteCounts = IFD.Zeroth + 289,
GrayResponseUnit = IFD.Zeroth + 290,
GrayResponseCurve = IFD.Zeroth + 291,
T4Options = IFD.Zeroth + 292,
T6Options = IFD.Zeroth + 293,
ResolutionUnit = IFD.Zeroth + 296,
PageNumber = IFD.Zeroth + 297,
TransferFunction = IFD.Zeroth + 301,
Software = IFD.Zeroth + 305,
DateTime = IFD.Zeroth + 306,
Artist = IFD.Zeroth + 315,
HostComputer = IFD.Zeroth + 316,
Predictor = IFD.Zeroth + 317,
WhitePoint = IFD.Zeroth + 318,
PrimaryChromaticities = IFD.Zeroth + 319,
ColorMap = IFD.Zeroth + 320,
HalftoneHints = IFD.Zeroth + 321,
TileWidth = IFD.Zeroth + 322,
TileLength = IFD.Zeroth + 323,
TileOffsets = IFD.Zeroth + 324,
TileByteCounts = IFD.Zeroth + 325,
InkSet = IFD.Zeroth + 332,
InkNames = IFD.Zeroth + 333,
NumberOfInks = IFD.Zeroth + 334,
DotRange = IFD.Zeroth + 336,
TargetPrinter = IFD.Zeroth + 337,
ExtraSamples = IFD.Zeroth + 338,
SampleFormat = IFD.Zeroth + 339,
SMinSampleValue = IFD.Zeroth + 340,
SMaxSampleValue = IFD.Zeroth + 341,
TransferRange = IFD.Zeroth + 342,
JPEGProc = IFD.Zeroth + 512,
JPEGInterchangeFormat = IFD.Zeroth + 513,
JPEGInterchangeFormatLength = IFD.Zeroth + 514,
JPEGRestartInterval = IFD.Zeroth + 515,
JPEGLosslessPredictors = IFD.Zeroth + 517,
JPEGPointTransforms = IFD.Zeroth + 518,
JPEGQTables = IFD.Zeroth + 519,
JPEGDCTables = IFD.Zeroth + 520,
JPEGACTables = IFD.Zeroth + 521,
YCbCrCoefficients = IFD.Zeroth + 529,
YCbCrSubSampling = IFD.Zeroth + 530,
YCbCrPositioning = IFD.Zeroth + 531,
ReferenceBlackWhite = IFD.Zeroth + 532,
Copyright = IFD.Zeroth + 33432,
// Pointers to other IFDs
EXIFIFDPointer = IFD.Zeroth + 34665,
GPSIFDPointer = IFD.Zeroth + 34853,
// Windows Tags
WindowsTitle = IFD.Zeroth + 0x9c9b,
WindowsComment = IFD.Zeroth + 0x9c9c,
WindowsAuthor = IFD.Zeroth + 0x9c9d,
WindowsKeywords = IFD.Zeroth + 0x9c9e,
WindowsSubject = IFD.Zeroth + 0x9c9f,
// Rating
Rating = IFD.Zeroth + 0x4746,
RatingPercent = IFD.Zeroth + 0x4749,
// Microsoft specifying padding and offset tags
ZerothIFDPadding = IFD.Zeroth + 0xea1c,
// ****************************
// EXIF Tags
// ****************************
ExifVersion = IFD.EXIF + 36864,
FlashpixVersion = IFD.EXIF + 40960,
ColorSpace = IFD.EXIF + 40961,
ComponentsConfiguration = IFD.EXIF + 37121,
CompressedBitsPerPixel = IFD.EXIF + 37122,
PixelXDimension = IFD.EXIF + 40962,
PixelYDimension = IFD.EXIF + 40963,
MakerNote = IFD.EXIF + 37500,
UserComment = IFD.EXIF + 37510,
RelatedSoundFile = IFD.EXIF + 40964,
DateTimeOriginal = IFD.EXIF + 36867,
DateTimeDigitized = IFD.EXIF + 36868,
SubSecTime = IFD.EXIF + 37520,
SubSecTimeOriginal = IFD.EXIF + 37521,
SubSecTimeDigitized = IFD.EXIF + 37522,
ExposureTime = IFD.EXIF + 33434,
FNumber = IFD.EXIF + 33437,
ExposureProgram = IFD.EXIF + 34850,
SpectralSensitivity = IFD.EXIF + 34852,
ISOSpeedRatings = IFD.EXIF + 34855,
OECF = IFD.EXIF + 34856,
ShutterSpeedValue = IFD.EXIF + 37377,
ApertureValue = IFD.EXIF + 37378,
BrightnessValue = IFD.EXIF + 37379,
ExposureBiasValue = IFD.EXIF + 37380,
MaxApertureValue = IFD.EXIF + 37381,
SubjectDistance = IFD.EXIF + 37382,
MeteringMode = IFD.EXIF + 37383,
LightSource = IFD.EXIF + 37384,
Flash = IFD.EXIF + 37385,
FocalLength = IFD.EXIF + 37386,
SubjectArea = IFD.EXIF + 37396,
FlashEnergy = IFD.EXIF + 41483,
SpatialFrequencyResponse = IFD.EXIF + 41484,
FocalPlaneXResolution = IFD.EXIF + 41486,
FocalPlaneYResolution = IFD.EXIF + 41487,
FocalPlaneResolutionUnit = IFD.EXIF + 41488,
SubjectLocation = IFD.EXIF + 41492,
ExposureIndex = IFD.EXIF + 41493,
SensingMethod = IFD.EXIF + 41495,
FileSource = IFD.EXIF + 41728,
SceneType = IFD.EXIF + 41729,
CFAPattern = IFD.EXIF + 41730,
CustomRendered = IFD.EXIF + 41985,
ExposureMode = IFD.EXIF + 41986,
WhiteBalance = IFD.EXIF + 41987,
DigitalZoomRatio = IFD.EXIF + 41988,
FocalLengthIn35mmFilm = IFD.EXIF + 41989,
SceneCaptureType = IFD.EXIF + 41990,
GainControl = IFD.EXIF + 41991,
Contrast = IFD.EXIF + 41992,
Saturation = IFD.EXIF + 41993,
Sharpness = IFD.EXIF + 41994,
DeviceSettingDescription = IFD.EXIF + 41995,
SubjectDistanceRange = IFD.EXIF + 41996,
ImageUniqueID = IFD.EXIF + 42016,
InteroperabilityIFDPointer = IFD.EXIF + 40965,
// Microsoft specifying padding and offset tags
ExifIFDPadding = IFD.EXIF + 0xea1c,
OffsetSchema = IFD.EXIF + 0xea1d,
// ****************************
// GPS Tags
// ****************************
GPSVersionID = IFD.GPS + 0,
GPSLatitudeRef = IFD.GPS + 1,
GPSLatitude = IFD.GPS + 2,
GPSLongitudeRef = IFD.GPS + 3,
GPSLongitude = IFD.GPS + 4,
GPSAltitudeRef = IFD.GPS + 5,
GPSAltitude = IFD.GPS + 6,
GPSTimeStamp = IFD.GPS + 7,
GPSSatellites = IFD.GPS + 8,
GPSStatus = IFD.GPS + 9,
GPSMeasureMode = IFD.GPS + 10,
GPSDOP = IFD.GPS + 11,
GPSSpeedRef = IFD.GPS + 12,
GPSSpeed = IFD.GPS + 13,
GPSTrackRef = IFD.GPS + 14,
GPSTrack = IFD.GPS + 15,
GPSImgDirectionRef = IFD.GPS + 16,
GPSImgDirection = IFD.GPS + 17,
GPSMapDatum = IFD.GPS + 18,
GPSDestLatitudeRef = IFD.GPS + 19,
GPSDestLatitude = IFD.GPS + 20,
GPSDestLongitudeRef = IFD.GPS + 21,
GPSDestLongitude = IFD.GPS + 22,
GPSDestBearingRef = IFD.GPS + 23,
GPSDestBearing = IFD.GPS + 24,
GPSDestDistanceRef = IFD.GPS + 25,
GPSDestDistance = IFD.GPS + 26,
GPSProcessingMethod = IFD.GPS + 27,
GPSAreaInformation = IFD.GPS + 28,
GPSDateStamp = IFD.GPS + 29,
GPSDifferential = IFD.GPS + 30,
// ****************************
// InterOp Tags
// ****************************
InteroperabilityIndex = IFD.Interop + 1,
InteroperabilityVersion = IFD.Interop + 2,
RelatedImageWidth = IFD.Interop + 0x1001,
RelatedImageHeight = IFD.Interop + 0x1002,
// ****************************
// First IFD TIFF Tags
// ****************************
ThumbnailImageWidth = IFD.First + 256,
ThumbnailImageLength = IFD.First + 257,
ThumbnailBitsPerSample = IFD.First + 258,
ThumbnailCompression = IFD.First + 259,
ThumbnailPhotometricInterpretation = IFD.First + 262,
ThumbnailOrientation = IFD.First + 274,
ThumbnailSamplesPerPixel = IFD.First + 277,
ThumbnailPlanarConfiguration = IFD.First + 284,
ThumbnailYCbCrSubSampling = IFD.First + 530,
ThumbnailYCbCrPositioning = IFD.First + 531,
ThumbnailXResolution = IFD.First + 282,
ThumbnailYResolution = IFD.First + 283,
ThumbnailResolutionUnit = IFD.First + 296,
ThumbnailStripOffsets = IFD.First + 273,
ThumbnailRowsPerStrip = IFD.First + 278,
ThumbnailStripByteCounts = IFD.First + 279,
ThumbnailJPEGInterchangeFormat = IFD.First + 513,
ThumbnailJPEGInterchangeFormatLength = IFD.First + 514,
ThumbnailTransferFunction = IFD.First + 301,
ThumbnailWhitePoint = IFD.First + 318,
ThumbnailPrimaryChromaticities = IFD.First + 319,
ThumbnailYCbCrCoefficients = IFD.First + 529,
ThumbnailReferenceBlackWhite = IFD.First + 532,
ThumbnailDateTime = IFD.First + 306,
ThumbnailImageDescription = IFD.First + 270,
ThumbnailMake = IFD.First + 271,
ThumbnailModel = IFD.First + 272,
ThumbnailSoftware = IFD.First + 305,
ThumbnailArtist = IFD.First + 315,
ThumbnailCopyright = IFD.First + 33432,
// ****************************
// JFIF Tags
// ****************************
/// <summary>
/// Represents the JFIF version.
/// </summary>
JFIFVersion = IFD.JFIF + 1,
/// <summary>
/// Represents units for X and Y densities.
/// </summary>
JFIFUnits = IFD.JFIF + 101,
/// <summary>
/// Horizontal pixel density.
/// </summary>
XDensity = IFD.JFIF + 102,
/// <summary>
/// Vertical pixel density
/// </summary>
YDensity = IFD.JFIF + 103,
/// <summary>
/// Thumbnail horizontal pixel count.
/// </summary>
JFIFXThumbnail = IFD.JFIF + 201,
/// <summary>
/// Thumbnail vertical pixel count.
/// </summary>
JFIFYThumbnail = IFD.JFIF + 202,
/// <summary>
/// JFIF JPEG thumbnail.
/// </summary>
JFIFThumbnail = IFD.JFIF + 203,
/// <summary>
/// Code which identifies the JFIF extension.
/// </summary>
JFXXExtensionCode = IFD.JFXX + 1,
/// <summary>
/// Thumbnail horizontal pixel count.
/// </summary>
JFXXXThumbnail = IFD.JFXX + 101,
/// <summary>
/// Thumbnail vertical pixel count.
/// </summary>
JFXXYThumbnail = IFD.JFXX + 102,
/// <summary>
/// The 256-Color RGB palette.
/// </summary>
JFXXPalette = IFD.JFXX + 201,
/// <summary>
/// JFIF thumbnail. The thumbnail will be either a JPEG,
/// a 256 color palette bitmap, or a 24-bit RGB bitmap.
/// </summary>
JFXXThumbnail = IFD.JFXX + 202,
}

View File

@@ -1,63 +0,0 @@
namespace Umbraco.Cms.Core.Media.Exif;
internal static class ExifTagFactory
{
#region Static Methods
/// <summary>
/// Returns the ExifTag corresponding to the given tag id.
/// </summary>
public static ExifTag GetExifTag(IFD ifd, ushort tagid) => (ExifTag)(ifd + tagid);
/// <summary>
/// Returns the tag id corresponding to the given ExifTag.
/// </summary>
public static ushort GetTagID(ExifTag exiftag)
{
IFD ifd = GetTagIFD(exiftag);
return (ushort)((int)exiftag - (int)ifd);
}
/// <summary>
/// Returns the IFD section containing the given tag.
/// </summary>
public static IFD GetTagIFD(ExifTag tag) => (IFD)((int)tag / 100000 * 100000);
/// <summary>
/// Returns the string representation for the given exif tag.
/// </summary>
public static string GetTagName(ExifTag tag)
{
var name = Enum.GetName(typeof(ExifTag), tag);
if (name == null)
{
return "Unknown";
}
return name;
}
/// <summary>
/// Returns the string representation for the given tag id.
/// </summary>
public static string GetTagName(IFD ifd, ushort tagid) => GetTagName(GetExifTag(ifd, tagid));
/// <summary>
/// Returns the string representation for the given exif tag including
/// IFD section and tag id.
/// </summary>
public static string GetTagLongName(ExifTag tag)
{
var ifdname = Enum.GetName(typeof(IFD), GetTagIFD(tag));
var name = Enum.GetName(typeof(ExifTag), tag);
if (name == null)
{
name = "Unknown";
}
var tagidname = GetTagID(tag).ToString();
return ifdname + ": " + name + " (" + tagidname + ")";
}
#endregion
}

View File

@@ -1,17 +0,0 @@
namespace Umbraco.Cms.Core.Media.Exif;
/// <summary>
/// Represents the IFD section containing tags.
/// </summary>
internal enum IFD
{
Unknown = 0,
Zeroth = 100000,
EXIF = 200000,
GPS = 300000,
Interop = 400000,
First = 500000,
MakerNote = 600000,
JFIF = 700000,
JFXX = 800000,
}

View File

@@ -1,144 +0,0 @@
using System.ComponentModel;
using System.Text;
using Umbraco.Cms.Core.Media.TypeDetector;
namespace Umbraco.Cms.Core.Media.Exif;
/// <summary>
/// Represents the base class for image files.
/// </summary>
[TypeDescriptionProvider(typeof(ExifFileTypeDescriptionProvider))]
internal abstract class ImageFile
{
#region Constructor
/// <summary>
/// Initializes a new instance of the <see cref="ImageFile" /> class.
/// </summary>
protected ImageFile()
{
Format = ImageFileFormat.Unknown;
Properties = new ExifPropertyCollection(this);
Encoding = Encoding.Default;
}
#endregion
#region Properties
/// <summary>
/// Returns the format of the <see cref="ImageFile" />.
/// </summary>
public ImageFileFormat Format { get; protected set; }
/// <summary>
/// Gets the collection of Exif properties contained in the <see cref="ImageFile" />.
/// </summary>
public ExifPropertyCollection Properties { get; }
/// <summary>
/// Gets or sets the embedded thumbnail image.
/// </summary>
public ImageFile? Thumbnail { get; set; }
/// <summary>
/// Gets or sets the Exif property with the given key.
/// </summary>
/// <param name="key">The Exif tag associated with the Exif property.</param>
public ExifProperty this[ExifTag key]
{
get => Properties[key];
set => Properties[key] = value;
}
/// <summary>
/// Gets the encoding used for text metadata when the source encoding is unknown.
/// </summary>
public Encoding Encoding { get; protected set; }
#endregion
#region Instance Methods
/// <summary>
/// Saves the <see cref="ImageFile" /> to the specified file.
/// </summary>
/// <param name="filename">A string that contains the name of the file.</param>
public virtual void Save(string filename)
{
using (var stream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None))
{
Save(stream);
}
}
/// <summary>
/// Saves the <see cref="ImageFile" /> to the specified stream.
/// </summary>
/// <param name="stream">A <see cref="Sytem.IO.Stream" /> to save image data to.</param>
public abstract void Save(Stream stream);
#endregion
#region Static Methods
/// <summary>
/// Creates an <see cref="ImageFile" /> from the specified file.
/// </summary>
/// <param name="filename">A string that contains the name of the file.</param>
/// <returns>The <see cref="ImageFile" /> created from the file.</returns>
public static ImageFile? FromFile(string filename) => FromFile(filename, Encoding.Default);
/// <summary>
/// Creates an <see cref="ImageFile" /> from the specified file.
/// </summary>
/// <param name="filename">A string that contains the name of the file.</param>
/// <param name="encoding">The encoding to be used for text metadata when the source encoding is unknown.</param>
/// <returns>The <see cref="ImageFile" /> created from the file.</returns>
public static ImageFile? FromFile(string filename, Encoding encoding)
{
using (var stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
{
return FromStream(stream, encoding);
}
}
/// <summary>
/// Creates an <see cref="ImageFile" /> from the specified data stream.
/// </summary>
/// <param name="stream">A <see cref="Sytem.IO.Stream" /> that contains image data.</param>
/// <returns>The <see cref="ImageFile" /> created from the file.</returns>
public static ImageFile? FromStream(Stream stream) => FromStream(stream, Encoding.Default);
/// <summary>
/// Creates an <see cref="ImageFile" /> from the specified data stream.
/// </summary>
/// <param name="stream">A <see cref="Sytem.IO.Stream" /> that contains image data.</param>
/// <param name="encoding">The encoding to be used for text metadata when the source encoding is unknown.</param>
/// <returns>The <see cref="ImageFile" /> created from the file.</returns>
public static ImageFile? FromStream(Stream stream, Encoding encoding)
{
// JPEG
if (JpegDetector.IsOfType(stream))
{
return new JPEGFile(stream, encoding);
}
// TIFF
if (TIFFDetector.IsOfType(stream))
{
return new TIFFFile(stream, encoding);
}
// SVG
if (SvgDetector.IsOfType(stream))
{
return new SvgFile(stream);
}
// We don't know
return null;
}
#endregion
}

View File

@@ -1,100 +0,0 @@
namespace Umbraco.Cms.Core.Media.Exif;
/// <summary>
/// Represents an image file directory.
/// </summary>
internal class ImageFileDirectory
{
/// <summary>
/// Initializes a new instance of the <see cref="ImageFileDirectory" /> class.
/// </summary>
public ImageFileDirectory()
{
Fields = new List<ImageFileDirectoryEntry>();
Strips = new List<TIFFStrip>();
}
/// <summary>
/// The fields contained in this IFD.
/// </summary>
public List<ImageFileDirectoryEntry> Fields { get; }
/// <summary>
/// Offset to the next IFD.
/// </summary>
public uint NextIFDOffset { get; private set; }
/// <summary>
/// Compressed image data.
/// </summary>
public List<TIFFStrip> Strips { get; }
/// <summary>
/// Returns a <see cref="ImageFileDirectory" /> initialized from the given byte data.
/// </summary>
/// <param name="data">The data.</param>
/// <param name="offset">The offset into <paramref name="data" />.</param>
/// <param name="byteOrder">The byte order of <paramref name="data" />.</param>
/// <returns>A <see cref="ImageFileDirectory" /> initialized from the given byte data.</returns>
public static ImageFileDirectory FromBytes(byte[] data, uint offset, BitConverterEx.ByteOrder byteOrder)
{
var ifd = new ImageFileDirectory();
var conv = new BitConverterEx(byteOrder, BitConverterEx.SystemByteOrder);
var stripOffsets = new List<uint>();
var stripLengths = new List<uint>();
// Count
var fieldcount = conv.ToUInt16(data, offset);
// Read fields
for (uint i = 0; i < fieldcount; i++)
{
var fieldoffset = offset + 2 + (12 * i);
var field = ImageFileDirectoryEntry.FromBytes(data, fieldoffset, byteOrder);
ifd.Fields.Add(field);
// Read strip offsets
if (field.Tag == 273)
{
var baselen = field.Data.Length / (int)field.Count;
for (uint j = 0; j < field.Count; j++)
{
var val = new byte[baselen];
Array.Copy(field.Data, j * baselen, val, 0, baselen);
var stripOffset = field.Type == 3 ? BitConverter.ToUInt16(val, 0) : BitConverter.ToUInt32(val, 0);
stripOffsets.Add(stripOffset);
}
}
// Read strip lengths
if (field.Tag == 279)
{
var baselen = field.Data.Length / (int)field.Count;
for (uint j = 0; j < field.Count; j++)
{
var val = new byte[baselen];
Array.Copy(field.Data, j * baselen, val, 0, baselen);
var stripLength = field.Type == 3 ? BitConverter.ToUInt16(val, 0) : BitConverter.ToUInt32(val, 0);
stripLengths.Add(stripLength);
}
}
}
// Save strips
if (stripOffsets.Count != stripLengths.Count)
{
throw new NotValidTIFFileException();
}
for (var i = 0; i < stripOffsets.Count; i++)
{
ifd.Strips.Add(new TIFFStrip(data, stripOffsets[i], stripLengths[i]));
}
// Offset to next ifd
ifd.NextIFDOffset = conv.ToUInt32(data, offset + 2 + (12 * fieldcount));
return ifd;
}
}

View File

@@ -1,144 +0,0 @@
namespace Umbraco.Cms.Core.Media.Exif;
/// <summary>
/// Represents an entry in the image file directory.
/// </summary>
internal struct ImageFileDirectoryEntry
{
/// <summary>
/// The tag that identifies the field.
/// </summary>
public ushort Tag;
/// <summary>
/// Field type identifier.
/// </summary>
public ushort Type;
/// <summary>
/// Count of Type.
/// </summary>
public uint Count;
/// <summary>
/// Field data.
/// </summary>
public byte[] Data;
/// <summary>
/// Initializes a new instance of the <see cref="ImageFileDirectoryEntry" /> struct.
/// </summary>
/// <param name="tag">The tag that identifies the field.</param>
/// <param name="type">Field type identifier.</param>
/// <param name="count">Count of Type.</param>
/// <param name="data">Field data.</param>
public ImageFileDirectoryEntry(ushort tag, ushort type, uint count, byte[] data)
{
Tag = tag;
Type = type;
Count = count;
Data = data;
}
/// <summary>
/// Returns a <see cref="ImageFileDirectoryEntry" /> initialized from the given byte data.
/// </summary>
/// <param name="data">The data.</param>
/// <param name="offset">The offset into <paramref name="data" />.</param>
/// <param name="byteOrder">The byte order of <paramref name="data" />.</param>
/// <returns>A <see cref="ImageFileDirectoryEntry" /> initialized from the given byte data.</returns>
public static ImageFileDirectoryEntry FromBytes(byte[] data, uint offset, BitConverterEx.ByteOrder byteOrder)
{
// Tag ID
var tag = BitConverterEx.ToUInt16(data, offset, byteOrder, BitConverterEx.SystemByteOrder);
// Tag Type
var type = BitConverterEx.ToUInt16(data, offset + 2, byteOrder, BitConverterEx.SystemByteOrder);
// Count of Type
var count = BitConverterEx.ToUInt32(data, offset + 4, byteOrder, BitConverterEx.SystemByteOrder);
// Field value or offset to field data
var value = new byte[4];
Array.Copy(data, offset + 8, value, 0, 4);
// Calculate the bytes we need to read
var baselength = GetBaseLength(type);
var totallength = count * baselength;
// If field value does not fit in 4 bytes
// the value field is an offset to the actual
// field value
if (totallength > 4)
{
var dataoffset = BitConverterEx.ToUInt32(value, 0, byteOrder, BitConverterEx.SystemByteOrder);
value = new byte[totallength];
Array.Copy(data, dataoffset, value, 0, totallength);
}
// Reverse array order if byte orders are different
if (byteOrder != BitConverterEx.SystemByteOrder)
{
for (uint i = 0; i < count; i++)
{
var val = new byte[baselength];
Array.Copy(value, i * baselength, val, 0, baselength);
Array.Reverse(val);
Array.Copy(val, 0, value, i * baselength, baselength);
}
}
return new ImageFileDirectoryEntry(tag, type, count, value);
}
/// <summary>
/// Gets the base byte length for the given type.
/// </summary>
/// <param name="type">Type identifier.</param>
private static uint GetBaseLength(ushort type)
{
// BYTE and SBYTE
if (type == 1 || type == 6)
{
return 1;
}
// ASCII and UNDEFINED
if (type == 2 || type == 7)
{
return 1;
}
// SHORT and SSHORT
if (type == 3 || type == 8)
{
return 2;
}
// LONG and SLONG
if (type == 4 || type == 9)
{
return 4;
}
// RATIONAL (2xLONG) and SRATIONAL (2xSLONG)
if (type == 5 || type == 10)
{
return 8;
}
// FLOAT
if (type == 11)
{
return 4;
}
// DOUBLE
if (type == 12)
{
return 8;
}
throw new ArgumentException("Unknown type identifier.", "type");
}
}

View File

@@ -1,27 +0,0 @@
namespace Umbraco.Cms.Core.Media.Exif;
/// <summary>
/// Represents the format of the <see cref="ImageFile" />.
/// </summary>
internal enum ImageFileFormat
{
/// <summary>
/// The file is not recognized.
/// </summary>
Unknown,
/// <summary>
/// The file is a JPEG/Exif or JPEG/JFIF file.
/// </summary>
JPEG,
/// <summary>
/// The file is a TIFF File.
/// </summary>
TIFF,
/// <summary>
/// The file is a SVG File.
/// </summary>
SVG,
}

View File

@@ -1,44 +0,0 @@
namespace Umbraco.Cms.Core.Media.Exif;
/// <summary>
/// Represents the units for the X and Y densities
/// for a JFIF file.
/// </summary>
internal enum JFIFDensityUnit : byte
{
/// <summary>
/// No units, XDensity and YDensity specify the pixel aspect ratio.
/// </summary>
None = 0,
/// <summary>
/// XDensity and YDensity are dots per inch.
/// </summary>
DotsPerInch = 1,
/// <summary>
/// XDensity and YDensity are dots per cm.
/// </summary>
DotsPerCm = 2,
}
/// <summary>
/// Represents the JFIF extension.
/// </summary>
internal enum JFIFExtension : byte
{
/// <summary>
/// Thumbnail coded using JPEG.
/// </summary>
ThumbnailJPEG = 0x10,
/// <summary>
/// Thumbnail stored using a 256-Color RGB palette.
/// </summary>
ThumbnailPaletteRGB = 0x11,
/// <summary>
/// Thumbnail stored using 3 bytes/pixel (24-bit) RGB values.
/// </summary>
Thumbnail24BitRGB = 0x13,
}

View File

@@ -1,76 +0,0 @@
namespace Umbraco.Cms.Core.Media.Exif;
/// <summary>
/// Represents the JFIF version as a 16 bit unsigned integer. (EXIF Specification: SHORT)
/// </summary>
internal class JFIFVersion : ExifUShort
{
public JFIFVersion(ExifTag tag, ushort value)
: base(tag, value)
{
}
/// <summary>
/// Gets the major version.
/// </summary>
public byte Major => (byte)(mValue >> 8);
/// <summary>
/// Gets the minor version.
/// </summary>
public byte Minor => (byte)(mValue - ((mValue >> 8) * 256));
public override string ToString() => string.Format("{0}.{1:00}", Major, Minor);
}
/// <summary>
/// Represents a JFIF thumbnail. (EXIF Specification: BYTE)
/// </summary>
internal class JFIFThumbnailProperty : ExifProperty
{
protected JFIFThumbnail mValue;
public JFIFThumbnailProperty(ExifTag tag, JFIFThumbnail value)
: base(tag) =>
mValue = value;
public new JFIFThumbnail Value
{
get => mValue;
set => mValue = value;
}
protected override object _Value
{
get => Value;
set => Value = (JFIFThumbnail)value;
}
public override ExifInterOperability Interoperability
{
get
{
if (mValue.Format == JFIFThumbnail.ImageFormat.BMP24Bit)
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 1, (uint)mValue.PixelData.Length, mValue.PixelData);
}
if (mValue.Format == JFIFThumbnail.ImageFormat.BMPPalette)
{
var data = new byte[mValue.Palette.Length + mValue.PixelData.Length];
Array.Copy(mValue.Palette, data, mValue.Palette.Length);
Array.Copy(mValue.PixelData, 0, data, mValue.Palette.Length, mValue.PixelData.Length);
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 1, (uint)data.Length, data);
}
if (mValue.Format == JFIFThumbnail.ImageFormat.JPEG)
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 1, (uint)mValue.PixelData.Length, mValue.PixelData);
}
throw new InvalidOperationException("Unknown thumbnail type.");
}
}
public override string ToString() => mValue.Format.ToString();
}

View File

@@ -1,62 +0,0 @@
namespace Umbraco.Cms.Core.Media.Exif;
/// <summary>
/// Represents a JFIF thumbnail.
/// </summary>
internal class JFIFThumbnail
{
#region Public Enums
public enum ImageFormat
{
JPEG,
BMPPalette,
BMP24Bit,
}
#endregion
#region Properties
/// <summary>
/// Gets the 256 color RGB palette.
/// </summary>
public byte[] Palette { get; }
/// <summary>
/// Gets raw image data.
/// </summary>
public byte[] PixelData { get; }
/// <summary>
/// Gets the image format.
/// </summary>
public ImageFormat Format { get; }
#endregion
#region Constructors
protected JFIFThumbnail()
{
Palette = new byte[0];
PixelData = new byte[0];
}
public JFIFThumbnail(ImageFormat format, byte[] data)
: this()
{
Format = format;
PixelData = data;
}
public JFIFThumbnail(byte[] palette, byte[] data)
: this()
{
Format = ImageFormat.BMPPalette;
Palette = palette;
PixelData = data;
}
#endregion
}

View File

@@ -7,6 +7,7 @@ namespace Umbraco.Cms.Core.Media.Exif;
/// </summary>
/// <seealso cref="System.Exception" />
[Serializable]
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class NotValidJPEGFileException : Exception
{
/// <summary>

File diff suppressed because it is too large Load Diff

View File

@@ -1,95 +0,0 @@
namespace Umbraco.Cms.Core.Media.Exif;
/// <summary>
/// Represents a JPEG marker byte.
/// </summary>
internal enum JPEGMarker : byte
{
// Start Of Frame markers, non-differential, Huffman coding
SOF0 = 0xc0,
SOF1 = 0xc1,
SOF2 = 0xc2,
SOF3 = 0xc3,
// Start Of Frame markers, differential, Huffman coding
SOF5 = 0xc5,
SOF6 = 0xc6,
SOF7 = 0xc7,
// Start Of Frame markers, non-differential, arithmetic coding
JPG = 0xc8,
SOF9 = 0xc9,
SOF10 = 0xca,
SOF11 = 0xcb,
// Start Of Frame markers, differential, arithmetic coding
SOF13 = 0xcd,
SOF14 = 0xce,
SOF15 = 0xcf,
// Huffman table specification
DHT = 0xc4,
// Arithmetic coding conditioning specification
DAC = 0xcc,
// Restart interval termination
RST0 = 0xd0,
RST1 = 0xd1,
RST2 = 0xd2,
RST3 = 0xd3,
RST4 = 0xd4,
RST5 = 0xd5,
RST6 = 0xd6,
RST7 = 0xd7,
// Other markers
SOI = 0xd8,
EOI = 0xd9,
SOS = 0xda,
DQT = 0xdb,
DNL = 0xdc,
DRI = 0xdd,
DHP = 0xde,
EXP = 0xdf,
// application segments
APP0 = 0xe0,
APP1 = 0xe1,
APP2 = 0xe2,
APP3 = 0xe3,
APP4 = 0xe4,
APP5 = 0xe5,
APP6 = 0xe6,
APP7 = 0xe7,
APP8 = 0xe8,
APP9 = 0xe9,
APP10 = 0xea,
APP11 = 0xeb,
APP12 = 0xec,
APP13 = 0xed,
APP14 = 0xee,
APP15 = 0xef,
// JPEG extensions
JPG0 = 0xf0,
JPG1 = 0xf1,
JPG2 = 0xf2,
JPG3 = 0xf3,
JPG4 = 0xf4,
JPG5 = 0xf5,
JPG6 = 0xf6,
JPG7 = 0xf7,
JPG8 = 0xf8,
JPG9 = 0xf9,
JPG10 = 0xfa,
JPG11 = 0xfb,
JP1G2 = 0xfc,
JPG13 = 0xfd,
// Comment
COM = 0xfe,
// Temporary
TEM = 0x01,
}

View File

@@ -1,66 +0,0 @@
namespace Umbraco.Cms.Core.Media.Exif;
/// <summary>
/// Represents the memory view of a JPEG section.
/// A JPEG section is the data between markers of the JPEG file.
/// </summary>
internal class JPEGSection
{
#region Instance Methods
/// <summary>
/// Returns a string representation of the current section.
/// </summary>
/// <returns>A System.String that represents the current section.</returns>
public override string ToString() => string.Format("{0} => Header: {1} bytes, Entropy Data: {2} bytes", Marker, Header.Length, EntropyData.Length);
#endregion
#region Properties
/// <summary>
/// The marker byte representing the section.
/// </summary>
public JPEGMarker Marker { get; }
/// <summary>
/// Section header as a byte array. This is different from the header
/// definition in JPEG specification in that it does not include the
/// two byte section length.
/// </summary>
public byte[] Header { get; set; }
/// <summary>
/// For the SOS and RST markers, this contains the entropy coded data.
/// </summary>
public byte[] EntropyData { get; set; }
#endregion
#region Constructors
/// <summary>
/// Constructs a JPEGSection represented by the marker byte and containing
/// the given data.
/// </summary>
/// <param name="marker">The marker byte representing the section.</param>
/// <param name="data">Section data.</param>
/// <param name="entropydata">Entropy coded data.</param>
public JPEGSection(JPEGMarker marker, byte[] data, byte[] entropydata)
{
Marker = marker;
Header = data;
EntropyData = entropydata;
}
/// <summary>
/// Constructs a JPEGSection represented by the marker byte.
/// </summary>
/// <param name="marker">The marker byte representing the section.</param>
public JPEGSection(JPEGMarker marker)
: this(marker, new byte[0], new byte[0])
{
}
#endregion
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,31 +0,0 @@
using System.Globalization;
using System.Xml.Linq;
namespace Umbraco.Cms.Core.Media.Exif;
internal class SvgFile : ImageFile
{
public SvgFile(Stream fileStream)
{
fileStream.Position = 0;
var document =
XDocument.Load(fileStream); // if it throws an exception the ugly try catch in MediaFileSystem will catch it
var width = document.Root?.Attributes().Where(x => x.Name == "width").Select(x => x.Value).FirstOrDefault();
var height = document.Root?.Attributes().Where(x => x.Name == "height").Select(x => x.Value).FirstOrDefault();
Properties.Add(new ExifSInt(
ExifTag.PixelYDimension,
height == null ? Constants.Conventions.Media.DefaultSize : int.Parse(height, CultureInfo.InvariantCulture)));
Properties.Add(new ExifSInt(
ExifTag.PixelXDimension,
width == null ? Constants.Conventions.Media.DefaultSize : int.Parse(width, CultureInfo.InvariantCulture)));
Format = ImageFileFormat.SVG;
}
public override void Save(Stream stream)
{
}
}

View File

@@ -1,186 +0,0 @@
using System.Text;
namespace Umbraco.Cms.Core.Media.Exif;
/// <summary>
/// Represents the binary view of a TIFF file.
/// </summary>
internal class TIFFFile : ImageFile
{
#region Constructor
/// <summary>
/// Initializes a new instance of the <see cref="JPEGFile" /> class from the
/// specified data stream.
/// </summary>
/// <param name="stream">A <see cref="Sytem.IO.Stream" /> that contains image data.</param>
/// <param name="encoding">The encoding to be used for text metadata when the source encoding is unknown.</param>
protected internal TIFFFile(Stream stream, Encoding encoding)
{
Format = ImageFileFormat.TIFF;
IFDs = new List<ImageFileDirectory>();
Encoding = encoding;
// Read the entire stream
var data = Utility.GetStreamBytes(stream);
// Read the TIFF header
TIFFHeader = TIFFHeader.FromBytes(data, 0);
var nextIFDOffset = TIFFHeader.IFDOffset;
if (nextIFDOffset == 0)
{
throw new NotValidTIFFileException("The first IFD offset is zero.");
}
// Read IFDs in order
while (nextIFDOffset != 0)
{
var ifd = ImageFileDirectory.FromBytes(data, nextIFDOffset, TIFFHeader.ByteOrder);
nextIFDOffset = ifd.NextIFDOffset;
IFDs.Add(ifd);
}
// Process IFDs
// TODO: Add support for multiple frames
foreach (ImageFileDirectoryEntry field in IFDs[0].Fields)
{
Properties.Add(ExifPropertyFactory.Get(field.Tag, field.Type, field.Count, field.Data, BitConverterEx.SystemByteOrder, IFD.Zeroth, Encoding));
}
}
#endregion
#region Properties
/// <summary>
/// Gets the TIFF header.
/// </summary>
public TIFFHeader TIFFHeader { get; }
#endregion
#region Instance Methods
/// <summary>
/// Saves the <see cref="ImageFile" /> to the given stream.
/// </summary>
/// <param name="stream">The data stream used to save the image.</param>
public override void Save(Stream stream)
{
BitConverterEx conv = BitConverterEx.SystemEndian;
// Write TIFF header
uint ifdoffset = 8;
// Byte order
stream.Write(
BitConverterEx.SystemByteOrder == BitConverterEx.ByteOrder.LittleEndian
? new byte[] { 0x49, 0x49 }
: new byte[] { 0x4D, 0x4D },
0,
2);
// TIFF ID
stream.Write(conv.GetBytes((ushort)42), 0, 2);
// Offset to 0th IFD, will be corrected below
stream.Write(conv.GetBytes(ifdoffset), 0, 4);
// Write IFD sections
for (var i = 0; i < IFDs.Count; i++)
{
ImageFileDirectory ifd = IFDs[i];
// Save the location of IFD offset
var ifdLocation = stream.Position - 4;
// Write strips first
var stripOffsets = new byte[4 * ifd.Strips.Count];
var stripLengths = new byte[4 * ifd.Strips.Count];
var stripOffset = ifdoffset;
for (var j = 0; j < ifd.Strips.Count; j++)
{
var stripData = ifd.Strips[j].Data;
var oBytes = BitConverter.GetBytes(stripOffset);
var lBytes = BitConverter.GetBytes((uint)stripData.Length);
Array.Copy(oBytes, 0, stripOffsets, 4 * j, 4);
Array.Copy(lBytes, 0, stripLengths, 4 * j, 4);
stream.Write(stripData, 0, stripData.Length);
stripOffset += (uint)stripData.Length;
}
// Remove old strip tags
for (var j = ifd.Fields.Count - 1; j > 0; j--)
{
var tag = ifd.Fields[j].Tag;
if (tag == 273 || tag == 279)
{
ifd.Fields.RemoveAt(j);
}
}
// Write new strip tags
ifd.Fields.Add(new ImageFileDirectoryEntry(273, 4, (uint)ifd.Strips.Count, stripOffsets));
ifd.Fields.Add(new ImageFileDirectoryEntry(279, 4, (uint)ifd.Strips.Count, stripLengths));
// Write fields after strips
ifdoffset = stripOffset;
// Correct IFD offset
var currentLocation = stream.Position;
stream.Seek(ifdLocation, SeekOrigin.Begin);
stream.Write(conv.GetBytes(ifdoffset), 0, 4);
stream.Seek(currentLocation, SeekOrigin.Begin);
// Offset to field data
var dataOffset = ifdoffset + 2 + ((uint)ifd.Fields.Count * 12) + 4;
// Field count
stream.Write(conv.GetBytes((ushort)ifd.Fields.Count), 0, 2);
// Fields
foreach (ImageFileDirectoryEntry field in ifd.Fields)
{
// Tag
stream.Write(conv.GetBytes(field.Tag), 0, 2);
// Type
stream.Write(conv.GetBytes(field.Type), 0, 2);
// Count
stream.Write(conv.GetBytes(field.Count), 0, 4);
// Field data
var data = field.Data;
if (data.Length <= 4)
{
stream.Write(data, 0, data.Length);
for (var j = data.Length; j < 4; j++)
{
stream.WriteByte(0);
}
}
else
{
stream.Write(conv.GetBytes(dataOffset), 0, 4);
var currentOffset = stream.Position;
stream.Seek(dataOffset, SeekOrigin.Begin);
stream.Write(data, 0, data.Length);
dataOffset += (uint)data.Length;
stream.Seek(currentOffset, SeekOrigin.Begin);
}
}
// Offset to next IFD
ifdoffset = dataOffset;
stream.Write(conv.GetBytes(i == IFDs.Count - 1 ? 0 : ifdoffset), 0, 4);
}
}
/// <summary>
/// Gets the image file directories.
/// </summary>
public List<ImageFileDirectory> IFDs { get; }
#endregion
}

View File

@@ -1,98 +0,0 @@
namespace Umbraco.Cms.Core.Media.Exif;
/// <summary>
/// Represents a TIFF Header.
/// </summary>
internal struct TIFFHeader
{
/// <summary>
/// The byte order of the image file.
/// </summary>
public BitConverterEx.ByteOrder ByteOrder;
/// <summary>
/// TIFF ID. This value should always be 42.
/// </summary>
public byte ID;
/// <summary>
/// The offset to the first IFD section from the
/// start of the TIFF header.
/// </summary>
public uint IFDOffset;
/// <summary>
/// The byte order of the TIFF header itself.
/// </summary>
public BitConverterEx.ByteOrder TIFFHeaderByteOrder;
/// <summary>
/// Initializes a new instance of the <see cref="TIFFHeader" /> struct.
/// </summary>
/// <param name="byteOrder">The byte order.</param>
/// <param name="id">The TIFF ID. This value should always be 42.</param>
/// <param name="ifdOffset">
/// The offset to the first IFD section from the
/// start of the TIFF header.
/// </param>
/// <param name="headerByteOrder">The byte order of the TIFF header itself.</param>
public TIFFHeader(BitConverterEx.ByteOrder byteOrder, byte id, uint ifdOffset, BitConverterEx.ByteOrder headerByteOrder)
{
if (id != 42)
{
throw new NotValidTIFFHeader();
}
ByteOrder = byteOrder;
ID = id;
IFDOffset = ifdOffset;
TIFFHeaderByteOrder = headerByteOrder;
}
/// <summary>
/// Returns a <see cref="TIFFHeader" /> initialized from the given byte data.
/// </summary>
/// <param name="data">The data.</param>
/// <param name="offset">The offset into <paramref name="data" />.</param>
/// <returns>A <see cref="TIFFHeader" /> initialized from the given byte data.</returns>
public static TIFFHeader FromBytes(byte[] data, int offset)
{
var header = default(TIFFHeader);
// TIFF header
if (data[offset] == 0x49 && data[offset + 1] == 0x49)
{
header.ByteOrder = BitConverterEx.ByteOrder.LittleEndian;
}
else if (data[offset] == 0x4D && data[offset + 1] == 0x4D)
{
header.ByteOrder = BitConverterEx.ByteOrder.BigEndian;
}
else
{
throw new NotValidTIFFHeader();
}
// TIFF header may have a different byte order
if (BitConverterEx.LittleEndian.ToUInt16(data, offset + 2) == 42)
{
header.TIFFHeaderByteOrder = BitConverterEx.ByteOrder.LittleEndian;
}
else if (BitConverterEx.BigEndian.ToUInt16(data, offset + 2) == 42)
{
header.TIFFHeaderByteOrder = BitConverterEx.ByteOrder.BigEndian;
}
else
{
throw new NotValidTIFFHeader();
}
header.ID = 42;
// IFD offset
header.IFDOffset =
BitConverterEx.ToUInt32(data, offset + 4, header.TIFFHeaderByteOrder, BitConverterEx.SystemByteOrder);
return header;
}
}

View File

@@ -1,24 +0,0 @@
namespace Umbraco.Cms.Core.Media.Exif;
/// <summary>
/// Represents a strip of compressed image data in a TIFF file.
/// </summary>
internal class TIFFStrip
{
/// <summary>
/// Initializes a new instance of the <see cref="TIFFStrip" /> class.
/// </summary>
/// <param name="data">The byte array to copy strip from.</param>
/// <param name="offset">The offset to the beginning of strip.</param>
/// <param name="length">The length of strip.</param>
public TIFFStrip(byte[] data, uint offset, uint length)
{
Data = new byte[length];
Array.Copy(data, offset, Data, 0, length);
}
/// <summary>
/// Compressed image data contained in this strip.
/// </summary>
public byte[] Data { get; }
}

View File

@@ -1,29 +0,0 @@
namespace Umbraco.Cms.Core.Media.Exif;
/// <summary>
/// Contains utility functions.
/// </summary>
internal class Utility
{
/// <summary>
/// Reads the entire stream and returns its contents as a byte array.
/// </summary>
/// <param name="stream">The <see cref="System.IO.Stream" /> to read.</param>
/// <returns>Contents of the <paramref name="stream" /> as a byte array.</returns>
public static byte[] GetStreamBytes(Stream stream)
{
using (var mem = new MemoryStream())
{
stream.Seek(0, SeekOrigin.Begin);
var b = new byte[32768];
int r;
while ((r = stream.Read(b, 0, b.Length)) > 0)
{
mem.Write(b, 0, r);
}
return mem.ToArray();
}
}
}

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Suppression>
<DiagnosticId>PKV006</DiagnosticId>
<Target>net6.0</Target>
</Suppression>
</Suppressions>

View File

@@ -1,7 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Suppression>
<DiagnosticId>PKV006</DiagnosticId>
<Target>net6.0</Target>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Umbraco.Cms.Core.Deploy.IGridCellValueConnector.GetValue(Umbraco.Cms.Core.Models.GridValue.GridControl,System.Collections.Generic.ICollection{Umbraco.Cms.Core.Deploy.ArtifactDependency},Umbraco.Cms.Core.Deploy.IContextCache)</Target>
<Left>lib/net7.0/Umbraco.Infrastructure.dll</Left>
<Right>lib/net7.0/Umbraco.Infrastructure.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Umbraco.Cms.Core.Deploy.IGridCellValueConnector.SetValue(Umbraco.Cms.Core.Models.GridValue.GridControl,Umbraco.Cms.Core.Deploy.IContextCache)</Target>
<Left>lib/net7.0/Umbraco.Infrastructure.dll</Left>
<Right>lib/net7.0/Umbraco.Infrastructure.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
</Suppressions>

View File

@@ -296,18 +296,7 @@ public static partial class UmbracoBuilderExtensions
private static IUmbracoBuilder AddPreValueMigrators(this IUmbracoBuilder builder)
{
builder.WithCollectionBuilder<PreValueMigratorCollectionBuilder>()
.Append<RenamingPreValueMigrator>()
.Append<RichTextPreValueMigrator>()
.Append<UmbracoSliderPreValueMigrator>()
.Append<MediaPickerPreValueMigrator>()
.Append<ContentPickerPreValueMigrator>()
.Append<NestedContentPreValueMigrator>()
.Append<DecimalPreValueMigrator>()
.Append<ListViewPreValueMigrator>()
.Append<DropDownFlexiblePreValueMigrator>()
.Append<ValueListPreValueMigrator>()
.Append<MarkdownEditorPreValueMigrator>();
builder.WithCollectionBuilder<PreValueMigratorCollectionBuilder>();
return builder;
}

View File

@@ -1,25 +1,7 @@
using System.Diagnostics.CodeAnalysis;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration;
using Umbraco.Cms.Core.Semver;
using Umbraco.Cms.Infrastructure.Migrations.Upgrade.Common;
using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_10_0_0;
using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_10_2_0;
using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_1;
using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_1_0;
using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_10_0;
using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_15_0;
using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_17_0;
using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_6_0;
using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_7_0;
using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_9_0;
using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_9_0_0;
using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_9_1_0;
using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_9_2_0;
using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_9_3_0;
using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_9_4_0;
using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade;
@@ -29,10 +11,6 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade;
/// <seealso cref="MigrationPlan" />
public class UmbracoPlan : MigrationPlan
{
private const string InitPrefix = "{init-";
private const string InitSuffix = "}";
private readonly IUmbracoVersion _umbracoVersion;
/// <summary>
/// Initializes a new instance of the <see cref="UmbracoPlan" /> class.
/// </summary>
@@ -40,7 +18,6 @@ public class UmbracoPlan : MigrationPlan
public UmbracoPlan(IUmbracoVersion umbracoVersion)
: base(Constants.Conventions.Migrations.UmbracoUpgradePlanName)
{
_umbracoVersion = umbracoVersion;
DefinePlan();
}
@@ -57,74 +34,9 @@ public class UmbracoPlan : MigrationPlan
/// upgrades (from a tool old version, or going back in time, etc).
/// </para>
/// </remarks>
public override string InitialState
{
get
{
SemVersion currentVersion = _umbracoVersion.SemanticVersion;
public override string InitialState => "{DED98755-4059-41BB-ADBD-3FEAB12D1D7B}";
// only from 8.0.0 and above
var minVersion = new SemVersion(8);
if (currentVersion < minVersion)
{
throw new InvalidOperationException(
$"Version {currentVersion} cannot be migrated to {_umbracoVersion.SemanticVersion}."
+ $" Please upgrade first to at least {minVersion}.");
}
// Force versions between 7.14.*-7.15.* into into 7.14 initial state. Because there is no db-changes,
// and we don't want users to workaround my putting in version 7.14.0 them self.
if (minVersion <= currentVersion && currentVersion < new SemVersion(7, 16))
{
return GetInitState(minVersion);
}
// initial state is eg "{init-7.14.0}"
return GetInitState(currentVersion);
}
}
/// <inheritdoc />
public override void ThrowOnUnknownInitialState(string state)
{
if (TryGetInitStateVersion(state, out var initVersion))
{
throw new InvalidOperationException(
$"Version {_umbracoVersion.SemanticVersion} does not support migrating from {initVersion}."
+ $" Please verify which versions support migrating from {initVersion}.");
}
base.ThrowOnUnknownInitialState(state);
}
/// <summary>
/// Gets the initial state corresponding to a version.
/// </summary>
/// <param name="version">The version.</param>
/// <returns>
/// The initial state.
/// </returns>
private static string GetInitState(SemVersion version) => InitPrefix + version + InitSuffix;
/// <summary>
/// Tries to extract a version from an initial state.
/// </summary>
/// <param name="state">The state.</param>
/// <param name="version">The version.</param>
/// <returns>
/// <c>true</c> when the state contains a version; otherwise, <c>false</c>.D
/// </returns>
private static bool TryGetInitStateVersion(string state, [MaybeNullWhen(false)] out string version)
{
if (state.StartsWith(InitPrefix) && state.EndsWith(InitSuffix))
{
version = state.TrimStart(InitPrefix).TrimEnd(InitSuffix);
return true;
}
version = null;
return false;
}
/// <summary>
/// Defines the plan.
@@ -138,154 +50,23 @@ public class UmbracoPlan : MigrationPlan
// * Creating a migration for version 8:
// Append the migration to the main chain, using a new guid, before the "//FINAL" comment
//
//
// If the new migration causes a merge conflict, because someone else also added another
// new migration, you NEED to fix the conflict by providing one default path, and paths
// out of the conflict states (see examples below).
// out of the conflict states, eg:
//
// * Porting from version 7:
// Append the ported migration to the main chain, using a new guid (same as above).
// Create a new special chain from the {init-...} state to the main chain.
// .From("state-1")
// .To<ChangeA>("state-a")
// .To<ChangeB>("state-b") // Some might already be in this state, without having applied ChangeA
//
// .From("state-1")
// .Merge()
// .To<ChangeA>("state-a")
// .With()
// .To<ChangeB>("state-b")
// .As("state-2");
// plan starts at 7.14.0 (anything before 7.14.0 is not supported)
From(GetInitState(new SemVersion(7, 14)));
// begin migrating from v7 - remove all keys and indexes
To<DeleteKeysAndIndexes>("{B36B9ABD-374E-465B-9C5F-26AB0D39326F}");
To<AddLockObjects>("{7C447271-CA3F-4A6A-A913-5D77015655CB}");
To<AddContentNuTable>("{CBFF58A2-7B50-4F75-8E98-249920DB0F37}");
To<RenameMediaVersionTable>("{5CB66059-45F4-48BA-BCBD-C5035D79206B}");
To<VariantsMigration>("{FB0A5429-587E-4BD0-8A67-20F0E7E62FF7}");
To<DropMigrationsTable>("{F0C42457-6A3B-4912-A7EA-F27ED85A2092}");
To<DataTypeMigration>("{8640C9E4-A1C0-4C59-99BB-609B4E604981}");
To<TagsMigration>("{DD1B99AF-8106-4E00-BAC7-A43003EA07F8}");
To<SuperZero>("{9DF05B77-11D1-475C-A00A-B656AF7E0908}");
To<PropertyEditorsMigration>("{6FE3EF34-44A0-4992-B379-B40BC4EF1C4D}");
To<LanguageColumns>("{7F59355A-0EC9-4438-8157-EB517E6D2727}");
ToWithReplace<AddVariationTables2, AddVariationTables1A>(
"{941B2ABA-2D06-4E04-81F5-74224F1DB037}",
"{76DF5CD7-A884-41A5-8DC6-7860D95B1DF5}"); // kill AddVariationTable1
To<RefactorMacroColumns>("{A7540C58-171D-462A-91C5-7A9AA5CB8BFD}");
Merge()
.To<UserForeignKeys>("{3E44F712-E2E3-473A-AE49-5D7F8E67CE3F}")
.With()
.To<AddTypedLabels>("{65D6B71C-BDD5-4A2E-8D35-8896325E9151}")
.As("{4CACE351-C6B9-4F0C-A6BA-85A02BBD39E4}");
To<ContentVariationMigration>("{1350617A-4930-4D61-852F-E3AA9E692173}");
To<FallbackLanguage>("{CF51B39B-9B9A-4740-BB7C-EAF606A7BFBF}");
To<UpdateDefaultMandatoryLanguage>("{5F4597F4-A4E0-4AFE-90B5-6D2F896830EB}");
To<RefactorVariantsModel>("{290C18EE-B3DE-4769-84F1-1F467F3F76DA}");
To<DropTaskTables>("{6A2C7C1B-A9DB-4EA9-B6AB-78E7D5B722A7}");
To<AddLogTableColumns>("{8804D8E8-FE62-4E3A-B8A2-C047C2118C38}");
To<DropPreValueTable>("{23275462-446E-44C7-8C2C-3B8C1127B07D}");
To<DropDownPropertyEditorsMigration>("{6B251841-3069-4AD5-8AE9-861F9523E8DA}");
To<TagsMigrationFix>("{EE429F1B-9B26-43CA-89F8-A86017C809A3}");
To<DropTemplateDesignColumn>("{08919C4B-B431-449C-90EC-2B8445B5C6B1}");
To<TablesForScheduledPublishing>("{7EB0254C-CB8B-4C75-B15B-D48C55B449EB}");
To<MakeTagsVariant>("{C39BF2A7-1454-4047-BBFE-89E40F66ED63}");
To<MakeRedirectUrlVariant>("{64EBCE53-E1F0-463A-B40B-E98EFCCA8AE2}");
To<AddContentTypeIsElementColumn>("{0009109C-A0B8-4F3F-8FEB-C137BBDDA268}");
To<ConvertRelatedLinksToMultiUrlPicker>("{ED28B66A-E248-4D94-8CDB-9BDF574023F0}");
To<UpdatePickerIntegerValuesToUdi>("{38C809D5-6C34-426B-9BEA-EFD39162595C}");
To<RenameUmbracoDomainsTable>("{6017F044-8E70-4E10-B2A3-336949692ADD}");
Merge()
.To<DropXmlTables>("{CDBEDEE4-9496-4903-9CF2-4104E00FF960}")
.With()
.To<RadioAndCheckboxPropertyEditorsMigration>("{940FD19A-00A8-4D5C-B8FF-939143585726}")
.As("{0576E786-5C30-4000-B969-302B61E90CA3}");
To<FixLanguageIsoCodeLength>("{48AD6CCD-C7A4-4305-A8AB-38728AD23FC5}");
To<AddPackagesSectionAccess>("{DF470D86-E5CA-42AC-9780-9D28070E25F9}");
// finish migrating from v7 - recreate all keys and indexes
To<CreateKeysAndIndexes>("{3F9764F5-73D0-4D45-8804-1240A66E43A2}");
To<RenameLabelAndRichTextPropertyEditorAliases>("{E0CBE54D-A84F-4A8F-9B13-900945FD7ED9}");
To<MergeDateAndDateTimePropertyEditor>("{78BAF571-90D0-4D28-8175-EF96316DA789}");
// release-8.0.0
// to 8.0.1
To<ChangeNuCacheJsonFormat>("{80C0A0CB-0DD5-4573-B000-C4B7C313C70D}");
// release-8.0.1
// to 8.1.0
To<ConvertTinyMceAndGridMediaUrlsToLocalLink>("{B69B6E8C-A769-4044-A27E-4A4E18D1645A}");
To<RenameUserLoginDtoDateIndex>("{0372A42B-DECF-498D-B4D1-6379E907EB94}");
To<FixContentNuCascade>("{5B1E0D93-F5A3-449B-84BA-65366B84E2D4}");
// to 8.6.0
To<UpdateRelationTypeTable>("{4759A294-9860-46BC-99F9-B4C975CAE580}");
To<AddNewRelationTypes>("{0BC866BC-0665-487A-9913-0290BD0169AD}");
To<AddPropertyTypeValidationMessageColumns>("{3D67D2C8-5E65-47D0-A9E1-DC2EE0779D6B}");
To<MissingContentVersionsIndexes>("{EE288A91-531B-4995-8179-1D62D9AA3E2E}");
To<AddMainDomLock>("{2AB29964-02A1-474D-BD6B-72148D2A53A2}");
// to 8.7.0
To<MissingDictionaryIndex>("{a78e3369-8ea3-40ec-ad3f-5f76929d2b20}");
// to 8.9.0
To<ExternalLoginTableUserData>("{B5838FF5-1D22-4F6C-BCEB-F83ACB14B575}");
// to 8.10.0
To<AddPropertyTypeLabelOnTopColumn>("{D6A8D863-38EC-44FB-91EC-ACD6A668BD18}");
// NOTE: we need to do a merge migration here because as of 'now',
// v9-beta* is already out and 8.15 isn't out yet
// so we need to ensure that migrations from 8.15 are included in the next
// v9*.
// to 8.15.0
To<AddCmsContentNuByteColumn>("{8DDDCD0B-D7D5-4C97-BD6A-6B38CA65752F}");
To<UpgradedIncludeIndexes>("{4695D0C9-0729-4976-985B-048D503665D8}");
To<UpdateCmsPropertyGroupIdSeed>("{5C424554-A32D-4852-8ED1-A13508187901}");
// to 8.17.0
To<AddPropertyTypeGroupColumns>("{153865E9-7332-4C2A-9F9D-F20AEE078EC7}");
// Hack to support migration from 8.18
To<NoopMigration>("{03482BB0-CF13-475C-845E-ECB8319DBE3C}");
// This should be safe to execute again. We need it with a new name to ensure updates from all the following has executed this step.
// - 8.15.0 RC - Current state: {4695D0C9-0729-4976-985B-048D503665D8}
// - 8.15.0 Final - Current state: {5C424554-A32D-4852-8ED1-A13508187901}
// - 9.0.0 RC1 - Current state: {5060F3D2-88BE-4D30-8755-CF51F28EAD12}
To<UpdateCmsPropertyGroupIdSeed>("{622E5172-42E1-4662-AD80-9504AF5A4E53}");
To<ExternalLoginTableIndexesFixup>("{10F7BB61-C550-426B-830B-7F954F689CDF}");
To<DictionaryTablesIndexes>("{5AAE6276-80DB-4ACF-B845-199BC6C37538}");
// to 9.0.0 RC1
To<MigrateLogViewerQueriesFromFileToDb>("{22D801BA-A1FF-4539-BFCC-2139B55594F8}");
To<ExternalLoginTableIndexes>("{50A43237-A6F4-49E2-A7A6-5DAD65C84669}");
To<ExternalLoginTokenTable>("{3D8DADEF-0FDA-4377-A5F0-B52C2110E8F2}");
To<MemberTableColumns>("{1303BDCF-2295-4645-9526-2F32E8B35ABD}");
To<AddPasswordConfigToMemberTable>("{5060F3D2-88BE-4D30-8755-CF51F28EAD12}");
To<AddPropertyTypeGroupColumns>(
"{A2686B49-A082-4B22-97FD-AAB154D46A57}"); // Re-run this migration to make sure it has executed to account for migrations going out of sync between versions.
// TO 9.0.0-rc4
To<UmbracoServerColumn>(
"5E02F241-5253-403D-B5D3-7DB00157E20F"); // Jaddie: This GUID is missing the { }, although this likely can't be changed now as it will break installs going forwards
// TO 9.1.0
To<AddContentVersionCleanupFeature>("{8BAF5E6C-DCB7-41AE-824F-4215AE4F1F98}");
// TO 9.2.0
To<AddUserGroup2NodeTable>("{0571C395-8F0B-44E9-8E3F-47BDD08D817B}");
To<AddDefaultForNotificationsToggle>("{AD3D3B7F-8E74-45A4-85DB-7FFAD57F9243}");
// TO 9.3.0
To<MovePackageXMLToDb>("{A2F22F17-5870-4179-8A8D-2362AA4A0A5F}");
To<UpdateExternalLoginToUseKeyInsteadOfId>("{CA7A1D9D-C9D4-4914-BC0A-459E7B9C3C8C}");
To<AddTwoFactorLoginTable>("{0828F206-DCF7-4F73-ABBB-6792275532EB}");
// TO 9.4.0
To<AddScheduledPublishingLock>("{DBBA1EA0-25A1-4863-90FB-5D306FB6F1E1}");
To<UpdateRelationTypesToHandleDependencies>("{DED98755-4059-41BB-ADBD-3FEAB12D1D7B}");
From(InitialState);
// TO 10.0.0
To<AddMemberPropertiesAsColumns>("{B7E0D53C-2B0E-418B-AB07-2DDE486E225F}");

View File

@@ -1,23 +0,0 @@
using Umbraco.Cms.Infrastructure.Persistence.Dtos;
using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
internal class AddContentNuTable : MigrationBase
{
public AddContentNuTable(IMigrationContext context)
: base(context)
{
}
protected override void Migrate()
{
IEnumerable<string> tables = SqlSyntax.GetTablesInSchema(Context.Database);
if (tables.InvariantContains("cmsContentNu"))
{
return;
}
Create.Table<ContentNuDto>(true).Do();
}
}

View File

@@ -2,6 +2,7 @@ using Umbraco.Cms.Infrastructure.Persistence.Dtos;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class AddContentTypeIsElementColumn : MigrationBase
{
public AddContentTypeIsElementColumn(IMigrationContext context)

View File

@@ -4,6 +4,7 @@ using Umbraco.Cms.Infrastructure.Persistence.Dtos;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class AddLockObjects : MigrationBase
{
public AddLockObjects(IMigrationContext context)

View File

@@ -2,6 +2,7 @@ using Umbraco.Cms.Infrastructure.Persistence.Dtos;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class AddLogTableColumns : MigrationBase
{
public AddLogTableColumns(IMigrationContext context)

View File

@@ -2,6 +2,7 @@ using Umbraco.Cms.Core;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class AddPackagesSectionAccess : MigrationBase
{
public AddPackagesSectionAccess(IMigrationContext context)

View File

@@ -6,6 +6,7 @@ using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class AddTypedLabels : MigrationBase
{
public AddTypedLabels(IMigrationContext context)

View File

@@ -3,6 +3,7 @@ using Umbraco.Cms.Infrastructure.Persistence.Dtos;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class AddVariationTables1A : MigrationBase
{
public AddVariationTables1A(IMigrationContext context)

View File

@@ -2,6 +2,7 @@ using Umbraco.Cms.Infrastructure.Persistence.Dtos;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class AddVariationTables2 : MigrationBase
{
public AddVariationTables2(IMigrationContext context)

View File

@@ -1,8 +1,9 @@
using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0.Models;
using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class ContentVariationMigration : MigrationBase
{
public ContentVariationMigration(IMigrationContext context)
@@ -12,50 +13,7 @@ public class ContentVariationMigration : MigrationBase
protected override void Migrate()
{
static byte GetNewValue(byte oldValue)
{
switch (oldValue)
{
case 0: // Unknown
case 1: // InvariantNeutral
return 0; // Unknown
case 2: // CultureNeutral
case 3: // CultureNeutral | InvariantNeutral
return 1; // Culture
case 4: // InvariantSegment
case 5: // InvariantSegment | InvariantNeutral
return 2; // Segment
case 6: // InvariantSegment | CultureNeutral
case 7: // InvariantSegment | CultureNeutral | InvariantNeutral
case 8: // CultureSegment
case 9: // CultureSegment | InvariantNeutral
case 10: // CultureSegment | CultureNeutral
case 11: // CultureSegment | CultureNeutral | InvariantNeutral
case 12: // etc
case 13:
case 14:
case 15:
return 3; // Culture | Segment
default:
throw new NotSupportedException($"Invalid value {oldValue}.");
}
}
List<PropertyTypeDto80>? propertyTypes =
Database.Fetch<PropertyTypeDto80>(Sql().Select<PropertyTypeDto80>().From<PropertyTypeDto80>());
foreach (PropertyTypeDto80? dto in propertyTypes)
{
dto.Variations = GetNewValue(dto.Variations);
Database.Update(dto);
}
List<ContentTypeDto80>? contentTypes =
Database.Fetch<ContentTypeDto80>(Sql().Select<ContentTypeDto80>().From<ContentTypeDto80>());
foreach (ContentTypeDto80? dto in contentTypes)
{
dto.Variations = GetNewValue(dto.Variations);
Database.Update(dto);
}
}
// we *need* to use these private DTOs here, which does *not* have extra properties, which would kill the migration

View File

@@ -1,15 +1,6 @@
using System.Globalization;
using System.Runtime.Serialization;
using Newtonsoft.Json;
using NPoco;
using Umbraco.Cms.Core;
using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0.Models;
using Umbraco.Cms.Infrastructure.Persistence;
using Umbraco.Cms.Infrastructure.Persistence.Dtos;
using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class ConvertRelatedLinksToMultiUrlPicker : MigrationBase
{
public ConvertRelatedLinksToMultiUrlPicker(IMigrationContext context)
@@ -19,144 +10,7 @@ public class ConvertRelatedLinksToMultiUrlPicker : MigrationBase
protected override void Migrate()
{
Sql<ISqlContext> sqlDataTypes = Sql()
.Select<DataTypeDto>()
.From<DataTypeDto>()
.Where<DataTypeDto>(x => x.EditorAlias == Constants.PropertyEditors.Legacy.Aliases.RelatedLinks
|| x.EditorAlias == Constants.PropertyEditors.Legacy.Aliases.RelatedLinks2);
List<DataTypeDto>? dataTypes = Database.Fetch<DataTypeDto>(sqlDataTypes);
var dataTypeIds = dataTypes.Select(x => x.NodeId).ToList();
if (dataTypeIds.Count == 0)
{
return;
}
foreach (DataTypeDto? dataType in dataTypes)
{
dataType.EditorAlias = Constants.PropertyEditors.Aliases.MultiUrlPicker;
Database.Update(dataType);
}
Sql<ISqlContext> sqlPropertyTpes = Sql()
.Select<PropertyTypeDto80>()
.From<PropertyTypeDto80>()
.Where<PropertyTypeDto80>(x => dataTypeIds.Contains(x.DataTypeId));
var propertyTypeIds = Database.Fetch<PropertyTypeDto80>(sqlPropertyTpes).Select(x => x.Id).ToList();
if (propertyTypeIds.Count == 0)
{
return;
}
Sql<ISqlContext> sqlPropertyData = Sql()
.Select<PropertyDataDto>()
.From<PropertyDataDto>()
.Where<PropertyDataDto>(x => propertyTypeIds.Contains(x.PropertyTypeId));
List<PropertyDataDto>? properties = Database.Fetch<PropertyDataDto>(sqlPropertyData);
// Create a Multi URL Picker datatype for the converted RelatedLinks data
foreach (PropertyDataDto? property in properties)
{
var value = property.Value?.ToString();
if (string.IsNullOrWhiteSpace(value))
{
continue;
}
List<RelatedLink>? relatedLinks = JsonConvert.DeserializeObject<List<RelatedLink>>(value);
var links = new List<LinkDto>();
if (relatedLinks is null)
{
return;
}
foreach (RelatedLink relatedLink in relatedLinks)
{
GuidUdi? udi = null;
if (relatedLink.IsInternal)
{
var linkIsUdi = UdiParser.TryParse(relatedLink.Link, out udi);
if (linkIsUdi == false)
{
// oh no.. probably an integer, yikes!
if (int.TryParse(relatedLink.Link, NumberStyles.Integer, CultureInfo.InvariantCulture,
out var intId))
{
Sql<ISqlContext> sqlNodeData = Sql()
.Select<NodeDto>()
.From<NodeDto>()
.Where<NodeDto>(x => x.NodeId == intId);
NodeDto? node = Database.Fetch<NodeDto>(sqlNodeData).FirstOrDefault();
if (node != null)
// Note: RelatedLinks did not allow for picking media items,
// so if there's a value this will be a content item - hence
// the hardcoded "document" here
{
udi = new GuidUdi("document", node.UniqueId);
}
}
}
}
var link = new LinkDto
{
Name = relatedLink.Caption,
Target = relatedLink.NewWindow ? "_blank" : null,
Udi = udi,
// Should only have a URL if it's an external link otherwise it wil be a UDI
Url = relatedLink.IsInternal == false ? relatedLink.Link : null,
};
links.Add(link);
}
var json = JsonConvert.SerializeObject(links);
// Update existing data
property.TextValue = json;
Database.Update(property);
}
}
}
internal class RelatedLink
{
public int? Id { get; internal set; }
[JsonProperty("caption")]
public string? Caption { get; set; }
internal bool IsDeleted { get; set; }
[JsonProperty("link")]
public string? Link { get; set; }
[JsonProperty("newWindow")]
public bool NewWindow { get; set; }
[JsonProperty("isInternal")]
public bool IsInternal { get; set; }
}
[DataContract]
internal class LinkDto
{
[DataMember(Name = "name")]
public string? Name { get; set; }
[DataMember(Name = "target")]
public string? Target { get; set; }
[DataMember(Name = "udi")]
public GuidUdi? Udi { get; set; }
[DataMember(Name = "url")]
public string? Url { get; set; }
}

View File

@@ -10,6 +10,7 @@ using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class DataTypeMigration : MigrationBase
{
private static readonly ISet<string> _legacyAliases = new HashSet<string>
@@ -45,100 +46,6 @@ public class DataTypeMigration : MigrationBase
protected override void Migrate()
{
// drop and create columns
Delete.Column("pk").FromTable("cmsDataType").Do();
// rename the table
Rename.Table("cmsDataType").To(Constants.DatabaseSchema.Tables.DataType).Do();
// create column
AddColumn<DataTypeDto>(Constants.DatabaseSchema.Tables.DataType, "config");
Execute.Sql(Sql().Update<DataTypeDto>(u => u.Set(x => x.Configuration, string.Empty))).Do();
// renames
Execute.Sql(Sql()
.Update<DataTypeDto>(u => u.Set(x => x.EditorAlias, "Umbraco.ColorPicker"))
.Where<DataTypeDto>(x => x.EditorAlias == "Umbraco.ColorPickerAlias")).Do();
// from preValues to configuration...
Sql<ISqlContext> sql = Sql()
.Select<DataTypeDto>()
.AndSelect<PreValueDto>(x => x.Id, x => x.Alias, x => x.SortOrder, x => x.Value)
.From<DataTypeDto>()
.InnerJoin<PreValueDto>().On<DataTypeDto, PreValueDto>((left, right) => left.NodeId == right.NodeId)
.OrderBy<DataTypeDto>(x => x.NodeId)
.AndBy<PreValueDto>(x => x.SortOrder);
IEnumerable<IGrouping<int, PreValueDto>> dtos = Database.Fetch<PreValueDto>(sql).GroupBy(x => x.NodeId);
foreach (IGrouping<int, PreValueDto> group in dtos)
{
DataTypeDto? dataType = Database.Fetch<DataTypeDto>(Sql()
.Select<DataTypeDto>()
.From<DataTypeDto>()
.Where<DataTypeDto>(x => x.NodeId == group.Key)).First();
// check for duplicate aliases
var aliases = group.Select(x => x.Alias).Where(x => !string.IsNullOrWhiteSpace(x)).ToArray();
if (aliases.Distinct().Count() != aliases.Length)
{
throw new InvalidOperationException(
$"Cannot migrate prevalues for datatype id={dataType.NodeId}, editor={dataType.EditorAlias}: duplicate alias.");
}
// handle null/empty aliases
var index = 0;
var dictionary = group.ToDictionary(x => string.IsNullOrWhiteSpace(x.Alias) ? index++.ToString() : x.Alias);
// migrate the preValues to configuration
IPreValueMigrator migrator =
_preValueMigrators.GetMigrator(dataType.EditorAlias) ?? new DefaultPreValueMigrator();
var config = migrator.GetConfiguration(dataType.NodeId, dataType.EditorAlias, dictionary);
var json = _configurationEditorJsonSerializer.Serialize(config);
// validate - and kill the migration if it fails
var newAlias = migrator.GetNewAlias(dataType.EditorAlias);
if (newAlias == null)
{
if (!_legacyAliases.Contains(dataType.EditorAlias))
{
_logger.LogWarning(
"Skipping validation of configuration for data type {NodeId} : {EditorAlias}."
+ " Please ensure that the configuration is valid. The site may fail to start and / or load data types and run.",
dataType.NodeId, dataType.EditorAlias);
}
}
else if (!_propertyEditors.TryGet(newAlias, out IDataEditor? propertyEditor))
{
if (!_legacyAliases.Contains(newAlias))
{
_logger.LogWarning(
"Skipping validation of configuration for data type {NodeId} : {NewEditorAlias} (was: {EditorAlias})"
+ " because no property editor with that alias was found."
+ " Please ensure that the configuration is valid. The site may fail to start and / or load data types and run.",
dataType.NodeId, newAlias, dataType.EditorAlias);
}
}
else
{
IConfigurationEditor configEditor = propertyEditor.GetConfigurationEditor();
try
{
var _ = configEditor.FromDatabase(json, _configurationEditorJsonSerializer);
}
catch (Exception e)
{
_logger.LogWarning(
e,
"Failed to validate configuration for data type {NodeId} : {NewEditorAlias} (was: {EditorAlias})."
+ " Please fix the configuration and ensure it is valid. The site may fail to start and / or load data types and run.",
dataType.NodeId, newAlias, dataType.EditorAlias);
}
}
// update
dataType.Configuration = _configurationEditorJsonSerializer.Serialize(config);
Database.Update(dataType);
}
}
}

View File

@@ -1,23 +0,0 @@
using Umbraco.Cms.Core;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0.DataTypes;
internal class ContentPickerPreValueMigrator : DefaultPreValueMigrator
{
public override bool CanMigrate(string editorAlias)
=> editorAlias == Constants.PropertyEditors.Legacy.Aliases.ContentPicker2;
public override string? GetNewAlias(string editorAlias)
=> null;
protected override object? GetPreValueValue(PreValueDto preValue)
{
if (preValue.Alias == "showOpenButton" ||
preValue.Alias == "ignoreUserStartNodes")
{
return preValue.Value == "1";
}
return base.GetPreValueValue(preValue);
}
}

View File

@@ -1,22 +0,0 @@
using Newtonsoft.Json;
using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0.DataTypes;
internal class DecimalPreValueMigrator : DefaultPreValueMigrator
{
public override bool CanMigrate(string editorAlias)
=> editorAlias == "Umbraco.Decimal";
protected override object? GetPreValueValue(PreValueDto preValue)
{
if (preValue.Alias == "min" ||
preValue.Alias == "step" ||
preValue.Alias == "max")
{
return decimal.TryParse(preValue.Value, out var d) ? (decimal?)d : null;
}
return preValue.Value?.DetectIsJson() ?? false ? JsonConvert.DeserializeObject(preValue.Value) : preValue.Value;
}
}

View File

@@ -1,44 +0,0 @@
using Newtonsoft.Json;
using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0.DataTypes;
internal class DefaultPreValueMigrator : IPreValueMigrator
{
public virtual bool CanMigrate(string editorAlias)
=> true;
public virtual string? GetNewAlias(string editorAlias)
=> editorAlias;
public object GetConfiguration(int dataTypeId, string editorAlias, Dictionary<string, PreValueDto> preValues)
{
var preValuesA = preValues.Values.ToList();
var aliases = preValuesA.Select(x => x.Alias).Distinct().ToArray();
if (aliases.Length == 1 && string.IsNullOrWhiteSpace(aliases[0]))
{
// array-based prevalues
return new Dictionary<string, object>
{
["values"] = preValuesA.OrderBy(x => x.SortOrder).Select(x => x.Value).ToArray(),
};
}
// assuming we don't want to fall back to array
if (aliases.Any(string.IsNullOrWhiteSpace))
{
throw new InvalidOperationException(
$"Cannot migrate prevalues for datatype id={dataTypeId}, editor={editorAlias}: null/empty alias.");
}
// dictionary-base prevalues
return GetPreValues(preValuesA).ToDictionary(x => x.Alias, GetPreValueValue);
}
protected virtual IEnumerable<PreValueDto> GetPreValues(IEnumerable<PreValueDto> preValues)
=> preValues;
protected virtual object? GetPreValueValue(PreValueDto preValue) => preValue.Value?.DetectIsJson() ?? false
? JsonConvert.DeserializeObject(preValue.Value)
: preValue.Value;
}

View File

@@ -1,30 +0,0 @@
using Umbraco.Cms.Core.PropertyEditors;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0.DataTypes;
internal class DropDownFlexiblePreValueMigrator : IPreValueMigrator
{
public bool CanMigrate(string editorAlias)
=> editorAlias == "Umbraco.DropDown.Flexible";
public virtual string? GetNewAlias(string editorAlias)
=> null;
public object GetConfiguration(int dataTypeId, string editorAlias, Dictionary<string, PreValueDto> preValues)
{
var config = new DropDownFlexibleConfiguration();
foreach (PreValueDto preValue in preValues.Values)
{
if (preValue.Alias == "multiple")
{
config.Multiple = preValue.Value == "1";
}
else
{
config.Items.Add(new ValueListConfiguration.ValueListItem { Id = preValue.Id, Value = preValue.Value });
}
}
return config;
}
}

View File

@@ -3,6 +3,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0.DataTypes;
/// <summary>
/// Defines a service migrating preValues.
/// </summary>
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public interface IPreValueMigrator
{
/// <summary>

View File

@@ -1,26 +0,0 @@
using System.Globalization;
using Newtonsoft.Json;
using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0.DataTypes;
internal class ListViewPreValueMigrator : DefaultPreValueMigrator
{
public override bool CanMigrate(string editorAlias)
=> editorAlias == "Umbraco.ListView";
protected override IEnumerable<PreValueDto> GetPreValues(IEnumerable<PreValueDto> preValues) =>
preValues.Where(preValue => preValue.Alias != "displayAtTabNumber");
protected override object? GetPreValueValue(PreValueDto preValue)
{
if (preValue.Alias == "pageSize")
{
return int.TryParse(preValue.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var i)
? (int?)i
: null;
}
return preValue.Value?.DetectIsJson() ?? false ? JsonConvert.DeserializeObject(preValue.Value) : preValue.Value;
}
}

View File

@@ -1,19 +0,0 @@
using Umbraco.Cms.Core;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0.DataTypes;
internal class MarkdownEditorPreValueMigrator : DefaultPreValueMigrator // PreValueMigratorBase
{
public override bool CanMigrate(string editorAlias)
=> editorAlias == Constants.PropertyEditors.Aliases.MarkdownEditor;
protected override object? GetPreValueValue(PreValueDto preValue)
{
if (preValue.Alias == "preview")
{
return preValue.Value == "1";
}
return base.GetPreValueValue(preValue);
}
}

View File

@@ -1,37 +0,0 @@
using Umbraco.Cms.Core;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0.DataTypes;
internal class MediaPickerPreValueMigrator : DefaultPreValueMigrator // PreValueMigratorBase
{
private readonly string[] _editors =
{
Constants.PropertyEditors.Legacy.Aliases.MediaPicker2, Constants.PropertyEditors.Aliases.MediaPicker,
};
public override bool CanMigrate(string editorAlias)
=> _editors.Contains(editorAlias);
public override string GetNewAlias(string editorAlias)
=> Constants.PropertyEditors.Aliases.MediaPicker;
// you wish - but MediaPickerConfiguration lives in Umbraco.Web
/*
public override object GetConfiguration(int dataTypeId, string editorAlias, Dictionary<string, PreValueDto> preValues)
{
return new MediaPickerConfiguration { ... };
}
*/
protected override object? GetPreValueValue(PreValueDto preValue)
{
if (preValue.Alias == "multiPicker" ||
preValue.Alias == "onlyImages" ||
preValue.Alias == "disableFolderSelect")
{
return preValue.Value == "1";
}
return base.GetPreValueValue(preValue);
}
}

View File

@@ -1,39 +0,0 @@
using System.Globalization;
using Newtonsoft.Json;
using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0.DataTypes;
internal class NestedContentPreValueMigrator : DefaultPreValueMigrator // PreValueMigratorBase
{
public override bool CanMigrate(string editorAlias)
=> editorAlias == "Umbraco.NestedContent";
// you wish - but NestedContentConfiguration lives in Umbraco.Web
/*
public override object GetConfiguration(int dataTypeId, string editorAlias, Dictionary<string, PreValueDto> preValues)
{
return new NestedContentConfiguration { ... };
}
*/
protected override object? GetPreValueValue(PreValueDto preValue)
{
if (preValue.Alias == "confirmDeletes" ||
preValue.Alias == "showIcons" ||
preValue.Alias == "hideLabel")
{
return preValue.Value == "1";
}
if (preValue.Alias == "minItems" ||
preValue.Alias == "maxItems")
{
return int.TryParse(preValue.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var i)
? (int?)i
: null;
}
return preValue.Value?.DetectIsJson() ?? false ? JsonConvert.DeserializeObject(preValue.Value) : preValue.Value;
}
}

View File

@@ -2,6 +2,7 @@ using NPoco;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0.DataTypes;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
[TableName("cmsDataTypePreValues")]
[ExplicitColumns]
public class PreValueDto

View File

@@ -1,5 +1,6 @@
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0.DataTypes;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public abstract class PreValueMigratorBase : IPreValueMigrator
{
public abstract bool CanMigrate(string editorAlias);

View File

@@ -3,6 +3,7 @@ using Umbraco.Cms.Core.Composing;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0.DataTypes;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class PreValueMigratorCollection : BuilderCollectionBase<IPreValueMigrator>
{
private readonly ILogger<PreValueMigratorCollection> _logger;

View File

@@ -2,6 +2,7 @@ using Umbraco.Cms.Core.Composing;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0.DataTypes;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class PreValueMigratorCollectionBuilder : OrderedCollectionBuilderBase<PreValueMigratorCollectionBuilder,
PreValueMigratorCollection, IPreValueMigrator>
{

View File

@@ -1,23 +0,0 @@
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Exceptions;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0.DataTypes;
internal class RenamingPreValueMigrator : DefaultPreValueMigrator
{
private readonly string[] _editors = { "Umbraco.NoEdit" };
public override bool CanMigrate(string editorAlias)
=> _editors.Contains(editorAlias);
public override string GetNewAlias(string editorAlias)
{
switch (editorAlias)
{
case "Umbraco.NoEdit":
return Constants.PropertyEditors.Aliases.Label;
default:
throw new PanicException($"The alias {editorAlias} is not supported");
}
}
}

View File

@@ -1,24 +0,0 @@
using Newtonsoft.Json;
using Umbraco.Cms.Core;
using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0.DataTypes;
internal class RichTextPreValueMigrator : DefaultPreValueMigrator
{
public override bool CanMigrate(string editorAlias)
=> editorAlias == "Umbraco.TinyMCEv3";
public override string GetNewAlias(string editorAlias)
=> Constants.PropertyEditors.Aliases.TinyMce;
protected override object? GetPreValueValue(PreValueDto preValue)
{
if (preValue.Alias == "hideLabel")
{
return preValue.Value == "1";
}
return preValue.Value?.DetectIsJson() ?? false ? JsonConvert.DeserializeObject(preValue.Value) : preValue.Value;
}
}

View File

@@ -1,21 +0,0 @@
using Umbraco.Cms.Core.PropertyEditors;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0.DataTypes;
internal class UmbracoSliderPreValueMigrator : PreValueMigratorBase
{
public override bool CanMigrate(string editorAlias)
=> editorAlias == "Umbraco.Slider";
public override object GetConfiguration(int dataTypeId, string editorAlias,
Dictionary<string, PreValueDto> preValues) =>
new SliderConfiguration
{
EnableRange = GetBoolValue(preValues, "enableRange"),
InitialValue = GetDecimalValue(preValues, "initVal1"),
InitialValue2 = GetDecimalValue(preValues, "initVal2"),
MaximumValue = GetDecimalValue(preValues, "maxVal"),
MinimumValue = GetDecimalValue(preValues, "minVal"),
StepIncrements = GetDecimalValue(preValues, "step"),
};
}

View File

@@ -1,29 +0,0 @@
using Umbraco.Cms.Core.PropertyEditors;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0.DataTypes;
internal class ValueListPreValueMigrator : IPreValueMigrator
{
private readonly string[] _editors =
{
"Umbraco.RadioButtonList", "Umbraco.CheckBoxList", "Umbraco.DropDown", "Umbraco.DropdownlistPublishingKeys",
"Umbraco.DropDownMultiple", "Umbraco.DropdownlistMultiplePublishKeys",
};
public bool CanMigrate(string editorAlias)
=> _editors.Contains(editorAlias);
public virtual string? GetNewAlias(string editorAlias)
=> null;
public object GetConfiguration(int dataTypeId, string editorAlias, Dictionary<string, PreValueDto> preValues)
{
var config = new ValueListConfiguration();
foreach (PreValueDto preValue in preValues.Values)
{
config.Items.Add(new ValueListConfiguration.ValueListItem { Id = preValue.Id, Value = preValue.Value });
}
return config;
}
}

View File

@@ -13,6 +13,7 @@ using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class DropDownPropertyEditorsMigration : PropertyEditorsMigrationBase
{
private readonly IConfigurationEditorJsonSerializer _configurationEditorJsonSerializer;

View File

@@ -1,5 +1,6 @@
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class DropMigrationsTable : MigrationBase
{
public DropMigrationsTable(IMigrationContext context)

View File

@@ -1,5 +1,6 @@
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class DropPreValueTable : MigrationBase
{
public DropPreValueTable(IMigrationContext context)

View File

@@ -1,5 +1,6 @@
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class DropTaskTables : MigrationBase
{
public DropTaskTables(IMigrationContext context)

View File

@@ -1,5 +1,6 @@
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class DropTemplateDesignColumn : MigrationBase
{
public DropTemplateDesignColumn(IMigrationContext context)

View File

@@ -1,5 +1,6 @@
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class DropXmlTables : MigrationBase
{
public DropXmlTables(IMigrationContext context)

View File

@@ -5,6 +5,7 @@ using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
/// <summary>
/// Adds a new, self-joined field to umbracoLanguages to hold the fall-back language for
/// a given language.

View File

@@ -1,5 +1,6 @@
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class FixLanguageIsoCodeLength : MigrationBase
{
public FixLanguageIsoCodeLength(IMigrationContext context)

View File

@@ -3,6 +3,7 @@ using Umbraco.Cms.Infrastructure.Persistence.Dtos;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class LanguageColumns : MigrationBase
{
public LanguageColumns(IMigrationContext context)

View File

@@ -2,6 +2,7 @@ using Umbraco.Cms.Infrastructure.Persistence.Dtos;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class MakeRedirectUrlVariant : MigrationBase
{
public MakeRedirectUrlVariant(IMigrationContext context)

View File

@@ -2,6 +2,7 @@ using Umbraco.Cms.Infrastructure.Persistence.Dtos;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class MakeTagsVariant : MigrationBase
{
public MakeTagsVariant(IMigrationContext context)

View File

@@ -11,6 +11,7 @@ using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class MergeDateAndDateTimePropertyEditor : MigrationBase
{
private readonly IConfigurationEditorJsonSerializer _configurationEditorJsonSerializer;

View File

@@ -1,63 +0,0 @@
using NPoco;
using Umbraco.Cms.Core;
using Umbraco.Cms.Infrastructure.Persistence.DatabaseAnnotations;
using Umbraco.Cms.Infrastructure.Persistence.Dtos;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0.Models;
/// <summary>
/// Snapshot of the <see cref="ContentTypeDto" /> as it was at version 8.0
/// </summary>
/// <remarks>
/// This is required during migrations the schema of this table changed and running SQL against the new table would
/// result in errors
/// </remarks>
[TableName(TableName)]
[PrimaryKey("pk")]
[ExplicitColumns]
internal class ContentTypeDto80
{
public const string TableName = Constants.DatabaseSchema.Tables.ContentType;
[Column("pk")]
[PrimaryKeyColumn(IdentitySeed = 535)]
public int PrimaryKey { get; set; }
[Column("nodeId")]
[ForeignKey(typeof(NodeDto))]
[Index(IndexTypes.UniqueNonClustered, Name = "IX_cmsContentType")]
public int NodeId { get; set; }
[Column("alias")]
[NullSetting(NullSetting = NullSettings.Null)]
public string? Alias { get; set; }
[Column("icon")]
[Index(IndexTypes.NonClustered)]
[NullSetting(NullSetting = NullSettings.Null)]
public string? Icon { get; set; }
[Column("thumbnail")]
[Constraint(Default = "folder.png")]
public string? Thumbnail { get; set; }
[Column("description")]
[NullSetting(NullSetting = NullSettings.Null)]
[Length(1500)]
public string? Description { get; set; }
[Column("isContainer")]
[Constraint(Default = "0")]
public bool IsContainer { get; set; }
[Column("allowAtRoot")]
[Constraint(Default = "0")]
public bool AllowAtRoot { get; set; }
[Column("variations")]
[Constraint(Default = "1" /*ContentVariation.InvariantNeutral*/)]
public byte Variations { get; set; }
[ResultColumn]
public NodeDto? NodeDto { get; set; }
}

View File

@@ -1,142 +0,0 @@
using NPoco;
using Umbraco.Cms.Core;
using Umbraco.Cms.Infrastructure.Persistence.DatabaseAnnotations;
using Umbraco.Cms.Infrastructure.Persistence.Dtos;
using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0.Models;
/// <summary>
/// Snapshot of the <see cref="PropertyDataDto" /> as it was at version 8.0
/// </summary>
/// <remarks>
/// This is required during migrations the schema of this table changed and running SQL against the new table would
/// result in errors
/// </remarks>
[TableName(TableName)]
[PrimaryKey("id")]
[ExplicitColumns]
internal class PropertyDataDto80
{
public const string TableName = Constants.DatabaseSchema.Tables.PropertyData;
public const int VarcharLength = 512;
public const int SegmentLength = 256;
private decimal? _decimalValue;
// pk, not used at the moment (never updating)
[Column("id")] [PrimaryKeyColumn] public int Id { get; set; }
[Column("versionId")]
[ForeignKey(typeof(ContentVersionDto))]
[Index(IndexTypes.UniqueNonClustered, Name = "IX_" + TableName + "_VersionId",
ForColumns = "versionId,propertyTypeId,languageId,segment")]
public int VersionId { get; set; }
[Column("propertyTypeId")]
[ForeignKey(typeof(PropertyTypeDto80))]
[Index(IndexTypes.NonClustered, Name = "IX_" + TableName + "_PropertyTypeId")]
public int PropertyTypeId { get; set; }
[Column("languageId")]
[ForeignKey(typeof(LanguageDto))]
[Index(IndexTypes.NonClustered, Name = "IX_" + TableName + "_LanguageId")]
[NullSetting(NullSetting = NullSettings.Null)]
public int? LanguageId { get; set; }
[Column("segment")]
[Index(IndexTypes.NonClustered, Name = "IX_" + TableName + "_Segment")]
[NullSetting(NullSetting = NullSettings.Null)]
[Length(SegmentLength)]
public string? Segment { get; set; }
[Column("intValue")]
[NullSetting(NullSetting = NullSettings.Null)]
public int? IntegerValue { get; set; }
[Column("decimalValue")]
[NullSetting(NullSetting = NullSettings.Null)]
public decimal? DecimalValue
{
get => _decimalValue;
set => _decimalValue = value?.Normalize();
}
[Column("dateValue")]
[NullSetting(NullSetting = NullSettings.Null)]
public DateTime? DateValue { get; set; }
[Column("varcharValue")]
[NullSetting(NullSetting = NullSettings.Null)]
[Length(VarcharLength)]
public string? VarcharValue { get; set; }
[Column("textValue")]
[NullSetting(NullSetting = NullSettings.Null)]
[SpecialDbType(SpecialDbTypes.NTEXT)]
public string? TextValue { get; set; }
[ResultColumn]
[Reference(ReferenceType.OneToOne, ColumnName = "PropertyTypeId")]
public PropertyTypeDto80? PropertyTypeDto { get; set; }
[Ignore]
public object? Value
{
get
{
if (IntegerValue.HasValue)
{
return IntegerValue.Value;
}
if (DecimalValue.HasValue)
{
return DecimalValue.Value;
}
if (DateValue.HasValue)
{
return DateValue.Value;
}
if (!string.IsNullOrEmpty(VarcharValue))
{
return VarcharValue;
}
if (!string.IsNullOrEmpty(TextValue))
{
return TextValue;
}
return null;
}
}
public PropertyDataDto80 Clone(int versionId) =>
new PropertyDataDto80
{
VersionId = versionId,
PropertyTypeId = PropertyTypeId,
LanguageId = LanguageId,
Segment = Segment,
IntegerValue = IntegerValue,
DecimalValue = DecimalValue,
DateValue = DateValue,
VarcharValue = VarcharValue,
TextValue = TextValue,
PropertyTypeDto = PropertyTypeDto
};
protected bool Equals(PropertyDataDto other) => Id == other.Id;
public override bool Equals(object? other) =>
!ReferenceEquals(null, other) // other is not null
&& (ReferenceEquals(this, other) // and either ref-equals, or same id
|| (other is PropertyDataDto pdata && pdata.Id == Id));
public override int GetHashCode() =>
// ReSharper disable once NonReadonlyMemberInGetHashCode
Id;
}

View File

@@ -1,76 +0,0 @@
using NPoco;
using Umbraco.Cms.Core;
using Umbraco.Cms.Infrastructure.Persistence.DatabaseAnnotations;
using Umbraco.Cms.Infrastructure.Persistence.DatabaseModelDefinitions;
using Umbraco.Cms.Infrastructure.Persistence.Dtos;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0.Models;
/// <summary>
/// Snapshot of the <see cref="PropertyTypeDto" /> as it was at version 8.0
/// </summary>
/// <remarks>
/// This is required during migrations before 8.6 since the schema has changed and running SQL against the new table
/// would result in errors
/// </remarks>
[TableName(Constants.DatabaseSchema.Tables.PropertyType)]
[PrimaryKey("id")]
[ExplicitColumns]
internal class PropertyTypeDto80
{
[Column("id")]
[PrimaryKeyColumn(IdentitySeed = 50)]
public int Id { get; set; }
[Column("dataTypeId")]
[ForeignKey(typeof(DataTypeDto), Column = "nodeId")]
public int DataTypeId { get; set; }
[Column("contentTypeId")]
[ForeignKey(typeof(ContentTypeDto), Column = "nodeId")]
public int ContentTypeId { get; set; }
[Column("propertyTypeGroupId")]
[NullSetting(NullSetting = NullSettings.Null)]
[ForeignKey(typeof(PropertyTypeGroupDto))]
public int? PropertyTypeGroupId { get; set; }
[Index(IndexTypes.NonClustered, Name = "IX_cmsPropertyTypeAlias")]
[Column("Alias")]
public string Alias { get; set; } = null!;
[Column("Name")]
[NullSetting(NullSetting = NullSettings.Null)]
public string? Name { get; set; }
[Column("sortOrder")]
[Constraint(Default = "0")]
public int SortOrder { get; set; }
[Column("mandatory")]
[Constraint(Default = "0")]
public bool Mandatory { get; set; }
[Column("validationRegExp")]
[NullSetting(NullSetting = NullSettings.Null)]
public string? ValidationRegExp { get; set; }
[Column("Description")]
[NullSetting(NullSetting = NullSettings.Null)]
[Length(2000)]
public string? Description { get; set; }
[Column("variations")]
[Constraint(Default = "1" /*ContentVariation.InvariantNeutral*/)]
public byte Variations { get; set; }
[ResultColumn]
[Reference(ReferenceType.OneToOne, ColumnName = "DataTypeId")]
public DataTypeDto? DataTypeDto { get; set; }
[Column("UniqueID")]
[NullSetting(NullSetting = NullSettings.NotNull)]
[Constraint(Default = SystemMethods.NewGuid)]
[Index(IndexTypes.UniqueNonClustered, Name = "IX_cmsPropertyTypeUniqueID")]
public Guid UniqueId { get; set; }
}

View File

@@ -4,6 +4,7 @@ using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class PropertyEditorsMigration : MigrationBase
{
public PropertyEditorsMigration(IMigrationContext context)

View File

@@ -12,6 +12,7 @@ using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public abstract class PropertyEditorsMigrationBase : MigrationBase
{
protected PropertyEditorsMigrationBase(IMigrationContext context)

View File

@@ -13,6 +13,7 @@ using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class RadioAndCheckboxPropertyEditorsMigration : PropertyEditorsMigrationBase
{
private readonly IConfigurationEditorJsonSerializer _configurationEditorJsonSerializer;

View File

@@ -3,6 +3,7 @@ using Umbraco.Cms.Infrastructure.Persistence.Dtos;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class RefactorMacroColumns : MigrationBase
{
public RefactorMacroColumns(IMigrationContext context)

View File

@@ -6,6 +6,7 @@ using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class RefactorVariantsModel : MigrationBase
{
public RefactorVariantsModel(IMigrationContext context)

View File

@@ -4,6 +4,7 @@ using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class RenameLabelAndRichTextPropertyEditorAliases : MigrationBase
{
public RenameLabelAndRichTextPropertyEditorAliases(IMigrationContext context)

View File

@@ -3,6 +3,7 @@ using Umbraco.Cms.Infrastructure.Persistence.Dtos;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class RenameMediaVersionTable : MigrationBase
{
public RenameMediaVersionTable(IMigrationContext context)

View File

@@ -2,6 +2,7 @@ using Umbraco.Cms.Core;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class RenameUmbracoDomainsTable : MigrationBase
{
public RenameUmbracoDomainsTable(IMigrationContext context)

View File

@@ -2,6 +2,7 @@ using Umbraco.Cms.Core;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class SuperZero : MigrationBase
{
public SuperZero(IMigrationContext context)

View File

@@ -4,6 +4,7 @@ using Umbraco.Cms.Infrastructure.Persistence.Dtos;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class TablesForScheduledPublishing : MigrationBase
{
public TablesForScheduledPublishing(IMigrationContext context)

View File

@@ -3,6 +3,7 @@ using Umbraco.Cms.Infrastructure.Persistence.Dtos;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class TagsMigration : MigrationBase
{
public TagsMigration(IMigrationContext context)

View File

@@ -2,6 +2,7 @@ using Umbraco.Cms.Core;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class TagsMigrationFix : MigrationBase
{
public TagsMigrationFix(IMigrationContext context)

View File

@@ -6,6 +6,7 @@ using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class UpdateDefaultMandatoryLanguage : MigrationBase
{
public UpdateDefaultMandatoryLanguage(IMigrationContext context)

View File

@@ -9,6 +9,7 @@ using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class UpdatePickerIntegerValuesToUdi : MigrationBase
{
public UpdatePickerIntegerValuesToUdi(IMigrationContext context)

View File

@@ -3,6 +3,7 @@ using Umbraco.Cms.Infrastructure.Persistence.Dtos;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
/// <summary>
/// Creates/Updates non mandatory FK columns to the user table
/// </summary>

View File

@@ -5,6 +5,7 @@ using Umbraco.Cms.Infrastructure.Persistence.Dtos;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class VariantsMigration : MigrationBase
{
public VariantsMigration(IMigrationContext context)

View File

@@ -2,6 +2,7 @@ using Umbraco.Cms.Infrastructure.Migrations.PostMigrations;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_1;
[Obsolete("This is not used anymore and will be removed in Umbraco 13")]
public class ChangeNuCacheJsonFormat : MigrationBase
{
public ChangeNuCacheJsonFormat(IMigrationContext context)

Some files were not shown because too many files have changed in this diff Show More