This splitter has been built because I didn't find a decent one in 5 minutes search. The reason behind a splitter is simple: Send files as an attachment (in my case using the gmail & gspace).
As for the code, I'm posting the full program here, and some highlights afterwards.
using System;
using System.Collections.Generic;
using System.Text;
namespace FileSplitter
{
class Program
{
const int DefalutBlockSize = 1000000;
private static byte[] STAMP = { 1, 2, 3 };
private static byte[] GetMD5(byte[] buf)
{
System.Security.Cryptography.MD5CryptoServiceProvider md = new System.Security.Cryptography.MD5CryptoServiceProvider();
md.Initialize();
return md.ComputeHash(buf);
}
private static void Split(string Filename, int BlockSize)
{
try
{
Console.WriteLine("Splitting " + Filename + " to " + BlockSize.ToString() + " bytes parts");
int part = 0;
byte[] buf;
System.IO.StreamReader in_fl = new System.IO.StreamReader(Filename);
System.IO.BinaryReader in_b = new System.IO.BinaryReader(in_fl.BaseStream);
while (true)
{
Console.WriteLine("Reading part " + part.ToString());
buf = in_b.ReadBytes(BlockSize);
if (buf.Length == 0)
{
in_b.Close();
Console.WriteLine("No more parts");
return;
}
Console.WriteLine("Writing part " + part.ToString());
System.IO.StreamWriter out_fl = new System.IO.StreamWriter(Filename + "." + part.ToString());
System.IO.BinaryWriter out_b = new System.IO.BinaryWriter(out_fl.BaseStream);
out_b.Write(STAMP);
byte[] MD = GetMD5(buf);
byte len = System.Convert.ToByte(MD.Length);
out_b.Write(len);
out_b.Write(MD);
out_b.Write(buf);
out_b.Flush();
out_b.Close();
part++;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
private static void Merge(string Filename)
{
try
{
Console.WriteLine("Merging " + Filename);
int part = 0;
byte[] buf;
System.IO.StreamWriter out_fl = new System.IO.StreamWriter(Filename);
System.IO.BinaryWriter out_b = new System.IO.BinaryWriter(out_fl.BaseStream);
while (System.IO.File.Exists(Filename + "." + part.ToString()))
{
Console.WriteLine("Reading part " + part.ToString());
System.IO.StreamReader in_fl = new System.IO.StreamReader(Filename + "." + part.ToString());
System.IO.BinaryReader in_b = new System.IO.BinaryReader(in_fl.BaseStream);
buf = in_b.ReadBytes(STAMP.Length);
for (int i = 0; i < STAMP.Length; i++)
{
if (buf[i] != STAMP[i])
{
Console.WriteLine("Incorrect STAMP!");
Environment.Exit(2);
}
}
byte len = in_b.ReadByte();
byte[] file_MD = in_b.ReadBytes(System.Convert.ToInt32(System.Convert.ToInt32(len)));
buf = in_b.ReadBytes(System.Convert.ToInt32(in_b.BaseStream.Length));
byte[] calc_MD = GetMD5(buf);
for (int i = 0; i < calc_MD.Length; i++)
{
if (file_MD[i] != calc_MD[i])
{
Console.WriteLine("Incorrect HASH!");
Environment.Exit(3);
}
}
out_b.Write(buf);
out_b.Flush();
Console.WriteLine("Wrote part " + part.ToString());
part++;
}
out_b.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
private static void ShowUsage()
{
Console.WriteLine("Usage: FileSplitter.exe -Filename <filename> [-blocksize <size>] [-stamp <file stamp>] {-split | -merge}");
Console.WriteLine("filename - the original filename");
Console.WriteLine("size - the size of the splitted parts");
Console.WriteLine("stamp - the header of the splitted parts");
Console.WriteLine("Parameters can be used more than once in the string, each split/merge is ran with the \"current\" values");
}
static void Main(string[] args)
{
Console.WriteLine("File splitting / merging utility by Liron");
Console.WriteLine("This utility is available as is.\r\n");
string Filename = "";
int BlockSize = DefalutBlockSize;
for (int i = 0; i < args.Length; i++)
{
switch (args[i].ToLower())
{
case "-stamp":
i++;
STAMP = new byte[args[i].Length];
for (int j = 0; j < args[i].Length; j++)
{
STAMP[j] = System.Convert.ToByte(args[i][j]);
}
break;
case "-filename":
i++;
Filename = args[i];
break;
case "-blocksize":
i++;
BlockSize = System.Convert.ToInt32(args[i]);
break;
case "-split":
Split(Filename, BlockSize);
break;
case "-merge":
Merge(Filename);
break;
case "-h":
ShowUsage();
Environment.Exit(0);
break;
default:
ShowUsage();
Environment.Exit(255);
break;
}
}
}
}
}
Some highlights
Note the way the HASH is added. The resulting file is in the following structure:
[STAMP][HASH length][HASH][Original part]
This structure allows an easy reconnection of the parts, plus a check for errors.
Another thing related to the structure is the fact that the resulting size would be BLOCKSIZE + HEADERSIZE which is slightly beigger than the intended size. It can be fixed quite easily by reading BLOCKSIZE - HEADERSIZE bytes instead of BLOCKSIZE bytes. I didn't need it so I left it out.
The most important note: This code has the minimal checks, if you want to use it, you'll need to add some checks (users can do many strange things if there's no check)
Wednesday, February 13, 2008
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment