Exemple #1
0
        public void ParseRDTNode(int offsetOfThisNode, string baseString)
        {
            int subnodeCount = filebytes[offsetOfThisNode];

            string currentStateOfString = baseString;

            for (int i = 0; i < subnodeCount; i++)
            {
                char letter = (char)filebytes[offsetOfThisNode + (i * 5) + 1];

                if ((byte)letter == 0x00)   //it's the end of the string
                {
                    if (!filenamesAndOffsets.ContainsKey(currentStateOfString))
                    {
                        filenamesAndOffsets.Add(currentStateOfString, BitConverter.ToInt32(filebytes, offsetOfThisNode + (i * 5) + 2));
                        archivedfile newFile = new archivedfile();

                        newFile.filename      = currentStateOfString;
                        newFile.offset        = filenamesAndOffsets[currentStateOfString];
                        newFile.form1         = form1;
                        newFile.parentrdtfile = this;

                        archivedfiles.Add(newFile);
                    }
                    Console.WriteLine(currentStateOfString + " file offset is " + filenamesAndOffsets[currentStateOfString]);
                }
                else          //keep following the string
                {
                    currentStateOfString += letter;
                    ParseRDTNode(BitConverter.ToInt32(filebytes, offsetOfThisNode + (i * 5) + 2), currentStateOfString);
                }
                currentStateOfString = baseString;
            }
        }
Exemple #2
0
        public void SetAuthorDetails()
        {
            archivedfile authorFile = embeddedArc.GetFileByName("/info.txt");

            saveFileEditor.author.Text     = "Author: None";
            saveFileEditor.authorNote.Text = "Author's note: None";

            if (authorFile != null)
            {
                authorFile.ReadFile();

                string authorFileText = "";

                for (int i = 0; i < authorFile.filebytes.Length; i++)
                {
                    authorFileText += (char)authorFile.filebytes[i];
                }

                string[] splitAuthorFile = authorFileText.Replace("\r", "").Split('\n');

                saveFileEditor.author.Text = "Author: " + splitAuthorFile[0];

                if (splitAuthorFile.Length > 1)
                {
                    saveFileEditor.authorNote.Text = "Author's note: " + splitAuthorFile[1].Replace("[newline]", "\n");
                }
            }
        }
Exemple #3
0
        public void ExportFolder(TreeNode topnode)
        {
            NodesForBatchExport = new List <TreeNode>();

            NodesForBatchExport.Add(topnode);

            RecursivelyAddChildrenToExportList(topnode);

            //now we should have all child, grandchild, etc folders

            SaveFileDialog saveFileDialog1 = new SaveFileDialog();

            saveFileDialog1.FileName = "Save here";

            saveFileDialog1.Title           = "Choose folder";
            saveFileDialog1.CheckPathExists = true;
            saveFileDialog1.Filter          = "Directory |directory";

            if (saveFileDialog1.ShowDialog() == DialogResult.OK)
            {
                Console.WriteLine(saveFileDialog1.FileName);
                foreach (TreeNode folder in NodesForBatchExport)
                {
                    foreach (TreeNode child in folder.Nodes)
                    {
                        if (form1.treeNodesAndArchivedFiles.ContainsKey(child)) //if it's a file
                        {
                            archivedfile file = form1.treeNodesAndArchivedFiles[child];

                            string path;
                            if (file.filename[0] == '/')
                            {
                                path = Path.GetDirectoryName(saveFileDialog1.FileName) + file.filename.Replace('/', '\\');
                            }
                            else
                            {
                                path = Path.GetDirectoryName(saveFileDialog1.FileName) + "\\" + file.filename.Replace('/', '\\');
                            }

                            if (file.filename == "FILENAME_NOT_SET")
                            {
                                path = Path.GetDirectoryName(saveFileDialog1.FileName) + "\\Names_not_found\\" + file.hash + "." + file.filemagic;
                            }

                            Console.WriteLine(path);
                            file.ReadFile();

                            file.Export(form1.GetOrMakeDirectoryForFileName(path.Replace('/', '\\').Replace(".luc", ".lua")));
                        }
                    }
                }
            }
        }
