g3gg0 avatar g3gg0 committed fe1ab5e

added some tools that might be useful

Comments (0)

Files changed (42)

contrib/g3gg0-tools/EOSMovieFixer/AtomParser.cs

+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using EOSMovieFixer.Atoms;
+using System.Collections;
+
+namespace EOSMovieFixer
+{
+    public class AtomParser
+    {
+        public string[] ContainerTypes = { "moov", "trak", "mdia", "minf", "stbl", "skip" };
+        public string[] AtomTypes = { "cmov", "cmvd", "co64", "ctts", "dcom", "edts", "elst", "esds", "fiel", "free", "ftyp", "gmhd", "hdlr", "iods", "junk", "mdat", "mdhd", "mdia", "minf", "moov", "mvhd", "pict", "pnot", "rdrf", "rmcd", "rmcs", "rmda", "rmdr", "rmqu", "rmra", "rmvc", "skip", "smhd", "stbl", "stco", "stsc", "stsd", "stss", "stsz", "stts", "tkhd", "trak", "uuid", "vmhd", "wide", "wfex" };
+
+        public ArrayList ParseFile(InputFile file)
+        {
+            ArrayList atoms = new ArrayList();
+            UInt64 position = 0;
+
+            while (position < file.Length)
+            {
+                string type = GetAtomType(file, position);
+                Atom atom = null;
+
+                if (IsContainer(type))
+                {
+                    atom = new ContainerAtom(type);
+                    ParseContainer(file, position, (ContainerAtom)atom);
+                }
+                else if (IsAtom(type))
+                {
+                    atom = new LeafAtom(type);
+                    ParseAtom(file, position, atom);
+                }
+                else
+                {
+                    throw new Exception("Invalid atom at pos 0x" + position.ToString("X16"));
+                }
+
+                atoms.Add(atom);
+                position += atom.TotalLength;
+            }
+
+            return atoms;
+        }
+
+        private bool IsAtom(string type)
+        {
+            return AtomTypes.Contains<string>(type);
+        }
+
+        private bool IsContainer(string type)
+        {
+            return ContainerTypes.Contains<string>(type);
+        }
+
+        private void ParseAtom(InputFile file, ulong position, Atom atom)
+        {
+            file.Seek(position);
+            UInt64 length = file.ReadUInt32(position);
+
+            if (length == 0)
+            {
+                atom.TotalLength = file.Length - position;
+                atom.HeaderLength = 8;
+            }
+            else if (length == 1)
+            {
+                atom.TotalLength = file.ReadUInt64(position + 8);
+                atom.HeaderLength = 16;
+            }
+            else
+            {
+                atom.TotalLength = length;
+                atom.HeaderLength = 8;
+            }
+
+            if (atom.Type == "mdat")
+            {
+                if (!IsAtom(GetAtomType(file, position + atom.TotalLength)))
+                {
+                    EOSMovieFixer.Log("      Buggy [mdat] section (32 bit overflow detected)...");
+                    EOSMovieFixer.Log("        Probing [mdat] end...");
+
+                    /* try to find end of mdat by probing next atom */
+                    EOSMovieFixer.Log("        length 0x" + atom.TotalLength.ToString("X16"));
+                    while (!IsAtom(GetAtomType(file, position + atom.TotalLength)) && ((position + atom.TotalLength) < file.Length))
+                    {
+                        atom.TotalLength += 0x0100000000;
+                        EOSMovieFixer.Log("        length 0x" + atom.TotalLength.ToString("X16"));
+                    }
+
+                    if (!IsAtom(GetAtomType(file, position + atom.TotalLength)))
+                    {
+                        throw new Exception("Could not find 'mdat' end");
+                    }
+                    else
+                    {
+                        EOSMovieFixer.Log("      Real atom end found successfully");
+                    }
+                }
+            }
+
+            atom.HeaderFileOffset = position;
+
+            /* save original length for rewriting purposes */
+            atom.OriginalPayloadLength = atom.PayloadLength;
+            atom.OriginalPayloadFileOffset = atom.PayloadFileOffset;
+
+            atom.ParsePayload(file, position);
+        }
+
+        private void ParseContainer(InputFile file, ulong position, ContainerAtom container)
+        {
+            ParseAtom(file, position, container); 
+            
+            ArrayList atoms = new ArrayList();
+            UInt64 offset = container.HeaderLength;
+
+            while (offset < container.TotalLength)
+            {
+                string type = GetAtomType(file, position + offset);
+                Atom atom = null;
+
+                if (IsContainer(type))
+                {
+                    atom = new ContainerAtom(type);
+                    ParseContainer(file, position + offset, (ContainerAtom)atom);
+                }
+                else
+                {
+                    atom = new LeafAtom(type);
+                    ParseAtom(file, position + offset, atom);
+                }
+
+                container.Children.Add(atom);
+                offset += atom.TotalLength;
+            }
+        }
+
+        private string GetAtomType(InputFile file, ulong position)
+        {
+            string type = "";
+            byte[] buffer = new byte[4];
+
+            file.ReadBytes(position + 4, buffer, 4);
+
+            for (int pos = 0; pos < 4; pos++)
+            {
+                type += (char)buffer[pos];
+            }
+
+            return type;
+        }
+    }
+}

contrib/g3gg0-tools/EOSMovieFixer/AtomWriter.cs

