Latest build (version 2.2)

This commit is contained in:
2013-11-18 20:11:53 +02:00
parent 8954fd2635
commit 9c3b53d4a6
503 changed files with 186904 additions and 1139 deletions

58
Tarball/IOHelper.cs Normal file
View File

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Storage;
namespace Tarball
{
static class IOHelper
{
/// <summary>
/// Gets a folder using relative path.
/// </summary>
public static async Task<StorageFolder> GetFolderRelativeAsync(StorageFolder root, string path)
{
// Split the path
var splitpath = path.Split(new char[] { '\\', '/' }, StringSplitOptions.RemoveEmptyEntries);
var currentdir = root;
// Browse to the last folder in the path
for (int i = 0; i < splitpath.Length; i++)
currentdir = await currentdir.GetFolderAsync(splitpath[i]);
// Return file
return currentdir;
}
/// <summary>
/// Creates a folder using relative path.
/// </summary>
public static async Task<StorageFolder> CreateFolderRelativeAsync(StorageFolder root, string path)
{
// Split the path
var splitpath = path.Split(new char[] { '\\', '/' }, StringSplitOptions.RemoveEmptyEntries);
var currentdir = root;
// Browse to the last folder in the path
for (int i = 0; i < splitpath.Length - 1; i++)
currentdir = await currentdir.GetFolderAsync(splitpath[i]);
// Create folder
return await currentdir.CreateFolderAsync(splitpath.Last(), CreationCollisionOption.ReplaceExisting);
}
/// <summary>
/// Creates a file using a relative path.
/// </summary>
public static async Task<StorageFile> CreateFileRelativeAsync(StorageFolder root, string path)
{
var currentdir = await GetFolderRelativeAsync(root, System.IO.Path.GetDirectoryName(path));
// Create file
return await currentdir.CreateFileAsync(System.IO.Path.GetFileName(path), CreationCollisionOption.ReplaceExisting);
}
}
}

View File

@ -0,0 +1,29 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Tarball")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Tarball")]
[assembly: AssemblyCopyright("Copyright © 2013")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: ComVisible(false)]

122
Tarball/Tarball.csproj Normal file
View File

@ -0,0 +1,122 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{5CB567D7-572E-4BAE-802F-7E3F62CDDF64}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Tarball</RootNamespace>
<AssemblyName>Tarball</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{BC8A1FFA-BEE3-4634-8014-F334798102B3};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\ARM\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>ARM</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
<OutputPath>bin\ARM\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>ARM</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<!-- A reference to the entire .Net Framework and Windows SDK are automatically included -->
</ItemGroup>
<ItemGroup>
<Compile Include="IOHelper.cs" />
<Compile Include="TarballHeader.cs" />
<Compile Include="TarballReader.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TarballWriter.cs" />
</ItemGroup>
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '11.0' ">
<VisualStudioVersion>11.0</VisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

23
Tarball/TarballHeader.cs Normal file
View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Tarball
{
/// <summary>
/// Tarball header structure
/// </summary>
struct TarballHeader
{
public string FileName;
public uint FileMode;
public uint OwnerId, GroupId;
public long Size;
public DateTime LastModified;
public uint Checksum;
public byte LinkIndicator;
public string LinkedFile;
}
}

318
Tarball/TarballReader.cs Normal file
View File

