Bläddra i källkod

Merge pull request #25 from Zambiorix/master

Added DocX.iOS + iOS Test app
master
PrzemyslawKlys 9 år sedan
förälder
incheckning
2d8d1ca886

+ 33
- 0
DocX.Xamarin.sln Visa fil

@@ -0,0 +1,33 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DocX.iOS.Test", "DocX.iOS.Test\DocX.iOS.Test.csproj", "{E504B3DA-ED72-4A45-ADCC-F573908A84EB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DocX.iOS", "DocX.iOS\DocX.iOS.csproj", "{70FC6AB5-5C6C-4E7A-92B7-0B24E16FE0EC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|iPhoneSimulator = Debug|iPhoneSimulator
Release|iPhone = Release|iPhone
Release|iPhoneSimulator = Release|iPhoneSimulator
Debug|iPhone = Debug|iPhone
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{70FC6AB5-5C6C-4E7A-92B7-0B24E16FE0EC}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{70FC6AB5-5C6C-4E7A-92B7-0B24E16FE0EC}.Debug|iPhone.Build.0 = Debug|Any CPU
{70FC6AB5-5C6C-4E7A-92B7-0B24E16FE0EC}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{70FC6AB5-5C6C-4E7A-92B7-0B24E16FE0EC}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{70FC6AB5-5C6C-4E7A-92B7-0B24E16FE0EC}.Release|iPhone.ActiveCfg = Release|Any CPU
{70FC6AB5-5C6C-4E7A-92B7-0B24E16FE0EC}.Release|iPhone.Build.0 = Release|Any CPU
{70FC6AB5-5C6C-4E7A-92B7-0B24E16FE0EC}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{70FC6AB5-5C6C-4E7A-92B7-0B24E16FE0EC}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{E504B3DA-ED72-4A45-ADCC-F573908A84EB}.Debug|iPhone.ActiveCfg = Debug|iPhone
{E504B3DA-ED72-4A45-ADCC-F573908A84EB}.Debug|iPhone.Build.0 = Debug|iPhone
{E504B3DA-ED72-4A45-ADCC-F573908A84EB}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
{E504B3DA-ED72-4A45-ADCC-F573908A84EB}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
{E504B3DA-ED72-4A45-ADCC-F573908A84EB}.Release|iPhone.ActiveCfg = Release|iPhone
{E504B3DA-ED72-4A45-ADCC-F573908A84EB}.Release|iPhone.Build.0 = Release|iPhone
{E504B3DA-ED72-4A45-ADCC-F573908A84EB}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
{E504B3DA-ED72-4A45-ADCC-F573908A84EB}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
EndGlobalSection
EndGlobal

+ 107
- 0
DocX.iOS.Test/DocX.iOS.Test.csproj Visa fil

@@ -0,0 +1,107 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">iPhoneSimulator</Platform>
<ProjectTypeGuids>{FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<ProjectGuid>{E504B3DA-ED72-4A45-ADCC-F573908A84EB}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>DocX.iOS.Test</RootNamespace>
<IPhoneResourcePrefix>Resources</IPhoneResourcePrefix>
<AssemblyName>DocX.iOS.Test</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhoneSimulator' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\iPhoneSimulator\Debug</OutputPath>
<DefineConstants>DEBUG;ENABLE_TEST_CLOUD;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<MtouchArch>i386</MtouchArch>
<MtouchLink>None</MtouchLink>
<MtouchUseRefCounting>true</MtouchUseRefCounting>
<MtouchUseSGen>true</MtouchUseSGen>
<MtouchFastDev>true</MtouchFastDev>
<MtouchDebug>true</MtouchDebug>
<CodesignKey>iPhone Developer</CodesignKey>
<MtouchProfiling>true</MtouchProfiling>
<MtouchI18n>west</MtouchI18n>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhone' ">
<DebugType>full</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\iPhone\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<MtouchArch>ARMv7, ARM64</MtouchArch>
<CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
<MtouchFloat32>true</MtouchFloat32>
<MtouchUseSGen>true</MtouchUseSGen>
<CodesignKey>iPhone Developer</CodesignKey>
<MtouchUseRefCounting>true</MtouchUseRefCounting>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhoneSimulator' ">
<DebugType>full</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\iPhoneSimulator\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<MtouchArch>i386</MtouchArch>
<MtouchLink>None</MtouchLink>
<MtouchUseRefCounting>true</MtouchUseRefCounting>
<CodesignKey>iPhone Developer</CodesignKey>
<MtouchUseSGen>true</MtouchUseSGen>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhone' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\iPhone\Debug</OutputPath>
<DefineConstants>DEBUG;ENABLE_TEST_CLOUD;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<MtouchArch>ARMv7, ARM64</MtouchArch>
<CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
<MtouchFloat32>true</MtouchFloat32>
<CodesignKey>iPhone Developer</CodesignKey>
<DeviceSpecificBuild>true</DeviceSpecificBuild>
<MtouchDebug>true</MtouchDebug>
<MtouchUseSGen>true</MtouchUseSGen>
<MtouchUseRefCounting>true</MtouchUseRefCounting>
<MtouchProfiling>true</MtouchProfiling>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="Xamarin.iOS" />
</ItemGroup>
<ItemGroup>
<ImageAsset Include="Resources\Images.xcassets\AppIcons.appiconset\Contents.json" />
</ItemGroup>
<ItemGroup>
<InterfaceDefinition Include="Resources\LaunchScreen.xib" />
</ItemGroup>
<ItemGroup>
<None Include="Info.plist" />
<None Include="Entitlements.plist" />
</ItemGroup>
<ItemGroup>
<Compile Include="Sources\App.cs" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
<ItemGroup>
<ProjectReference Include="..\DocX.iOS\DocX.iOS.csproj">
<Project>{70FC6AB5-5C6C-4E7A-92B7-0B24E16FE0EC}</Project>
<Name>DocX.iOS</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Folder Include="Sources\" />
</ItemGroup>
</Project>

+ 6
- 0
DocX.iOS.Test/Entitlements.plist Visa fil

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
</dict>
</plist>

+ 43
- 0
DocX.iOS.Test/Info.plist Visa fil

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleName</key>
<string>DocX Test</string>
<key>CFBundleIdentifier</key>
<string>com.managingsoftware.docx.docx-ios-test</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>MinimumOSVersion</key>
<string>9.3</string>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
<integer>2</integer>
</array>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>XSAppIconAssets</key>
<string>Resources/Images.xcassets/AppIcons.appiconset</string>
</dict>
</plist>

+ 162
- 0
DocX.iOS.Test/Resources/Images.xcassets/AppIcons.appiconset/Contents.json Visa fil

@@ -0,0 +1,162 @@
{
"images": [
{
"idiom": "iphone",
"size": "29x29",
"scale": "1x"
},
{
"idiom": "iphone",
"size": "29x29",
"scale": "2x"
},
{
"idiom": "iphone",
"size": "29x29",
"scale": "3x"
},
{
"idiom": "iphone",
"size": "40x40",
"scale": "2x"
},
{
"idiom": "iphone",
"size": "40x40",
"scale": "3x"
},
{
"idiom": "iphone",
"size": "57x57",
"scale": "1x"
},
{
"idiom": "iphone",
"size": "57x57",
"scale": "2x"
},
{
"idiom": "iphone",
"size": "60x60",
"scale": "2x"
},
{
"idiom": "iphone",
"size": "60x60",
"scale": "3x"
},
{
"idiom": "ipad",
"size": "29x29",
"scale": "1x"
},
{
"idiom": "ipad",
"size": "29x29",
"scale": "2x"
},
{
"idiom": "ipad",
"size": "40x40",
"scale": "1x"
},
{
"idiom": "ipad",
"size": "40x40",
"scale": "2x"
},
{
"idiom": "ipad",
"size": "50x50",
"scale": "1x"
},
{
"idiom": "ipad",
"size": "50x50",
"scale": "2x"
},
{
"idiom": "ipad",
"size": "72x72",
"scale": "1x"
},
{
"idiom": "ipad",
"size": "72x72",
"scale": "2x"
},
{
"idiom": "ipad",
"size": "76x76",
"scale": "1x"
},
{
"idiom": "ipad",
"size": "76x76",
"scale": "2x"
},
{
"idiom": "car",
"size": "120x120",
"scale": "1x"
},
{
"size": "24x24",
"idiom": "watch",
"scale": "2x",
"role": "notificationCenter",
"subtype": "38mm"
},
{
"size": "27.5x27.5",
"idiom": "watch",
"scale": "2x",
"role": "notificationCenter",
"subtype": "42mm"
},
{
"size": "29x29",
"idiom": "watch",
"role": "companionSettings",
"scale": "2x"
},
{
"size": "29x29",
"idiom": "watch",
"role": "companionSettings",
"scale": "3x"
},
{
"size": "40x40",
"idiom": "watch",
"scale": "2x",
"role": "appLauncher",
"subtype": "38mm"
},
{
"size": "44x44",
"idiom": "watch",
"scale": "2x",
"role": "longLook",
"subtype": "42mm"
},
{
"size": "86x86",
"idiom": "watch",
"scale": "2x",
"role": "quickLook",
"subtype": "38mm"
},
{
"size": "98x98",
"idiom": "watch",
"scale": "2x",
"role": "quickLook",
"subtype": "42mm"
}
],
"info": {
"version": 1,
"author": "xcode"
}
}

+ 32
- 0
DocX.iOS.Test/Resources/LaunchScreen.xib Visa fil

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6214" systemVersion="14A314h" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6207"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="DocX Test" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX" misplaced="YES">
<rect key="frame" x="20" y="140" width="441" height="43"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
</constraints>
<nil key="simulatedStatusBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<point key="canvasLocation" x="548" y="455"/>
</view>
</objects>
</document>

+ 143
- 0
DocX.iOS.Test/Sources/App.cs Visa fil

@@ -0,0 +1,143 @@
using System;
using System.IO;

using Foundation;
using UIKit;

namespace DocX.iOS.Test
{
[Register ("App")]

public class App : UIApplicationDelegate
{
// Main

private static void Main (string[] args)
{
UIApplication.Main (args, null, "App");
}

// constants

private const string messageFormat = @"
<html>
<head>
<style type='text/css'>

html, body
{{
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
font-family: Arial;
vertical-align: baseline;
color: #666666;
}}

body
{{
padding: 2em 2em;
}}

pre
{{
white-space: pre-wrap;
}}

</style>
</head>
<body>
<h2>{0}</h2>
<pre><code>{1}</code></pre>
</body>
</html>
";
// publics

public override UIWindow Window { get; set; }

// FinishedLaunching

public override bool FinishedLaunching (UIApplication application, NSDictionary launchOptions)
{
// create webview + controller

var controller = new UIViewController ();

controller.Title = "DocX - Test";

var webview = new UIWebView (controller.View.Frame);

webview.AutoresizingMask = UIViewAutoresizing.FlexibleDimensions;
webview.ScalesPageToFit = true;

controller.View.AddSubview (webview);

// create navigation controller

var navigation = new UINavigationController (controller);

// initialize window

this.Window = new UIWindow (UIScreen.MainScreen.Bounds);

this.Window.RootViewController = navigation;

this.Window.MakeKeyAndVisible ();

//

try
{
// path to our temp docx file

string pathDocx = Path.Combine(Path.GetTempPath (), "Document.docx");

// inform user of what we are about to do

webview.LoadHtmlString (string.Format(messageFormat, "Generating .docx file, please wait...", pathDocx), null);

// generating docx

using (var document = Novacode.DocX.Create (pathDocx))
{
Novacode.Paragraph p = document.InsertParagraph();

p.Append("This is a Word Document");

p = document.InsertParagraph();

p.Append("");

p = document.InsertParagraph();

p.Append("Hello World");

document.Save();
}

// showing docx in webview, with delay, otherwise we don't see our initial message

this.Invoke(() => {

webview.LoadRequest (NSUrlRequest.FromUrl (NSUrl.FromFilename (pathDocx)));

}, 2.0f);

// done
}
catch (Exception e)
{
webview.LoadHtmlString (string.Format(messageFormat, "Exception Occurred :", e), null);
}

// done

return true;
}
}
}

+ 200
- 0
DocX.iOS/DocX.iOS.csproj Visa fil

@@ -0,0 +1,200 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectTypeGuids>{FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<ProjectGuid>{70FC6AB5-5C6C-4E7A-92B7-0B24E16FE0EC}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>DocX.iOS</RootNamespace>
<IPhoneResourcePrefix>Resources</IPhoneResourcePrefix>
<AssemblyName>DocX.iOS</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<NoWarn>219;414;168;</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<NoWarn>219;414;168;</NoWarn>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="Xamarin.iOS" />
<Reference Include="System.Xml.Linq" />
<Reference Include="OpenTK-1.0" />
</ItemGroup>
<ItemGroup>
<Folder Include="Resources\" />
<Folder Include="Sources\" />
<Folder Include="Sources\Charts\" />
<Folder Include="System\" />
<Folder Include="System\IO\" />
<Folder Include="System\IO\Packaging\" />
<Folder Include="System\Drawing\" />
<Folder Include="Zip\" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="..\DocX\Charts\Axis.cs">
<Link>Sources\Charts\Axis.cs</Link>
</Compile>
<Compile Include="..\DocX\Charts\BarChart.cs">
<Link>Sources\Charts\BarChart.cs</Link>
</Compile>
<Compile Include="..\DocX\Charts\Chart.cs">
<Link>Sources\Charts\Chart.cs</Link>
</Compile>
<Compile Include="..\DocX\Charts\LineChart.cs">
<Link>Sources\Charts\LineChart.cs</Link>
</Compile>
<Compile Include="..\DocX\Charts\PieChart.cs">
<Link>Sources\Charts\PieChart.cs</Link>
</Compile>
<Compile Include="..\DocX\Charts\XElementHelpers.cs">
<Link>Sources\Charts\XElementHelpers.cs</Link>
</Compile>
<Compile Include="..\DocX\Bookmark.cs">
<Link>Sources\Bookmark.cs</Link>
</Compile>
<Compile Include="..\DocX\BookmarkCollection.cs">
<Link>Sources\BookmarkCollection.cs</Link>
</Compile>
<Compile Include="..\DocX\Border.cs">
<Link>Sources\Border.cs</Link>
</Compile>
<Compile Include="..\DocX\Container.cs">
<Link>Sources\Container.cs</Link>
</Compile>
<Compile Include="..\DocX\CustomProperty.cs">
<Link>Sources\CustomProperty.cs</Link>
</Compile>
<Compile Include="..\DocX\DocProperty.cs">
<Link>Sources\DocProperty.cs</Link>
</Compile>
<Compile Include="..\DocX\DocX.cs">
<Link>Sources\DocX.cs</Link>
</Compile>
<Compile Include="..\DocX\DocumentTypes.cs">
<Link>Sources\DocumentTypes.cs</Link>
</Compile>
<Compile Include="..\DocX\ExtensionsHeadings.cs">
<Link>Sources\ExtensionsHeadings.cs</Link>
</Compile>
<Compile Include="..\DocX\Footer.cs">
<Link>Sources\Footer.cs</Link>
</Compile>
<Compile Include="..\DocX\Footers.cs">
<Link>Sources\Footers.cs</Link>
</Compile>
<Compile Include="..\DocX\FormattedText.cs">
<Link>Sources\FormattedText.cs</Link>
</Compile>
<Compile Include="..\DocX\Formatting.cs">
<Link>Sources\Formatting.cs</Link>
</Compile>
<Compile Include="..\DocX\Header.cs">
<Link>Sources\Header.cs</Link>
</Compile>
<Compile Include="..\DocX\Headers.cs">
<Link>Sources\Headers.cs</Link>
</Compile>
<Compile Include="..\DocX\HelperFunctions.cs">
<Link>Sources\HelperFunctions.cs</Link>
</Compile>
<Compile Include="..\DocX\Hyperlink.cs">
<Link>Sources\Hyperlink.cs</Link>
</Compile>
<Compile Include="..\DocX\IParagraphContainer.cs">
<Link>Sources\IParagraphContainer.cs</Link>
</Compile>
<Compile Include="..\DocX\Image.cs">
<Link>Sources\Image.cs</Link>
</Compile>
<Compile Include="..\DocX\List.cs">
<Link>Sources\List.cs</Link>
</Compile>
<Compile Include="..\DocX\PageLayout.cs">
<Link>Sources\PageLayout.cs</Link>
</Compile>
<Compile Include="..\DocX\Paragraph.cs">
<Link>Sources\Paragraph.cs</Link>
</Compile>
<Compile Include="..\DocX\Picture.cs">
<Link>Sources\Picture.cs</Link>
</Compile>
<Compile Include="..\DocX\Section.cs">
<Link>Sources\Section.cs</Link>
</Compile>
<Compile Include="..\DocX\Table.cs">
<Link>Sources\Table.cs</Link>
</Compile>
<Compile Include="..\DocX\TableOfContents.cs">
<Link>Sources\TableOfContents.cs</Link>
</Compile>
<Compile Include="..\DocX\_BaseClasses.cs">
<Link>Sources\_BaseClasses.cs</Link>
</Compile>
<Compile Include="..\DocX\_Enumerations.cs">
<Link>Sources\_Enumerations.cs</Link>
</Compile>
<Compile Include="..\DocX\_Extensions.cs">
<Link>Sources\_Extensions.cs</Link>
</Compile>
<Compile Include="System\IO\Packaging\Check.cs" />
<Compile Include="System\IO\Packaging\CompressionOption.cs" />
<Compile Include="System\IO\Packaging\Package.cs" />
<Compile Include="System\IO\Packaging\PackagePart.cs" />
<Compile Include="System\IO\Packaging\PackagePartCollection.cs" />
<Compile Include="System\IO\Packaging\PackageProperties.cs" />
<Compile Include="System\IO\Packaging\PackagePropertiesPart.cs" />
<Compile Include="System\IO\Packaging\PackageRelationship.cs" />
<Compile Include="System\IO\Packaging\PackageRelationshipCollection.cs" />
<Compile Include="System\IO\Packaging\PackUriHelper.cs" />
<Compile Include="System\IO\Packaging\PackUriParser.cs" />
<Compile Include="System\IO\Packaging\TargetMode.cs" />
<Compile Include="System\IO\Packaging\ZipPackage.cs" />
<Compile Include="System\IO\Packaging\ZipPackagePart.cs" />
<Compile Include="System\IO\Packaging\ZipPartStream.cs" />
<Compile Include="System\Drawing\ColorTranslator.cs" />
<Compile Include="System\Drawing\FontFamily.cs" />
<Compile Include="System\Drawing\Image.cs" />
<Compile Include="Zip\ZipStorer.cs" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
<ItemGroup>
<EmbeddedResource Include="..\DocX\Resources\default_styles.xml.gz">
<Link>Resources\default_styles.xml.gz</Link>
<LogicalName>Novacode.Resources.default_styles.xml.gz</LogicalName>
</EmbeddedResource>
<EmbeddedResource Include="..\DocX\Resources\numbering.default_bullet_abstract.xml.gz">
<Link>Resources\numbering.default_bullet_abstract.xml.gz</Link>
<LogicalName>Novacode.Resources.default_bullet_abstract.xml.gz</LogicalName>
</EmbeddedResource>
<EmbeddedResource Include="..\DocX\Resources\numbering.default_decimal_abstract.xml.gz">
<Link>Resources\numbering.default_decimal_abstract.xml.gz</Link>
<LogicalName>Novacode.Resources.default_decimal_abstract.xml.gz</LogicalName>
</EmbeddedResource>
<EmbeddedResource Include="..\DocX\Resources\numbering.xml.gz">
<Link>Resources\numbering.xml.gz</Link>
<LogicalName>Novacode.Resources.numbering.xml.gz</LogicalName>
</EmbeddedResource>
<EmbeddedResource Include="..\DocX\Resources\styles.xml.gz">
<Link>Resources\styles.xml.gz</Link>
<LogicalName>Novacode.Resources.styles.xml.gz</LogicalName>
</EmbeddedResource>
</ItemGroup>
</Project>

+ 27
- 0
DocX.iOS/Properties/AssemblyInfo.cs Visa fil

@@ -0,0 +1,27 @@
using System.Reflection;
using System.Runtime.CompilerServices;

// Information about this assembly is defined by the following attributes.
// Change them to the values specific to your project.

[assembly: AssemblyTitle ("DocX.iOS")]
[assembly: AssemblyDescription ("")]
[assembly: AssemblyConfiguration ("")]
[assembly: AssemblyCompany ("Managing Software")]
[assembly: AssemblyProduct ("")]
[assembly: AssemblyCopyright ("Managing Software")]
[assembly: AssemblyTrademark ("")]
[assembly: AssemblyCulture ("")]

// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
// and "{Major}.{Minor}.{Build}.*" will update just the revision.

[assembly: AssemblyVersion ("1.0.*")]

// The following attributes are used to specify the signing key for the assembly,
// if desired. See the Mono documentation for more information about signing.

//[assembly: AssemblyDelaySign(false)]
//[assembly: AssemblyKeyFile("")]


+ 89
- 0
DocX.iOS/System/Drawing/ColorTranslator.cs Visa fil

@@ -0,0 +1,89 @@
using System;
using System.Drawing;

using Foundation;
using UIKit;

namespace System.Drawing
{
// ColorTranslator

public static class ColorTranslator
{
// FromHtml

public static Color FromHtml(string color, float alpha = 1.0f)
{
color = color.Replace ("#", "").Replace (" ", "").Trim ();

if (alpha > 1.0f)
{
alpha = 1.0f;
}

if (alpha < 0.0f)
{
alpha = 0.0f;
}

int A = 0, R = 0, G = 0, B = 0;

switch (color.Length)
{
case 3 : // #RGB
{
A = (int)(alpha * 255);

R = Convert.ToInt32(string.Format("{0}{0}", color.Substring(0, 1)), 16);

G = Convert.ToInt32(string.Format("{0}{0}", color.Substring(1, 1)), 16);

B = Convert.ToInt32(string.Format("{0}{0}", color.Substring(2, 1)), 16);

break;
}

case 4 : // #ARGB
{
A = Convert.ToInt32(string.Format("{0}{0}", color.Substring(0, 1)), 16);

R = Convert.ToInt32(string.Format("{0}{0}", color.Substring(1, 1)), 16);

G = Convert.ToInt32(string.Format("{0}{0}", color.Substring(2, 1)), 16);

B = Convert.ToInt32(string.Format("{0}{0}", color.Substring(3, 1)), 16);

break;
}

case 6 : // #RRGGBB
{
A = (int)(alpha * 255);

R = Convert.ToInt32(color.Substring(0, 2), 16);

G = Convert.ToInt32(color.Substring(2, 2), 16);

B = Convert.ToInt32(color.Substring(4, 2), 16);

break;
}

case 8 : // #RRGGBB
{
A = Convert.ToInt32(color.Substring(0, 2), 16);

R = Convert.ToInt32(color.Substring(2, 2), 16);

G = Convert.ToInt32(color.Substring(4, 2), 16);

B = Convert.ToInt32(color.Substring(6, 2), 16);

break;
}
}

return Color.FromArgb (A, R, G, B);
}
}
}

+ 20
- 0
DocX.iOS/System/Drawing/FontFamily.cs Visa fil

@@ -0,0 +1,20 @@
using System;

namespace System.Drawing
{
// FontFamily

public class FontFamily : MarshalByRefObject
{
// properties

public string Name { get; private set; }

// constructor

public FontFamily (string name)
{
this.Name = name;
}
}
}

+ 85
- 0
DocX.iOS/System/Drawing/Image.cs Visa fil

@@ -0,0 +1,85 @@
using System;
using System.IO;

using Foundation;
using UIKit;

namespace System.Drawing
{
// Image

public class Image : MarshalByRefObject, IDisposable
{
// FromStream

public static Image FromStream(Stream stream)
{
return new Image (stream);
}

// properties

public bool Disposed { get; private set; }

public int Height { get; private set; }

public int Width { get; private set; }

// constructor

private Image (Stream stream)
{
using (var image = UIImage.LoadFromData (NSData.FromStream (stream)))
{
this.Width = (int)image.Size.Width;

this.Height = (int)image.Size.Height;
}
}

// destructor

~Image()
{
Dispose(false);
}

// Dispose

public void Dispose()
{
this.Dispose(true);

GC.SuppressFinalize(this);
}

// Dispose

protected virtual void Dispose(bool disposing)
{
if (this.Disposed)
{
return;
}

try
{
try
{
if (disposing)
{
// dispose managed
}
}
finally
{
// dispose unmanaged
}
}
finally
{
this.Disposed = true;
}
}
}
}

+ 163
- 0
DocX.iOS/System/IO/Packaging/Check.cs Visa fil

@@ -0,0 +1,163 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//using DocumentFormat.OpenXml.Packaging;

namespace System.IO.Packaging
{
internal static class Check
{
static void NotNull(object o, string name)
{
if (o == null)
throw new ArgumentNullException(name);
}

public static void ContentTypeIsValid(string contentType)
{
if (string.IsNullOrEmpty(contentType))
return;

// Must be in form of: type/subtype
int index = contentType.IndexOf('/');
bool result = (index > 0) && contentType.Length > (index + 1) && contentType.IndexOf('/', index + 1) == -1;

if (!result)
throw new ArgumentException("contentType", "contentType must be in the form of 'type/subtype'");
}

public static void Id(object id)
{
NotNull(id, "id");
}

public static void IdIsValid(string id)
{
if (id == null)
return;

// If the ID is a zero string, need to throw a ArgNullEx
if (id.Length == 0)
throw new ArgumentNullException("id", "Cannot be whitespace or empty");

// FIXME: I need to XSD parse this to make sure it's valid
// If it's not, throw an XmlException
}

private static bool EmptyOrBlank(string s)
{
return (s != null && (s == "" || s.Trim().Length == 0));
}

private static void PartUriDoesntEndWithSlash(Uri uri)
{
var s = !uri.IsAbsoluteUri ? uri.OriginalString
: uri.GetComponents(UriComponents.Path, UriFormat.UriEscaped);

// We allow '/' at uri's beggining.
if ((s.Length > 1) && s.EndsWith("/"))
{
throw new ArgumentException("Part URI cannot end with a forward slash.");
}
}

public static void Package(object package)
{
if (package == null)
throw new ArgumentNullException("package");
}


public static void PackageUri(object packageUri)
{
NotNull(packageUri, "packageUri");
}

public static void PackageUriIsValid(Uri packageUri)
{
if (!packageUri.IsAbsoluteUri)
throw new ArgumentException("packageUri", "Uri must be absolute");
}

public static void PackUriIsValid(Uri packUri)
{
if (!packUri.IsAbsoluteUri)
throw new ArgumentException("packUri", "PackUris must be absolute");

if (packUri.Scheme != PackUriHelper.UriSchemePack)
throw new ArgumentException("packUri", "Uri scheme is not a valid PackUri scheme");
}

public static void PartUri(object partUri)
{
if (partUri == null)
throw new ArgumentNullException("partUri");
}

public static void PartUriIsValid(Uri partUri)
{
if (!partUri.OriginalString.StartsWith("/"))
throw new ArgumentException("PartUris must start with '/'");

if (partUri.IsAbsoluteUri)
throw new ArgumentException("PartUris cannot be absolute");
}

public static void RelationshipTypeIsValid(string relationshipType)
{
if (relationshipType == null)
throw new ArgumentNullException("relationshipType");
if (EmptyOrBlank(relationshipType))
throw new ArgumentException("relationshipType", "Cannot be whitespace or empty");
}

public static void PartUri(Uri partUri)
{
if (partUri == null)
throw new ArgumentNullException("partUri");
if (partUri.IsAbsoluteUri)
throw new ArgumentException("partUri", "Absolute URIs are not supported");
if (string.IsNullOrEmpty(partUri.OriginalString))
throw new ArgumentException("partUri", "Part uri cannot be an empty string");
}

public static void PackUri(Uri packUri)
{
NotNull(packUri, "packUri");
}

public static void SourcePartUri(Uri sourcePartUri)
{
NotNull(sourcePartUri, "sourcePartUri");
PartUriDoesntEndWithSlash(sourcePartUri);
}

public static void TargetPartUri(Uri targetPartUri)
{
NotNull(targetPartUri, "targetPartUri");
PartUriDoesntEndWithSlash(targetPartUri);
}

public static void SourceUri(Uri sourceUri)
{
if (sourceUri == null)
throw new ArgumentNullException("sourceUri");
// if (sourceUri.IsAbsoluteUri)
// throw new ArgumentException ("sourceUri", "Absolute URIs are not supported");
if (string.IsNullOrEmpty(sourceUri.OriginalString))
throw new ArgumentException("sourceUri", "Part uri cannot be an empty string");
}

public static void TargetUri(Uri targetUri)
{
if (targetUri == null)
throw new ArgumentNullException("targetUri");
// if (targetUri.IsAbsoluteUri)
// throw new ArgumentException ("targetUri", "Absolute URIs are not supported");
if (string.IsNullOrEmpty(targetUri.OriginalString))
throw new ArgumentException("targetUri", "Part uri cannot be an empty string");
}
}
}

+ 17
- 0
DocX.iOS/System/IO/Packaging/CompressionOption.cs Visa fil

@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace System.IO.Packaging
{
public enum CompressionOption
{
NotCompressed = -1,
Normal,
Maximum,
Fast,
SuperFast,
}
}

+ 185
- 0
DocX.iOS/System/IO/Packaging/PackUriHelper.cs Visa fil

@@ -0,0 +1,185 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace System.IO.Packaging
{
public static class PackUriHelper
{
public static readonly string UriSchemePack = "pack";
static readonly Uri PackSchemeUri = new Uri("pack://", UriKind.Absolute);
static readonly char[] _escapedChars = new char[] { '%', ',', '?', '@' };


static PackUriHelper()
{
if (!UriParser.IsKnownScheme(UriSchemePack))
UriParser.Register(new PackUriParser(), UriSchemePack, -1);
}

public static int ComparePackUri(Uri firstPackUri, Uri secondPackUri)
{
if (firstPackUri == null)
return secondPackUri == null ? 0 : -1;
if (secondPackUri == null)
return 1;

Check.PackUriIsValid(firstPackUri);
Check.PackUriIsValid(secondPackUri);

// FIXME: What exactly is compared. Lets assume originalstring
return firstPackUri.OriginalString.CompareTo(secondPackUri.OriginalString);
}

public static int ComparePartUri(Uri firstPartUri, Uri secondPartUri)
{
if (firstPartUri == null)
return secondPartUri == null ? 0 : -1;
if (secondPartUri == null)
return 1;

Check.PartUriIsValid(firstPartUri);
Check.PartUriIsValid(secondPartUri);

return firstPartUri.OriginalString.CompareTo(secondPartUri.OriginalString);
}

public static Uri Create(Uri packageUri)
{
return Create(packageUri, null, null);
}

public static Uri Create(Uri packageUri, Uri partUri)
{
return Create(packageUri, partUri, null);
}

public static Uri Create(Uri packageUri, Uri partUri, string fragment)
{
Check.PackageUri(packageUri);
Check.PackageUriIsValid(packageUri);

if (partUri != null)
Check.PartUriIsValid(partUri);

if (fragment != null && (fragment.Length == 0 || fragment[0] != '#'))
throw new ArgumentException("Fragment", "Fragment must not be empty and must start with '#'");

// FIXME: Validate that partUri is a valid one? Must be relative, must start with '/'

// First replace the slashes, then escape the special characters
//string orig = packageUri.GetComponents(UriComponents.AbsoluteUri, UriFormat.UriEscaped);
string orig = packageUri.OriginalString;

foreach (var ch in _escapedChars)
{
orig = !orig.Contains(ch.ToString()) ? orig : orig.Replace(ch.ToString(), Uri.HexEscape(ch));
}

orig = orig.Replace('/', ',');

if (partUri != null)
orig += partUri.OriginalString;

if ((fragment == null && partUri == null) && orig[orig.Length - 1] != '/')
orig += '/';

if (fragment != null)
orig += fragment;

return new Uri("pack://" + orig);
}

public static Uri CreatePartUri(Uri partUri)
{
Check.PartUri(partUri);

if (partUri.OriginalString[0] != '/')
partUri = new Uri("/" + partUri.ToString(), UriKind.Relative);
return partUri;
}

public static Uri GetNormalizedPartUri(Uri partUri)
{
Check.PartUri(partUri);
return new Uri(partUri.ToString().ToUpperInvariant(), UriKind.Relative);
}

public static Uri GetPackageUri(Uri packUri)
{
Check.PackUri(packUri);
Check.PackUriIsValid(packUri);

string s = packUri.Host.Replace(',', '/');
return new Uri(Uri.UnescapeDataString(s), UriKind.RelativeOrAbsolute);
}

public static Uri GetPartUri(Uri packUri)
{
Check.PackUri(packUri);
Check.PackUriIsValid(packUri);

if (string.IsNullOrEmpty(packUri.AbsolutePath) || packUri.AbsolutePath == "/")
return null;

return new Uri(packUri.AbsolutePath, UriKind.Relative);
}

public static Uri GetRelationshipPartUri(Uri partUri)
{
Check.PartUri(partUri);
Check.PartUriIsValid(partUri);

int index = partUri.OriginalString.LastIndexOf("/");
string s = partUri.OriginalString.Substring(0, index);
s += "/_rels" + partUri.OriginalString.Substring(index) + ".rels";
return new Uri(s, UriKind.Relative);
}

public static Uri GetRelativeUri(Uri sourcePartUri, Uri targetPartUri)
{
Check.SourcePartUri(sourcePartUri);
Check.TargetPartUri(targetPartUri);

Uri uri = new Uri("http://fake.com");
Uri a = new Uri(uri, sourcePartUri.OriginalString);
Uri b = new Uri(uri, targetPartUri.OriginalString);

return a.MakeRelativeUri(b);
}

public static Uri GetSourcePartUriFromRelationshipPartUri(Uri relationshipPartUri)
{
//Check.RelationshipPartUri (relationshipPartUri);
if (!IsRelationshipPartUri(relationshipPartUri))
throw new Exception("is not a relationship part!?");
return null;
}

public static bool IsRelationshipPartUri(Uri partUri)
{
Check.PartUri(partUri);
return partUri.OriginalString.StartsWith("/_rels") && partUri.OriginalString.EndsWith(".rels");
}

public static Uri ResolvePartUri(Uri sourcePartUri, Uri targetUri)
{
Check.SourcePartUri(sourcePartUri);
Check.TargetUri(targetUri);

Check.PartUriIsValid(sourcePartUri);
// commented out because on Android they are absolute file:///
// if (targetUri.IsAbsoluteUri)
// throw new ArgumentException("targetUri", "Absolute URIs are not supported");

Uri uri = new Uri("http://fake.com");
uri = new Uri(uri, sourcePartUri);
uri = new Uri(uri, targetUri);

// Trim out 'http://fake.com'
return new Uri(uri.OriginalString.Substring(15), UriKind.Relative);
}
}
}

+ 109
- 0
DocX.iOS/System/IO/Packaging/PackUriParser.cs Visa fil

@@ -0,0 +1,109 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace System.IO.Packaging
{
class PackUriParser : GenericUriParser
{
const string SchemaName = "pack";

StringBuilder builder = new StringBuilder();

public PackUriParser()
: base(GenericUriParserOptions.Default)
{
}

protected override string GetComponents(Uri uri, UriComponents components, UriFormat format)
{
string s = uri.OriginalString;
builder.Remove(0, builder.Length);

if ((components & UriComponents.Scheme) == UriComponents.Scheme)
{
int start = 0;
int end = s.IndexOf(':');
builder.Append(s, start, end - start);
}

if ((components & UriComponents.Host) == UriComponents.Host)
{
// Skip past pack://
int start = 7;
int end = s.IndexOf('/', start);
if (end == -1)
end = s.Length;

if (builder.Length > 0)
builder.Append("://");

builder.Append(s, start, end - start);
}

// Port is always -1, so i think i can ignore both Port and StrongPort
// Normally they'd get parsed here

if ((components & UriComponents.Path) == UriComponents.Path)
{
// Skip past pack://
int start = s.IndexOf('/', 7);
int end = s.IndexOf('?');
if (end == -1)
end = s.IndexOf('#');
if (end == -1)
end = s.Length;

if ((components & UriComponents.KeepDelimiter) != UriComponents.KeepDelimiter &&
builder.Length == 0)
start++;

if (start > 0) builder.Append(s, start, end - start);
}

if ((components & UriComponents.Query) == UriComponents.Query)
{
int index = s.IndexOf('?');

if (index != -1)
{
if ((components & UriComponents.KeepDelimiter) != UriComponents.KeepDelimiter &&
builder.Length == 0)
index++;

int fragIndex = s.IndexOf('#');
int end = fragIndex == -1 ? s.Length : fragIndex;
builder.Append(s, index, end - index);
}
}

if ((components & UriComponents.Fragment) == UriComponents.Fragment)
{
int index = s.IndexOf('#');

if (index != -1)
{
if ((components & UriComponents.KeepDelimiter) != UriComponents.KeepDelimiter &&
builder.Length == 0)
index++;

builder.Append(s, index, s.Length - index);
}
}

return builder.ToString();
}

protected override void InitializeAndValidate(Uri uri, out UriFormatException parsingError)
{
parsingError = null;
}

protected override UriParser OnNewUri()
{
return new PackUriParser();
}
}
}

+ 488
- 0
DocX.iOS/System/IO/Packaging/Package.cs Visa fil

@@ -0,0 +1,488 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
//using DocumentFormat.OpenXml.Packaging;

namespace System.IO.Packaging
{
public abstract class Package : IDisposable
{
internal const string RelationshipContentType = "application/vnd.openxmlformats-package.relationships+xml";
internal const string RelationshipNamespace = "http://schemas.openxmlformats.org/package/2006/relationships";
internal static readonly Uri RelationshipUri = new Uri("/_rels/.rels", UriKind.Relative);

private PackageProperties packageProperties;
private PackagePartCollection partsCollection;
private Dictionary<string, PackageRelationship> relationships;
private PackageRelationshipCollection relationshipsCollection = new PackageRelationshipCollection();
private Uri Uri = new Uri("/", UriKind.Relative);

private bool Disposed { get; set; }

public FileAccess FileOpenAccess { get; private set; }

public PackageProperties PackageProperties
{
get
{
// PackageProperties are loaded when the relationships are loaded.
// Therefore ensure we've already loaded the relationships.
int count = Relationships.Count;

if (packageProperties == null)
{
packageProperties = new PackagePropertiesPart();
packageProperties.Package = this;
}
return packageProperties;
}
}

private PackagePartCollection PartsCollection
{
get
{
if (partsCollection == null)
{
partsCollection = new PackagePartCollection();
partsCollection.Parts.AddRange(GetPartsCore());
}
return partsCollection;
}
}

private int RelationshipId { get; set; }

private Dictionary<string, PackageRelationship> Relationships
{
get
{
if (relationships == null)
{
LoadRelationships();
}
return relationships;
}
}

private bool Streaming { get; set; }


protected Package(FileAccess openFileAccess)
: this(openFileAccess, false)
{

}

protected Package(FileAccess openFileAccess, bool streaming)
{
FileOpenAccess = openFileAccess;
Streaming = streaming;
}


internal void CheckIsReadOnly()
{
if (FileOpenAccess == FileAccess.Read)
throw new IOException("Operation not valid when package is read-only");
}

public void Close()
{
// FIXME: Ensure that Flush is actually called before dispose
((IDisposable) this).Dispose();
}

public PackagePart CreatePart(Uri partUri, string contentType)
{
return CreatePart(partUri, contentType, CompressionOption.NotCompressed);
}

public PackagePart CreatePart(Uri partUri, string contentType, CompressionOption compressionOption)
{
CheckIsReadOnly();
Check.PartUri(partUri);
Check.ContentTypeIsValid(contentType);

if (PartExists(partUri))
throw new InvalidOperationException("This partUri is already contained in the package");

PackagePart part = CreatePartCore(partUri, contentType, compressionOption);
PartsCollection.Parts.Add(part);
return part;
}

protected abstract PackagePart CreatePartCore(Uri partUri, string contentType,
CompressionOption compressionOption);

public PackageRelationship CreateRelationship(Uri targetUri, TargetMode targetMode, string relationshipType)
{
return CreateRelationship(targetUri, targetMode, relationshipType, null);
}

public PackageRelationship CreateRelationship(Uri targetUri, TargetMode targetMode, string relationshipType,
string id)
{
return CreateRelationship(targetUri, targetMode, relationshipType, id, false);
}

internal PackageRelationship CreateRelationship(Uri targetUri, TargetMode targetMode, string relationshipType,
string id, bool loading)
{
if (!loading)
CheckIsReadOnly();

Check.TargetUri(targetUri);
if (targetUri.IsAbsoluteUri && targetMode == TargetMode.Internal)
throw new ArgumentException("TargetUri cannot be absolute for an internal relationship");

Check.RelationshipTypeIsValid(relationshipType);
Check.IdIsValid(id);

if (id == null)
id = NextId();

PackageRelationship r = new PackageRelationship(id, this, relationshipType, Uri, targetMode, targetUri);

if (!PartExists(RelationshipUri))
CreatePartCore(RelationshipUri, RelationshipContentType, CompressionOption.NotCompressed).IsRelationship
= true;

Relationships.Add(r.Id, r);
relationshipsCollection.Relationships.Add(r);

if (!loading)
{
using (Stream s = GetPart(RelationshipUri).GetStream())
WriteRelationships(relationships, s);
}

return r;
}


public void DeletePart(Uri partUri)
{
CheckIsReadOnly();
Check.PartUri(partUri);

PackagePart part = GetPart(partUri);
if (part != null)
{
if (part.Package == null)
throw new InvalidOperationException("This part has already been removed");

// FIXME: MS.NET doesn't remove the relationship part
// Instead it throws an exception if you try to use it
if (PartExists(part.RelationshipsPartUri))
GetPart(part.RelationshipsPartUri).Package = null;

part.Package = null;
DeletePartCore(partUri);
PartsCollection.Parts.RemoveAll(p => p.Uri == partUri);
}
}

protected abstract void DeletePartCore(Uri partUri);

public void DeleteRelationship(string id)
{
Check.Id(id);
CheckIsReadOnly();

Relationships.Remove(id);

relationshipsCollection.Relationships.RemoveAll(r => r.Id == id);
if (Relationships.Count > 0)
using (Stream s = GetPart(RelationshipUri).GetStream())
WriteRelationships(relationships, s);
else
DeletePart(RelationshipUri);
}

void IDisposable.Dispose()
{
if (!Disposed)
{
Flush();
Dispose(true);
Disposed = true;
}
}

protected virtual void Dispose(bool disposing)
{
// Nothing here needs to be disposed of
}

private bool flushing = false;

public void Flush()
{
if (FileOpenAccess == FileAccess.Read || flushing)
return;

flushing = true;

// Ensure we've loaded the relationships, parts and properties
int count = Relationships.Count;

if (packageProperties != null)
packageProperties.Flush();

FlushCore();

flushing = false;
}

protected abstract void FlushCore();

public PackagePart GetPart(Uri partUri)
{
Check.PartUri(partUri);
return GetPartCore(partUri);
}

protected abstract PackagePart GetPartCore(Uri partUri);

public PackagePartCollection GetParts()
{
PartsCollection.Parts.Clear();
PartsCollection.Parts.AddRange(GetPartsCore());
return PartsCollection;
}

protected abstract PackagePart[] GetPartsCore();

public PackageRelationship GetRelationship(string id)
{
return Relationships[id];
}

public PackageRelationshipCollection GetRelationships()
{
// Ensure the Relationships dict is instantiated first.
ICollection<PackageRelationship> rels = Relationships.Values;
relationshipsCollection.Relationships.Clear();
relationshipsCollection.Relationships.AddRange(rels);
return relationshipsCollection;
}

public PackageRelationshipCollection GetRelationshipsByType(string relationshipType)
{
PackageRelationshipCollection collection = new PackageRelationshipCollection();
foreach (PackageRelationship r in Relationships.Values)
if (r.RelationshipType == relationshipType)
collection.Relationships.Add(r);

return collection;
}

private void LoadRelationships()
{
relationships = new Dictionary<string, PackageRelationship>();

if (!PartExists(RelationshipUri))
return;

using (Stream stream = GetPart(RelationshipUri).GetStream())
{
XmlDocument doc = new XmlDocument();
doc.Load(stream);
XmlNamespaceManager manager = new XmlNamespaceManager(doc.NameTable);
manager.AddNamespace("rel", RelationshipNamespace);

foreach (XmlNode node in doc.SelectNodes("/rel:Relationships/*", manager))
{
TargetMode mode = TargetMode.Internal;
if (node.Attributes["TargetMode"] != null)
mode = (TargetMode) Enum.Parse(typeof (TargetMode), node.Attributes["TargetMode"].Value);

Uri uri;
try
{
uri = new Uri(node.Attributes["Target"].Value.ToString(), UriKind.Relative);
}
catch
{
uri = new Uri(node.Attributes["Target"].Value.ToString(), UriKind.Absolute);
}
CreateRelationship(uri,
mode,
node.Attributes["Type"].Value.ToString(),
node.Attributes["Id"].Value.ToString(),
true);
}

foreach (PackageRelationship r in relationships.Values)
{
if (r.RelationshipType == PackageProperties.NSPackagePropertiesRelation)
{
PackagePart part = GetPart(PackUriHelper.ResolvePartUri(Uri, r.TargetUri));
packageProperties = new PackagePropertiesPart();
packageProperties.Package = this;
packageProperties.Part = part;
packageProperties.LoadFrom(part.GetStream());
}
}
}
}

private string NextId()
{
while (true)
{
string s = "Re" + RelationshipId.ToString();
if (!Relationships.ContainsKey(s))
return s;

RelationshipId++;
}
}

public static Package Open(Stream stream)
{
return Open(stream, FileMode.Open);
}

public static Package Open(string path)
{
return Open(path, FileMode.OpenOrCreate);
}

public static Package Open(Stream stream, FileMode packageMode)
{
FileAccess access = packageMode == FileMode.Open ? FileAccess.Read : FileAccess.ReadWrite;
return Open(stream, packageMode, access);
}

public static Package Open(string path, FileMode packageMode)
{
return Open(path, packageMode, FileAccess.ReadWrite);
}

public static Package Open(Stream stream, FileMode packageMode, FileAccess packageAccess)
{
return Open(stream, packageMode, packageAccess, false);
}

private static Package Open(Stream stream, FileMode packageMode, FileAccess packageAccess, bool ownsStream)
{
return OpenCore(stream, packageMode, packageAccess, ownsStream);
}

public static Package Open(string path, FileMode packageMode, FileAccess packageAccess)
{
return Open(path, packageMode, packageAccess, FileShare.None);
}

public static Package Open(string path, FileMode packageMode, FileAccess packageAccess, FileShare packageShare)
{
if (packageShare != FileShare.Read && packageShare != FileShare.None)
throw new NotSupportedException("FileShare.Read and FileShare.None are the only supported options");

FileInfo info = new FileInfo(path);

// Bug - MS.NET appears to test for FileAccess.ReadWrite, not FileAccess.Write
if (packageAccess != FileAccess.ReadWrite && !info.Exists)
throw new ArgumentException("packageAccess", "Cannot create stream with FileAccess.Read");


if (info.Exists && packageMode == FileMode.OpenOrCreate && info.Length == 0)
throw new FileFormatException("Stream length cannot be zero with FileMode.Open");

Stream s = File.Open(path, packageMode, packageAccess, packageShare);
return Open(s, packageMode, packageAccess, true);
}

private static Package OpenCore(Stream stream, FileMode packageMode, FileAccess packageAccess, bool ownsStream)
{
if ((packageAccess & FileAccess.Read) == FileAccess.Read && !stream.CanRead)
throw new IOException("Stream does not support reading");

if ((packageAccess & FileAccess.Write) == FileAccess.Write && !stream.CanWrite)
throw new IOException("Stream does not support reading");

if (!stream.CanSeek)
throw new ArgumentException("stream", "Stream must support seeking");

if (packageMode == FileMode.Open && stream.Length == 0)
throw new FileFormatException("Stream length cannot be zero with FileMode.Open");

if (packageMode == FileMode.CreateNew && stream.Length > 0)
throw new IOException("Cannot use CreateNew when stream contains data");

if (packageMode == FileMode.Append || packageMode == FileMode.Truncate)
{
if (stream.CanWrite)
throw new NotSupportedException(string.Format("PackageMode.{0} is not supported", packageMode));
else
throw new IOException(string.Format("PackageMode.{0} is not supported", packageMode));
}

return new ZipPackage(packageAccess, ownsStream, stream);
}

public virtual bool PartExists(Uri partUri)
{
return GetPart(partUri) != null;
}

public bool RelationshipExists(string id)
{
return Relationships.ContainsKey(id);
}

internal static void WriteRelationships(Dictionary<string, PackageRelationship> relationships, Stream stream)
{
XmlDocument doc = new XmlDocument();
XmlNamespaceManager manager = new XmlNamespaceManager(doc.NameTable);
manager.AddNamespace("rel", RelationshipNamespace);

doc.AppendChild(doc.CreateNode(XmlNodeType.XmlDeclaration, "", ""));

XmlNode root = doc.CreateNode(XmlNodeType.Element, "Relationships", RelationshipNamespace);
doc.AppendChild(root);

foreach (PackageRelationship relationship in relationships.Values)
{
XmlNode node = doc.CreateNode(XmlNodeType.Element, "Relationship", RelationshipNamespace);

XmlAttribute idAtt = doc.CreateAttribute("Id");
idAtt.Value = relationship.Id;
node.Attributes.Append(idAtt);

XmlAttribute targetAtt = doc.CreateAttribute("Target");
targetAtt.Value = relationship.TargetUri.ToString();
node.Attributes.Append(targetAtt);

if (relationship.TargetMode != TargetMode.Internal)
{
XmlAttribute modeAtt = doc.CreateAttribute("TargetMode");
modeAtt.Value = relationship.TargetMode.ToString();
node.Attributes.Append(modeAtt);
}
XmlAttribute typeAtt = doc.CreateAttribute("Type");
typeAtt.Value = relationship.RelationshipType;
node.Attributes.Append(typeAtt);

root.AppendChild(node);
}

using (XmlTextWriter writer = new XmlTextWriter(stream, System.Text.Encoding.UTF8))
doc.WriteTo(writer);
}
}

internal class FileFormatException : Exception
{
public FileFormatException(string message): base(message)
{
}
}
}

+ 257
- 0
DocX.iOS/System/IO/Packaging/PackagePart.cs Visa fil

@@ -0,0 +1,257 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
//using DocumentFormat.OpenXml.Packaging;

namespace System.IO.Packaging
{
public abstract class PackagePart
{
string contentType;

internal bool IsRelationship { get; set; }

int relationshipId;
Dictionary<string, PackageRelationship> relationships;
PackageRelationshipCollection relationshipsCollection = new PackageRelationshipCollection();

Dictionary<string, PackageRelationship> Relationships
{
get
{
if (relationships == null)
{
relationships = new Dictionary<string, PackageRelationship>(StringComparer.OrdinalIgnoreCase);
if (Package.PartExists(RelationshipsPartUri))
using (Stream s = Package.GetPart(RelationshipsPartUri).GetStream())
LoadRelationships(relationships, s);
}

return relationships;
}
}
Stream PartStream { get; set; }

internal Uri RelationshipsPartUri
{
get;
set;
}

protected PackagePart(Package package, Uri partUri)
: this(package, partUri, null)
{

}

protected internal PackagePart(Package package, Uri partUri, string contentType)
: this(package, partUri, contentType, CompressionOption.Normal)
{

}

protected internal PackagePart(Package package, Uri partUri, string contentType, CompressionOption compressionOption)
{
Check.Package(package);
Check.PartUri(partUri);
Check.ContentTypeIsValid(contentType);

Package = package;
Uri = partUri;
ContentType = contentType;
CompressionOption = compressionOption;
RelationshipsPartUri = PackUriHelper.GetRelationshipPartUri(Uri);
}

public CompressionOption CompressionOption
{
get;
private set;
}

public string ContentType
{
get
{
if (contentType == null && (contentType = GetContentTypeCore()) == null)
throw new NotSupportedException("If contentType is not supplied in the constructor, GetContentTypeCore must be overridden");
return contentType;
}
private set
{
contentType = value;
}
}

public Package Package
{
get;
internal set;
}

public Uri Uri
{
get;
private set;
}

private void CheckIsRelationship()
{
if (IsRelationship)
throw new InvalidOperationException("A relationship cannot have relationships to other parts");
}

public PackageRelationship CreateRelationship(Uri targetUri, TargetMode targetMode, string relationshipType)
{
return CreateRelationship(targetUri, targetMode, relationshipType, null);
}

public PackageRelationship CreateRelationship(Uri targetUri, TargetMode targetMode, string relationshipType, string id)
{
return CreateRelationship(targetUri, targetMode, relationshipType, id, false);
}

private PackageRelationship CreateRelationship(Uri targetUri, TargetMode targetMode, string relationshipType, string id, bool loading)
{
//Package.CheckIsReadOnly();
Check.TargetUri(targetUri);
Check.RelationshipTypeIsValid(relationshipType);
Check.IdIsValid(id);

if (id == null)
id = NextId();

if (Relationships.ContainsKey(id))
throw new XmlException("A relationship with this ID already exists");

PackageRelationship r = new PackageRelationship(id, Package, relationshipType, Uri, targetMode, targetUri);
Relationships.Add(r.Id, r);

if (!loading)
WriteRelationships();
return r;
}

public void DeleteRelationship(string id)
{
Package.CheckIsReadOnly();
CheckIsRelationship();
Relationships.Remove(id);
WriteRelationships();
}

void LoadRelationships(Dictionary<string, PackageRelationship> relationships, Stream stream)
{
XmlDocument doc = new XmlDocument();
doc.Load(stream);
XmlNamespaceManager manager = new XmlNamespaceManager(doc.NameTable);
manager.AddNamespace("rel", Package.RelationshipNamespace);

foreach (XmlNode node in doc.SelectNodes("/rel:Relationships/*", manager))
{
TargetMode mode = TargetMode.Internal;
if (node.Attributes["TargetMode"] != null)
mode = (TargetMode)Enum.Parse(typeof(TargetMode), node.Attributes["TargetMode"].Value);

CreateRelationship(new Uri(node.Attributes["Target"].Value.ToString(), UriKind.RelativeOrAbsolute),
mode,
node.Attributes["Type"].Value.ToString(),
node.Attributes["Id"].Value.ToString(),
true);
}
}

public bool RelationshipExists(string id)
{
CheckIsRelationship();
return Relationships.ContainsKey(id);
}

public PackageRelationship GetRelationship(string id)
{
CheckIsRelationship();
return Relationships[id];
}

public PackageRelationshipCollection GetRelationships()
{
CheckIsRelationship();
relationshipsCollection.Relationships.Clear();
relationshipsCollection.Relationships.AddRange(Relationships.Values);
return relationshipsCollection;
}

public PackageRelationshipCollection GetRelationshipsByType(string relationshipType)
{
CheckIsRelationship();
PackageRelationshipCollection collection = new PackageRelationshipCollection();
foreach (PackageRelationship r in Relationships.Values)
if (r.RelationshipType == relationshipType)
collection.Relationships.Add(r);

return collection;
}

public Stream GetStream()
{
return GetStream(Package.FileOpenAccess == FileAccess.Read && !IsRelationship ? FileMode.Open : FileMode.OpenOrCreate);
}

public Stream GetStream(FileMode mode)
{
return GetStream(mode, IsRelationship ? FileAccess.ReadWrite : Package.FileOpenAccess);
}

public Stream GetStream(FileMode mode, FileAccess access)
{
bool notAllowed = mode == FileMode.Append || mode == FileMode.CreateNew || mode == FileMode.Truncate;
if (access != FileAccess.Read && notAllowed)
throw new ArgumentException(string.Format(string.Format("FileMode '{0}' not supported", mode)));

if (access == FileAccess.Read && (notAllowed || mode == FileMode.Create))
throw new IOException(string.Format("FileMode '{0}' not allowed on a readonly stream", mode));

return GetStreamCore(mode, access);
}

protected abstract Stream GetStreamCore(FileMode mode, FileAccess access);

protected virtual string GetContentTypeCore()
{
return null;
}

private string NextId()
{
while (true)
{
string s = "Re" + relationshipId.ToString();
if (!RelationshipExists(s))
return s;
relationshipId++;
}
}

void WriteRelationships()
{
bool exists = Package.PartExists(RelationshipsPartUri);
if (exists && Relationships.Count == 0)
{
Package.DeletePart(RelationshipsPartUri);
return;
}

if (!exists)
{
PackagePart part = Package.CreatePart(RelationshipsPartUri, Package.RelationshipContentType);
part.IsRelationship = true;
}
using (Stream s = Package.GetPart(RelationshipsPartUri).GetStream())
Package.WriteRelationships(Relationships, s);
}
}
}

+ 29
- 0
DocX.iOS/System/IO/Packaging/PackagePartCollection.cs Visa fil

@@ -0,0 +1,29 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace System.IO.Packaging
{
public class PackagePartCollection : IEnumerable<PackagePart>, IEnumerable
{
internal List<PackagePart> Parts { get; private set; }

internal PackagePartCollection()
{
Parts = new List<PackagePart>();
}

public IEnumerator<PackagePart> GetEnumerator()
{
return Parts.GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
return Parts.GetEnumerator();
}
}
}

+ 91
- 0
DocX.iOS/System/IO/Packaging/PackageProperties.cs Visa fil

@@ -0,0 +1,91 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace System.IO.Packaging
{
public abstract class PackageProperties : IDisposable
{
internal const string NSPackageProperties = "http://schemas.openxmlformats.org/package/2006/metadata/core-properties";
internal const string NSPackagePropertiesRelation = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
internal const string PackagePropertiesContentType = "application/vnd.openxmlformats-package.core-properties+xml";


static int uuid;

protected PackageProperties()
{

}

public abstract string Category { get; set; }
public abstract string ContentStatus { get; set; }
public abstract string ContentType { get; set; }
public abstract DateTime? Created { get; set; }
public abstract string Creator { get; set; }
public abstract string Description { get; set; }
public abstract string Identifier { get; set; }
public abstract string Keywords { get; set; }
public abstract string Language { get; set; }
public abstract string LastModifiedBy { get; set; }
public abstract DateTime? LastPrinted { get; set; }
public abstract DateTime? Modified { get; set; }
internal Package Package { get; set; }
internal PackagePart Part { get; set; }
public abstract string Revision { get; set; }
public abstract string Subject { get; set; }
public abstract string Title { get; set; }
public abstract string Version { get; set; }


public void Dispose()
{
Dispose(true);
}

protected virtual void Dispose(bool disposing)
{
// Nothing
}

internal void Flush()
{
using (MemoryStream temp = new MemoryStream())
{
using (XmlTextWriter writer = new XmlTextWriter(temp, System.Text.Encoding.UTF8))
{
WriteTo(writer);
writer.Flush();
if (temp.Length == 0)
return;
}
}

if (Part == null)
{
int id = System.Threading.Interlocked.Increment(ref uuid);
Uri uri = new Uri(string.Format("/package/services/metadata/core-properties/{0}.psmdcp", id), UriKind.Relative);
Part = Package.CreatePart(uri, PackagePropertiesContentType);
PackageRelationship rel = Package.CreateRelationship(uri, TargetMode.Internal, NSPackagePropertiesRelation);
}

using (Stream s = Part.GetStream(FileMode.Create))
using (XmlTextWriter writer = new XmlTextWriter(s, System.Text.Encoding.UTF8))
WriteTo(writer);
}

internal virtual void LoadFrom(Stream stream)
{

}

internal virtual void WriteTo(XmlTextWriter writer)
{

}
}
}

+ 355
- 0
DocX.iOS/System/IO/Packaging/PackagePropertiesPart.cs Visa fil

@@ -0,0 +1,355 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace System.IO.Packaging
{
class PackagePropertiesPart : PackageProperties
{
const string NSDc = "http://purl.org/dc/elements/1.1/";
const string NSDcTerms = "http://purl.org/dc/terms/";
const string NSXsi = "http://www.w3.org/2001/XMLSchema-instance";

string category;
string contentStatus;
string contentType;
DateTime? created;
string creator;
string description;
string identifier;
string keywords;
string language;
string lastModifiedBy;
DateTime? lastPrinted;
DateTime? modified;
string revision;
string subject;
string title;
string version;

public PackagePropertiesPart()
{

}

public override string Category
{
get
{
return category;
}
set
{
Package.CheckIsReadOnly();
category = value;
}
}
public override string ContentStatus
{
get
{
return contentStatus;
}
set
{
Package.CheckIsReadOnly();
contentStatus = value;
}
}
public override string ContentType
{
get
{
return contentType;
}
set
{
Package.CheckIsReadOnly();
contentType = value;
}
}
public override DateTime? Created
{
get
{
return created;
}
set
{
Package.CheckIsReadOnly();
created = value;
}
}
public override string Creator
{
get
{
return creator;
}
set
{
Package.CheckIsReadOnly();
creator = value;
}
}
public override string Description
{
get
{
return description;
}
set
{
Package.CheckIsReadOnly();
description = value;
}
}
public override string Identifier
{
get
{
return identifier;
}
set
{
Package.CheckIsReadOnly();
identifier = value;
}
}
public override string Keywords
{
get
{
return keywords;
}
set
{
Package.CheckIsReadOnly();
keywords = value;
}
}
public override string Language
{
get
{
return language;
}
set
{
Package.CheckIsReadOnly();
language = value;
}
}
public override string LastModifiedBy
{
get
{
return lastModifiedBy;
}
set
{
Package.CheckIsReadOnly();
lastModifiedBy = value;
}
}
public override DateTime? LastPrinted
{
get
{
return lastPrinted;
}
set
{
Package.CheckIsReadOnly();
lastPrinted = value;
}
}
public override DateTime? Modified
{
get
{
return modified;
}
set
{
Package.CheckIsReadOnly();
modified = value;
}
}
public override string Revision
{
get
{
return revision;
}
set
{
Package.CheckIsReadOnly();
revision = value;
}
}
public override string Subject
{
get
{
return subject;
}
set
{
Package.CheckIsReadOnly();
subject = value;
}
}
public override string Title
{
get
{
return title;
}
set
{
Package.CheckIsReadOnly();
title = value;
}
}
public override string Version
{
get
{
return version;
}
set
{
Package.CheckIsReadOnly();
version = value;
}
}

internal override void LoadFrom(Stream stream)
{
if (stream.Length == 0)
return;

XmlDocument doc = new XmlDocument();
doc.Load(stream);

XmlNamespaceManager manager = new XmlNamespaceManager(doc.NameTable);
manager.AddNamespace("prop", NSPackageProperties);
manager.AddNamespace("dc", NSDc);
manager.AddNamespace("dcterms", NSDcTerms);
manager.AddNamespace("xsi", NSXsi);

XmlNode node;
if ((node = doc.SelectSingleNode("prop:coreProperties/prop:category", manager)) != null)
category = node.InnerXml;
if ((node = doc.SelectSingleNode("prop:coreProperties/prop:contentStatus", manager)) != null)
contentStatus = node.InnerXml;
if ((node = doc.SelectSingleNode("prop:coreProperties/prop:contentType", manager)) != null)
contentType = node.InnerXml;
if ((node = doc.SelectSingleNode("prop:coreProperties/dcterms:created", manager)) != null)
created = DateTime.Parse(node.InnerXml);
if ((node = doc.SelectSingleNode("prop:coreProperties/dc:creator", manager)) != null)
creator = node.InnerXml;
if ((node = doc.SelectSingleNode("prop:coreProperties/dc:description", manager)) != null)
description = node.InnerXml;
if ((node = doc.SelectSingleNode("prop:coreProperties/dc:identifier", manager)) != null)
identifier = node.InnerXml;
if ((node = doc.SelectSingleNode("prop:coreProperties/prop:keywords", manager)) != null)
keywords = node.InnerXml;
if ((node = doc.SelectSingleNode("prop:coreProperties/dc:language", manager)) != null)
language = node.InnerXml;
if ((node = doc.SelectSingleNode("prop:coreProperties/prop:lastModifiedBy", manager)) != null)
lastModifiedBy = node.InnerXml;
if ((node = doc.SelectSingleNode("prop:coreProperties/prop:lastPrinted", manager)) != null)
lastPrinted = DateTime.Parse(node.InnerXml);
if ((node = doc.SelectSingleNode("prop:coreProperties/dcterms:modified", manager)) != null)
modified = DateTime.Parse(node.InnerXml);
if ((node = doc.SelectSingleNode("prop:coreProperties/prop:revision", manager)) != null)
revision = node.InnerXml;
if ((node = doc.SelectSingleNode("prop:coreProperties/dc:subject", manager)) != null)
subject = node.InnerXml;
if ((node = doc.SelectSingleNode("prop:coreProperties/dc:title", manager)) != null)
title = node.InnerXml;
if ((node = doc.SelectSingleNode("prop:coreProperties/prop:version", manager)) != null)
version = node.InnerXml;
}

internal override void WriteTo(XmlTextWriter writer)
{
XmlDocument doc = new XmlDocument();
XmlNamespaceManager manager = new XmlNamespaceManager(doc.NameTable);
manager.AddNamespace("prop", NSPackageProperties);
manager.AddNamespace("dc", NSDc);
manager.AddNamespace("dcterms", NSDcTerms);
manager.AddNamespace("xsi", NSXsi);

// Create XML declaration
doc.AppendChild(doc.CreateXmlDeclaration("1.0", "UTF-8", null));

// Create root node with required namespace declarations
XmlNode coreProperties = doc.AppendChild(doc.CreateNode(XmlNodeType.Element, "coreProperties", NSPackageProperties));
coreProperties.Attributes.Append(doc.CreateAttribute("xmlns:dc")).Value = NSDc;
coreProperties.Attributes.Append(doc.CreateAttribute("xmlns:dcterms")).Value = NSDcTerms;
coreProperties.Attributes.Append(doc.CreateAttribute("xmlns:xsi")).Value = NSXsi;

// Create the children
if (Category != null)
coreProperties.AppendChild(doc.CreateNode(XmlNodeType.Element, "category", NSPackageProperties)).InnerXml = Category;
if (ContentStatus != null)
coreProperties.AppendChild(doc.CreateNode(XmlNodeType.Element, "contentStatus", NSPackageProperties)).InnerXml = ContentStatus;
if (ContentType != null)
coreProperties.AppendChild(doc.CreateNode(XmlNodeType.Element, "contentType", NSPackageProperties)).InnerXml = ContentType;
if (Created.HasValue)
{
XmlAttribute att = doc.CreateAttribute("xsi", "type", NSXsi);
att.Value = "dcterms:W3CDTF";

XmlNode created = coreProperties.AppendChild(doc.CreateNode(XmlNodeType.Element, "dcterms", "created", NSDcTerms));
created.Attributes.Append(att);
created.InnerXml = Created.Value.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss") + "Z";
}
if (Creator != null)
coreProperties.AppendChild(doc.CreateNode(XmlNodeType.Element, "dc", "creator", NSDc)).InnerXml = Creator;
if (Description != null)
coreProperties.AppendChild(doc.CreateNode(XmlNodeType.Element, "dc", "description", NSDc)).InnerXml = Description;
if (Identifier != null)
coreProperties.AppendChild(doc.CreateNode(XmlNodeType.Element, "dc", "identifier", NSDc)).InnerXml = Identifier;
if (Keywords != null)
coreProperties.AppendChild(doc.CreateNode(XmlNodeType.Element, "keywords", NSPackageProperties)).InnerXml = Keywords;
if (Language != null)
coreProperties.AppendChild(doc.CreateNode(XmlNodeType.Element, "dc", "language", NSDc)).InnerXml = Language;
if (LastModifiedBy != null)
coreProperties.AppendChild(doc.CreateNode(XmlNodeType.Element, "lastModifiedBy", NSPackageProperties)).InnerXml = LastModifiedBy;
if (LastPrinted.HasValue)
{
XmlNode lastPrinted = coreProperties.AppendChild(doc.CreateNode(XmlNodeType.Element, "lastPrinted", NSPackageProperties));

lastPrinted.InnerXml = LastPrinted.Value.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss") + "Z";
}
if (Revision != null)
coreProperties.AppendChild(doc.CreateNode(XmlNodeType.Element, "revision", NSPackageProperties)).InnerXml = Revision;
if (Subject != null)
coreProperties.AppendChild(doc.CreateNode(XmlNodeType.Element, "dc", "subject", NSDc)).InnerXml = Subject;
if (Title != null)
coreProperties.AppendChild(doc.CreateNode(XmlNodeType.Element, "dc", "title", NSDc)).InnerXml = Title;
if (Version != null)
coreProperties.AppendChild(doc.CreateNode(XmlNodeType.Element, "version", NSPackageProperties)).InnerXml = Version;

if (Modified.HasValue)
{
XmlAttribute att = doc.CreateAttribute("xsi", "type", NSXsi);
att.Value = "dcterms:W3CDTF";

XmlNode modified = coreProperties.AppendChild(doc.CreateNode(XmlNodeType.Element, "dcterms", "modified", NSDcTerms));
modified.Attributes.Append(att);
modified.InnerXml = Modified.Value.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss") + "Z";
}

doc.WriteContentTo(writer);
}
}
}

+ 59
- 0
DocX.iOS/System/IO/Packaging/PackageRelationship.cs Visa fil

@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace System.IO.Packaging
{
public class PackageRelationship
{
internal PackageRelationship(string id, Package package, string relationshipType,
Uri sourceUri, TargetMode targetMode, Uri targetUri)
{
Check.IdIsValid(id);
Check.Package(package);
Check.RelationshipTypeIsValid(relationshipType);
Check.SourceUri(sourceUri);
Check.TargetUri(targetUri);

Id = id;
Package = package;
RelationshipType = relationshipType;
SourceUri = sourceUri;
TargetMode = targetMode;
TargetUri = targetUri;
}

public string Id
{
get;
private set;
}
public Package Package
{
get;
private set;
}
public string RelationshipType
{
get;
private set;
}
public Uri SourceUri
{
get;
private set;
}
public TargetMode TargetMode
{
get;
private set;
}
public Uri TargetUri
{
get;
private set;
}
}
}

+ 29
- 0
DocX.iOS/System/IO/Packaging/PackageRelationshipCollection.cs Visa fil

@@ -0,0 +1,29 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace System.IO.Packaging
{
public class PackageRelationshipCollection : IEnumerable<PackageRelationship>, IEnumerable
{
internal List<PackageRelationship> Relationships { get; private set; }

internal PackageRelationshipCollection()
{
Relationships = new List<PackageRelationship>();
}

public IEnumerator<PackageRelationship> GetEnumerator()
{
return Relationships.GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

+ 14
- 0
DocX.iOS/System/IO/Packaging/TargetMode.cs Visa fil

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace System.IO.Packaging
{
public enum TargetMode
{
Internal,
External
}
}

+ 266
- 0
DocX.iOS/System/IO/Packaging/ZipPackage.cs Visa fil

@@ -0,0 +1,266 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using DocX.iOS.Zip;

namespace System.IO.Packaging
{
class UriComparer : IEqualityComparer<Uri>
{
public int GetHashCode(Uri uri)
{
return 1;
}

public bool Equals(Uri x, Uri y)
{
return x.OriginalString.Equals(y.OriginalString, StringComparison.OrdinalIgnoreCase);
}
}

public sealed class ZipPackage : Package
{
public ZipStorer Archive { get; set; }
private const string ContentNamespace = "http://schemas.openxmlformats.org/package/2006/content-types";
private const string ContentUri = "[Content_Types].xml";

bool OwnsStream
{
get;
set;
}

Dictionary<Uri, ZipPackagePart> parts;
internal Dictionary<Uri, MemoryStream> PartStreams = new Dictionary<Uri, MemoryStream>(new UriComparer());

internal Stream PackageStream { get; set; }

Dictionary<Uri, ZipPackagePart> Parts
{
get
{
if (parts == null)
LoadParts();
return parts;
}
}

internal ZipPackage(FileAccess access, bool ownsStream, Stream stream)
: base(access)
{
OwnsStream = ownsStream;
PackageStream = stream;
}

internal ZipPackage(FileAccess access, bool ownsStream, Stream stream, bool streaming)
: base(access, streaming)
{
OwnsStream = ownsStream;
PackageStream = stream;
}

protected override void Dispose(bool disposing)
{
foreach (Stream s in PartStreams.Values)
s.Close();

if (Archive != null) // GZE fixed bug where Archive == null
{
Archive.Close();
}

base.Dispose(disposing);

if (OwnsStream)
PackageStream.Close();
}

protected override void FlushCore()
{
// Ensure that all the data has been read out of the package
// stream already. Otherwise we'll lose data when we recreate the zip

foreach (ZipPackagePart part in Parts.Values)
{
part.GetStream();
}
if (!PackageStream.CanSeek)
return;
// Empty the package stream
PackageStream.Position = 0;
PackageStream.SetLength(0);

// Recreate the zip file
using (ZipStorer archive = ZipStorer.Create(PackageStream, "", false))
{

// Write all the part streams
foreach (ZipPackagePart part in Parts.Values)
{
Stream partStream = part.GetStream();
partStream.Seek(0, SeekOrigin.Begin);

archive.AddStream(ZipStorer.Compression.Deflate, part.Uri.ToString().Substring(1), partStream,
DateTime.UtcNow, "");
}

using (var ms = new MemoryStream())
{
WriteContentType(ms);
ms.Seek(0, SeekOrigin.Begin);

archive.AddStream(ZipStorer.Compression.Deflate, ContentUri, ms, DateTime.UtcNow, "");
}
}
}


protected override PackagePart CreatePartCore(Uri partUri, string contentType, CompressionOption compressionOption)
{
ZipPackagePart part = new ZipPackagePart(this, partUri, contentType, compressionOption);
Parts.Add(part.Uri, part);
return part;
}

protected override void DeletePartCore(Uri partUri)
{
Parts.Remove(partUri);
}

protected override PackagePart GetPartCore(Uri partUri)
{
ZipPackagePart part;
Parts.TryGetValue(partUri, out part);
return part;
}

protected override PackagePart[] GetPartsCore()
{
ZipPackagePart[] p = new ZipPackagePart[Parts.Count];
Parts.Values.CopyTo(p, 0);
return p;
}

void LoadParts()
{
parts = new Dictionary<Uri, ZipPackagePart>(new UriComparer());
try
{
PackageStream.Seek(0, SeekOrigin.Begin);
if (Archive == null)
{
Archive = ZipStorer.Open(PackageStream, FileAccess.Read, false);
}
List<ZipStorer.ZipFileEntry> dir = Archive.ReadCentralDir();

// Load the content type map file
XmlDocument doc = new XmlDocument();
var content = dir.FirstOrDefault(x => x.FilenameInZip == ContentUri);
using (var ms = new MemoryStream())
{
Archive.ExtractFile(content, ms);
ms.Seek(0, SeekOrigin.Begin);
doc.Load(ms);
}

XmlNamespaceManager manager = new XmlNamespaceManager(doc.NameTable);
manager.AddNamespace("content", ContentNamespace);

// The file names in the zip archive are not prepended with '/'
foreach (var file in dir)
{
if (file.FilenameInZip.Equals(ContentUri, StringComparison.Ordinal))
continue;

XmlNode node;

if (file.FilenameInZip == RelationshipUri.ToString().Substring(1))
{
CreatePartCore(RelationshipUri, RelationshipContentType, CompressionOption.Normal);
continue;
}

string xPath = string.Format("/content:Types/content:Override[@PartName='/{0}']", file);
node = doc.SelectSingleNode(xPath, manager);

if (node == null)
{
string ext = Path.GetExtension(file.FilenameInZip);
if (ext.StartsWith("."))
ext = ext.Substring(1);
xPath = string.Format("/content:Types/content:Default[@Extension='{0}']", ext);
node = doc.SelectSingleNode(xPath, manager);
}

// What do i do if the node is null? This means some has tampered with the
// package file manually
if (node != null)
CreatePartCore(new Uri("/" + file, UriKind.Relative), node.Attributes["ContentType"].Value,
CompressionOption.Normal);
}
}
catch
{
// The archive is invalid - therefore no parts
}
}

void WriteContentType(Stream s)
{
XmlDocument doc = new XmlDocument();
XmlNamespaceManager manager = new XmlNamespaceManager(doc.NameTable);
Dictionary<string, string> mimes = new Dictionary<string, string>();

manager.AddNamespace("content", ContentNamespace);

doc.AppendChild(doc.CreateNode(XmlNodeType.XmlDeclaration, "", ""));

XmlNode root = doc.CreateNode(XmlNodeType.Element, "Types", ContentNamespace);
doc.AppendChild(root);
foreach (ZipPackagePart part in Parts.Values)
{
XmlNode node = null;
string existingMimeType;

var extension = Path.GetExtension(part.Uri.OriginalString);
if (extension.Length > 0)
extension = extension.Substring(1);

if (!mimes.TryGetValue(extension, out existingMimeType))
{
node = doc.CreateNode(XmlNodeType.Element, "Default", ContentNamespace);

XmlAttribute ext = doc.CreateAttribute("Extension");
ext.Value = extension;
node.Attributes.Append(ext);
mimes[extension] = part.ContentType;
}
else if (part.ContentType != existingMimeType)
{
node = doc.CreateNode(XmlNodeType.Element, "Override", ContentNamespace);

XmlAttribute name = doc.CreateAttribute("PartName");
name.Value = part.Uri.ToString();
node.Attributes.Append(name);
}

if (node != null)
{
XmlAttribute contentType = doc.CreateAttribute("ContentType");
contentType.Value = part.ContentType;
node.Attributes.Prepend(contentType);

root.AppendChild(node);
}
}

XmlTextWriter writer = new XmlTextWriter(s, System.Text.Encoding.UTF8);
doc.WriteTo(writer);
writer.Flush();
}
}
}

+ 77
- 0
DocX.iOS/System/IO/Packaging/ZipPackagePart.cs Visa fil

@@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DocX.iOS.Zip;

namespace System.IO.Packaging
{
public sealed class ZipPackagePart : PackagePart
{
new ZipPackage Package
{
get { return (ZipPackage)base.Package; }
}

internal ZipPackagePart(Package package, Uri partUri)
: base(package, partUri)
{

}

internal ZipPackagePart(Package package, Uri partUri, string contentType)
: base(package, partUri, contentType)
{

}

internal ZipPackagePart(Package package, Uri partUri, string contentType, CompressionOption compressionOption)
: base(package, partUri, contentType, compressionOption)
{

}

protected override Stream GetStreamCore(FileMode mode, FileAccess access)
{
ZipPartStream zps;
MemoryStream stream;
if (Package.PartStreams.TryGetValue(Uri, out stream))
{
//zps = new ZipPartStream(Package, stream, access);
if (mode == FileMode.Create)
stream.SetLength(0);
return new ZipPartStream(Package, stream, access);
}

stream = new MemoryStream();
try
{
if (Package.Archive == null)
{
Package.Archive = ZipStorer.Open(Package.PackageStream, access, false);
}
List<ZipStorer.ZipFileEntry> dir = Package.Archive.ReadCentralDir();
foreach (ZipStorer.ZipFileEntry entry in dir)
{
if (entry.FilenameInZip != Uri.ToString().Substring(1))
continue;

Package.Archive.ExtractFile(entry, stream);
}
}
catch
{
// The zipfile is invalid, so just create the file
// as if it didn't exist
stream.SetLength(0);
}

Package.PartStreams.Add(Uri, stream);
if (mode == FileMode.Create)
stream.SetLength(0);
return new ZipPartStream(Package, stream, access);
}
}
}

+ 131
- 0
DocX.iOS/System/IO/Packaging/ZipPartStream.cs Visa fil

@@ -0,0 +1,131 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace System.IO.Packaging
{
internal class ZipPartStream : Stream
{
public MemoryStream BaseStream { get; private set; }
public ZipPackage Package { get; private set; }

public override bool CanRead
{
get
{
return BaseStream.CanRead;
}
}

public override bool CanSeek
{
get
{
return BaseStream.CanSeek;
}
}

public override bool CanTimeout
{
get { return BaseStream.CanTimeout; }
}

public override bool CanWrite
{
get { return Writeable; }
}

public override long Length
{
get { return BaseStream.Length; }
}

public override long Position
{
get;
set;
}

public bool Writeable
{
get;
set;
}

public override int WriteTimeout
{
get
{
return BaseStream.WriteTimeout;
}
set
{
BaseStream.WriteTimeout = value;
}
}

public override int ReadTimeout
{
get
{
return BaseStream.ReadTimeout;
}
set
{
BaseStream.ReadTimeout = value;
}
}

public ZipPartStream(ZipPackage package, MemoryStream stream, FileAccess access)
{
BaseStream = stream;
Package = package;
Writeable = access != FileAccess.Read;
}

public override void Flush()
{
// If the user flushes any of the part streams,
// we need to flush the entire package

// FIXME: Ensure that this actually happens with a testcase
// ...if possible
// Package.Flush();
}

public override int Read(byte[] buffer, int offset, int count)
{
Seek(Position, SeekOrigin.Begin);
int read = BaseStream.Read(buffer, offset, count);
Position += read;
return read;
}

public override long Seek(long offset, SeekOrigin origin)
{
Position = BaseStream.Seek(offset, origin);
return Position;
}

public override void SetLength(long value)
{
if (!CanWrite)
throw new InvalidOperationException("Stream is not writeable");

BaseStream.SetLength(value);
}

public override void Write(byte[] buffer, int offset, int count)
{
if (!CanWrite)
throw new InvalidOperationException("Stream is not writeable");

Seek(Position, SeekOrigin.Begin);
BaseStream.Write(buffer, offset, count);
Position += count;
}
}
}

+ 758
- 0
DocX.iOS/Zip/ZipStorer.cs Visa fil

@@ -0,0 +1,758 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DocX.iOS.Zip
{
/// <summary>
/// Unique class for compression/decompression file. Represents a Zip file.
/// </summary>
public class ZipStorer : IDisposable
{
/// <summary>
/// Compression method enumeration
/// </summary>
public enum Compression : ushort
{
/// <summary>Uncompressed storage</summary>
Store = 0,
/// <summary>Deflate compression method</summary>
Deflate = 8
}

/// <summary>
/// Represents an entry in Zip file directory
/// </summary>
public struct ZipFileEntry
{
/// <summary>Compression method</summary>
public Compression Method;
/// <summary>Full path and filename as stored in Zip</summary>
public string FilenameInZip;
/// <summary>Original file size</summary>
public uint FileSize;
/// <summary>Compressed file size</summary>
public uint CompressedSize;
/// <summary>Offset of header information inside Zip storage</summary>
public uint HeaderOffset;
/// <summary>Offset of file inside Zip storage</summary>
public uint FileOffset;
/// <summary>Size of header information</summary>
public uint HeaderSize;
/// <summary>32-bit checksum of entire file</summary>
public uint Crc32;
/// <summary>Last modification time of file</summary>
public DateTime ModifyTime;
/// <summary>User comment for file</summary>
public string Comment;
/// <summary>True if UTF8 encoding for filename and comments, false if default (CP 437)</summary>
public bool EncodeUTF8;

/// <summary>Overriden method</summary>
/// <returns>Filename in Zip</returns>
public override string ToString()
{
return this.FilenameInZip;
}
}

#region Public fields
/// <summary>True if UTF8 encoding for filename and comments, false if default (CP 437)</summary>
public bool EncodeUTF8 = false;
/// <summary>Force deflate algotithm even if it inflates the stored file. Off by default.</summary>
public bool ForceDeflating = false;
#endregion

#region Private fields
// List of files to store
private List<ZipFileEntry> Files = new List<ZipFileEntry>();
// Filename of storage file
private string FileName;
// Stream object of storage file
private Stream ZipFileStream;
private bool OwnsStream = true;
// General comment
private string Comment = "";
// Central dir image
private byte[] CentralDirImage = null;
// Existing files in zip
private ushort ExistingFiles = 0;
// File access for Open method
private FileAccess Access;
// Static CRC32 Table
private static UInt32[] CrcTable = null;
// Default filename encoder
private static Encoding DefaultEncoding = Encoding.GetEncoding(437);
#endregion

#region Public methods
// Static constructor. Just invoked once in order to create the CRC32 lookup table.
static ZipStorer()
{
// Generate CRC32 table
CrcTable = new UInt32[256];
for (int i = 0; i < CrcTable.Length; i++)
{
UInt32 c = (UInt32)i;
for (int j = 0; j < 8; j++)
{
if ((c & 1) != 0)
c = 3988292384 ^ (c >> 1);
else
c >>= 1;
}
CrcTable[i] = c;
}
}
/// <summary>
/// Method to create a new storage file
/// </summary>
/// <param name="_filename">Full path of Zip file to create</param>
/// <param name="_comment">General comment for Zip file</param>
/// <returns>A valid ZipStorer object</returns>
public static ZipStorer Create(string _filename, string _comment)
{
Stream stream = new FileStream(_filename, FileMode.Create, FileAccess.ReadWrite);

ZipStorer zip = Create(stream, _comment, true);
zip.Comment = _comment;
zip.FileName = _filename;

return zip;
}
/// <summary>
/// Method to create a new zip storage in a stream
/// </summary>
/// <param name="_stream"></param>
/// <param name="_comment"></param>
/// <returns>A valid ZipStorer object</returns>
public static ZipStorer Create(Stream _stream, string _comment, bool _ownsStream = false)
{
ZipStorer zip = new ZipStorer();
zip.Comment = _comment;
zip.ZipFileStream = _stream;
zip.OwnsStream = _ownsStream;
zip.Access = FileAccess.Write;

return zip;
}
/// <summary>
/// Method to open an existing storage file
/// </summary>
/// <param name="_filename">Full path of Zip file to open</param>
/// <param name="_access">File access mode as used in FileStream constructor</param>
/// <returns>A valid ZipStorer object</returns>
public static ZipStorer Open(string _filename, FileAccess _access)
{
Stream stream = (Stream)new FileStream(_filename, FileMode.Open, _access == FileAccess.Read ? FileAccess.Read : FileAccess.ReadWrite);

ZipStorer zip = Open(stream, _access, true);
zip.FileName = _filename;

return zip;
}
/// <summary>
/// Method to open an existing storage from stream
/// </summary>
/// <param name="_stream">Already opened stream with zip contents</param>
/// <param name="_access">File access mode for stream operations</param>
/// <returns>A valid ZipStorer object</returns>
public static ZipStorer Open(Stream _stream, FileAccess _access, bool _ownsStream = false)
{
if (!_stream.CanSeek && _access != FileAccess.Read)
throw new InvalidOperationException("Stream cannot seek");

ZipStorer zip = new ZipStorer();
//zip.FileName = _filename;
zip.ZipFileStream = _stream;
zip.OwnsStream = _ownsStream;
zip.Access = _access;

if (zip.ReadFileInfo())
return zip;

throw new System.IO.InvalidDataException();
}
/// <summary>
/// Add full contents of a file into the Zip storage
/// </summary>
/// <param name="_method">Compression method</param>
/// <param name="_pathname">Full path of file to add to Zip storage</param>
/// <param name="_filenameInZip">Filename and path as desired in Zip directory</param>
/// <param name="_comment">Comment for stored file</param>
public void AddFile(Compression _method, string _pathname, string _filenameInZip, string _comment)
{
if (Access == FileAccess.Read)
throw new InvalidOperationException("Writing is not alowed");

FileStream stream = new FileStream(_pathname, FileMode.Open, FileAccess.Read);
AddStream(_method, _filenameInZip, stream, File.GetLastWriteTime(_pathname), _comment);
stream.Close();
}
/// <summary>
/// Add full contents of a stream into the Zip storage
/// </summary>
/// <param name="_method">Compression method</param>
/// <param name="_filenameInZip">Filename and path as desired in Zip directory</param>
/// <param name="_source">Stream object containing the data to store in Zip</param>
/// <param name="_modTime">Modification time of the data to store</param>
/// <param name="_comment">Comment for stored file</param>
public void AddStream(Compression _method, string _filenameInZip, Stream _source, DateTime _modTime, string _comment)
{
if (Access == FileAccess.Read)
throw new InvalidOperationException("Writing is not alowed");

long offset;
if (this.Files.Count == 0)
offset = 0;
else
{
ZipFileEntry last = this.Files[this.Files.Count - 1];
offset = last.HeaderOffset + last.HeaderSize;
}

// Prepare the fileinfo
ZipFileEntry zfe = new ZipFileEntry();
zfe.Method = _method;
zfe.EncodeUTF8 = this.EncodeUTF8;
zfe.FilenameInZip = NormalizedFilename(_filenameInZip);
zfe.Comment = (_comment == null ? "" : _comment);

// Even though we write the header now, it will have to be rewritten, since we don't know compressed size or crc.
zfe.Crc32 = 0; // to be updated later
zfe.HeaderOffset = (uint)this.ZipFileStream.Position; // offset within file of the start of this local record
zfe.ModifyTime = _modTime;

// Write local header
WriteLocalHeader(ref zfe);
zfe.FileOffset = (uint)this.ZipFileStream.Position;

// Write file to zip (store)
Store(ref zfe, _source);
_source.Close();

this.UpdateCrcAndSizes(ref zfe);

Files.Add(zfe);
}
/// <summary>
/// Updates central directory (if pertinent) and close the Zip storage
/// </summary>
/// <remarks>This is a required step, unless automatic dispose is used</remarks>
public void Close()
{
if (this.Access != FileAccess.Read)
{
uint centralOffset = (uint)this.ZipFileStream.Position;
uint centralSize = 0;

if (this.CentralDirImage != null)
this.ZipFileStream.Write(CentralDirImage, 0, CentralDirImage.Length);

for (int i = 0; i < Files.Count; i++)
{
long pos = this.ZipFileStream.Position;
this.WriteCentralDirRecord(Files[i]);
centralSize += (uint)(this.ZipFileStream.Position - pos);
}

if (this.CentralDirImage != null)
this.WriteEndRecord(centralSize + (uint)CentralDirImage.Length, centralOffset);
else
this.WriteEndRecord(centralSize, centralOffset);
}

if (this.ZipFileStream != null && ZipFileStream.CanSeek)
{
this.ZipFileStream.Flush();

// GZE added ownsStream, to prevent premature closure

if (this.OwnsStream)
{
this.ZipFileStream.Dispose();
}

this.ZipFileStream = null;
}
}
/// <summary>
/// Read all the file records in the central directory
/// </summary>
/// <returns>List of all entries in directory</returns>
public List<ZipFileEntry> ReadCentralDir()
{
if (this.CentralDirImage == null)
throw new InvalidOperationException("Central directory currently does not exist");

List<ZipFileEntry> result = new List<ZipFileEntry>();

for (int pointer = 0; pointer < this.CentralDirImage.Length; )
{
uint signature = BitConverter.ToUInt32(CentralDirImage, pointer);
if (signature != 0x02014b50)
break;

bool encodeUTF8 = (BitConverter.ToUInt16(CentralDirImage, pointer + 8) & 0x0800) != 0;
ushort method = BitConverter.ToUInt16(CentralDirImage, pointer + 10);
uint modifyTime = BitConverter.ToUInt32(CentralDirImage, pointer + 12);
uint crc32 = BitConverter.ToUInt32(CentralDirImage, pointer + 16);
uint comprSize = BitConverter.ToUInt32(CentralDirImage, pointer + 20);
uint fileSize = BitConverter.ToUInt32(CentralDirImage, pointer + 24);
ushort filenameSize = BitConverter.ToUInt16(CentralDirImage, pointer + 28);
ushort extraSize = BitConverter.ToUInt16(CentralDirImage, pointer + 30);
ushort commentSize = BitConverter.ToUInt16(CentralDirImage, pointer + 32);
uint headerOffset = BitConverter.ToUInt32(CentralDirImage, pointer + 42);
uint headerSize = (uint)(46 + filenameSize + extraSize + commentSize);

Encoding encoder = encodeUTF8 ? Encoding.UTF8 : DefaultEncoding;

ZipFileEntry zfe = new ZipFileEntry();
zfe.Method = (Compression)method;
zfe.FilenameInZip = encoder.GetString(CentralDirImage, pointer + 46, filenameSize);
zfe.FileOffset = GetFileOffset(headerOffset);
zfe.FileSize = fileSize;
zfe.CompressedSize = comprSize;
zfe.HeaderOffset = headerOffset;
zfe.HeaderSize = headerSize;
zfe.Crc32 = crc32;
zfe.ModifyTime = DosTimeToDateTime(modifyTime);
if (commentSize > 0)
zfe.Comment = encoder.GetString(CentralDirImage, pointer + 46 + filenameSize + extraSize, commentSize);

result.Add(zfe);
pointer += (46 + filenameSize + extraSize + commentSize);
}

return result;
}
/// <summary>
/// Copy the contents of a stored file into a physical file
/// </summary>
/// <param name="_zfe">Entry information of file to extract</param>
/// <param name="_filename">Name of file to store uncompressed data</param>
/// <returns>True if success, false if not.</returns>
/// <remarks>Unique compression methods are Store and Deflate</remarks>
public bool ExtractFile(ZipFileEntry _zfe, string _filename)
{
// Make sure the parent directory exist
string path = System.IO.Path.GetDirectoryName(_filename);

if (!Directory.Exists(path))
Directory.CreateDirectory(path);
// Check it is directory. If so, do nothing
if (Directory.Exists(_filename))
return true;

Stream output = new FileStream(_filename, FileMode.Create, FileAccess.Write);
bool result = ExtractFile(_zfe, output);
if (result)
output.Close();

File.SetCreationTime(_filename, _zfe.ModifyTime);
File.SetLastWriteTime(_filename, _zfe.ModifyTime);

return result;
}
/// <summary>
/// Copy the contents of a stored file into an opened stream
/// </summary>
/// <param name="_zfe">Entry information of file to extract</param>
/// <param name="_stream">Stream to store the uncompressed data</param>
/// <returns>True if success, false if not.</returns>
/// <remarks>Unique compression methods are Store and Deflate</remarks>
public bool ExtractFile(ZipFileEntry _zfe, Stream _stream)
{
if (!_stream.CanWrite)
throw new InvalidOperationException("Stream cannot be written");

// check signature
byte[] signature = new byte[4];
this.ZipFileStream.Seek(_zfe.HeaderOffset, SeekOrigin.Begin);
this.ZipFileStream.Read(signature, 0, 4);
if (BitConverter.ToUInt32(signature, 0) != 0x04034b50)
return false;

// Select input stream for inflating or just reading
Stream inStream;
if (_zfe.Method == Compression.Store)
inStream = this.ZipFileStream;
else if (_zfe.Method == Compression.Deflate)
inStream = new DeflateStream(this.ZipFileStream, CompressionMode.Decompress, true);
else
return false;

// Buffered copy
byte[] buffer = new byte[16384];
this.ZipFileStream.Seek(_zfe.FileOffset, SeekOrigin.Begin);
uint bytesPending = _zfe.FileSize;
while (bytesPending > 0)
{
int bytesRead = inStream.Read(buffer, 0, (int)Math.Min(bytesPending, buffer.Length));
_stream.Write(buffer, 0, bytesRead);
bytesPending -= (uint)bytesRead;
}
_stream.Flush();

if (_zfe.Method == Compression.Deflate)
inStream.Dispose();
return true;
}
/// <summary>
/// Removes one of many files in storage. It creates a new Zip file.
/// </summary>
/// <param name="_zip">Reference to the current Zip object</param>
/// <param name="_zfes">List of Entries to remove from storage</param>
/// <returns>True if success, false if not</returns>
/// <remarks>This method only works for storage of type FileStream</remarks>
public static bool RemoveEntries(ref ZipStorer _zip, List<ZipFileEntry> _zfes)
{
if (!(_zip.ZipFileStream is FileStream))
throw new InvalidOperationException("RemoveEntries is allowed just over streams of type FileStream");


//Get full list of entries
List<ZipFileEntry> fullList = _zip.ReadCentralDir();

//In order to delete we need to create a copy of the zip file excluding the selected items
string tempZipName = Path.GetTempFileName();
string tempEntryName = Path.GetTempFileName();

try
{
ZipStorer tempZip = ZipStorer.Create(tempZipName, string.Empty);

foreach (ZipFileEntry zfe in fullList)
{
if (!_zfes.Contains(zfe))
{
if (_zip.ExtractFile(zfe, tempEntryName))
{
tempZip.AddFile(zfe.Method, tempEntryName, zfe.FilenameInZip, zfe.Comment);
}
}
}
_zip.Close();
tempZip.Close();

File.Delete(_zip.FileName);
File.Move(tempZipName, _zip.FileName);

_zip = ZipStorer.Open(_zip.FileName, _zip.Access);
}
catch
{
return false;
}
finally
{
if (File.Exists(tempZipName))
File.Delete(tempZipName);
if (File.Exists(tempEntryName))
File.Delete(tempEntryName);
}
return true;
}
#endregion

#region Private methods
// Calculate the file offset by reading the corresponding local header
private uint GetFileOffset(uint _headerOffset)
{
byte[] buffer = new byte[2];

this.ZipFileStream.Seek(_headerOffset + 26, SeekOrigin.Begin);
this.ZipFileStream.Read(buffer, 0, 2);
ushort filenameSize = BitConverter.ToUInt16(buffer, 0);
this.ZipFileStream.Read(buffer, 0, 2);
ushort extraSize = BitConverter.ToUInt16(buffer, 0);

return (uint)(30 + filenameSize + extraSize + _headerOffset);
}
/* Local file header:
local file header signature 4 bytes (0x04034b50)
version needed to extract 2 bytes
general purpose bit flag 2 bytes
compression method 2 bytes
last mod file time 2 bytes
last mod file date 2 bytes
crc-32 4 bytes
compressed size 4 bytes
uncompressed size 4 bytes
filename length 2 bytes
extra field length 2 bytes

filename (variable size)
extra field (variable size)
*/
private void WriteLocalHeader(ref ZipFileEntry _zfe)
{
long pos = this.ZipFileStream.Position;
Encoding encoder = _zfe.EncodeUTF8 ? Encoding.UTF8 : DefaultEncoding;
byte[] encodedFilename = encoder.GetBytes(_zfe.FilenameInZip);

this.ZipFileStream.Write(new byte[] { 80, 75, 3, 4, 20, 0 }, 0, 6); // No extra header
this.ZipFileStream.Write(BitConverter.GetBytes((ushort)(_zfe.EncodeUTF8 ? 0x0800 : 0)), 0, 2); // filename and comment encoding
this.ZipFileStream.Write(BitConverter.GetBytes((ushort)_zfe.Method), 0, 2); // zipping method
this.ZipFileStream.Write(BitConverter.GetBytes(DateTimeToDosTime(_zfe.ModifyTime)), 0, 4); // zipping date and time
this.ZipFileStream.Write(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0, 12); // unused CRC, un/compressed size, updated later
this.ZipFileStream.Write(BitConverter.GetBytes((ushort)encodedFilename.Length), 0, 2); // filename length
this.ZipFileStream.Write(BitConverter.GetBytes((ushort)0), 0, 2); // extra length

this.ZipFileStream.Write(encodedFilename, 0, encodedFilename.Length);
_zfe.HeaderSize = (uint)(this.ZipFileStream.Position - pos);
}
/* Central directory's File header:
central file header signature 4 bytes (0x02014b50)
version made by 2 bytes
version needed to extract 2 bytes
general purpose bit flag 2 bytes
compression method 2 bytes
last mod file time 2 bytes
last mod file date 2 bytes
crc-32 4 bytes
compressed size 4 bytes
uncompressed size 4 bytes
filename length 2 bytes
extra field length 2 bytes
file comment length 2 bytes
disk number start 2 bytes
internal file attributes 2 bytes
external file attributes 4 bytes
relative offset of local header 4 bytes

filename (variable size)
extra field (variable size)
file comment (variable size)
*/
private void WriteCentralDirRecord(ZipFileEntry _zfe)
{
Encoding encoder = _zfe.EncodeUTF8 ? Encoding.UTF8 : DefaultEncoding;
byte[] encodedFilename = encoder.GetBytes(_zfe.FilenameInZip);
byte[] encodedComment = encoder.GetBytes(_zfe.Comment);

this.ZipFileStream.Write(new byte[] { 80, 75, 1, 2, 23, 0xB, 20, 0 }, 0, 8);
this.ZipFileStream.Write(BitConverter.GetBytes((ushort)(_zfe.EncodeUTF8 ? 0x0800 : 0)), 0, 2); // filename and comment encoding
this.ZipFileStream.Write(BitConverter.GetBytes((ushort)_zfe.Method), 0, 2); // zipping method
this.ZipFileStream.Write(BitConverter.GetBytes(DateTimeToDosTime(_zfe.ModifyTime)), 0, 4); // zipping date and time
this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.Crc32), 0, 4); // file CRC
this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.CompressedSize), 0, 4); // compressed file size
this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.FileSize), 0, 4); // uncompressed file size
this.ZipFileStream.Write(BitConverter.GetBytes((ushort)encodedFilename.Length), 0, 2); // Filename in zip
this.ZipFileStream.Write(BitConverter.GetBytes((ushort)0), 0, 2); // extra length
this.ZipFileStream.Write(BitConverter.GetBytes((ushort)encodedComment.Length), 0, 2);

this.ZipFileStream.Write(BitConverter.GetBytes((ushort)0), 0, 2); // disk=0
this.ZipFileStream.Write(BitConverter.GetBytes((ushort)0), 0, 2); // file type: binary
this.ZipFileStream.Write(BitConverter.GetBytes((ushort)0), 0, 2); // Internal file attributes
this.ZipFileStream.Write(BitConverter.GetBytes((ushort)0x8100), 0, 2); // External file attributes (normal/readable)
this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.HeaderOffset), 0, 4); // Offset of header

this.ZipFileStream.Write(encodedFilename, 0, encodedFilename.Length);
this.ZipFileStream.Write(encodedComment, 0, encodedComment.Length);
}
/* End of central dir record:
end of central dir signature 4 bytes (0x06054b50)
number of this disk 2 bytes
number of the disk with the
start of the central directory 2 bytes
total number of entries in
the central dir on this disk 2 bytes
total number of entries in
the central dir 2 bytes
size of the central directory 4 bytes
offset of start of central
directory with respect to
the starting disk number 4 bytes
zipfile comment length 2 bytes
zipfile comment (variable size)
*/
private void WriteEndRecord(uint _size, uint _offset)
{
Encoding encoder = this.EncodeUTF8 ? Encoding.UTF8 : DefaultEncoding;
byte[] encodedComment = encoder.GetBytes(this.Comment);

this.ZipFileStream.Write(new byte[] { 80, 75, 5, 6, 0, 0, 0, 0 }, 0, 8);
this.ZipFileStream.Write(BitConverter.GetBytes((ushort)Files.Count + ExistingFiles), 0, 2);
this.ZipFileStream.Write(BitConverter.GetBytes((ushort)Files.Count + ExistingFiles), 0, 2);
this.ZipFileStream.Write(BitConverter.GetBytes(_size), 0, 4);
this.ZipFileStream.Write(BitConverter.GetBytes(_offset), 0, 4);
this.ZipFileStream.Write(BitConverter.GetBytes((ushort)encodedComment.Length), 0, 2);
this.ZipFileStream.Write(encodedComment, 0, encodedComment.Length);
}
// Copies all source file into storage file
private void Store(ref ZipFileEntry _zfe, Stream _source)
{
byte[] buffer = new byte[16384];
int bytesRead;
uint totalRead = 0;
Stream outStream;

long posStart = this.ZipFileStream.Position;
long sourceStart = _source.Position;

if (_zfe.Method == Compression.Store)
outStream = this.ZipFileStream;
else
outStream = new DeflateStream(this.ZipFileStream, CompressionMode.Compress, true);

_zfe.Crc32 = 0 ^ 0xffffffff;

do
{
bytesRead = _source.Read(buffer, 0, buffer.Length);
totalRead += (uint)bytesRead;
if (bytesRead > 0)
{
outStream.Write(buffer, 0, bytesRead);

for (uint i = 0; i < bytesRead; i++)
{
_zfe.Crc32 = ZipStorer.CrcTable[(_zfe.Crc32 ^ buffer[i]) & 0xFF] ^ (_zfe.Crc32 >> 8);
}
}
} while (bytesRead == buffer.Length);
outStream.Flush();

if (_zfe.Method == Compression.Deflate)
outStream.Dispose();

_zfe.Crc32 ^= 0xffffffff;
_zfe.FileSize = totalRead;
_zfe.CompressedSize = (uint)(this.ZipFileStream.Position - posStart);

// Verify for real compression
if (_zfe.Method == Compression.Deflate && !this.ForceDeflating && _source.CanSeek && _zfe.CompressedSize > _zfe.FileSize)
{
// Start operation again with Store algorithm
_zfe.Method = Compression.Store;
this.ZipFileStream.Position = posStart;
this.ZipFileStream.SetLength(posStart);
_source.Position = sourceStart;
this.Store(ref _zfe, _source);
}
}
/* DOS Date and time:
MS-DOS date. The date is a packed value with the following format. Bits Description
0-4 Day of the month (1–31)
5-8 Month (1 = January, 2 = February, and so on)
9-15 Year offset from 1980 (add 1980 to get actual year)
MS-DOS time. The time is a packed value with the following format. Bits Description
0-4 Second divided by 2
5-10 Minute (0–59)
11-15 Hour (0–23 on a 24-hour clock)
*/
private uint DateTimeToDosTime(DateTime _dt)
{
return (uint)(
(_dt.Second / 2) | (_dt.Minute << 5) | (_dt.Hour << 11) |
(_dt.Day << 16) | (_dt.Month << 21) | ((_dt.Year - 1980) << 25));
}
private DateTime DosTimeToDateTime(uint _dt)
{
return new DateTime(
(int)(_dt >> 25) + 1980,
(int)(_dt >> 21) & 15,
(int)(_dt >> 16) & 31,
(int)(_dt >> 11) & 31,
(int)(_dt >> 5) & 63,
(int)(_dt & 31) * 2);
}

/* CRC32 algorithm
The 'magic number' for the CRC is 0xdebb20e3.
The proper CRC pre and post conditioning
is used, meaning that the CRC register is
pre-conditioned with all ones (a starting value
of 0xffffffff) and the value is post-conditioned by
taking the one's complement of the CRC residual.
If bit 3 of the general purpose flag is set, this
field is set to zero in the local header and the correct
value is put in the data descriptor and in the central
directory.
*/
private void UpdateCrcAndSizes(ref ZipFileEntry _zfe)
{
long lastPos = this.ZipFileStream.Position; // remember position

this.ZipFileStream.Position = _zfe.HeaderOffset + 8;
this.ZipFileStream.Write(BitConverter.GetBytes((ushort)_zfe.Method), 0, 2); // zipping method

this.ZipFileStream.Position = _zfe.HeaderOffset + 14;
this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.Crc32), 0, 4); // Update CRC
this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.CompressedSize), 0, 4); // Compressed size
this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.FileSize), 0, 4); // Uncompressed size