Exemple #4
0
        public void GetDownloadableMissionName()
        {
            archivedfile downloadstrings = embeddedArc.GetFileByName("/strings/downloadstrings.st");

            if (downloadstrings == null)
            {
                Console.WriteLine("downloadstrings was not found in that arc!");
            }
            else
            {
                downloadstrings.ReadFile();
                saveFileEditor.downloadableMissionNameDisplay.Text = "Downloadable Mission: " + downloadstrings.STstrings[0];
            }
        }
Exemple #5
0
        public void EndHerbertsRevengeChain(int offsetOfThisNode, string currentStateOfString)
        {
            if (!filenamesAndOffsets.ContainsKey(currentStateOfString))
            {
                filenamesAndOffsets.Add(currentStateOfString, BitConverter.ToInt32(filebytes, offsetOfThisNode));
                offsetOfThisNode += 4;
                archivedfile newFile = new archivedfile();

                newFile.filename      = currentStateOfString;
                newFile.offset        = filenamesAndOffsets[currentStateOfString];
                newFile.form1         = form1;
                newFile.parentrdtfile = this;

                archivedfiles.Add(newFile);
            }
            Console.WriteLine(currentStateOfString + " file offset is " + filenamesAndOffsets[currentStateOfString]);
        }
Exemple #6
0
        public void RDTBlagger3000()   //attempts to scrape likely file offsets from the index table. Intended for HR RDTs, where the file tree is in an annoying format
        {
            int endOfIndexTable = BitConverter.ToInt32(filebytes, 0x0B);

            for (int i = 0x12; i < endOfIndexTable; i++)
            {
                int possibleOffset = BitConverter.ToInt32(filebytes, i);

                if (possibleOffset >= endOfIndexTable && possibleOffset < filebytes.Length && filebytes[possibleOffset] == 0x03 && BitConverter.ToInt32(filebytes, possibleOffset + 1) > 0 && BitConverter.ToUInt16(filebytes, possibleOffset + 1) < 65535)
                {
                    archivedfile newFile = new archivedfile();
                    newFile.offset        = possibleOffset;
                    newFile.filename      = "PotentialFile" + newFile.offset.ToString();
                    newFile.form1         = form1;
                    newFile.parentrdtfile = this;
                    archivedfiles.Add(newFile);
                }
            }
        }
Exemple #7
0
        public archivedfile(archivedfile basis)
        {
            form1        = basis.form1;
            spriteEditor = basis.spriteEditor;

            hash      = basis.hash;
            offset    = basis.offset;
            size      = basis.size;
            filebytes = basis.filebytes;
            filemagic = basis.filemagic;
            filename  = basis.filename;

            parentarcfile = basis.parentarcfile;
            parentrdtfile = basis.parentrdtfile;

            treeNode = basis.treeNode;

            should_this_file_be_decompressed__and_compressed_when_read = basis.should_this_file_be_decompressed__and_compressed_when_read;

            has_LZ11_filesize = basis.has_LZ11_filesize;

            was_LZ10_compressed = basis.was_LZ10_compressed;
            was_LZ11_compressed = basis.was_LZ11_compressed;

            STstrings = basis.STstrings;

            textFileStringType = basis.textFileStringType;

            rdtSubfileDataList = basis.rdtSubfileDataList;

            RDTSpriteNumFrames      = basis.RDTSpriteNumFrames;
            RDTSpriteWidth          = basis.RDTSpriteWidth;
            RDTSpriteHeight         = basis.RDTSpriteHeight;
            RDTSpriteBPP            = basis.RDTSpriteBPP;
            RDTSpriteFrameDurations = basis.RDTSpriteFrameDurations;
            RDTSpriteAlphaColour    = basis.RDTSpriteAlphaColour;
        }