@ -0,0 +1,318 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Windows.Storage;
namespace Tarball
{
public class TarballReader
{
#region Private attributes
private Stream stream;
private TarballHeader header;
#endregion
#region Constructor
/// <summary>
/// Creates a new instance of a tarball archive reader.
/// </summary>
public TarballReader()
{
stream = null;
header = new TarballHeader();
}
#endregion
#region Public functions (unpack)
/// <summary>
/// Unpacks a tarball in a temporary folder.
/// </summary>
/// <param name="file">An URI to the tarball file.</param>
/// <returns>Storage folder pointing to where the files were unpacked.</returns>
public async Task<StorageFolder> Unpack(Uri file)
{
var stfile = await StorageFile.GetFileFromApplicationUriAsync(file);
return await this.Unpack(stfile);
}
/// <summary>
/// Unpacks a tarball in a specified folder.
/// </summary>
/// <param name="file">An URI to the tarball file.</param>
/// <param name="destination">A folder where files will be unpacked.</param>
/// <returns>Storage folder pointing to where the files were unpacked.</returns>
public async Task<StorageFolder> Unpack(Uri file, StorageFolder destination)
{
var stfile = await StorageFile.GetFileFromApplicationUriAsync(file);
return await this.Unpack(stfile, destination);
}
/// <summary>
/// Unpacks a tarball in a temporary folder.
/// </summary>
/// <param name="file">A path to the tarball file.</param>
/// <returns>Storage folder pointing to where the files were unpacked.</returns>
public async Task<StorageFolder> Unpack(string file)
{
var stfile = await StorageFile.GetFileFromPathAsync(file);
return await this.Unpack(stfile);
}
/// <summary>
/// Unpacks a tarball in a specified folder.
/// </summary>
/// <param name="file">A path to the tarball file.</param>
/// <param name="destination">A folder where files will be unpacked.</param>
/// <returns>Storage folder pointing to where the files were unpacked.</returns>
public async Task<StorageFolder> Unpack(string file, StorageFolder destination)
{
var stfile = await StorageFile.GetFileFromPathAsync(file);
return await this.Unpack(stfile, destination);
}
/// <summary>
/// Unpacks a tarball in a temporary folder.
/// </summary>
/// <param name="file">The tarball file.</param>
/// <returns>Storage folder pointing to where the files were unpacked.</returns>
public async Task<StorageFolder> Unpack(StorageFile file)
{
// Prepare temp folder
var dest = await this.CreateTempFolder();
// Unpack
await this.Initialize(file);
await this.UnpackFiles(dest);
this.Dispose();
// Results
return dest;
}
/// <summary>
/// Unpacks a tarball in a specified folder.
/// </summary>
/// <param name="file">The tarball file.</param>
/// <param name="destination">A folder where files will be unpacked.</param>
/// <returns>Storage folder pointing to where the files were unpacked.</returns>
public async Task<StorageFolder> Unpack(StorageFile file, StorageFolder destination)
{
// Unpack
await this.Initialize(file);
await this.UnpackFiles(destination);
this.Dispose();
// Results
return destination;
}
#endregion
#region Initialize, dispose
/// <summary>
/// Performs initialization actions before unpacking (such as opening the stream).
/// </summary>
private async Task Initialize(StorageFile file)
{
var str = await file.OpenReadAsync();
this.stream = str.AsStream();
}
/// <summary>
/// Performs cleanups after unpacking finished.
/// </summary>
private void Dispose()
{
// Clean up
this.stream.Dispose();
this.stream = null;
this.header = new TarballHeader();
}
#endregion
#region Headers
/// <summary>
/// Calculates the checksum from a header.
/// </summary>
/// <param name="buffer">The header bytes</param>
private uint CalculateChecksum(byte[] buffer)
{
uint result = 0;
// Calculate sum of all bytes, with the exception of bytes 148-155
// (checksum field). These are all assumed to be 0x20.
for (int i = 0; i < buffer.Length; i++)
if (i >= 148 && i < 156)
result += 0x20;
else result += Convert.ToUInt32(buffer[i]);
// Done
return result;
}
/// <summary>
/// Converts binary data to a TarballHeader.
/// </summary>
private TarballHeader ParseHeaderFields(byte[] buffer)
{
TarballHeader header = new TarballHeader();
string temp;
// File name
temp = UTF8Encoding.UTF8.GetString(buffer, 0, 100).Trim('\0', ' ');
header.FileName = temp;
// File mode
temp = UTF8Encoding.UTF8.GetString(buffer, 100, 8).Trim('\0', ' ');
header.FileMode = (string.IsNullOrEmpty(temp)) ? 0 : Convert.ToUInt32(temp, 8);
// Owner id
temp = UTF8Encoding.UTF8.GetString(buffer, 108, 8).Trim('\0', ' ');
header.OwnerId = (string.IsNullOrEmpty(temp)) ? 0 : Convert.ToUInt32(temp, 8);
// Group id
temp = UTF8Encoding.UTF8.GetString(buffer, 116, 8).Trim('\0', ' ');
header.GroupId = (string.IsNullOrEmpty(temp)) ? 0 : Convert.ToUInt32(temp, 8);
// Size
temp = UTF8Encoding.UTF8.GetString(buffer, 124, 12).Trim('\0', ' ');
header.Size = (string.IsNullOrEmpty(temp)) ? 0 : Convert.ToInt64(temp, 8);
// Last modified date
temp = UTF8Encoding.UTF8.GetString(buffer, 136, 12).Trim('\0', ' ');
long seconds = (string.IsNullOrEmpty(temp)) ? 0 : Convert.ToInt64(temp, 8);
header.LastModified = new DateTime(1970, 1, 1, 0, 0, 0, 0).AddSeconds(seconds).ToLocalTime();
// Checksum
temp = UTF8Encoding.UTF8.GetString(buffer, 148, 8).Trim('\0', ' ');
header.Checksum = (string.IsNullOrEmpty(temp)) ? 0 : Convert.ToUInt32(temp, 8);
// Link indicator
header.LinkIndicator = buffer[156];
// Linked file
temp = UTF8Encoding.UTF8.GetString(buffer, 157, 100).Trim('\0', ' ');
header.LinkedFile = temp;
// Done
return header;
}
/// <summary>
/// Reads a file header.
/// </summary>
/// <returns>True if another header was read, false otherwise.</returns>
private async Task<bool> ReadNextFileHeader()
{
byte[] buffer = new byte[512];
// Check current position
if (stream.Position >= stream.Length)
return false;
// Read header
await stream.ReadAsync(buffer, 0, 512);
// Parse header fields
try
{
this.header = this.ParseHeaderFields(buffer);
}
catch (Exception)
{
throw new IOException("Invalid tarball header!");
}
// Verify checksum
uint checksum = this.CalculateChecksum(buffer);
if (checksum == 256) // If 256 (only the checksum bytes different than 0), then
return false; // we most likely hit an invalid entry, probably marking the
// end of the file
if (checksum != header.Checksum)
throw new IOException("Invalid tarball checksum!");
// Done
return true;
}
#endregion
#region File system helpers
/// <summary>
/// Creates a temporary folder.
/// </summary>
private async Task<StorageFolder> CreateTempFolder()
{
// Generate file name
string name = "tar" + DateTime.Now.Ticks.ToString();
// Create file
var temp = ApplicationData.Current.TemporaryFolder;
return await temp.CreateFolderAsync(name, CreationCollisionOption.GenerateUniqueName);
}
#endregion
#region Unpack
/// <summary>
/// Unpacks a file using the information from the header.
/// The function assumes the header was previously read.
/// </summary>
/// <param name="destination">The destination file.</param>
private async Task UnpackNextFile(StorageFile destination)
{
// Open destination file
var str = await destination.OpenAsync(FileAccessMode.ReadWrite);
var iostr = str.AsStream();
// Write data
var buffer = new byte[512];
int read = 0, total = 0;
while (total < this.header.Size)
{
read = await this.stream.ReadAsync(buffer, 0, 512);
await iostr.WriteAsync(buffer, 0, Math.Min(read, Convert.ToInt32(this.header.Size) - total));
total += read;
}
// Cleanup
await iostr.FlushAsync();
iostr.Dispose();
}
/// <summary>
/// Unpacks the files from the loaded tarball.
/// </summary>
/// <param name="destination">Destination folder.</param>
private async Task UnpackFiles(StorageFolder destination)
{
if (this.stream == null)
throw new ArgumentNullException("No file opened!");
while (await this.ReadNextFileHeader())
{
// Directory?
if (this.header.FileName.EndsWith("/"))
await IOHelper.CreateFolderRelativeAsync(destination, this.header.FileName);
// Create file
else
{
var file = await IOHelper.CreateFileRelativeAsync(destination, this.header.FileName);
await this.UnpackNextFile(file);
}
}
}
#endregion
}
}