this.ZipFileStream.Position = lastPos; // restore position
}
// Replaces backslashes with slashes to store in zip header
private string NormalizedFilename(string _filename)
{
string filename = _filename.Replace('\\', '/');

int pos = filename.IndexOf(':');
if (pos >= 0)
filename = filename.Remove(0, pos + 1);

return filename.Trim('/');
}
// Reads the end-of-central-directory record
private bool ReadFileInfo()
{
if (this.ZipFileStream.Length < 22)
return false;

try
{
this.ZipFileStream.Seek(-17, SeekOrigin.End);
BinaryReader br = new BinaryReader(this.ZipFileStream);
do
{
this.ZipFileStream.Seek(-5, SeekOrigin.Current);
UInt32 sig = br.ReadUInt32();
if (sig == 0x06054b50)
{
this.ZipFileStream.Seek(6, SeekOrigin.Current);

UInt16 entries = br.ReadUInt16();
Int32 centralSize = br.ReadInt32();
UInt32 centralDirOffset = br.ReadUInt32();
UInt16 commentSize = br.ReadUInt16();

// check if comment field is the very last data in file
if (this.ZipFileStream.Position + commentSize != this.ZipFileStream.Length)
return false;

// Copy entire central directory to a memory buffer
this.ExistingFiles = entries;
this.CentralDirImage = new byte[centralSize];
this.ZipFileStream.Seek(centralDirOffset, SeekOrigin.Begin);
this.ZipFileStream.Read(this.CentralDirImage, 0, centralSize);

// Leave the pointer at the begining of central dir, to append new files
this.ZipFileStream.Seek(centralDirOffset, SeekOrigin.Begin);
return true;
}
} while (this.ZipFileStream.Position > 0);
}
catch { }

return false;
}
#endregion

#region IDisposable Members
/// <summary>
/// Closes the Zip file stream
/// </summary>
public void Dispose()
{
this.Close();
}
#endregion
}
}

Laddar…
Avbryt
Spara