MVH/Scripts/TaglibSharp/PictureLazy.cs

378 lines
9.6 KiB
C#
Raw Normal View History

2024-06-07 00:47:07 +02:00
//
// PictureLazy.cs:
//
// Author:
// Sebastien Mouy <starwer@laposte.net>
//
// Copyright (C) 2018 Starwer
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License version
// 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
//
using System;
using System.IO;
namespace TagLib
{
/// <summary>
/// This class implements <see cref="IPicture" /> and provides
/// mechanisms for loading pictures from files.
/// Contrary to <see cref="Picture" />, a reference to a file
/// where the picture is located can be given and the picture
/// is lazily loaded from the file, meaning that it will be
/// read from the file only when needed. This saves time and
/// memory if the picture loading is not required.
/// </summary>
public class PictureLazy : IPicture, ILazy
{
#region Private Fields
/// <summary>
/// Contains the mime-type.
/// </summary>
string mime_type;
/// <summary>
/// Contains the content type.
/// </summary>
PictureType type;
/// <summary>
/// Contains the filename.
/// </summary>
string filename;
/// <summary>
/// Contains the picture data.
/// </summary>
ByteVector data;
/// <summary>
/// Stream where the picture is located
/// </summary>
File.IFileAbstraction file;
/// <summary>
/// Offset from where the picture start in the <see cref="file"/>
/// </summary>
readonly long stream_offset;
/// <summary>
/// Size of the picture in the <see cref="file"/> (-1 = until end of Stream)
/// </summary>
readonly long stream_size = -1;
#endregion
#region Constructors
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="PictureLazy" /> with no data or values.
/// </summary>
public PictureLazy ()
{
}
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="PictureLazy" /> from a file.
/// The content will be lazily loaded.
/// </summary>
/// <param name="path">
/// A <see cref="string"/> object containing the path of the
/// file to read.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="path" /> is <see langword="null" />.
/// </exception>
public PictureLazy (string path)
{
if (path == null)
throw new ArgumentNullException (nameof (path));
file = new File.LocalFileAbstraction (path);
filename = Path.GetFileName (path);
Description = filename;
mime_type = Picture.GetMimeFromExtension (filename);
type = mime_type.StartsWith ("image/") ? PictureType.FrontCover : PictureType.NotAPicture;
}
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="PictureLazy" /> from a file abstraction.
/// The content will be lazily loaded.
/// </summary>
/// <param name="abstraction">
/// A <see cref="File.IFileAbstraction"/> object containing
/// abstraction of the file to read.
/// </param>
/// <param name="offset">
/// The position in bytes where the picture is located in the
/// <see cref="File.IFileAbstraction"/>.
/// </param>
/// <param name="size">
/// The size in bytes of the picture in the
/// <see cref="File.IFileAbstraction"/> (default: read all).
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="abstraction" /> is <see langword="null"
/// />.
/// </exception>
public PictureLazy (File.IFileAbstraction abstraction, long offset = 0, long size = -1)
{
if (abstraction == null)
throw new ArgumentNullException (nameof (abstraction));
file = abstraction;
stream_offset = offset;
stream_size = size;
filename = abstraction.Name;
Description = abstraction.Name;
if (!string.IsNullOrEmpty (filename) && filename.Contains (".")) {
mime_type = Picture.GetMimeFromExtension (filename);
type = mime_type.StartsWith ("image/") ? PictureType.FrontCover : PictureType.NotAPicture;
}
}
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="PictureLazy" /> by using the contents of a <see
/// cref="ByteVector" /> object.
/// The content will not be lazily loaded.
/// </summary>
/// <param name="data">
/// A <see cref="ByteVector"/> object containing picture data
/// to use.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="data" /> is <see langword="null" />.
/// </exception>
public PictureLazy (ByteVector data)
{
if (data == null)
throw new ArgumentNullException (nameof (data));
Data = new ByteVector (data);
string ext = Picture.GetExtensionFromData (data);
MimeType = Picture.GetMimeFromExtension (ext);
if (ext != null) {
type = PictureType.FrontCover;
filename = Description = "cover" + ext;
} else {
type = PictureType.NotAPicture;
filename = "UnknownType";
}
}
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="PictureLazy" /> by doing a shallow copy of <see
/// cref="IPicture" />.
/// The content will not be lazily loaded.
/// </summary>
/// <param name="picture">
/// A <see cref="IPicture"/> object containing picture data
/// to convert to an Picture.
/// </param>
public PictureLazy (IPicture picture)
{
mime_type = picture.MimeType;
type = picture.Type;
filename = picture.Filename;
Description = picture.Description;
data = picture.Data;
}
#endregion
#region Public Methods
/// <summary>
/// Load the picture data from the file,
/// if not done yet.
/// </summary>
public void Load ()
{
// Already loaded ?
if (data != null) return;
// Load the picture from the stream
Stream stream = null;
try {
if (stream_size == 0) {
data = new ByteVector ();
} else if (stream_size > 0) {
stream = file.ReadStream;
stream.Seek (stream_offset, SeekOrigin.Begin);
int count = 0, read = 0, needed = (int)stream_size;
byte[] buffer = new byte[needed];
do {
count = stream.Read (buffer, read, needed);
read += count;
needed -= count;
} while (needed > 0 && count != 0);
data = new ByteVector (buffer, read);
} else {
stream = file.ReadStream;
stream.Seek (stream_offset, SeekOrigin.Begin);
data = ByteVector.FromStream (stream);
}
} finally {
// Free the resources
if (stream != null && file != null) {
file.CloseStream (stream);
}
file = null;
}
// Retrieve remaining properties from data (if required)
if (mime_type == null) {
string ext = Picture.GetExtensionFromData (data);
MimeType = Picture.GetMimeFromExtension (ext);
if (ext != null) {
type = PictureType.FrontCover;
if (filename == null)
filename = Description = "cover" + ext;
} else {
type = PictureType.NotAPicture;
if (filename == null)
filename = "UnknownType";
}
}
}
#endregion
#region Public Properties
/// <summary>
/// Gets and sets the mime-type of the picture data
/// stored in the current instance.
/// </summary>
/// <value>
/// A <see cref="string" /> object containing the mime-type
/// of the picture data stored in the current instance.
/// </value>
public string MimeType {
get {
if (mime_type == null)
Load ();
return mime_type;
}
set { mime_type = value; }
}
/// <summary>
/// Gets and sets the type of content visible in the picture
/// stored in the current instance.
/// </summary>
/// <value>
/// A <see cref="PictureType" /> containing the type of
/// content visible in the picture stored in the current
/// instance.
/// </value>
public PictureType Type {
get {
if (type == PictureType.Other && mime_type == null)
Load ();
return type;
}
set { type = value; }
}
/// <summary>
/// Gets and sets a filename of the picture stored in the
/// current instance.
/// </summary>
/// <value>
/// A <see cref="string" /> object containing a fielname, with
/// extension, of the picture stored in the current instance.
/// </value>
public string Filename {
get {
if (filename == null)
Load ();
return filename;
}
set { filename = value; }
}
/// <summary>
/// Gets and sets a description of the picture stored in the
/// current instance.
/// </summary>
/// <value>
/// A <see cref="string" /> object containing a description
/// of the picture stored in the current instance.
/// </value>
public string Description { get; set; }
/// <summary>
/// Gets and sets the picture data stored in the current
/// instance.
/// </summary>
/// <value>
/// A <see cref="ByteVector" /> object containing the picture
/// data stored in the current instance.
/// </value>
public ByteVector Data {
get {
if (data == null)
Load ();
return data;
}
set { data = value; }
}
/// <summary>
/// Gets an indication whether the picture is loaded.
/// </summary>
public bool IsLoaded {
get {
return data != null;
}
}
#endregion
}
}