using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Threading.Tasks;
using VersOne.Epub.Internal;
namespace VersOne.Epub
{
public static class EpubReader
{
///
/// Opens the book synchronously without reading its whole content. Holds the handle to the EPUB file.
///
/// path to the EPUB file
///
public static EpubBookRef OpenBook(string filePath)
{
return OpenBookAsync(filePath).Result;
}
///
/// Opens the book synchronously without reading its whole content.
///
/// path to the EPUB file
///
public static EpubBookRef OpenBook(Stream stream)
{
return OpenBookAsync(stream).Result;
}
///
/// Opens the book asynchronously without reading its whole content. Holds the handle to the EPUB file.
///
/// path to the EPUB file
///
public static Task OpenBookAsync(string filePath)
{
if (!File.Exists(filePath))
{
throw new FileNotFoundException("Specified epub file not found.", filePath);
}
return OpenBookAsync(GetZipArchive(filePath));
}
///
/// Opens the book asynchronously without reading its whole content.
///
/// path to the EPUB file
///
public static Task OpenBookAsync(Stream stream)
{
return OpenBookAsync(GetZipArchive(stream));
}
///
/// Opens the book synchronously and reads all of its content into the memory. Does not hold the handle to the EPUB file.
///
/// path to the EPUB file
///
public static EpubBook ReadBook(string filePath)
{
return ReadBookAsync(filePath).Result;
}
///
/// Opens the book synchronously and reads all of its content into the memory. Does not hold the handle to the EPUB file.
///
/// path to the EPUB file
///
public static EpubBook ReadBook(Stream stream)
{
return ReadBookAsync(stream).Result;
}
///
/// Opens the book asynchronously and reads all of its content into the memory. Does not hold the handle to the EPUB file.
///
/// path to the EPUB file
///
public static async Task ReadBookAsync(string filePath)
{
EpubBookRef epubBookRef = await OpenBookAsync(filePath).ConfigureAwait(false);
return await ReadBookAsync(epubBookRef).ConfigureAwait(false);
}
///
/// Opens the book asynchronously and reads all of its content into the memory.
///
/// path to the EPUB file
///
public static async Task ReadBookAsync(Stream stream)
{
EpubBookRef epubBookRef = await OpenBookAsync(stream).ConfigureAwait(false);
return await ReadBookAsync(epubBookRef).ConfigureAwait(false);
}
private static async Task OpenBookAsync(ZipArchive zipArchive, string filePath = null)
{
EpubBookRef result = null;
try
{
result = new EpubBookRef(zipArchive);
result.FilePath = filePath;
result.Schema = await SchemaReader.ReadSchemaAsync(zipArchive).ConfigureAwait(false);
result.Title = result.Schema.Package.Metadata.Titles.FirstOrDefault() ?? String.Empty;
result.AuthorList = result.Schema.Package.Metadata.Creators.Select(creator => creator.Creator).ToList();
result.Author = String.Join(", ", result.AuthorList);
result.Content = await Task.Run(() => ContentReader.ParseContentMap(result)).ConfigureAwait(false);
return result;
}
catch
{
result?.Dispose();
throw;
}
}
private static async Task ReadBookAsync(EpubBookRef epubBookRef)
{
EpubBook result = new EpubBook();
using (epubBookRef)
{
result.FilePath = epubBookRef.FilePath;
result.Schema = epubBookRef.Schema;
result.Title = epubBookRef.Title;
result.AuthorList = epubBookRef.AuthorList;
result.Author = epubBookRef.Author;
result.Content = await ReadContent(epubBookRef.Content).ConfigureAwait(false);
result.CoverImage = await epubBookRef.ReadCoverAsync().ConfigureAwait(false);
List chapterRefs = await epubBookRef.GetChaptersAsync().ConfigureAwait(false);
result.Chapters = await ReadChapters(chapterRefs).ConfigureAwait(false);
}
return result;
}
private static ZipArchive GetZipArchive(string filePath)
{
return ZipFile.OpenRead(filePath);
}
private static ZipArchive GetZipArchive(Stream stream)
{
return new ZipArchive(stream, ZipArchiveMode.Read);
}
private static async Task ReadContent(EpubContentRef contentRef)
{
EpubContent result = new EpubContent();
result.Html = await ReadTextContentFiles(contentRef.Html).ConfigureAwait(false);
result.Css = await ReadTextContentFiles(contentRef.Css).ConfigureAwait(false);
result.Images = await ReadByteContentFiles(contentRef.Images).ConfigureAwait(false);
result.Fonts = await ReadByteContentFiles(contentRef.Fonts).ConfigureAwait(false);
result.AllFiles = new Dictionary();
foreach (KeyValuePair textContentFile in result.Html.Concat(result.Css))
{
result.AllFiles.Add(textContentFile.Key, textContentFile.Value);
}
foreach (KeyValuePair byteContentFile in result.Images.Concat(result.Fonts))
{
result.AllFiles.Add(byteContentFile.Key, byteContentFile.Value);
}
foreach (KeyValuePair contentFileRef in contentRef.AllFiles)
{
if (!result.AllFiles.ContainsKey(contentFileRef.Key))
{
result.AllFiles.Add(contentFileRef.Key, await ReadByteContentFile(contentFileRef.Value).ConfigureAwait(false));
}
}
return result;
}
private static async Task> ReadTextContentFiles(Dictionary textContentFileRefs)
{
Dictionary result = new Dictionary();
foreach (KeyValuePair textContentFileRef in textContentFileRefs)
{
EpubTextContentFile textContentFile = new EpubTextContentFile
{
FileName = textContentFileRef.Value.FileName,
ContentType = textContentFileRef.Value.ContentType,
ContentMimeType = textContentFileRef.Value.ContentMimeType
};
textContentFile.Content = await textContentFileRef.Value.ReadContentAsTextAsync().ConfigureAwait(false);
result.Add(textContentFileRef.Key, textContentFile);
}
return result;
}
private static async Task> ReadByteContentFiles(Dictionary byteContentFileRefs)
{
Dictionary result = new Dictionary();
foreach (KeyValuePair byteContentFileRef in byteContentFileRefs)
{
result.Add(byteContentFileRef.Key, await ReadByteContentFile(byteContentFileRef.Value).ConfigureAwait(false));
}
return result;
}
private static async Task ReadByteContentFile(EpubContentFileRef contentFileRef)
{
EpubByteContentFile result = new EpubByteContentFile
{
FileName = contentFileRef.FileName,
ContentType = contentFileRef.ContentType,
ContentMimeType = contentFileRef.ContentMimeType
};
result.Content = await contentFileRef.ReadContentAsBytesAsync().ConfigureAwait(false);
return result;
}
private static async Task> ReadChapters(List chapterRefs)
{
List result = new List();
foreach (EpubChapterRef chapterRef in chapterRefs)
{
EpubChapter chapter = new EpubChapter
{
Title = chapterRef.Title,
ContentFileName = chapterRef.ContentFileName,
Anchor = chapterRef.Anchor
};
chapter.HtmlContent = await chapterRef.ReadHtmlContentAsync().ConfigureAwait(false);
chapter.SubChapters = await ReadChapters(chapterRef.SubChapters).ConfigureAwait(false);
result.Add(chapter);
}
return result;
}
}
}