Exemple #8
0
        public void AddSubNodesToByteArray(TreeNode node, Byte[] nodeTree)
        {
            nodeTree[posInNodeTree] = (byte)node.Nodes.Count;
            posInNodeTree++;
            int basePos = posInNodeTree;

            posInNodeTree = basePos + (node.Nodes.Count * 5);


            for (int i = 0; i < node.Nodes.Count; i++)
            {
                if (node.Nodes[i].Text == "nullNode")
                {
                    nodeTree[basePos + (i * 5)] = 0x00;
                    archivedfile file = archivedfiles[NullNodesInArchivedFileOrder.IndexOf(node.Nodes[i])];


                    List <rdtSubfileData> backuplist = new List <rdtSubfileData>(file.rdtSubfileDataList);

                    //prepare data for import

                    List <Image>  images   = new List <Image>();
                    List <Byte[]> palettes = new List <Byte[]>();

                    List <rdtSubfileData> savedImages   = new List <rdtSubfileData>();
                    List <rdtSubfileData> savedPalettes = new List <rdtSubfileData>();



                    foreach (rdtSubfileData subfiledata in file.rdtSubfileDataList) //get palettes
                    {
                        if (subfiledata.graphicsType == "palette")
                        {
                            subfiledata.DecompressLZ10IfCompressed();
                            palettes.Add(subfiledata.filebytes);
                            savedPalettes.Add(subfiledata);
                        }
                    }

                    int        imageIndex  = 0;
                    List <int> skipIndices = new List <int>();

                    bool is_modified = false;

                    List <ushort> offsetsX = new List <ushort>();
                    List <ushort> offsetsY = new List <ushort>();

                    foreach (rdtSubfileData subfiledata in file.rdtSubfileDataList) //get images
                    {
                        if (subfiledata.graphicsType == "image")
                        {
                            if (subfiledata.image != null) //if it was modified or viewed by the user, use the modified one
                            {
                                images.Add(subfiledata.image);
                                savedImages.Add(subfiledata);
                                is_modified = true;
                            }
                            else          //otherwise, just read the existing image for the first time and apply the existing palette
                            {
                                subfiledata.LoadImage(file.GetPalette(palettes[imageIndex], 1, file.RDTSpriteBPP));
                                images.Add(subfiledata.image);
                                skipIndices.Add(images.Count - 1); //so that we know not to bother rereading it and its palette
                                savedImages.Add(subfiledata);
                            }
                            offsetsX.Add(subfiledata.offsetX);
                            offsetsY.Add(subfiledata.offsetY);

                            imageIndex++;
                        }
                    }

                    //remove the existing images and palette subfiledata in the archivedfile
                    int indexOfFirstImageOrPalette = 0;

                    foreach (rdtSubfileData f in file.rdtSubfileDataList)
                    {
                        if (f.graphicsType != "image" && f.graphicsType != "palette")
                        {
                            indexOfFirstImageOrPalette++;
                            continue;
                        }
                        break;
                    }

                    file.rdtSubfileDataList.RemoveRange(indexOfFirstImageOrPalette, file.rdtSubfileDataList.Count - indexOfFirstImageOrPalette);


                    //now we add the updated images back to the list


                    //make global palette for sprite

                    rdtSubfileData newPalette = new rdtSubfileData();



                    // read individual frames

                    for (int j = 0; j < images.Count; j++)
                    {
                        //make palette

                        newPalette = new rdtSubfileData();

                        if (skipIndices.Contains(j))       //no need to reread image data, as the user didn't edit or view it
                        {
                            newPalette = savedPalettes[0];
                            newPalette.graphicsType = "palette";
                            newPalette.DecompressLZ10IfCompressed();
                            file.rdtSubfileDataList.Add(newPalette);
                            file.rdtSubfileDataList.Add(savedImages[j]);
                        }
                        else                       //the user edited or viewed this file, so rebuild the image and palette
                        {
                            //make palette
                            newPalette = new rdtSubfileData();
                            Color[] palette = new Color[0];

                            if (file.RDTSpriteBPP == 4)
                            {
                                palette = new Color[16];
                            }
                            else if (file.RDTSpriteBPP == 8)
                            {
                                palette = new Color[256];
                            }

                            //put image colours in palette

                            if (file.RDTSpriteAlphaColour.A == 0 && file.RDTSpriteAlphaColour.R == 0 && file.RDTSpriteAlphaColour.G == 0 && file.RDTSpriteAlphaColour.B == 0)
                            {
                                file.RDTSpriteAlphaColour = file.GetPalette(palettes[j], 1, file.RDTSpriteBPP)[0];
                            }

                            Color[] coloursToAdd = Get_Unique_Colours(images, palette.Length);
                            Array.Copy(coloursToAdd, 0, palette, 0, coloursToAdd.Length);
                            //Console.WriteLine("number of unique colours: " + coloursToAdd.Length);

                            file.RDTSpriteAlphaColour = Color.FromArgb(0x00, file.RDTSpriteAlphaColour.R, file.RDTSpriteAlphaColour.G, file.RDTSpriteAlphaColour.B); //make sure the dummy A value is 0x00

                            //now make sure the alpha colour is at index 0
                            if (palette[0] != file.RDTSpriteAlphaColour)
                            {
                                int checkIndex = 0;

                                while (checkIndex < palette.Length)     //go through the palette looking for the alpha colour's current position
                                {
                                    if (palette[checkIndex] == file.RDTSpriteAlphaColour)
                                    {
                                        break;
                                    }
                                    checkIndex++;
                                }

                                //swap the alpha colour into index 0, and the index 0 colour to where the alpha colour used to be
                                palette[checkIndex] = palette[0];
                                palette[0]          = file.RDTSpriteAlphaColour;
                            }

                            //CREATE BINARY NBFC IMAGE AND PALETTE, THEN MAKE SUBFILEDATAS FOR THEM AND ADD THEM TO LIST

                            //create binary palette


                            newPalette.subfileType  = 0x04;
                            newPalette.graphicsType = "palette";

                            newPalette.filebytes = new byte[1 + (palette.Length * 2)];

                            int colorindex = 0;

                            foreach (Color c in palette)
                            {
                                ushort ABGR1555Color = form1.ColorToABGR1555(c);
                                newPalette.filebytes[1 + (colorindex * 2)] = (byte)(ABGR1555Color & 0x00FF);
                                newPalette.filebytes[2 + (colorindex * 2)] = (byte)((ABGR1555Color & 0xFF00) >> 8);

                                colorindex++;
                            }

                            file.rdtSubfileDataList.Add(newPalette);

                            //create binary image here

                            rdtSubfileData newImage = new rdtSubfileData();
                            newImage.subfileType = 0x04;

                            int fakeWidth = images[j].Width;       //fakewidth should only be used when setting the size of the byte array, and nowhere else!

                            if (file.RDTSpriteBPP == 4)
                            {
                                while (fakeWidth % 2 != 0)
                                {
                                    fakeWidth++;
                                }
                                newImage.filebytes = new byte[8 + ((fakeWidth / 2) * images[j].Height)];
                            }
                            else
                            {
                                newImage.filebytes = new byte[8 + (fakeWidth * images[j].Height)];
                            }

                            form1.WriteU16ToArray(newImage.filebytes, 0, (ushort)images[j].Width);
                            form1.WriteU16ToArray(newImage.filebytes, 2, (ushort)images[j].Height);
                            form1.WriteU16ToArray(newImage.filebytes, 4, offsetsX[j]);
                            form1.WriteU16ToArray(newImage.filebytes, 6, offsetsY[j]);

                            int curOffset = 8;

                            Bitmap imageTemp = (Bitmap)images[j];

                            Color newPixel;

                            if (file.RDTSpriteBPP == 4)
                            {
                                for (int y = 0; y < imageTemp.Height; y++)
                                {
                                    for (int x = 0; x < imageTemp.Width; x++)
                                    {
                                        newPixel = imageTemp.GetPixel(x, y);
                                        newImage.filebytes[curOffset] = (byte)(newImage.filebytes[curOffset] | (byte)form1.FindIndexOfColorInPalette(palette, Color.FromArgb(newPixel.A, newPixel.R & 0xF8, newPixel.G & 0xF8, newPixel.B & 0xF8)));
                                        if (x < imageTemp.Width - 1)
                                        {
                                            x++;
                                            newPixel = imageTemp.GetPixel(x, y);
                                            newImage.filebytes[curOffset] = (byte)(newImage.filebytes[curOffset] | (byte)(form1.FindIndexOfColorInPalette(palette, Color.FromArgb(newPixel.A, newPixel.R & 0xF8, newPixel.G & 0xF8, newPixel.B & 0xF8)) << 4));
                                        }

                                        curOffset++;
                                    }
                                }
                            }
                            else
                            {
                                for (int y = 0; y < imageTemp.Height; y++)
                                {
                                    for (int x = 0; x < imageTemp.Width; x++)
                                    {
                                        newPixel = imageTemp.GetPixel(x, y);
                                        newImage.filebytes[curOffset] = (byte)form1.FindIndexOfColorInPalette(palette, Color.FromArgb(newPixel.A, newPixel.R & 0xF8, newPixel.G & 0xF8, newPixel.B & 0xF8));
                                        curOffset++;
                                    }
                                }
                            }

                            file.rdtSubfileDataList.Add(newImage);
                        }
                    }

                    form1.WriteU16ToArray(file.rdtSubfileDataList[2].filebytes, 0, file.RDTSpriteNumFrames);
                    form1.WriteU16ToArray(file.rdtSubfileDataList[2].filebytes, 2, file.RDTSpriteWidth);
                    form1.WriteU16ToArray(file.rdtSubfileDataList[2].filebytes, 4, file.RDTSpriteHeight);
                    file.rdtSubfileDataList[2].filebytes[6] = (byte)file.RDTSpriteBPP;

                    file.rdtSubfileDataList[3].filebytes = new byte[file.RDTSpriteNumFrames * 2];

                    for (int j = 0; j < file.RDTSpriteFrameDurations.Count; j++)
                    {
                        form1.WriteU16ToArray(file.rdtSubfileDataList[3].filebytes, j * 2, file.RDTSpriteFrameDurations[j]);
                    }



                    file.rdtSubfileDataList[1].RebuildFilebytesFromSettings();  //rebuild centre bounds etc config


                    int offsetOfSubfileTable = 0x11 + nodeTree.Length + data.Count;

                    file.rdtSubfileDataList[0].filebytes = new Byte[8 + ((file.rdtSubfileDataList.Count - 1) * 4)];  //make space in the subfile table

                    file.rdtSubfileDataList[0].filebytes[0] = 2;
                    file.rdtSubfileDataList[0].filebytes[4] = 1;
                    form1.WriteU16ToArray(file.rdtSubfileDataList[0].filebytes, 0x0A, (ushort)(file.rdtSubfileDataList.Count - 2));

                    int pos_in_subfiletable = 0x0C;


                    //a lot of things need to be updated before the following happens! I don't know if they all read into their filebytes in the first place, so you need to rebuild them first!

                    int spritePaletteOffset = 0; //global palette for the sprite so that it can just be pasted around


                    foreach (rdtSubfileData subfiledata in file.rdtSubfileDataList)
                    {
                        subfiledata.writeAddress = 0;

                        int  offsetOfThisSubfile = 0;
                        bool dontWrite           = false;

                        int offset_in_subfiletable_where_address_should_be_written = (offsetOfSubfileTable - (0x11 + nodeTree.Length)) + pos_in_subfiletable;

                        if (file.rdtSubfileDataList.IndexOf(subfiledata) > 0) //if it's not the subfile table, add an entry to the subfile table
                        {
                            if (offsetOfThisSubfile == 0)                     //if it wasn't written to by the previous check
                            {
                                offsetOfThisSubfile      = 0x11 + nodeTree.Length + data.Count;
                                subfiledata.writeAddress = offsetOfThisSubfile;
                            }

                            if (subfiledata.graphicsType == "palette" && spritePaletteOffset != 0)  //if it's not the first palette to be processed, just store a reference to the earlier palette
                            {
                                dontWrite           = true;
                                offsetOfThisSubfile = spritePaletteOffset;
                            }
                            else if (subfiledata.graphicsType == "palette") //but if it is the first one, store its offset so we can reference it later
                            {
                                spritePaletteOffset = offsetOfThisSubfile;
                            }


                            subfiledata.writeAddress = offsetOfThisSubfile;


                            data[offset_in_subfiletable_where_address_should_be_written]     = (byte)(offsetOfThisSubfile & 0x000000FF);
                            data[offset_in_subfiletable_where_address_should_be_written + 1] = (byte)((offsetOfThisSubfile & 0x0000FF00) >> 8);
                            data[offset_in_subfiletable_where_address_should_be_written + 2] = (byte)((offsetOfThisSubfile & 0x00FF0000) >> 16);
                            data[offset_in_subfiletable_where_address_should_be_written + 3] = (byte)((offsetOfThisSubfile & 0xFF000000) >> 24);

                            if (pos_in_subfiletable == 0x0C)
                            {
                                pos_in_subfiletable += 2;
                            }

                            pos_in_subfiletable += 4;
                        }

                        //now write the subfile file into data

                        if (dontWrite)  //if it's just an instance of an existing subfile, don't write a new one
                        {
                            continue;
                        }


                        //compress if needed

                        if (subfiledata.subfileType == 0x04)
                        {
                            subfiledata.filebytes = DSDecmp.NewestProgram.Compress(subfiledata.filebytes, new DSDecmp.Formats.Nitro.LZ10());
                        }

                        //check for identical files that were already processed

                        if (file.rdtSubfileDataList.IndexOf(subfiledata) > 0 && subfiledata.graphicsType != "palette")
                        {
                            foreach (Byte[] alreadyProcessedFile in AlreadyProcessedFilesAndOffsetsInData.Keys) //if this file is equal to one that was already processed
                            {
                                if (ByteArraysAreEqual(alreadyProcessedFile, subfiledata.filebytes))
                                {
                                    //this file is identical to one that was already processed, so just store a reference to the existing one
                                    dontWrite = true;

                                    data[offset_in_subfiletable_where_address_should_be_written]     = (byte)AlreadyProcessedFilesAndOffsetsInData[alreadyProcessedFile];
                                    data[offset_in_subfiletable_where_address_should_be_written + 1] = (byte)(AlreadyProcessedFilesAndOffsetsInData[alreadyProcessedFile] >> 8);
                                    data[offset_in_subfiletable_where_address_should_be_written + 2] = (byte)(AlreadyProcessedFilesAndOffsetsInData[alreadyProcessedFile] >> 16);
                                    data[offset_in_subfiletable_where_address_should_be_written + 3] = (byte)(AlreadyProcessedFilesAndOffsetsInData[alreadyProcessedFile] >> 24);
                                    break;
                                }
                            }
                        }


                        if (dontWrite)  //check again for dontwrite
                        {
                            continue;
                        }

                        //otherwise, write subfiletype and size, then write filebytes

                        AlreadyProcessedFilesAndOffsetsInData.Add(subfiledata.filebytes, offsetOfThisSubfile);
                        //Console.WriteLine(AlreadyProcessedFilesAndOffsetsInData.Count);

                        data.Add((byte)subfiledata.subfileType);
                        data.Add((byte)0);

                        data.Add((byte)(subfiledata.filebytes.Length & 0x000000FF));
                        data.Add((byte)((subfiledata.filebytes.Length & 0x0000FF00) >> 8));
                        data.Add((byte)((subfiledata.filebytes.Length & 0x00FF0000) >> 16));
                        data.Add((byte)((subfiledata.filebytes.Length & 0xFF000000) >> 24));

                        foreach (Byte b in subfiledata.filebytes)
                        {
                            data.Add(b);
                        }
                    }

                    form1.WriteU32ToArray(nodeTree, basePos + (i * 5) + 1, (uint)offsetOfSubfileTable); //write offset of the subfile table to the last node in the string

                    file.rdtSubfileDataList = backuplist;
                }
                else
                {
                    nodeTree[basePos + (i * 5)] = (byte)node.Nodes[i].Text[0];
                    form1.WriteU32ToArray(nodeTree, basePos + (i * 5) + 1, 0x11 + (uint)posInNodeTree);
                    AddSubNodesToByteArray(node.Nodes[i], nodeTree);
                }
            }
        }