345
Tarball/TarballWriter.cs Normal file
View File

@ -0,0 +1,345 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Windows.Storage;
namespace Tarball
{
public class TarballWriter
{
#region Private members
private List<IStorageItem> items;
private System.IO.Stream stream;
#endregion
#region Constructor
/// <summary>
/// Creates a new instance of tarball writer
/// </summary>
public TarballWriter()
{
this.items = new List<IStorageItem>();
this.stream = null;
}
#endregion
#region Public methods
/// <summary>
/// Adds an item to the list to be packed.
/// </summary>
public void AddItem(IStorageItem item)
{
this.items.Add(item);
}
/// <summary>
/// Adds a list of items to the list to be packed
/// </summary>
public void AddItems(IEnumerable<IStorageItem> items)
{
this.items.AddRange(items);
}
/// <summary>
/// Packs the added items into the destination file.
/// </summary>
/// <param name="destination_file_path">The path of the tarball which will be created.</param>
public async Task Pack(string destination_file_path)
{
// Initialize
await this.InitializeDestFilename(destination_file_path);
// Write file
await this.Write();
// Cleanup
await this.Dispose();
}
/// <summary>
/// Packs the added items into the destination file.
/// </summary>
/// <param name="destination">The destination StorageFile where the tarball will be written.</param>
public async Task Pack(StorageFile destination)
{
// Initialize
await this.InitializeDestStoragefile(destination);
// Write file
await this.Write();
// Cleanup
await this.Dispose();
}
/// <summary>
/// Packs the added items into the destination stream.
/// </summary>
/// <param name="destination">The destination stream where the tarball will be written.</param>
public async Task Pack(System.IO.Stream destination)
{
// Initialize
this.stream = destination;
// Write file
await this.Write();
// Cleanup
await this.Dispose();
}
#endregion
#region Initialization
/// <summary>
/// Prepares for writing: creates and opens the destination file from path.
/// </summary>
private async Task InitializeDestFilename(string destfile)
{
// Get file and folder name from path
string folder_path = Path.GetDirectoryName(destfile);
string file_name = Path.GetFileName(destfile);
// Create file
StorageFolder folder = await StorageFolder.GetFolderFromPathAsync(folder_path);
StorageFile file = await folder.CreateFileAsync(file_name, CreationCollisionOption.GenerateUniqueName);
// Continue initialization
await this.InitializeDestStoragefile(file);
}
/// <summary>
/// Prepares for writing: opens the destination file.
/// </summary>
private async Task InitializeDestStoragefile(StorageFile file)
{
// Open destination file
var stream = await file.OpenAsync(FileAccessMode.ReadWrite);
var iostream = stream.AsStream();
// Set up stream
this.stream = iostream;
}
#endregion
#region Cleanup
/// <summary>
/// Disposes resources, flushes and closes the stream.
/// </summary>
/// <returns></returns>
private async Task Dispose()
{
// Close the file
await this.stream.FlushAsync();
this.stream.Dispose();
// Finish this
this.stream = null;
}
#endregion
#region Write
/// <summary>
/// Writes all the added items, and the final null headers.
/// </summary>
private async Task Write()
{
// Write every item in the list
foreach (var i in this.items)
await WriteItemsRecursively(i, "");
// Write 2 empty entries
await WriteItemsRecursively(null, "");
await WriteItemsRecursively(null, "");
}
/// <summary>
/// Writes a storage item, and if it is a folder writes those files recursively.
/// </summary>
/// <param name="root">The current (root) item</param>
/// <param name="path">The path to the current (root) item</param>
private async Task WriteItemsRecursively(IStorageItem root, string path)
{
// Write this item
await this.WriteItem(root, path);
// Directory?
if (root != null && root.IsOfType(StorageItemTypes.Folder))
{
// Read and write children
StorageFolder folder = root as StorageFolder;
var items = await folder.GetItemsAsync();
foreach (var i in items)
await this.WriteItemsRecursively(i, path + folder.Name + "/");
}
}
/// <summary>
/// Writes an item (header and bytes) to the file.
/// </summary>
/// <param name="item">The item to be written.</param>
/// <param name="path">Path of the file.</param>
private async Task WriteItem(IStorageItem item, string path)
{
// Initial stream
Stream iostr = null;
// If it is a file, open the stream and get correct size.
if (item != null && item.IsOfType(StorageItemTypes.File))
{
var file = item as StorageFile;
var stream = await file.OpenReadAsync();
iostr = stream.AsStream();
await WriteItemHeader(item, path, iostr.Length);
}
// Not a file, just write the header with size 0.
else await WriteItemHeader(item, path, 0);
// If possible, write bytes
if (iostr != null)
await WriteItemBytes(iostr);
}
/// <summary>
/// Writes the header information for an item.
/// </summary>
/// <param name="item">The storage item.</param>
/// <param name="path">The path to the storage item.</param>
/// <param name="size">The size of the storage item (0 for folders).</param>
private async Task WriteItemHeader(IStorageItem item, string path, long size)
{
// Create header
byte[] header = new byte[512];
// Special null item => empty header
if (item == null) {
await this.stream.WriteAsync(header, 0, 512);
return;
}
// Is it a directory?
bool isDir = item.IsOfType(StorageItemTypes.Folder);
// File name
StringToBytes(this.HeaderCalculatePath(item.Name, path, isDir), header, 0, 100);
// File mode
if (isDir) StringToBytes("40777", header, 100, 8);
else StringToBytes("777", header, 100, 8);
// Owner and group ids
StringToBytes("0", header, 108, 8);
StringToBytes("0", header, 116, 8);
// Write size
StringToBytes(Convert.ToString(size, 8), header, 124, 12);
// Write last modification date
StringToBytes(this.HeaderDatetimeToUnix(item), header, 136, 12);
// Write temporary checksum
for (int i = 148; i < 156; i++)
header[i] = 0x20;
// Write link indicator
StringToBytes("", header, 156, 101);
// Checksum
this.HeaderChecksum(header);
// And (finally) WRITE
await this.stream.WriteAsync(header, 0, 512);
}
/// <summary>
/// Writes the data of the storage item. The file must be opened, and stream passed as parameter.
/// </summary>
private async Task WriteItemBytes(Stream stream)
{
// Create buffer
byte[] buffer = new byte[512];
// Read & write bytes
while (stream.Position < stream.Length)
{
int read = await stream.ReadAsync(buffer, 0, 512);
for (; read < 512; read++)
buffer[read] = 0;
await this.stream.WriteAsync(buffer, 0, 512);
}
}
#endregion
#region Misc
/// <summary>
/// Converts a string to null terminated UTF8 byte array. Padded with spaces.
/// </summary>
private void StringToBytes(string source, byte[] array, int index, int size)
{
byte[] bytes = UTF8Encoding.UTF8.GetBytes(source);
for (int i = 0; i < size; i++)
if (i < bytes.Length)
array[index + i] = bytes[i];
else array[index + i] = 0;
}
/// <summary>
/// Obtains the path of the file from given information.
/// </summary>
/// <param name="name">The name of the item.</param>
/// <param name="path">The path to the item.</param>
/// <param name="isDir">True if the item is a directory.</param>
/// <returns>A strign with combined path.</returns>
private string HeaderCalculatePath(string name, string path, bool isDir)
{
string temp1 = path + name;
string temp2 = temp1.Replace('\\', '/');
if (isDir && !temp2.EndsWith("/"))
return temp2 + "/";
return temp2;
}
/// <summary>
/// Converts the created date time to unix time, and returns the string representation in octal.
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
private string HeaderDatetimeToUnix(IStorageItem item)
{
DateTime created = item.DateCreated.UtcDateTime;
TimeSpan unix_span = created - new DateTime(1970, 1, 1, 0, 0, 0, 0);
double seconds_d = Math.Truncate(unix_span.TotalSeconds);
long seconds_l = Convert.ToInt64(seconds_d);
return Convert.ToString(seconds_l, 8);
}
/// <summary>
/// Calculates the header checksum, and writes it in the byte array.
/// </summary>
private void HeaderChecksum(byte[] bytes)
{
// Calculate checksum
long checksum = 0;
foreach (var i in bytes)
checksum += Convert.ToInt64(i);
// Write checksum
StringToBytes(Convert.ToString(checksum, 8), bytes, 148, 8);
}
#endregion
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

View File

@ -0,0 +1,10 @@
F:\Dev\Windows8\DrumKit\Tarball\bin\Debug\Tarball.dll
F:\Dev\Windows8\DrumKit\Tarball\bin\Debug\Tarball.pdb
F:\Dev\Windows8\DrumKit\Tarball\bin\Debug\Tarball.pri
F:\Dev\Windows8\DrumKit\Tarball\obj\Debug\Tarball.dll
F:\Dev\Windows8\DrumKit\Tarball\obj\Debug\Tarball.pdb
F:\Dev\Windows8\DrumKit\Tarball\obj\Debug\priconfig.xml
F:\Dev\Windows8\DrumKit\Tarball\obj\Debug\layout.resfiles
F:\Dev\Windows8\DrumKit\Tarball\obj\Debug\resources.resfiles
F:\Dev\Windows8\DrumKit\Tarball\obj\Debug\pri.resfiles
F:\Dev\Windows8\DrumKit\Tarball\obj\Debug\LanguageQualifiers.txt

Binary file not shown.

Binary file not shown.

View File

View File

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<index root="\" startIndexAt="obj\Debug\layout.resfiles">
<default>
<qualifier name="language" value="en-US" />
</default>
<indexer-config type="RESFILES" qualifierDelimiter="." />
</index>
<index root="\" startIndexAt="obj\Debug\resources.resfiles">
<default>
<qualifier name="language" value="en-US" />
</default>
<indexer-config type="RESW" convertDotsToSlashes="true" initialPath="Tarball" />
<indexer-config type="RESJSON" initialPath="Tarball" />
<indexer-config type="RESFILES" qualifierDelimiter="." />
</index>
<index root="\" startIndexAt="obj\Debug\pri.resfiles">
<default>
<qualifier name="language" value="en-US" />
</default>
<indexer-config type="PRI" />
<indexer-config type="RESFILES" qualifierDelimiter="." />
</index>
</resources>

View File

View File

@ -0,0 +1,10 @@
F:\Dev\Windows8\DrumKit\Tarball\bin\Release\Tarball.dll
F:\Dev\Windows8\DrumKit\Tarball\bin\Release\Tarball.pdb
F:\Dev\Windows8\DrumKit\Tarball\bin\Release\Tarball.pri
F:\Dev\Windows8\DrumKit\Tarball\obj\Release\Tarball.dll
F:\Dev\Windows8\DrumKit\Tarball\obj\Release\Tarball.pdb
F:\Dev\Windows8\DrumKit\Tarball\obj\Release\priconfig.xml
F:\Dev\Windows8\DrumKit\Tarball\obj\Release\layout.resfiles
F:\Dev\Windows8\DrumKit\Tarball\obj\Release\resources.resfiles
F:\Dev\Windows8\DrumKit\Tarball\obj\Release\pri.resfiles
F:\Dev\Windows8\DrumKit\Tarball\obj\Release\LanguageQualifiers.txt

Binary file not shown.

Binary file not shown.

View File

View File

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<index root="\" startIndexAt="obj\Release\layout.resfiles">
<default>
<qualifier name="language" value="en-US" />
</default>
<indexer-config type="RESFILES" qualifierDelimiter="." />
</index>
<index root="\" startIndexAt="obj\Release\resources.resfiles">
<default>
<qualifier name="language" value="en-US" />
</default>
<indexer-config type="RESW" convertDotsToSlashes="true" initialPath="Tarball" />
<indexer-config type="RESJSON" initialPath="Tarball" />
<indexer-config type="RESFILES" qualifierDelimiter="." />
</index>
<index root="\" startIndexAt="obj\Release\pri.resfiles">
<default>
<qualifier name="language" value="en-US" />
</default>
<indexer-config type="PRI" />
<indexer-config type="RESFILES" qualifierDelimiter="." />
</index>
</resources>

View File