예제 #1
0
        public void TestReadTestDGF()
        {
            IDGF test_dgf = DGFIO.OpenDGF("./test.dgf");

            Assert.IsNotNull(test_dgf);
            Assert.AreEqual("Ethem Kurt", test_dgf.AuthorName);
            Assert.AreEqual("https://github.com/BigETI/DGFSharp", test_dgf.Comments);
            Assert.AreEqual((ushort)1, test_dgf.ApplyPlayPasswordUntilGardenNumber);
            Assert.AreEqual("Edit", test_dgf.EditPassword);
            Assert.AreEqual("Play", test_dgf.PlayPassword);
            Assert.AreEqual(3, test_dgf.Garden.Count);
            foreach (IGarden garden in test_dgf.Garden)
            {
                Assert.IsNotNull(garden);
            }
            Assert.AreEqual("DAISYG_5.MID", test_dgf.GardenOneMIDIPath);
            Assert.AreEqual("Round trip around flying ground", test_dgf.Garden[0].Name);
            Assert.AreEqual("Marmot garden", test_dgf.Garden[1].Name);
            Assert.AreEqual("Underground garden", test_dgf.Garden[2].Name);
            Assert.AreEqual(85, test_dgf.Garden[0].Time);
            Assert.AreEqual(120, test_dgf.Garden[1].Time);
            Assert.AreEqual(225, test_dgf.Garden[2].Time);
            Assert.AreEqual("DAISYG_5.MID", test_dgf.Garden[0].MIDIPath);
            Assert.AreEqual("DAISYG_2.MID", test_dgf.Garden[1].MIDIPath);
            Assert.AreEqual("DAISYG_6.MID", test_dgf.Garden[2].MIDIPath);
            Assert.AreEqual(new Size(17, 12), test_dgf.Garden[0].Size);
            Assert.AreEqual(new Size(17, 12), test_dgf.Garden[1].Size);
            Assert.AreEqual(new Size(40, 40), test_dgf.Garden[2].Size);
            Assert.AreEqual(new Position(0, 10), GetDaisysPosition(test_dgf.Garden[0]));
            Assert.AreEqual(new Position(0, 10), GetDaisysPosition(test_dgf.Garden[1]));
            Assert.AreEqual(new Position(1, 4), GetDaisysPosition(test_dgf.Garden[2]));
        }
예제 #2
0
        public void TestOutputDGFFile()
        {
            IDGF test_dgf = DGFIO.OpenDGF("./test.dgf");

            Assert.IsNotNull(test_dgf);
            Assert.IsTrue(test_dgf.Save("./output.dgf"));
            FileAssert.AreEqual("./output.dgf", "./test.dgf");
        }
예제 #3
0
        /// <summary>
        /// Saves Daisy's Garden to the specified file
        /// </summary>
        /// <param name="dgf">Daisy's Garden file</param>
        /// <param name="path">Path</param>
        /// <returns>"true" if successful, otherwise "false"</returns>
        public static bool SaveDGF(IDGF dgf, string path)
        {
            if (dgf == null)
            {
                throw new ArgumentNullException(nameof(dgf));
            }
            if (path == null)
            {
                throw new ArgumentNullException(nameof(path));
            }
            bool ret;

            using (FileStream file_stream = File.OpenWrite(path))
            {
                ret = WriteDGFStream(dgf, file_stream);
            }
            return(ret);
        }