Exemple #9
0
        private void compareArcs_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog1 = new OpenFileDialog();

            openFileDialog1.Title           = "Select first arc file";
            openFileDialog1.CheckFileExists = true;
            openFileDialog1.CheckPathExists = true;

            openFileDialog1.Filter = "1PP archives (*.arc)|*.arc";
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                OpenFileDialog openFileDialog2 = new OpenFileDialog();

                openFileDialog2.Title           = "Select second arc file";
                openFileDialog2.CheckFileExists = true;
                openFileDialog2.CheckPathExists = true;

                openFileDialog1.Filter = "1PP archives (*.arc)|*.arc";
                if (openFileDialog2.ShowDialog() == DialogResult.OK)
                {
                    arcfile arc1 = new arcfile();
                    arc1.arcname   = Path.GetFileName(openFileDialog1.FileName);
                    arc1.filename  = openFileDialog1.FileName;
                    arc1.filebytes = File.ReadAllBytes(openFileDialog1.FileName);
                    arc1.form1     = form1;
                    arc1.ReadArc();

                    arcfile arc2 = new arcfile();
                    arc2.arcname   = Path.GetFileName(openFileDialog2.FileName);
                    arc2.filename  = openFileDialog2.FileName;
                    arc2.filebytes = File.ReadAllBytes(openFileDialog2.FileName);
                    arc2.form1     = form1;
                    arc2.ReadArc();

                    List <string> report = new List <string>();

                    foreach (archivedfile f in arc1.archivedfiles)
                    {
                        if (arc2.GetFileWithHash(f.hash) == null)
                        { //if arc2 straight up doesn't have it
                            string evaluatedFilename = f.filename;
                            if (f.filename == "FILENAME_NOT_SET")
                            {
                                evaluatedFilename = f.hash.ToString();
                            }

                            report.Add("File " + evaluatedFilename + " was present in " + Path.GetFileNameWithoutExtension(arc1.filename) + ", but not " + Path.GetFileNameWithoutExtension(arc2.filename) + "!");
                        }
                        else
                        {
                            archivedfile equivalent = arc2.GetFileWithHash(f.hash);
                            if (equivalent != null)
                            {
                                f.ReadFile();
                                equivalent.ReadFile();
                                if (f.filebytes.Length != equivalent.filebytes.Length)
                                { //if it's present in both, but with different filesizes
                                    string evaluatedFilename = f.filename;
                                    if (f.filename == "FILENAME_NOT_SET")
                                    {
                                        evaluatedFilename = f.hash.ToString();
                                    }

                                    report.Add("File " + evaluatedFilename + " was present in both archives, but is a different size in " + Path.GetFileNameWithoutExtension(arc2.filename) + "!");
                                }
                            }
                        }
                    }

                    foreach (archivedfile f in arc2.archivedfiles)
                    {
                        if (arc1.GetFileWithHash(f.hash) == null)
                        { //if arc1 straight up doesn't have it
                            string evaluatedFilename = f.filename;
                            if (f.filename == "FILENAME_NOT_SET")
                            {
                                evaluatedFilename = f.hash.ToString();
                            }
                            report.Add("File " + evaluatedFilename + " was present in " + Path.GetFileNameWithoutExtension(arc2.filename) + ", but not " + Path.GetFileNameWithoutExtension(arc1.filename) + "!");
                        }
                        //don't need to do the second part again because it was already two-way
                    }

                    SaveFileDialog saveFileDialog1 = new SaveFileDialog();
                    saveFileDialog1.Filter = ".txt files (*.txt)|*.txt";
                    saveFileDialog1.Title  = "Save report";

                    if (saveFileDialog1.ShowDialog() == DialogResult.OK)
                    {
                        File.WriteAllLines(saveFileDialog1.FileName, report.ToArray());
                    }
                }
            }
        }