Singularity/Library/PackageCache/com.unity.2d.psdimporter@6.0.7/Editor/PSDPlugin/PsdFile/Layers/LayerInfo.cs
2024-05-06 11:45:45 -07:00

169 lines
6.0 KiB
C#

/////////////////////////////////////////////////////////////////////////////////
//
// Photoshop PSD FileType Plugin for Paint.NET
// http://psdplugin.codeplex.com/
//
// This software is provided under the MIT License:
// Copyright (c) 2006-2007 Frank Blumenberg
// Copyright (c) 2010-2016 Tao Yue
//
// See LICENSE.txt for complete licensing and attribution information.
//
/////////////////////////////////////////////////////////////////////////////////
using System;
using System.Diagnostics;
using System.IO;
namespace PhotoshopFile
{
internal static class LayerInfoFactory
{
/// <summary>
/// Loads the next LayerInfo record.
/// </summary>
/// <param name="reader">The file reader</param>
/// <param name="psdFile">The PSD file.</param>
/// <param name="globalLayerInfo">True if the LayerInfo record is being
/// loaded from the end of the Layer and Mask Information section;
/// false if it is being loaded from the end of a Layer record.</param>
public static LayerInfo Load(PsdBinaryReader reader, PsdFile psdFile,
bool globalLayerInfo, long fileEndPos)
{
Util.DebugMessage(reader.BaseStream, "Load, Begin, LayerInfo");
// Some keys use a signature of 8B64, but the identity of these keys
// is undocumented. We will therefore accept either signature.
var signature = reader.ReadAsciiChars(4);
if ((signature != "8BIM") && (signature != "8B64"))
{
throw new PsdInvalidException(
"LayerInfo signature invalid, must be 8BIM or 8B64.");
}
var key = reader.ReadAsciiChars(4);
var hasLongLength = LayerInfoUtil.HasLongLength(key, psdFile.IsLargeDocument);
LayerInfo result = new RawLayerInfo("dummy");
bool breakFromLoop = false;
while (!breakFromLoop)
{
var baseStartPosition = reader.BaseStream.Position;
var length = hasLongLength
? reader.ReadInt64()
: reader.ReadInt32();
var startPosition = reader.BaseStream.Position;
switch (key)
{
case "Layr":
case "Lr16":
case "Lr32":
result = new InfoLayers(reader, psdFile, key, length);
break;
case "lsct":
case "lsdk":
result = new LayerSectionInfo(reader, key, (int)length);
break;
case "luni":
result = new LayerUnicodeName(reader);
break;
case "lyid":
result = new LayerId(reader, key, length);
break;
default:
result = new RawLayerInfo(reader, signature, key, length);
break;
}
// May have additional padding applied.
var endPosition = startPosition + length;
if (reader.BaseStream.Position < endPosition)
reader.BaseStream.Position = endPosition;
// Documentation states that the length is even-padded. Actually:
// 1. Most keys have 4-padded lengths.
// 2. However, some keys (LMsk) have even-padded lengths.
// 3. Other keys (Txt2, Lr16, Lr32) have unpadded lengths.
//
// Photoshop writes data that is always 4-padded, even when the stated
// length is not a multiple of 4. The length mismatch seems to occur
// only on global layer info. We do not read extra padding in other
// cases because third-party programs are likely to follow the spec.
if (globalLayerInfo)
{
reader.ReadPadding(startPosition, 4);
}
//try if we can read the next signature
if (reader.BaseStream.Position < fileEndPos)
{
var nowPosition = reader.BaseStream.Position;
signature = reader.ReadAsciiChars(4);
if ((signature != "8BIM") && (signature != "8B64"))
{
hasLongLength = true;
reader.BaseStream.Position = baseStartPosition;
}
else
{
reader.BaseStream.Position = nowPosition;
breakFromLoop = true;
}
}
else
breakFromLoop = true;
}
Util.DebugMessage(reader.BaseStream, "Load, End, LayerInfo, {0}, {1}",
result.Signature, result.Key);
return result;
}
}
internal static class LayerInfoUtil
{
internal static bool HasLongLength(string key, bool isLargeDocument)
{
if (!isLargeDocument)
{
return false;
}
//return false;
switch (key)
{
case "LMsk":
case "Lr16":
case "Lr32":
case "Layr":
case "Mt16":
case "Mt32":
case "Mtrn":
case "Alph":
case "FMsk":
case "lnk2":
case "FEid":
case "FXid":
case "PxSD":
case "lnkE": // Undocumented
case "extn": // Undocumented
case "cinf": // Undocumented
return true;
default:
return false;
}
}
}
internal abstract class LayerInfo
{
public abstract string Signature { get; }
public abstract string Key { get; }
}
}