예제 #4
0
        /// <summary>
        /// Main entry point
        /// </summary>
        /// <param name="args">Command line arguments</param>
        private static void Main(string[] args)
        {
            Dictionary <string, string> files = new Dictionary <string, string>();
            string     output_directory       = string.Empty;
            bool       show_help          = false;
            bool       verbose            = false;
            EInputFlag current_input_flag = EInputFlag.Nothing;
            string     last_path          = null;
            string     help_topic         = null;

            foreach (string arg in args)
            {
                string trimmed_arg = arg.Trim().ToLower();
                if (trimmed_arg.Length > 0)
                {
                    if (trimmed_arg[0] == '-')
                    {
                        string    key        = ((trimmed_arg.Length > 1) ? trimmed_arg.Substring(1) : string.Empty);
                        InputFlag?input_flag = null;
                        if (inputFlags.ContainsKey(key))
                        {
                            input_flag = inputFlags[key];
                        }
                        else if (inputFlagAliases.ContainsKey(key))
                        {
                            input_flag = inputFlags[inputFlagAliases[key]];
                        }
                        if (input_flag == null)
                        {
                            Console.Error.Write("Invalid input flag \"");
                            Console.Error.Write(arg);
                            Console.Error.WriteLine("\"");
                        }
                        else
                        {
                            PrintInputFlagError(current_input_flag);
                            current_input_flag = input_flag.Value.Flag;
                            switch (current_input_flag)
                            {
                            case EInputFlag.ShowHelp:
                                show_help = true;
                                break;

                            case EInputFlag.Verbose:
                                verbose            = true;
                                current_input_flag = EInputFlag.Nothing;
                                break;
                            }
                        }
                    }
                    else
                    {
                        switch (current_input_flag)
                        {
                        case EInputFlag.Nothing:
                            if (!(files.ContainsKey(arg)))
                            {
                                files.Add(arg, arg);
                            }
                            last_path = arg;
                            break;

                        case EInputFlag.ShowHelp:
                            help_topic = trimmed_arg;
                            break;

                        case EInputFlag.SpecifyOutputPath:
                            if (last_path == null)
                            {
                                Console.Error.WriteLine("No input path is defined");
                            }
                            else
                            {
                                files[last_path] = arg;
                            }
                            current_input_flag = EInputFlag.Nothing;
                            break;

                        case EInputFlag.SpecifyOutputDirectoryPath:
                            output_directory   = arg;
                            current_input_flag = EInputFlag.Nothing;
                            break;
                        }
                        current_input_flag = EInputFlag.Nothing;
                    }
                }
            }
            PrintInputFlagError(current_input_flag);
            if (show_help || (files.Count <= 0))
            {
                if (help_topic == null)
                {
                    PrintInputFlags();
                }
                else
                {
                    InputFlag?input_flag = null;
                    if (inputFlags.ContainsKey(help_topic))
                    {
                        input_flag = inputFlags[help_topic];
                    }
                    else if (inputFlagAliases.ContainsKey(help_topic))
                    {
                        input_flag = inputFlags[inputFlagAliases[help_topic]];
                    }
                    if (input_flag == null)
                    {
                        Console.Error.Write("Invalid help topic \"");
                        Console.Error.Write(help_topic);
                        Console.Error.WriteLine("\".");
                        PrintInputFlags();
                    }
                    else
                    {
                        Console.WriteLine();
                        Console.Write("Help topic: ");
                        Console.WriteLine(input_flag.Value.Description);
                        Console.WriteLine();
                        string[] full_description = input_flag.Value.FullDescription.Split(Environment.NewLine);
                        if (full_description != null)
                        {
                            foreach (string full_description_line in full_description)
                            {
                                if (full_description_line != null)
                                {
                                    Console.Write("\t");
                                    Console.WriteLine(full_description_line);
                                }
                            }
                        }
                        Console.WriteLine();
                    }
                }
            }
            else
            {
                foreach (KeyValuePair <string, string> file in files)
                {
                    try
                    {
                        string input_file_path = Path.GetFullPath(file.Key);
                        if (File.Exists(input_file_path))
                        {
                            if (verbose)
                            {
                                Console.Write("Opening file \"");
                                Console.Write(input_file_path);
                                Console.WriteLine("\"...");
                            }
                            IDGF dgf = DGFIO.OpenDGF(input_file_path);
                            dgf.EditPassword = string.Empty;
                            dgf.PlayPassword = string.Empty;
                            dgf.ApplyPlayPasswordUntilGardenNumber = 1;
                            if (dgf == null)
                            {
                                Console.Error.Write("Could not open file \"");
                                Console.Error.Write(input_file_path);
                                Console.Error.WriteLine("\".");
                            }
                            else
                            {
                                string output_path    = Path.GetFullPath(Path.Combine(output_directory, file.Value));
                                string directory_path = Path.GetFullPath(Path.GetDirectoryName(output_path));
                                if (!(Directory.Exists(directory_path)))
                                {
                                    Directory.CreateDirectory(directory_path);
                                    if (verbose)
                                    {
                                        Console.Write("Created directory \"");
                                        Console.Write(directory_path);
                                        Console.WriteLine("\".");
                                    }
                                }
                                if (dgf.Save(output_path))
                                {
                                    if (verbose)
                                    {
                                        Console.Write("Created file \"");
                                        Console.Write(output_path);
                                        Console.WriteLine("\".");
                                    }
                                }
                                else
                                {
                                    Console.Error.Write("Failed to write output to \"");
                                    Console.Error.Write(output_path);
                                    Console.Error.WriteLine("\".");
                                }
                            }
                        }
                        else
                        {
                            Console.Error.Write("File \"");
                            Console.Error.Write(input_file_path);
                            Console.Error.WriteLine("\" does not exist.");
                        }
                    }
                    catch (Exception e)
                    {
                        Console.Error.WriteLine(e);
                    }
                }
            }
        }
예제 #5
0
        /// <summary>
        /// Writes to Daisy's Garden file stream
        /// </summary>
        /// <param name="dgf">Daisy's Garden file</param>
        /// <param name="stream">Stream</param>
        /// <returns>"true" if successful, otherwise "false"</returns>
        public static bool WriteDGFStream(IDGF dgf, Stream stream)
        {
            if (dgf == null)
            {
                throw new ArgumentNullException(nameof(dgf));
            }
            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream));
            }
            if (!stream.CanWrite)
            {
                throw new AccessViolationException("Specified DGF stream can not be written to.");
            }
            bool ret = false;

            using (BinaryWriter binary_writer = new BinaryWriter(stream, Encoding.ASCII, true))
            {
                binary_writer.Write(dgfFileHeader);
                WriteDGFString(binary_writer, gameName);
                binary_writer.Write(unknownConstantAfterGameName);
                EncryptAndWriteDGFString(binary_writer, dgf.EditPassword);
                EncryptAndWriteDGFString(binary_writer, dgf.PlayPassword);
                EncryptAndWriteDGFString(binary_writer, dgf.ApplyPlayPasswordUntilGardenNumber.ToString());
                WriteDGFString(binary_writer, dgf.AuthorName);
                WriteDGFString(binary_writer, dgf.Comments);
                WriteDGFString(binary_writer, dgf.GardenOneMIDIPath);
                binary_writer.Write((ushort)dgf.Garden.Count);
                binary_writer.Write(unknownConstantAfterGardenCount);
                binary_writer.Write(Encoding.ASCII.GetBytes(daisysGardenClassName));
                binary_writer.Write(outputVersionNumber);
                bool first = true;
                foreach (IGarden garden_list_item in dgf.Garden)
                {
                    if (first)
                    {
                        first = false;
                    }
                    else
                    {
                        binary_writer.Write(dgfFileGardenSeparator);
                    }
                    WriteDGFString(binary_writer, garden_list_item.Name);
                    WriteDGFString(binary_writer, garden_list_item.MIDIPath);
                    ISize garden_size = garden_list_item.Size;
                    binary_writer.Write(garden_size.Width);
                    binary_writer.Write(garden_size.Height);
                    binary_writer.Write(garden_list_item.Time);
                    binary_writer.Write((uint)(garden_size.Width * garden_size.Height));
                    for (int x, y = 0; y < garden_size.Height; y++)
                    {
                        for (x = 0; x < garden_size.Width; x++)
                        {
                            ETile tile = garden_list_item.GetTile((byte)x, (byte)y);
                            binary_writer.Write((byte)((int)tile & 0xFF));
                            binary_writer.Write((ushort)(((int)tile >> 8) & 0xFFFF));
                        }
                    }
                    binary_writer.Write(garden_list_item.Entities.Count);
                    foreach (IEntity entity in garden_list_item.Entities)
                    {
                        binary_writer.Write((byte)((int)entity.Type & 0xFF));
                        binary_writer.Write((ushort)(((int)entity.Type >> 8) & 0xFFFF));
                        binary_writer.Write(entity.Position.X);
                        binary_writer.Write(entity.Position.Y);
                        switch (entity.Type)
                        {
                        case EEntityType.Marmot:
                        case EEntityType.RightMovingWorm:
                        case EEntityType.LeftMovingWorm:
                        case EEntityType.UpMovingLift:
                        case EEntityType.DownMovingLift:
                        case EEntityType.LeftMovingLift:
                        case EEntityType.RightMovingLift:
                            binary_writer.Write(entity.Bounds.Left);
                            binary_writer.Write(entity.Bounds.Top);
                            binary_writer.Write(entity.Bounds.Right);
                            binary_writer.Write(entity.Bounds.Bottom);
                            break;

                        case EEntityType.QuestionMark:
                            WriteDGFString(binary_writer, entity.Hint);
                            break;
                        }
                    }
                }
                ret = true;
            }
            return(ret);
        }
