Skip to content

Commit

Permalink
Expose physical file paths in EPUB archive for all content files
Browse files Browse the repository at this point in the history
  • Loading branch information
vers-one committed Apr 29, 2022
1 parent 31495ec commit e16385d
Show file tree
Hide file tree
Showing 15 changed files with 128 additions and 24 deletions.
3 changes: 3 additions & 0 deletions Source/.editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ dotnet_diagnostic.IDE0060.severity = error
# IDE0090: Use 'new(...)'
dotnet_diagnostic.IDE0090.severity = error

# S1168: Empty arrays and collections should be returned instead of null
dotnet_diagnostic.S1168.severity = none

# S3963: "static" fields should be initialized inline
dotnet_diagnostic.S3963.severity = none

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<Product />
<Description />
<Copyright>vers, 2015-2022</Copyright>
<Version>3.1.0</Version>
<Version>3.1.1</Version>
<DocumentationFile></DocumentationFile>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
Expand Down
67 changes: 62 additions & 5 deletions Source/VersOne.Epub.WpfDemo/Controls/BookHtmlContent.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.IO.Packaging;
using System.Windows;
using System.Windows.Media;
Expand All @@ -13,6 +14,7 @@ namespace VersOne.Epub.WpfDemo.Controls
{
public class BookHtmlContent : HtmlPanel
{
public static readonly DependencyProperty EpubArchiveProperty = DependencyProperty.Register("EpubArchive", typeof(ZipArchive), typeof(BookHtmlContent));
public static readonly DependencyProperty HtmlContentFileProperty = DependencyProperty.Register("HtmlContentFile", typeof(HtmlContentFileViewModel), typeof(BookHtmlContent), new PropertyMetadata(OnHtmlContentFileChanged));
public static readonly DependencyProperty AnchorProperty = DependencyProperty.Register("Anchor", typeof(string), typeof(BookHtmlContent), new PropertyMetadata(OnAnchorChanged));

Expand All @@ -27,6 +29,18 @@ public BookHtmlContent()
queuedScrollToAnchor = null;
}

public ZipArchive EpubArchive
{
get
{
return (ZipArchive)GetValue(EpubArchiveProperty);
}
set
{
SetValue(EpubArchiveProperty, value);
}
}

public HtmlContentFileViewModel HtmlContentFile
{
get
Expand All @@ -53,8 +67,8 @@ public string Anchor

protected override void OnImageLoad(HtmlImageLoadEventArgs e)
{
string imageFilePath = GetFullPath(HtmlContentFile.HtmlFilePath, e.Src);
if (HtmlContentFile.Images.TryGetValue(imageFilePath, out byte[] imageContent))
byte[] imageContent = GetImageContent(e.Src);
if (imageContent != null)
{
using (MemoryStream imageStream = new MemoryStream(imageContent))
{
Expand All @@ -73,8 +87,8 @@ protected override void OnImageLoad(HtmlImageLoadEventArgs e)

protected override void OnStylesheetLoad(HtmlStylesheetLoadEventArgs e)
{
string styleSheetFilePath = GetFullPath(HtmlContentFile.HtmlFilePath, e.Src);
if (HtmlContentFile.StyleSheets.TryGetValue(styleSheetFilePath, out string styleSheetContent))
string styleSheetContent = GetStyleSheetContent(e.Src);
if (styleSheetContent != null)
{
e.SetStyleSheet = styleSheetContent;
}
Expand Down Expand Up @@ -123,6 +137,45 @@ private static void OnHtmlContentFileChanged(DependencyObject dependencyObject,
bookHtmlContent.Text = bookHtmlContent.HtmlContentFile.HtmlContent;
}

private byte[] GetImageContent(string imageFilePath)
{
if (HtmlContentFile.Images.TryGetValue(GetFullPath(HtmlContentFile.HtmlFilePathInEpubManifest, imageFilePath), out byte[] imageContent))
{
return imageContent;
}
ZipArchiveEntry zipArchiveEntry = EpubArchive.GetEntry(GetFullPath(HtmlContentFile.HtmlFilePathInEpubArchive, imageFilePath));
if (zipArchiveEntry != null)
{
imageContent = new byte[(int)zipArchiveEntry.Length];
using (Stream zipArchiveEntryStream = zipArchiveEntry.Open())
using (MemoryStream memoryStream = new MemoryStream(imageContent))
{
zipArchiveEntryStream.CopyTo(memoryStream);
}
return imageContent;
}
return null;
}

private string GetStyleSheetContent(string styleSheetFilePath)
{
if (HtmlContentFile.StyleSheets.TryGetValue(GetFullPath(HtmlContentFile.HtmlFilePathInEpubManifest, styleSheetFilePath), out string styleSheetContent))
{
return styleSheetContent;
}
ZipArchiveEntry zipArchiveEntry = EpubArchive.GetEntry(GetFullPath(HtmlContentFile.HtmlFilePathInEpubArchive, styleSheetFilePath));
if (zipArchiveEntry != null)
{
using (Stream zipArchiveEntryStream = zipArchiveEntry.Open())
using (StreamReader streamReader = new StreamReader(zipArchiveEntryStream))
{
styleSheetContent = streamReader.ReadToEnd();
}
return styleSheetContent;
}
return null;
}

private string GetFullPath(string htmlFilePath, string relativePath)
{
if (relativePath.StartsWith("/"))
Expand All @@ -136,7 +189,11 @@ private string GetFullPath(string htmlFilePath, string relativePath)
basePath = Path.GetDirectoryName(basePath);
}
string fullPath = String.Concat(basePath.Replace('\\', '/'), '/', relativePath);
return fullPath.Length > 1 ? fullPath.Substring(1) : String.Empty;
if (fullPath.StartsWith("/"))
{
fullPath = fullPath.Length > 1 ? fullPath.Substring(1) : String.Empty;
}
return fullPath;
}

private void RegisterFonts()
Expand Down
4 changes: 2 additions & 2 deletions Source/VersOne.Epub.WpfDemo/Models/BookModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ public List<HtmlContentFileViewModel> GetReadingOrder(EpubBook epubBook)
List<HtmlContentFileViewModel> result = new List<HtmlContentFileViewModel>();
foreach (EpubTextContentFile epubHtmlFile in epubBook.ReadingOrder)
{
HtmlContentFileViewModel htmlContentFileViewModel = new HtmlContentFileViewModel(epubHtmlFile.FileName, epubHtmlFile.Content, images,
styleSheets, fonts);
HtmlContentFileViewModel htmlContentFileViewModel = new HtmlContentFileViewModel(epubHtmlFile.FileName, epubHtmlFile.FilePathInEpubArchive,
epubHtmlFile.Content, images, styleSheets, fonts);
result.Add(htmlContentFileViewModel);
}
return result;
Expand Down
4 changes: 2 additions & 2 deletions Source/VersOne.Epub.WpfDemo/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[assembly: AssemblyTitle("VersOne.Epub.WpfDemo")]
[assembly: AssemblyDescription("WPF demo application for VersOne.Epub library")]
[assembly: AssemblyCopyright("Unlicense <http://unlicense.org>")]
[assembly: AssemblyVersion("3.1.0.0")]
[assembly: AssemblyFileVersion("3.1.0.0")]
[assembly: AssemblyVersion("3.1.1.0")]
[assembly: AssemblyFileVersion("3.1.1.0")]
[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]
[assembly: ComVisible(false)]
5 changes: 5 additions & 0 deletions Source/VersOne.Epub.WpfDemo/VersOne.Epub.WpfDemo.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
<DocumentationFile>bin\Release\VersOne.Epub.WpfDemo.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>Resources\Book_icon.ico</ApplicationIcon>
Expand All @@ -53,6 +54,10 @@
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.IO.Compression, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
<HintPath>..\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll</HintPath>
</Reference>
<Reference Include="System.IO.Compression.FileSystem" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
Expand Down
23 changes: 22 additions & 1 deletion Source/VersOne.Epub.WpfDemo/ViewModels/BookViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.ObjectModel;
using System.IO.Compression;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;
Expand All @@ -14,6 +15,7 @@ public class BookViewModel : ViewModel
private bool isLoading;
private ObservableCollection<NavigationItemViewModel> navigation;
private ObservableCollection<HtmlContentFileViewModel> readingOrder;
private ZipArchive currentEpubArchive;
private HtmlContentFileViewModel currentHtmlContentFile;
private HtmlContentFileViewModel previousHtmlContentFile;
private HtmlContentFileViewModel nextHtmlContentFile;
Expand All @@ -26,6 +28,7 @@ public BookViewModel(int bookId)
{
bookModel = new BookModel();
isLoading = true;
currentEpubArchive = null;
currentHtmlContentFile = null;
previousHtmlContentFile = null;
nextHtmlContentFile = null;
Expand Down Expand Up @@ -75,6 +78,19 @@ private set
}
}

public ZipArchive CurrentEpubArchive
{
get
{
return currentEpubArchive;
}
set
{
currentEpubArchive = value;
NotifyPropertyChanged();
}
}

public HtmlContentFileViewModel CurrentHtmlContentFile
{
get
Expand Down Expand Up @@ -156,6 +172,11 @@ public ICommand NextCommand
private void BookOpened(Task<EpubBook> task)
{
EpubBook epubBook = task.Result;
if (currentEpubArchive != null)
{
currentEpubArchive.Dispose();
}
CurrentEpubArchive = ZipFile.OpenRead(epubBook.FilePath);
Navigation = new ObservableCollection<NavigationItemViewModel>(bookModel.GetNavigation(epubBook));
ReadingOrder = new ObservableCollection<HtmlContentFileViewModel>(bookModel.GetReadingOrder(epubBook));
if (ReadingOrder.Any())
Expand All @@ -176,7 +197,7 @@ private void Navigate(NavigationItemViewModel navigationItemViewModel)
navigationItemViewModel.IsTreeItemExpanded = true;
if (navigationItemViewModel.IsLink)
{
Navigate(ReadingOrder.FirstOrDefault(htmlContentFile => htmlContentFile.HtmlFilePath == navigationItemViewModel.FilePath));
Navigate(ReadingOrder.FirstOrDefault(htmlContentFile => htmlContentFile.HtmlFilePathInEpubManifest == navigationItemViewModel.FilePath));
CurrentAnchor = navigationItemViewModel.Anchor;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,19 @@ namespace VersOne.Epub.WpfDemo.ViewModels
{
public class HtmlContentFileViewModel : ViewModel
{
public HtmlContentFileViewModel(string htmlFilePath, string htmlContent, Dictionary<string, byte[]> images, Dictionary<string, string> styleSheets, Dictionary<string, byte[]> fonts)
public HtmlContentFileViewModel(string htmlFilePathInEpubManifest, string htmlFilePathInEpubArchive, string htmlContent, Dictionary<string, byte[]> images,
Dictionary<string, string> styleSheets, Dictionary<string, byte[]> fonts)
{
HtmlFilePath = htmlFilePath;
HtmlFilePathInEpubManifest = htmlFilePathInEpubManifest;
HtmlFilePathInEpubArchive = htmlFilePathInEpubArchive;
HtmlContent = htmlContent;
Images = images;
StyleSheets = styleSheets;
Fonts = fonts;
}

public string HtmlFilePath { get; }
public string HtmlFilePathInEpubManifest { get; }
public string HtmlFilePathInEpubArchive { get; }
public string HtmlContent { get; }
public Dictionary<string, byte[]> Images { get; }
public Dictionary<string, string> StyleSheets { get; }
Expand Down
15 changes: 9 additions & 6 deletions Source/VersOne.Epub.WpfDemo/Views/BookView.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,28 @@
<controls:NavigationTemplateSelector>
<controls:NavigationTemplateSelector.NavigationHeaderTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding NestedItems}">
<controls:NavigationHeader Command="{Binding DataContext.NavigateCommand, RelativeSource={RelativeSource AncestorType=controls:NavigationTreeView}}" CommandParameter="{Binding}" />
<controls:NavigationHeader Command="{Binding DataContext.NavigateCommand, RelativeSource={RelativeSource AncestorType=controls:NavigationTreeView}}"
CommandParameter="{Binding}" />
</HierarchicalDataTemplate>
</controls:NavigationTemplateSelector.NavigationHeaderTemplate>
<controls:NavigationTemplateSelector.NavigationItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding NestedItems}">
<controls:NavigationItem Command="{Binding DataContext.NavigateCommand, RelativeSource={RelativeSource AncestorType=controls:NavigationTreeView}}" CommandParameter="{Binding}" />
<controls:NavigationItem Command="{Binding DataContext.NavigateCommand, RelativeSource={RelativeSource AncestorType=controls:NavigationTreeView}}"
CommandParameter="{Binding}" />
</HierarchicalDataTemplate>
</controls:NavigationTemplateSelector.NavigationItemTemplate>
</controls:NavigationTemplateSelector>
</controls:NavigationTreeView.ItemTemplateSelector>
</controls:NavigationTreeView>
<GridSplitter Grid.Column="1" Width="4" Height="Auto" HorizontalAlignment="Stretch" Background="White" BorderBrush="#FF989898"
BorderThickness="0,0,1,0" />
BorderThickness="0,0,1,0" />
<Grid Grid.Column="2">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<controls:BookHtmlContent Grid.Row="0" HtmlContentFile="{Binding CurrentHtmlContentFile}"
Anchor="{Binding CurrentAnchor}" />
<controls:BookHtmlContent Grid.Row="0" EpubArchive="{Binding CurrentEpubArchive}" HtmlContentFile="{Binding CurrentHtmlContentFile}"
Anchor="{Binding CurrentAnchor}" />
<Border Grid.Row="1" BorderThickness="0,1,0,0" BorderBrush="#FF989898" Padding="4">
<Grid>
<Grid.ColumnDefinitions>
Expand All @@ -61,6 +63,7 @@
</Grid>
</Grid>
</Border>
<TextBlock Text="Loading book..." HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="{Binding IsLoading, Converter={StaticResource booleanToVisibilityConverter}}" />
<TextBlock Text="Loading book..." HorizontalAlignment="Center" VerticalAlignment="Center"
Visibility="{Binding IsLoading, Converter={StaticResource booleanToVisibilityConverter}}" />
</Grid>
</Window>
1 change: 1 addition & 0 deletions Source/VersOne.Epub.WpfDemo/packages.config
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@
<package id="StyleCop.Analyzers" version="1.2.0-beta.406" targetFramework="net46" developmentDependency="true" />
<package id="StyleCop.Analyzers.Unstable" version="1.2.0.406" targetFramework="net46" developmentDependency="true" />
<package id="System.Collections" version="4.3.0" targetFramework="net46" />
<package id="System.IO.Compression" version="4.3.0" targetFramework="net46" />
</packages>
1 change: 1 addition & 0 deletions Source/VersOne.Epub/Entities/EpubContentFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
public abstract class EpubContentFile
{
public string FileName { get; set; }
public string FilePathInEpubArchive { get; set; }
public EpubContentType ContentType { get; set; }
public string ContentMimeType { get; set; }
}
Expand Down
2 changes: 2 additions & 0 deletions Source/VersOne.Epub/EpubReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ private static async Task<Dictionary<string, EpubTextContentFile>> ReadTextConte
EpubTextContentFile textContentFile = new EpubTextContentFile
{
FileName = textContentFileRef.Value.FileName,
FilePathInEpubArchive = textContentFileRef.Value.FilePathInEpubArchive,
ContentType = textContentFileRef.Value.ContentType,
ContentMimeType = textContentFileRef.Value.ContentMimeType
};
Expand All @@ -223,6 +224,7 @@ private static async Task<EpubByteContentFile> ReadByteContentFile(EpubContentFi
EpubByteContentFile result = new EpubByteContentFile
{
FileName = contentFileRef.FileName,
FilePathInEpubArchive = contentFileRef.FilePathInEpubArchive,
ContentType = contentFileRef.ContentType,
ContentMimeType = contentFileRef.ContentMimeType
};
Expand Down
10 changes: 9 additions & 1 deletion Source/VersOne.Epub/RefEntities/EpubContentFileRef.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ protected EpubContentFileRef(EpubBookRef epubBookRef)
public EpubContentType ContentType { get; set; }
public string ContentMimeType { get; set; }

public string FilePathInEpubArchive
{
get
{
return ZipPathUtils.Combine(epubBookRef.Schema.ContentDirectoryPath, FileName);
}
}

public byte[] ReadContentAsBytes()
{
return ReadContentAsBytesAsync().Result;
Expand Down Expand Up @@ -61,7 +69,7 @@ private IZipFileEntry GetContentFileEntry()
{
throw new Exception("EPUB parsing error: file name of the specified content file is empty.");
}
string contentFilePath = ZipPathUtils.Combine(epubBookRef.Schema.ContentDirectoryPath, FileName);
string contentFilePath = FilePathInEpubArchive;
IZipFileEntry contentFileEntry = epubBookRef.EpubFile.GetEntry(contentFilePath);
if (contentFileEntry == null)
{
Expand Down
2 changes: 1 addition & 1 deletion Source/VersOne.Epub/VersOne.Epub.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<Product />
<Description />
<Copyright>vers, 2015-2022</Copyright>
<Version>3.1.0</Version>
<Version>3.1.1</Version>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
Expand Down
4 changes: 2 additions & 2 deletions Source/VersOne.Epub/VersOne.Epub.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
<metadata>
<id>VersOne.Epub</id>
<version>3.1.0</version>
<version>3.1.1</version>
<title>EPUB reader</title>
<description>.NET library for reading EPUB files</description>
<authors>vers</authors>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<license type="expression">Unlicense</license>
<projectUrl>https://github.com/vers-one/EpubReader</projectUrl>
<releaseNotes>Some configuration options to handle malformed EPUB files.</releaseNotes>
<releaseNotes>All content files now expose their physical file path in EPUB archive.</releaseNotes>
<copyright>Unlicense &lt;http://unlicense.org&gt;</copyright>
<tags>epub</tags>
<dependencies>
Expand Down

0 comments on commit e16385d

Please sign in to comment.