///////////////////////////////////////////////////////////////////////////////// // // 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 { /// /// Loads the next LayerInfo record. /// /// The file reader /// The PSD file. /// 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. 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; } } }