예제 #6
0
        /// <summary>
        /// Reads Daisy's Garden file stream
        /// </summary>
        /// <param name="stream">Stream</param>
        /// <returns>DGF if successful, otherwise "null"</returns>
        public static IDGF ReadDGFStream(Stream stream)
        {
            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream));
            }
            IDGF ret = null;

            if (!stream.CanRead)
            {
                throw new AccessViolationException("Specified DGF stream can not be read from.");
            }
            using (BinaryReader binary_reader = new BinaryReader(stream, Encoding.ASCII, true))
            {
                if (binary_reader.ReadInt32() != dgfFileHeader)
                {
                    throw new InvalidDataException("File header does not match the expected file header");
                }
                if (ReadDGFString(binary_reader) != gameName)
                {
                    throw new InvalidDataException("Game name does not match the expected game name.");
                }
                if ((binary_reader.ReadInt16() != 0x7) || (binary_reader.ReadByte() != 0x0))
                {
                    throw new InvalidDataException($"Unknown constant after game name does not match the documented unknown constant after game name.");
                }
                string edit_password = ReadAndDecryptDGFString(binary_reader);
                string play_password = ReadAndDecryptDGFString(binary_reader);
                string apply_play_password_until_garden_number_string = ReadAndDecryptDGFString(binary_reader);
                if (!ushort.TryParse(apply_play_password_until_garden_number_string, out ushort apply_play_password_until_garden_number))
                {
                    throw new InvalidDataException($"Failed to parse \"apply play password until garden number\".");
                }
                string author_name          = ReadDGFString(binary_reader);
                string comments             = ReadDGFString(binary_reader);
                string garden_one_midi_path = ReadDGFString(binary_reader);
                ushort number_of_garden     = binary_reader.ReadUInt16();
                byte   constant             = binary_reader.ReadByte();
                bool   failure = true;
                if (constant == 0x0)
                {
                    failure = false;
                }
                else if (constant == 0xFF)
                {
                    if (binary_reader.ReadInt32() == 0x090001FF)
                    {
                        failure = binary_reader.ReadByte() != 0x0;
                    }
                }
                if (failure)
                {
                    throw new InvalidDataException($"Unknown constant after the number of garden does not match to any of the documented values.");
                }
                if (Encoding.ASCII.GetString(binary_reader.ReadBytes(daisysGardenClassName.Length)) != daisysGardenClassName)
                {
                    throw new InvalidDataException($"Incorrect Daisy's Garden class name.");
                }
                ushort program_version = binary_reader.ReadUInt16();
                if ((program_version != 0x1) && (program_version != 0x2))
                {
                    throw new InvalidDataException($"Program version \"{ program_version }\" is not supported.");
                }
                List <IGarden> garden = new List <IGarden>();
                for (ushort garden_index = 0; garden_index != number_of_garden; garden_index++)
                {
                    if ((garden_index > 0) && (binary_reader.ReadInt32() != dgfFileGardenSeparator))
                    {
                        throw new InvalidDataException($"Incorrect garden seperator.");
                    }
                    string garden_name       = ReadDGFString(binary_reader);
                    string garden_midi_path  = ReadDGFString(binary_reader);
                    ushort garden_width      = binary_reader.ReadUInt16();
                    ushort garden_height     = binary_reader.ReadUInt16();
                    ushort garden_time       = binary_reader.ReadUInt16();
                    uint   garden_tile_count = binary_reader.ReadUInt32();
                    if (garden_tile_count != (garden_width * garden_height))
                    {
                        throw new InvalidDataException($"Garden tile count does not match with garden width times garden height.");
                    }
                    ETile[,] tile_grid = new ETile[garden_width, garden_height];
                    for (uint cell_index = 0U; cell_index != garden_tile_count; cell_index++)
                    {
                        byte   tile_id       = binary_reader.ReadByte();
                        ushort tile_variant  = binary_reader.ReadUInt16();
                        ETile  computed_tile = (ETile)(tile_id | (tile_variant << 8));
                        if (tileEnumItems.Contains(computed_tile))
                        {
                            tile_grid[cell_index % garden_width, cell_index / garden_width] = computed_tile;
                        }
                    }
                    uint           number_of_entities = binary_reader.ReadUInt32();
                    List <IEntity> entities           = new List <IEntity>();
                    for (uint entity_index = 0; entity_index < number_of_entities; entity_index++)
                    {
                        byte        entity_type     = binary_reader.ReadByte();
                        ushort      entity_variant  = binary_reader.ReadUInt16();
                        EEntityType computed_entity = (EEntityType)(entity_type | (entity_variant << 8));
                        if (entityEnumItems.Contains(computed_entity))
                        {
                            IPosition position = new Position(binary_reader.ReadUInt16(), binary_reader.ReadUInt16());
                            IBounds   bounds   = Bounds.Infinite;
                            string    hint     = string.Empty;
                            switch (computed_entity)
                            {
                            case EEntityType.Daisy:
                            case EEntityType.RedKey:
                            case EEntityType.YellowKey:
                            case EEntityType.GreenKey:
                            case EEntityType.Apple:
                            case EEntityType.Lemon:
                            case EEntityType.Cherry:
                            case EEntityType.Pineapple:
                            case EEntityType.Garlic:
                            case EEntityType.Mushroom:
                            case EEntityType.Spinach:
                            case EEntityType.Carrot:
                            case EEntityType.Sunflower:
                            case EEntityType.Tulip:
                            case EEntityType.YellowDaisy:
                            case EEntityType.Rose:
                                break;

                            case EEntityType.Marmot:
                            case EEntityType.RightMovingWorm:
                            case EEntityType.LeftMovingWorm:
                            case EEntityType.UpMovingLift:
                            case EEntityType.DownMovingLift:
                            case EEntityType.LeftMovingLift:
                            case EEntityType.RightMovingLift:
                                short left   = binary_reader.ReadInt16();
                                short top    = binary_reader.ReadInt16();
                                short right  = binary_reader.ReadInt16();
                                short bottom = binary_reader.ReadInt16();
                                bounds = new Bounds(top, bottom, left, right);
                                break;

                            case EEntityType.QuestionMark:
                                hint = ReadDGFString(binary_reader);
                                break;

                            default:
                                throw new InvalidDataException($"Invalid entity type \"{ (int)computed_entity }\"");
                            }
                            entities.Add(new Entity(computed_entity, position, bounds, hint));
                        }
                    }
                    garden.Add(new Garden(garden_name, garden_midi_path, garden_time, tile_grid, entities));
                }
                ret = new DGF(edit_password, play_password, apply_play_password_until_garden_number, author_name, comments, garden_one_midi_path, garden);
            }
            return(ret);
        }