+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Collections;
+using EOSMovieFixer.Atoms;
+
+namespace EOSMovieFixer
+{
+    public class AtomWriter
+    {
+        public AtomWriter()
+        {
+        }
+
+        public void SaveFile(InputFile inFile, OutputFile outFile, ArrayList atoms)
+        {
+            foreach (var obj in atoms)
+            {
+                if (obj is ContainerAtom)
+                {
+                    SaveContainer(inFile, outFile, (ContainerAtom)obj);
+                }
+                else
+                {
+                    SaveAtom(inFile, outFile, (LeafAtom)obj);
+                }
+            }
+        }
+
+        private void SaveContainer(InputFile inFile, OutputFile outFile, ContainerAtom container)
+        {
+            if (container.HeaderLength == 8)
+            {
+                outFile.WriteUInt32((UInt32)container.TotalLength);
+                outFile.WriteChars(container.Type.ToCharArray());
+            }
+            else
+            {
+                outFile.WriteUInt32(1);
+                outFile.WriteChars(container.Type.ToCharArray());
+                outFile.WriteUInt64(container.TotalLength);
+            }
+
+            foreach (var obj in container.Children)
+            {
+                if (obj is ContainerAtom)
+                {
+                    SaveContainer(inFile, outFile, (ContainerAtom)obj);
+                }
+                else
+                {
+                    SaveAtom(inFile, outFile, (LeafAtom)obj);
+                }
+            }
+        }
+
+        private void SaveAtom(InputFile inFile, OutputFile outFile, LeafAtom leaf)
+        {
+            if (leaf.HeaderLength == 8)
+            {
+                outFile.WriteUInt32((UInt32)leaf.TotalLength);
+                outFile.WriteChars(leaf.Type.ToCharArray());
+            }
+            else
+            {
+                outFile.WriteUInt32(1);
+                outFile.WriteChars(leaf.Type.ToCharArray());
+                outFile.WriteUInt64(leaf.TotalLength);
+            }
+
+            if (leaf.PayloadData != null)
+            {
+                outFile.WriteBytes(leaf.PayloadData);
+            }
+            else
+            {
+                if (leaf.OriginalPayloadFileOffset > 0)
+                {
+                    outFile.WriteFromInput(inFile, leaf.OriginalPayloadFileOffset, leaf.PayloadLength);
+                }
+                else
+                {
+                    outFile.WriteFromInput(inFile, leaf.PayloadFileOffset, leaf.PayloadLength);
+                }
+            }
+        }
+    }
+}

contrib/g3gg0-tools/EOSMovieFixer/Atoms/Atom.cs

+using System;
+using System.Text;
+
+namespace EOSMovieFixer.Atoms
+{
+    public class Atom
+    {
+        public UInt64 TotalLength = 0;
+        public UInt64 HeaderLength = 0;
+        public UInt64 OriginalPayloadLength = 0;
+        public UInt64 OriginalPayloadFileOffset = 0;
+        
+        public UInt64 PayloadLength
+        {
+            get
+            {
+                return TotalLength - HeaderLength;
+            }
+        }
+
+        public string Type = "";
+        public UInt64 HeaderFileOffset = 0;
+        public UInt64 PayloadFileOffset
+        {
+            get
+            {
+                return HeaderFileOffset + HeaderLength;
+            }
+        }
+        public byte[] PayloadData = null;
+
+        public Atom()
+        {
+        }
+
+        public Atom(string type)
+        {
+            Type = type;
+        }
+
+        public override string ToString()
+        {
+            return Type + " L:" + TotalLength.ToString("X16") + " O:" + HeaderFileOffset.ToString("X16");
+        }
+
+        public virtual void ParsePayload(InputFile file, ulong position)
+        {
+        }
+    }
+}

contrib/g3gg0-tools/EOSMovieFixer/Atoms/ContainerAtom.cs

+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Collections;
+
+namespace EOSMovieFixer.Atoms
+{
+    public class ContainerAtom : Atom
+    {
+        public ArrayList Children = new ArrayList();
+
+        public ContainerAtom()
+        {
+        }
+
+        public ContainerAtom(string type)
+        {
+            Type = type;
+        }
+
+        public override void ParsePayload(InputFile file, ulong position)
+        {
+            /* must not do anything */
+        }
+    }
+}

contrib/g3gg0-tools/EOSMovieFixer/Atoms/LeafAtom.cs

+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace EOSMovieFixer.Atoms
+{
+    public class LeafAtom : Atom
+    {
+        public LeafAtom()
+        {
+        }
+        public LeafAtom(string type)
+        {
+            Type = type;
+        }
+
+        public override void ParsePayload(InputFile file, ulong position)
+        {
+            base.ParsePayload(file, position);
+        }
+    }
+}

contrib/g3gg0-tools/EOSMovieFixer/EOSMovieFixer.Designer.cs

+namespace EOSMovieFixer
+{
+    partial class EOSMovieFixer
+    {
+        /// <summary>
+        /// Erforderliche Designervariable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Verwendete Ressourcen bereinigen.
+        /// </summary>
+        /// <param name="disposing">True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Vom Windows Form-Designer generierter Code
+
+        /// <summary>
+        /// Erforderliche Methode für die Designerunterstützung.
+        /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(EOSMovieFixer));
+            this.btnLoad = new System.Windows.Forms.Button();
+            this.treeStructure = new System.Windows.Forms.TreeView();
+            this.txtLog = new System.Windows.Forms.TextBox();
+            this.btnPatch = new System.Windows.Forms.Button();
+            this.btnSave = new System.Windows.Forms.Button();
+            this.groupBox1 = new System.Windows.Forms.GroupBox();
+            this.splitContainer1 = new System.Windows.Forms.SplitContainer();
+            this.splitContainer2 = new System.Windows.Forms.SplitContainer();
+            this.label1 = new System.Windows.Forms.Label();
+            this.groupBox1.SuspendLayout();
+            this.splitContainer1.Panel1.SuspendLayout();
+            this.splitContainer1.Panel2.SuspendLayout();
+            this.splitContainer1.SuspendLayout();
+            this.splitContainer2.Panel1.SuspendLayout();
+            this.splitContainer2.Panel2.SuspendLayout();
+            this.splitContainer2.SuspendLayout();
+            this.SuspendLayout();
+            // 
+            // btnLoad
+            // 
+            this.btnLoad.Location = new System.Drawing.Point(15, 19);
+            this.btnLoad.Name = "btnLoad";
+            this.btnLoad.Size = new System.Drawing.Size(81, 23);
+            this.btnLoad.TabIndex = 0;
+            this.btnLoad.Text = "Load File...";
+            this.btnLoad.UseVisualStyleBackColor = true;
+            this.btnLoad.Click += new System.EventHandler(this.btnLoad_Click);
+            // 
+            // treeStructure
+            // 
+            this.treeStructure.Dock = System.Windows.Forms.DockStyle.Fill;
+            this.treeStructure.Font = new System.Drawing.Font("Courier New", 7F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.treeStructure.Location = new System.Drawing.Point(0, 0);
+            this.treeStructure.Name = "treeStructure";
+            this.treeStructure.Size = new System.Drawing.Size(250, 553);
+            this.treeStructure.TabIndex = 1;
+            // 
+            // txtLog
+            // 
+            this.txtLog.Dock = System.Windows.Forms.DockStyle.Fill;
+            this.txtLog.Font = new System.Drawing.Font("Courier New", 7F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.txtLog.Location = new System.Drawing.Point(0, 0);
+            this.txtLog.Multiline = true;
+            this.txtLog.Name = "txtLog";
+            this.txtLog.ScrollBars = System.Windows.Forms.ScrollBars.Both;
+            this.txtLog.Size = new System.Drawing.Size(488, 553);
+            this.txtLog.TabIndex = 2;
+            // 
+            // btnPatch
+            // 
+            this.btnPatch.Enabled = false;
+            this.btnPatch.Location = new System.Drawing.Point(102, 19);
+            this.btnPatch.Name = "btnPatch";
+            this.btnPatch.Size = new System.Drawing.Size(81, 23);
+            this.btnPatch.TabIndex = 3;
+            this.btnPatch.Text = "Patch";
+            this.btnPatch.UseVisualStyleBackColor = true;
+            this.btnPatch.Click += new System.EventHandler(this.btnPatch_Click);
+            // 
+            // btnSave
+            // 
+            this.btnSave.Enabled = false;
+            this.btnSave.Location = new System.Drawing.Point(189, 19);
+            this.btnSave.Name = "btnSave";
+            this.btnSave.Size = new System.Drawing.Size(81, 23);
+            this.btnSave.TabIndex = 4;
+            this.btnSave.Text = "Save File...";
+            this.btnSave.UseVisualStyleBackColor = true;
+            this.btnSave.Click += new System.EventHandler(this.btnSave_Click);
+            // 
+            // groupBox1
+            // 
+            this.groupBox1.Controls.Add(this.btnLoad);
+            this.groupBox1.Controls.Add(this.btnSave);
+            this.groupBox1.Controls.Add(this.btnPatch);
+            this.groupBox1.Location = new System.Drawing.Point(12, 12);
+            this.groupBox1.Name = "groupBox1";
+            this.groupBox1.Size = new System.Drawing.Size(284, 52);
+            this.groupBox1.TabIndex = 5;
+            this.groupBox1.TabStop = false;
+            this.groupBox1.Text = "Actions";
+            // 
+            // splitContainer1
+            // 
+            this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
+            this.splitContainer1.FixedPanel = System.Windows.Forms.FixedPanel.Panel1;
+            this.splitContainer1.IsSplitterFixed = true;
+            this.splitContainer1.Location = new System.Drawing.Point(0, 0);
+            this.splitContainer1.Name = "splitContainer1";
+            this.splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal;
+            // 
+            // splitContainer1.Panel1
+            // 
+            this.splitContainer1.Panel1.Controls.Add(this.label1);
+            this.splitContainer1.Panel1.Controls.Add(this.groupBox1);
+            // 
+            // splitContainer1.Panel2
+            // 
+            this.splitContainer1.Panel2.Controls.Add(this.splitContainer2);
+            this.splitContainer1.Size = new System.Drawing.Size(742, 626);
+            this.splitContainer1.SplitterDistance = 69;
+            this.splitContainer1.TabIndex = 6;
+            // 
+            // splitContainer2
+            // 
+            this.splitContainer2.Dock = System.Windows.Forms.DockStyle.Fill;
+            this.splitContainer2.Location = new System.Drawing.Point(0, 0);
+            this.splitContainer2.Name = "splitContainer2";
+            // 
+            // splitContainer2.Panel1
+            // 
+            this.splitContainer2.Panel1.Controls.Add(this.txtLog);
+            // 
+            // splitContainer2.Panel2
+            // 
+            this.splitContainer2.Panel2.Controls.Add(this.treeStructure);
+            this.splitContainer2.Size = new System.Drawing.Size(742, 553);
+            this.splitContainer2.SplitterDistance = 488;
+            this.splitContainer2.TabIndex = 0;
+            // 
+            // label1
+            // 
+            this.label1.AutoSize = true;
+            this.label1.Font = new System.Drawing.Font("Courier New", 7F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.label1.Location = new System.Drawing.Point(302, 9);
+            this.label1.Name = "label1";
+            this.label1.Size = new System.Drawing.Size(407, 48);
+            this.label1.TabIndex = 6;
+            this.label1.Text = resources.GetString("label1.Text");
+            // 
+            // EOSMovieFixer
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.ClientSize = new System.Drawing.Size(742, 626);
+            this.Controls.Add(this.splitContainer1);
+            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow;
+            this.Name = "EOSMovieFixer";
+            this.Text = "EOSMovieFixer";
+            this.groupBox1.ResumeLayout(false);
+            this.splitContainer1.Panel1.ResumeLayout(false);
+            this.splitContainer1.Panel1.PerformLayout();
+            this.splitContainer1.Panel2.ResumeLayout(false);
+            this.splitContainer1.ResumeLayout(false);
+            this.splitContainer2.Panel1.ResumeLayout(false);
+            this.splitContainer2.Panel1.PerformLayout();
+            this.splitContainer2.Panel2.ResumeLayout(false);
+            this.splitContainer2.ResumeLayout(false);
+            this.ResumeLayout(false);
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.Button btnLoad;
+        private System.Windows.Forms.TreeView treeStructure;
+        private System.Windows.Forms.TextBox txtLog;
+        private System.Windows.Forms.Button btnPatch;
+        private System.Windows.Forms.Button btnSave;
+        private System.Windows.Forms.GroupBox groupBox1;
+        private System.Windows.Forms.SplitContainer splitContainer1;
+        private System.Windows.Forms.SplitContainer splitContainer2;
+        private System.Windows.Forms.Label label1;
+    }
+}
+

contrib/g3gg0-tools/EOSMovieFixer/EOSMovieFixer.cs

+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+using System.Collections;
+using EOSMovieFixer.Atoms;
+using System.Threading;
+
+namespace EOSMovieFixer
+{
+    public partial class EOSMovieFixer : Form
+    {
+        InputFile InFile = null;
+        ArrayList Atoms = null;
+        string Version = "v1.01";
+        static EOSMovieFixer Instance = null;
+
+        public EOSMovieFixer()
+        {
+            InitializeComponent();
+            Text += " " + Version;
+
+            Instance = this;
+        }
+
+        public static void Log(string msg)
+        {
+            if (Instance.InvokeRequired)
+            {
+                Instance.BeginInvoke(new Action(() => { Log(msg); }));
+            }
+            else
+            {
+                Instance.txtLog.AppendText(msg + Environment.NewLine);
+            }
+        }
+
+        private void btnLoad_Click(object sender, EventArgs e)
+        {
+            OpenFileDialog dlg = new OpenFileDialog();
+
+            if(dlg.ShowDialog() == DialogResult.OK)
+            {
+                txtLog.Clear();
+                treeStructure.Nodes.Clear();
+
+                Log("[i] Loading file...");
+
+                try
+                {
+                    InFile = new InputFile(dlg.FileName);
+                    Log("      Size: 0x" + InFile.Length.ToString("X8"));
+                    AtomParser parser = new AtomParser();
+                    Atoms = parser.ParseFile(InFile);
+                    Log("      Atoms in root: " + Atoms.Count);
+
+                    DisplayTree(Atoms);
+                }
+                catch (Exception ex)
+                {
+                    Log("");
+                    Log("[E] " + ex.ToString());
+                    InFile.Close();
+
+                    btnLoad.Enabled = true;
+                    btnPatch.Enabled = false;
+                    btnSave.Enabled = false;
+                    return;
+                }
+
+                btnLoad.Enabled = false;
+                btnPatch.Enabled = true;
+                btnSave.Enabled = false;
+                Log("");
+                Log("--------------------------------");
+            }
+        }
+
+        private void btnSave_Click(object sender, EventArgs e)
+        {
+            SaveFileDialog dlg = new SaveFileDialog();
+
+            if (dlg.ShowDialog() == DialogResult.OK)
+            {
+                Log("[i] Saving file...");
+
+                OutputFile outFile = new OutputFile(dlg.FileName);
+                AtomWriter writer = new AtomWriter();
+
+                btnSave.Enabled = false;
+                Thread writerThread = new Thread(() =>
+                {
+                    try
+                    {
+                        writer.SaveFile(InFile, outFile, Atoms);
+                        Log("[i] Done");
+                    }
+                    catch (Exception ex)
+                    {
+                        Log("");
+                        Log("[E] " + ex.ToString());
+                    }
+
+                    BeginInvoke(new Action(() =>
+                    {
+                        InFile.Close();
+                        outFile.Close();
+
+                        btnLoad.Enabled = true;
+                        btnPatch.Enabled = false;
+                        btnSave.Enabled = false;
+                    }));
+                });
+
+                writerThread.Start();
+            }
+        }
+
+        private void DisplayTree(ArrayList atoms)
+        {
+            TreeNode root = new TreeNode("original");
+            BuildTree(root, atoms);
+            treeStructure.Nodes.Add(root);
+        }
+
+        private void BuildTree(TreeNode root, ArrayList atoms)
+        {
+            foreach (var obj in atoms)
+            {
+                if (obj is ContainerAtom)
+                {
+                    ContainerAtom container = (ContainerAtom)obj;
+                    TreeNode node = new TreeNode(container + " C:" + container.Children.Count);
+                    BuildTree(node, ((ContainerAtom)obj).Children);
+                    root.Nodes.Add(node);
+                }
+                else
+                {
+                    LeafAtom leaf = (LeafAtom)obj;
+                    TreeNode node = new TreeNode(leaf + "");
+                    root.Nodes.Add(node);
+                }
+            }
+        }
+
+        private void btnPatch_Click(object sender, EventArgs e)
+        {
+            Log("");
+            Log("[i] Locating sections");
+
+            try
+            {
+
+                ArrayList stcoAtoms = new ArrayList();
+                ArrayList stcoChunks = new ArrayList();
+
+                Atom mdat = FindAtom(Atoms, "mdat");
+                if (mdat != null)
+                {
+                    Log("      [mdat] at: 0x" + mdat.PayloadFileOffset.ToString("X8"));
+                }
+                else
+                {
+                    Log("      [mdat] not found");
+                }
+
+                Atom stco = null;
+                int num = 0;
+                do
+                {
+                    stco = FindAtom(Atoms, "stco");
+
+                    if (stco != null)
+                    {
+                        Log("      [stco#" + num + "] at: 0x" + stco.PayloadFileOffset.ToString("X8"));
+                        Log("        Extracting...");
+
+                        ArrayList chunkOffsets = StcoExtractOffsets(stco, mdat);
+
+                        Log("      Extending [stco#" + num + "] to [co64]...");
+                        StcoExtend(stco, mdat, chunkOffsets);
+
+                        stcoAtoms.Add(stco);
+                        stcoChunks.Add(chunkOffsets);
+                        num++;
+                    }
+                } while (stco != null);
+
+                Log("");
+                Log("[i] Removing filler atoms...");
+                CleanupAtoms(Atoms);
+
+                Log("");
+                Log("[i] Updating atom sizes...");
+                UInt64 size = CalculateSizes(Atoms, 0, true);
+                Log("      (total size: 0x" + size.ToString("X8") + ")");
+
+                Log("");
+                Log("[i] Updating new [co64]...");
+                /* now update chunk pointers */
+                for (num = 0; num < stcoAtoms.Count; num++)
+                {
+                    stco = (Atom)stcoAtoms[num];
+                    ArrayList chunkOffsets = (ArrayList)stcoChunks[num];
+                    Log("      Updating [co64#" + num + "] (" + chunkOffsets.Count + " chunks)...");
+                    StcoUpdate(stco, mdat, chunkOffsets);
+                }
+                Log("");
+                Log("--------------------------------");
+            }
+            catch (Exception ex)
+            {
+                Log("");
+                Log("[E] " + ex.ToString());
+            }
+
+            TreeNode root = new TreeNode("patched");
+            BuildTree(root, Atoms);
+            treeStructure.Nodes.Add(root);
+
+            btnLoad.Enabled = false;
+            btnPatch.Enabled = false;
+            btnSave.Enabled = true;
+        }
+
+        private void CleanupAtoms(ArrayList atoms)
+        {
+            ArrayList deleted = new ArrayList();
+
+            foreach (var obj in atoms)
+            {
+                Atom atom = (Atom)obj;
+
+                if (atom.Type == "skip" || atom.Type == "free")
+                {
+                    Log("      Deleting [" + atom.Type + "]");
+                    deleted.Add(atom);
+                }
+
+                if (obj is ContainerAtom)
+                {
+                    CleanupAtoms(((ContainerAtom)obj).Children);
+                }
+            }
+
+            foreach (var obj in deleted)
+            {
+                atoms.Remove(obj);
+            }
+        }
+
+        private int TreeDepth = 0;
+        private UInt64 CalculateSizes(ArrayList atoms, UInt64 outFileOffset, bool absolute)
+        {
+            UInt64 totalSize = 0;
+
+            string tabs = "";
+            for (int pos = 0; pos < TreeDepth; pos++)
+            {
+                tabs += "  ";
+            }
+
+            foreach (var obj in atoms)
+            {
+                if (obj is ContainerAtom)
+                {
+                    ContainerAtom container = (ContainerAtom)obj;
+
+                    if (absolute)
+                    {
+                        Log(tabs + "  [" + container.Type + "] size: 0x" + container.TotalLength.ToString("X8") + " bytes");
+                    }
+
+                    /* run first with absolute file offset set to zero, as it is not clear yet if we have 8 or 16 byte header */
+                    UInt64 containerSize = CalculateSizes(container.Children, 0, false);
+
+                    if ((containerSize + 8) > 0xFFFFFFFF)
+                    {
+                        container.HeaderLength = 16;
+                    }
+                    else
+                    {
+                        container.HeaderLength = 8;
+                    }
+                    container.TotalLength = container.HeaderLength + containerSize;
+                    container.HeaderFileOffset = outFileOffset + totalSize;
+
+                    /* run again with the real absolute file offset */
+                    if (absolute)
+                    {
+                        TreeDepth++;
+                        CalculateSizes(container.Children, container.PayloadFileOffset, true);
+                        TreeDepth--;
+                    }
+
+                    /* now we are done with that container */
+                    totalSize += container.TotalLength;
+
+                }
+                else
+                {
+                    LeafAtom leaf = (LeafAtom)obj;
+                    UInt64 contentSize = leaf.PayloadLength;
+
+                    /* replace content with our patched? */
+                    if (leaf.PayloadData != null)
+                    {
+                        contentSize = (UInt64)leaf.PayloadData.Length;
+                        if (absolute)
+                        {
+                            Log(tabs + "      [" + leaf.Type + "] Replacing data (0x" + leaf.OriginalPayloadLength.ToString("X8") + " bytes) with 0x" + contentSize.ToString("X8") + " bytes");
+                        }
+                    }
+
+                    if ((contentSize + 8) > 0xFFFFFFFF)
+                    {
+                        leaf.HeaderLength = 16;
+                    }
+                    else
+                    {
+                        leaf.HeaderLength = 8;
+                    }
+
+                    leaf.TotalLength = leaf.HeaderLength + contentSize;
+                    leaf.HeaderFileOffset = outFileOffset + totalSize;
+
+                    totalSize += leaf.TotalLength;
+
+                    if (absolute)
+                    {
+                        Log(tabs + "      [" + leaf.Type + "] size: 0x" + leaf.TotalLength.ToString("X8") + " pos: 0x" + leaf.HeaderFileOffset.ToString("X8"));
+                    }
+                }
+            }
+
+            return totalSize;
+        }
+
+        private ArrayList StcoExtractOffsets(Atom stco, Atom mdat)
+        {
+            ArrayList offsetsInMdat = new ArrayList();
+            UInt64 lastOffset = 0;
+            UInt64 overflow = 0;
+            int entry = 0;
+
+            for (UInt64 pos = 8; pos < stco.PayloadLength; pos += 4)
+            {
+                UInt64 offset = InFile.ReadUInt32(stco.PayloadFileOffset + pos) + overflow;
+                if (lastOffset > offset)
+                {
+                    offset += 0x0100000000;
+                    overflow += 0x0100000000;
+                }
+                lastOffset = offset;
+                if ((lastOffset < mdat.PayloadFileOffset) || ((lastOffset - mdat.PayloadFileOffset) >= mdat.PayloadLength))
+                {
+                    throw new Exception("Offset not pointing into 'mdat'");
+                }
+
+                UInt64 relativeOffset = (UInt64)(lastOffset - mdat.PayloadFileOffset);
+                if (entry < 5)
+                {
+                    Log("        abs: 0x" + offset.ToString("X08") + " -> rel: 0x" + relativeOffset.ToString("X08"));
+                }
+                offsetsInMdat.Add(relativeOffset);
+                entry++;
+            }
+
+            Log("        ...");
+
+            UInt32 entries = InFile.ReadUInt32(stco.PayloadFileOffset + 4);
+            Log("        (" + offsetsInMdat.Count + " chunks)");
+
+            if (entries != offsetsInMdat.Count)
+            {
+                throw new Exception("Offset count invalid");
+            }
+
+            return offsetsInMdat;
+        }
+
+        private void StcoExtend(Atom stco, Atom mdat, ArrayList offsetsInMdat)
+        {
+            byte[] newPayload = new byte[2 * 4 + offsetsInMdat.Count * 8];
+
+            /* read 8 bytes - version, flags and entry count */
+            InFile.ReadBytes(stco.PayloadFileOffset, newPayload, 8);
+
+            /* apply changes */
+            stco.Type = "co64";
+            stco.PayloadData = newPayload;
+        }
+
+        private void StcoUpdate(Atom stco, Atom mdat, ArrayList offsetsInMdat)
+        {
+            for (int entry = 0; entry < offsetsInMdat.Count; entry++)
+            {
+                UInt64 relativeOffset = (UInt64)offsetsInMdat[entry];
+                UInt64 offset = relativeOffset + mdat.PayloadFileOffset;
+                if (entry < 5)
+                {
+                    Log("        rel: 0x" + relativeOffset.ToString("X08") + " -> abs: 0x" + offset.ToString("X08"));
+                }
+
+                byte[] a64 = BitConverter.GetBytes(offset);
+                Array.Reverse(a64);
+                Array.Copy(a64, 0, stco.PayloadData, 2 * 4 + entry * 8, 8);
+            }
+            Log("        ...");
+        }
+
+        private Atom FindAtom(ArrayList atoms, string name)
+        {
+            foreach (var obj in atoms)
+            {
+                if (((Atom)obj).Type == name)
+                {
+                    return (Atom)obj;
+                }
+
+                if (obj is ContainerAtom)
+                {
+                    ContainerAtom container = (ContainerAtom)obj;
+                    Atom sub = FindAtom(((ContainerAtom)obj).Children, name);
+
+                    if (sub != null)
+                    {
+                        return sub;
+                    }
+                }
+            }
+
+            return null;
+        }
+    }
+}

contrib/g3gg0-tools/EOSMovieFixer/EOSMovieFixer.csproj

+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.21022</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{1D2DCBB5-7B16-4DB4-BB51-42B9BDD26913}</ProjectGuid>
+    <OutputType>WinExe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>EOSMovieFixer</RootNamespace>
+    <AssemblyName>EOSMovieFixer</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</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</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Xml.Linq">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data.DataSetExtensions">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data" />
+    <Reference Include="System.Deployment" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Windows.Forms" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="AtomParser.cs" />
+    <Compile Include="Atoms\Atom.cs" />
+    <Compile Include="Atoms\ContainerAtom.cs" />
+    <Compile Include="Atoms\LeafAtom.cs" />
+    <Compile Include="AtomWriter.cs" />
+    <Compile Include="EOSMovieFixer.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="EOSMovieFixer.Designer.cs">
+      <DependentUpon>EOSMovieFixer.cs</DependentUpon>
+    </Compile>
+    <Compile Include="InputFile.cs" />
+    <Compile Include="OutputFile.cs" />
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <EmbeddedResource Include="EOSMovieFixer.resx">
+      <DependentUpon>EOSMovieFixer.cs</DependentUpon>
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Properties\Resources.resx">
+      <Generator>ResXFileCodeGenerator</Generator>
+      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
+    <Compile Include="Properties\Resources.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DependentUpon>Resources.resx</DependentUpon>
+    </Compile>
+    <None Include="Properties\Settings.settings">
+      <Generator>SettingsSingleFileGenerator</Generator>
+      <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+    </None>
+    <Compile Include="Properties\Settings.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DependentUpon>Settings.settings</DependentUpon>
+      <DesignTimeSharedInput>True</DesignTimeSharedInput>
+    </Compile>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.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>

contrib/g3gg0-tools/EOSMovieFixer/EOSMovieFixer.resx

+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <data name="label1.Text" xml:space="preserve">
+    <value>This tool is used for patching Apple QuickTime (.mov)
+files that contain video data beyond 4GiB length.
+Canon EOS cameras using Magic Lantern can produce such large files.
+If you find it useful, say thanks:  paypal@g3gg0.de</value>
+  </data>
+</root>

contrib/g3gg0-tools/EOSMovieFixer/InputFile.cs

+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+
+namespace EOSMovieFixer
+{
+    public class InputFile
+    {
+        private BinaryReader reader = null;
+        public UInt64 Length
+        {
+            get
+            {
+                return (UInt64)reader.BaseStream.Length;
+            }
+        }
+
+        public InputFile(string fileName)
+        {
+            reader = new BinaryReader(File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite));
+        }
+
+        internal void ReadBytes(UInt64 position, byte[] buffer, int bytes)
+        {
+            Seek(position);
+            byte[] buf = reader.ReadBytes(bytes);
+            if (buf.Length == bytes)
+            {
+                Array.Copy(buf, buffer, bytes);
+            }
+        }
+
+        internal void Seek(UInt64 position)
+        {
+            reader.BaseStream.Seek((long)position, SeekOrigin.Begin);
+        }
+
+        internal UInt32 ReadUInt32(UInt64 position)
+        {
+            Seek(position);
+
+            byte[] a32 = new byte[4];
+            a32 = reader.ReadBytes(4);
+            Array.Reverse(a32);
+            return BitConverter.ToUInt32(a32, 0);
+        }
+
+        internal UInt64 ReadUInt64(UInt64 position)
+        {
+            Seek(position);
+
+            byte[] a64 = new byte[8];
+            a64 = reader.ReadBytes(8);
+            Array.Reverse(a64);
+            return BitConverter.ToUInt64(a64, 0);
+        }
+
+        internal void Close()
+        {
+            reader.Close();
+            reader = null;
+        }
+    }
+}

contrib/g3gg0-tools/EOSMovieFixer/OutputFile.cs

+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+
+namespace EOSMovieFixer
+{
+    public class OutputFile
+    {
+        private BinaryWriter writer = null;
+
+        public OutputFile(string fileName)
+        {
+            writer = new BinaryWriter(File.Open(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite));
+        }
+
+        internal void WriteUInt32(UInt32 p)
+        {
+            byte[] buf = BitConverter.GetBytes(p);
+            Array.Reverse(buf);
+            writer.Write(buf);
+        }
+
+        internal void WriteChars(char[] p)
+        {
+            writer.Write(p);
+        }
+
+        internal void WriteUInt64(UInt64 p)
+        {
+            byte[] buf = BitConverter.GetBytes(p);
+            Array.Reverse(buf);
+            writer.Write(buf);
+        }
+
+        internal void WriteBytes(byte[] p)
+        {
+            writer.Write(p);
+        }
+
+        internal void WriteFromInput(InputFile inFile, ulong position, ulong length)
+        {
+            ulong blockSize = 8 * 1024 * 1024;
+            ulong remaining = length;
+
+            while(remaining>0)
+            {
+                byte[] buf = new byte[Math.Min(remaining, blockSize)];
+                inFile.ReadBytes(position, buf, buf.Length);
+                writer.Write(buf);
+
+                remaining -= (ulong)buf.Length;
+                position += (ulong)buf.Length;
+            }
+        }
+
+        internal void Close()
+        {
+            writer.Close();
+            writer = null;
+        }
+    }
+}

contrib/g3gg0-tools/EOSMovieFixer/Program.cs

+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Windows.Forms;
+
+namespace EOSMovieFixer
+{
+    static class Program
+    {
+        /// <summary>
+        /// Der Haupteinstiegspunkt für die Anwendung.
+        /// </summary>
+        [STAThread]
+        static void Main()
+        {
+            Application.EnableVisualStyles();
+            Application.SetCompatibleTextRenderingDefault(false);
+            Application.Run(new EOSMovieFixer());
+        }
+    }
+}

contrib/g3gg0-tools/EOSMovieFixer/Properties/AssemblyInfo.cs

+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// Allgemeine Informationen über eine Assembly werden über die folgenden 
+// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
+// die mit einer Assembly verknüpft sind.
+[assembly: AssemblyTitle("EOSMovieFixer")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("EOSMovieFixer")]
+[assembly: AssemblyCopyright("Copyright ©  2012")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar 
+// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von 
+// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest.
+[assembly: ComVisible(false)]
+
+// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
+[assembly: Guid("3b4bd6bf-b835-4c0e-b8e8-0ad86173e565")]
+
+// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
+//
+//      Hauptversion
+//      Nebenversion 
+//      Buildnummer
+//      Revision
+//
+// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern 
+// übernehmen, indem Sie "*" eingeben:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

contrib/g3gg0-tools/EOSMovieFixer/Properties/Resources.Designer.cs

+//------------------------------------------------------------------------------
+// <auto-generated>
+//     Dieser Code wurde von einem Tool generiert.
+//     Laufzeitversion:2.0.50727.5456
+//
+//     Änderungen an dieser Datei können fehlerhaftes Verhalten verursachen und gehen verloren, wenn
+//     der Code neu generiert wird.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace EOSMovieFixer.Properties
+{
+
+
+    /// <summary>
+    ///   Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw.
+    /// </summary>
+    // Diese Klasse wurde von der StronglyTypedResourceBuilder-Klasse
+    // über ein Tool wie ResGen oder Visual Studio automatisch generiert.
+    // Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen
+    // mit der Option /str erneut aus, oder erstellen Sie Ihr VS-Projekt neu.
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    internal class Resources
+    {
+
+        private static global::System.Resources.ResourceManager resourceMan;
+
+        private static global::System.Globalization.CultureInfo resourceCulture;
+
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal Resources()
+        {
+        }
+
+        /// <summary>
+        ///   Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Resources.ResourceManager ResourceManager
+        {
+            get
+            {
+                if ((resourceMan == null))
+                {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("EOSMovieFixer.Properties.Resources", typeof(Resources).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+
+        /// <summary>
+        ///   Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle
+        ///   Ressourcenlookups, die diese stark typisierte Ressourcenklasse verwenden.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Globalization.CultureInfo Culture
+        {
+            get
+            {
+                return resourceCulture;
+            }
+            set
+            {
+                resourceCulture = value;
+            }
+        }
+    }
+}

contrib/g3gg0-tools/EOSMovieFixer/Properties/Resources.resx

+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>

contrib/g3gg0-tools/EOSMovieFixer/Properties/Settings.Designer.cs

+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:2.0.50727.5456
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace EOSMovieFixer.Properties
+{
+
+
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")]
+    internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
+    {
+
+        private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+        public static Settings Default
+        {
+            get
+            {
+                return defaultInstance;
+            }
+        }
+    }
+}

contrib/g3gg0-tools/EOSMovieFixer/Properties/Settings.settings

+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
+  <Profiles>
+    <Profile Name="(Default)" />
+  </Profiles>
+  <Settings />
+</SettingsFile>

contrib/g3gg0-tools/LensDumper/LensDataAccessor.cs

+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Collections;
+using System.Xml.Serialization;
+
+namespace LensDumper
+{
+    public class LensDataAccessor
+    {
+        public class LensDataStructure
+        {
+            public UInt16 Identifier;
+            public UInt16 LensEntryCount;
+            public UInt16 HeaderSize;
+            public UInt16 LensEntriesReserved;
+
+            public UInt16 Unknown1;
+            public UInt16 Unknown2;
+            public UInt16 Unknown3;
+            public UInt16 Unknown4;
+            public UInt16 Unknown5;
+
+            public LensEntry[] LensEntries;
+            public LensData[] LensDatas;
+        }
+
+        public class LensEntry
+        {
+            public UInt32 LensId;
+            public UInt16 Wide;
+            public UInt16 ExtenderType;
+            public UInt32 Offset;
+        }
+
+        public class LensData
+        {
+            public UInt16 Unknown1;
+            public UInt16 Unknown2;
+            public UInt16 FocalLengthMin;
+            public UInt16 FocalLengthMax;
+            public UInt16 FocusDistMin;
+
+            public ProfileTypeA ProfileTypesA;
+            public ProfileTypeB ProfileTypesB;
+            public ProfileTypeC ProfileTypesC;
+        }
+
+        public class ProfileTypeA
+        {
+            /* 0x14 bytes */
+            [XmlIgnore]
+            public byte[] HeaderData;
+
+            [XmlAttribute("header")]
+            public string HeaderData_
+            {
+                get
+                {
+                    StringBuilder str = new StringBuilder();
+                    if (HeaderData != null)
+                    {
+                        for (int pos = 0; pos < HeaderData.Length; pos++)
+                        {
+                            str.AppendFormat("{0:X2}", HeaderData[pos]);
+                        }
+                    }
+                    return str.ToString();
+                }
+                set
+                {
+                }
+            }
+
+            public ProfileTypeAData[] Data;
+        }
+
+        public class ProfileTypeB
+        {
+            /* 0x14 bytes */
+            [XmlIgnore]
+            public byte[] HeaderData;
+
+            [XmlAttribute("header")]
+            public string HeaderData_
+            {
+                get
+                {
+                    StringBuilder str = new StringBuilder();
+                    if (HeaderData != null)
+                    {
+                        for (int pos = 0; pos < HeaderData.Length; pos++)
+                        {
+                            str.AppendFormat("{0:X2}", HeaderData[pos]);
+                        }
+                    }
+                    return str.ToString();
+                }
+                set
+                {
+                }
+            }
+
+            public ProfileTypeBData[] Data;
+        }
+
+        public class ProfileTypeC
+        {
+            /* 0x14 bytes */
+            [XmlIgnore]
+            public byte[] HeaderData;
+
+            [XmlAttribute("header")]
+            public string HeaderData_
+            {
+                get
+                {
+                    StringBuilder str = new StringBuilder();
+                    if (HeaderData != null)
+                    {
+                        for (int pos = 0; pos < HeaderData.Length; pos++)
+                        {
+                            str.AppendFormat("{0:X2}", HeaderData[pos]);
+                        }
+                    }
+                    return str.ToString();
+                }
+                set
+                {
+                }
+            }
+
+            public ProfileTypeCData[] Data;
+        }
+
+        public class ProfileTypeAData
+        {
+            [XmlAttribute("focalLength")]
+            public UInt16 FocalLength;
+
+            /* 0xC0 bytes */
+            [XmlElement("CorrectionData")]
+            public CorrectionDataTypeA[] CorrectionData;
+        }
+
+        public class ProfileTypeBData
+        {
+            [XmlAttribute("focalLength")]
+            public UInt16 FocalLength;
+            /* 0x30 bytes */
+            public CorrectionDataTypeB[] CorrectionData;
+        }
+
+        public class ProfileTypeCData
+        {
+            [XmlAttribute("focalLength")]
+            public UInt16 FocalLength;
+
+            /* 0x188 bytes */
+            [XmlElement("CorrectionData")]
+            public CorrectionDataTypeC[] CorrectionData;
+        }
+
+
+        public class CorrectionDataTypeA
+        {
+            [XmlAttribute("aperture")]
+            public UInt16 Aperture;
+
+            [XmlElement("Coeff")]
+            public Int16[] Coeff;
+        }
+
+        public class CorrectionDataTypeB
+        {
+            [XmlElement("Coeff")]
+            public Int16[] Coeff;
+        }
+
+        public class CorrectionDataTypeC
+        {
+            [XmlAttribute("aperture")]
+            public UInt16 Aperture;
+
+            [XmlElement("Coeff")]
+            public Int16[] Coeff;
+        }
+
+        public static LensDataStructure ParseLensData(byte[] buffer)
+        {
+            ulong offset = 0;
+            LensDataStructure data = new LensDataStructure();
+            
+            data.Identifier = GetUInt16(buffer, 0x00);
+            data.LensEntryCount = GetUInt16(buffer, 0x02);
+            data.HeaderSize = GetUInt16(buffer, 0x04);
+            data.LensEntriesReserved = GetUInt16(buffer, 0x06);
+            data.Unknown1 = GetUInt16(buffer, 0x10);
+            data.Unknown2 = GetUInt16(buffer, 0x12);
+            data.Unknown3 = GetUInt16(buffer, 0x14);
+            data.Unknown4 = GetUInt16(buffer, 0x16);
+            data.Unknown5 = GetUInt16(buffer, 0x18);
+
+            offset += data.HeaderSize;
+
+            Log.WriteLine("  Parsing " + data.LensEntryCount + " index entries");
+            data.LensEntries = new LensEntry[data.LensEntryCount];
+            for (ulong entry = 0; entry < data.LensEntryCount; entry++)
+            {
+                LensEntry lensEntry = new LensEntry();
+
+                lensEntry.LensId = GetUInt16(buffer, offset + entry * 0x10 + 0x00);
+                lensEntry.Wide = GetUInt16(buffer, offset + entry * 0x10 + 0x02);
+                lensEntry.ExtenderType = GetUInt16(buffer, offset + entry * 0x10 + 0x04);
+                lensEntry.Offset = GetUInt32(buffer, offset + entry * 0x10 + 0x0C);
+
+                Log.WriteLine("  Lens #{0} has ID 0x{1:X8} [Wide: {2}, ExtenderType: {3}]", entry, lensEntry.LensId, lensEntry.Wide, lensEntry.ExtenderType);
+                data.LensEntries[entry] = lensEntry;
+            }
+
+            offset += (ulong)data.LensEntriesReserved * 0x10;
+
+            Log.WriteLine("  Parsing " + data.LensEntryCount + " lens datas");
+            data.LensDatas = new LensData[data.LensEntryCount];
+            for (ulong entry = 0; entry < data.LensEntryCount; entry++)
+            {
+                LensEntry lensEntry = data.LensEntries[entry];
+
+                data.LensDatas[entry] = ParseLensCorrection(buffer, offset + lensEntry.Offset);
+            }
+
+            return data;
+        }
+
+        private static LensData ParseLensCorrection(byte[] buffer, ulong offset)
+        {
+            LensData data = new LensData();
+
+            data.Unknown1 = GetUInt16(buffer, offset + 0x00);
+            data.Unknown2 = GetUInt16(buffer, offset + 0x02);
+            data.FocalLengthMin = GetUInt16(buffer, offset + 0x04);
+            data.FocalLengthMax = GetUInt16(buffer, offset + 0x06);
+            data.FocusDistMin = GetUInt16(buffer, offset + 0x08);
+
+            if (data.FocalLengthMax != data.FocalLengthMin)
+            {
+                Log.WriteLine("    Parsing lens {0}-{1} mm (min focus {2} mm) lens data [{3}, {4}]", data.FocalLengthMin, data.FocalLengthMax, data.FocusDistMin, data.Unknown1, data.Unknown2);
+            }
+            else
+            {
+                Log.WriteLine("    Parsing lens {0} mm (min focus {2} mm) lens data [{3}, {4}]", data.FocalLengthMin, data.FocalLengthMax, data.FocusDistMin, data.Unknown1, data.Unknown2);
+            }
+
+            /* this header */
+            offset += 0x20;
+
+            Log.WriteLine("      Reading profile type A");