예제 #1
0
        /// <summary>
        /// Creates a new instance of a LuigiDataBlock by inflating it from a BinaryReader.
        /// </summary>
        /// <param name="reader">The binary reader containing the data to deserialize to create the object.</param>
        /// <returns>A new instance of a LuigiDataBlock.</returns>
        /// <remarks>It is assumed that the reader is currently positioned at the beginning of a serialized LUIGI data block.</remarks>
        public static LuigiDataBlock Inflate(INTV.Core.Utility.BinaryReader reader)
        {
            LuigiDataBlock dataBlock = null;
            var            blockType = (LuigiDataBlockType)reader.ReadByte();

            switch (blockType)
            {
            case LuigiDataBlockType.SetScrambleKey:
                dataBlock = new LuigiScrambleKeyBlock();
                break;

            case LuigiDataBlockType.MemoryMapAndPermissionsTable:
                dataBlock = new LuigiMemoryMapAndPermissionsTableBlock();
                break;

            case LuigiDataBlockType.DataHunk:
                dataBlock = new LuigiDataHunkBlock();
                break;

            case LuigiDataBlockType.Metadata:
                dataBlock = new LuigiMetadataBlock();
                break;

            case LuigiDataBlockType.EndOfFile:
                dataBlock = new LuigiEndOfFileBlock();
                break;

            default:
                dataBlock = new LuigiDataBlock((LuigiDataBlockType)blockType);
                break;
            }
            dataBlock._deserializeByteCount  = BlockTypeSize;
            dataBlock._deserializeByteCount += dataBlock.Deserialize(reader);
            return(dataBlock);
        }
예제 #2
0
        /// <inheritdoc/>
        protected override uint DeserializePayload(INTV.Core.Utility.BinaryReader reader)
        {
            var bytesParsed = 0u;

            while (bytesParsed < Length)
            {
                bytesParsed += ParseCreditRecord(reader, bytesParsed);
            }
            return(Length);
        }
예제 #3
0
        /// <summary>
        /// Creates a new instance of a LuigiDataBlock by inflating it from a Stream.
        /// </summary>
        /// <param name="stream">The stream containing the data to deserialize to create the object.</param>
        /// <returns>A new instance of a LuigiDataBlock.</returns>
        public static LuigiDataBlock Inflate(System.IO.Stream stream)
        {
            LuigiDataBlock dataBlock = null;

            using (var reader = new INTV.Core.Utility.BinaryReader(stream))
            {
                dataBlock = Inflate(reader);
            }
            return(dataBlock);
        }
예제 #4
0
        /// <summary>
        /// Parses string metadata, checking for invalid content.
        /// </summary>
        /// <param name="reader">A binary reader to use to get the data.</param>
        /// <param name="payloadLength">Payload length of the metadata to parse, in bytes.</param>
        /// <param name="allowLineBreaks">If <c>true</c>, line breaks are allowed in the string and preserved; otherwise, line breaks are considered invalid and a string containing one is rejected.</param>
        /// <returns>The string as parsed. If invalid characters are found, an empty string is returned.</returns>
        public static string ParseStringFromMetadata(this INTV.Core.Utility.BinaryReader reader, uint payloadLength, bool allowLineBreaks)
        {
            // PCLs only support UTF-8...
            // LUIGI documentation indicates this could be ASCII or UTF-8 (LUIGI)...
            // ROM metadata spec supports UTF-8 as of jzintv version 1843 and later. Let's hope we don't run into anything *too* weird.
            var bytes        = reader.ReadBytes((int)payloadLength);
            var stringResult = System.Text.Encoding.UTF8.GetString(bytes, 0, bytes.Length).Trim('\0');

            return(stringResult);
        }
예제 #5
0
        private uint ParseCreditRecord(INTV.Core.Utility.BinaryReader reader, uint runningTotal)
        {
            // The format of the Credits block consists of:
            // 1 byte bit-field describing which credits apply to the subsequent name
            // EITHER a 1-byte shorthand for the name (0x80-0xFF), or, a NULL-terminated UTF-8 string for the name.
            var bytesParsed = 0u;
            var creditFlags = (CreditFlags)reader.ReadByte();

            ++bytesParsed;
            ++runningTotal;

            var name      = string.Empty;
            var character = reader.ReadByte();

            ++bytesParsed;
            ++runningTotal;

            if (!Authors.TryGetValue(character, out name))
            {
                // Discard the "stuffing" byte that indicates  UTF-8 or 0x01 should follow.
                if (character == 0x01)
                {
                    character = reader.ReadByte();
                    ++bytesParsed;
                    ++runningTotal;
                }

                var nameBuffer = new List <byte>();
                nameBuffer.Add(character);

                while ((character != 0) && (runningTotal < Length))
                {
                    character = reader.ReadByte();
                    nameBuffer.Add(character);
                    ++bytesParsed;
                    ++runningTotal;
                }

                name = System.Text.Encoding.UTF8.GetString(nameBuffer.ToArray(), 0, nameBuffer.Count).Trim('\0');
            }

            for (int i = 0; i < NumberOfCreditFlags; ++i)
            {
                var credit = (CreditFlags)(1 << i);
                if (creditFlags.HasFlag(credit))
                {
                    AddCredit(credit, name);
                }
            }
            return(bytesParsed);
        }
예제 #6
0
            /// <inheritdoc />
            protected override LuigiFileHeader GetMemo(string filePath, object data)
            {
                LuigiFileHeader luigiHeader = null;

                try
                {
                    using (var file = StreamUtilities.OpenFileStream(filePath))
                    {
                        var    reader = new INTV.Core.Utility.BinaryReader(file);
                        byte[] header = reader.ReadBytes(MagicKey.Length);
                        if (header.SequenceEqual(MagicKey))
                        {
                            file.Seek(0, System.IO.SeekOrigin.Begin);
                            luigiHeader = LuigiFileHeader.Inflate(file);
                        }
                    }
                }
                catch (Exception)
                {
                    // Just in case the header looks OK, but turns out to be bad.
                }
                return(luigiHeader);
            }
예제 #7
0
        /// <summary>
        /// Parses a date / time value from ROM metadata.
        /// </summary>
        /// <param name="reader">A binary reader to use to get the data.</param>
        /// <param name="payloadLength">Payload length of the metadata to parse, in bytes.</param>
        /// <returns>A MetadataDateTime that contains the date and time parsed from metadata, as well as flags indicating date and time field validity and specifics.</returns>
        public static MetadataDateTime ParseDateTimeFromMetadata(this INTV.Core.Utility.BinaryReader reader, uint payloadLength)
        {
            var remainingPayload = (int)payloadLength;
            var dateTimeFlags    = MetadataDateTimeFlags.None;

            var year = MetadataDateTime.DefaultYear;

            if (remainingPayload > 0)
            {
                dateTimeFlags |= MetadataDateTimeFlags.Year;
                year           = 1900 + reader.ReadByte();
                --remainingPayload;
            }

            var month = MetadataDateTime.DefaultMonth;

            if (remainingPayload > 0)
            {
                month = reader.ReadByte();
                --remainingPayload;
                var monthRange = new Range <int>(1, 12);
                if (!monthRange.IsValueInRange(month))
                {
                    month = MetadataDateTime.DefaultMonth;
                }
                else
                {
                    dateTimeFlags |= MetadataDateTimeFlags.Month;
                }
            }

            var day = MetadataDateTime.DefaultDay;

            if (remainingPayload > 0)
            {
                day = reader.ReadByte();
                --remainingPayload;
                var dayRange = new Range <int>(1, DateTime.DaysInMonth(year, month));
                if (!dateTimeFlags.HasFlag(MetadataDateTimeFlags.Month) || !dayRange.IsValueInRange(day))
                {
                    day = MetadataDateTime.DefaultDay;
                }
                else
                {
                    dateTimeFlags |= MetadataDateTimeFlags.Day;
                }
            }

            var hour = MetadataDateTime.DefaultHour;

            if (remainingPayload > 0)
            {
                hour = reader.ReadByte();
                --remainingPayload;
                var hourRange = new Range <int>(0, 23);
                if (!dateTimeFlags.HasFlag(MetadataDateTimeFlags.Day) || !hourRange.IsValueInRange(hour))
                {
                    hour = MetadataDateTime.DefaultHour;
                }
                else
                {
                    dateTimeFlags |= MetadataDateTimeFlags.Hour;
                }
            }

            var minute = MetadataDateTime.DefaultMinute;

            if (remainingPayload > 0)
            {
                minute = reader.ReadByte();
                --remainingPayload;
                var minuteRange = new Range <int>(0, 59);
                if (!dateTimeFlags.HasFlag(MetadataDateTimeFlags.Hour) || !minuteRange.IsValueInRange(minute))
                {
                    minute = MetadataDateTime.DefaultMinute;
                }
                else
                {
                    dateTimeFlags |= MetadataDateTimeFlags.Minute;
                }
            }

            var second = MetadataDateTime.DefaultSecond;

            if (remainingPayload > 0)
            {
                second = reader.ReadByte();
                --remainingPayload;
                if (dateTimeFlags.HasFlag(MetadataDateTimeFlags.Minute) && (second == 60))
                {
                    dateTimeFlags |= MetadataDateTimeFlags.LeapSecond | MetadataDateTimeFlags.Second;
                    second         = 59;
                }
                else if (!dateTimeFlags.HasFlag(MetadataDateTimeFlags.Minute) || (second > 59))
                {
                    second = MetadataDateTime.DefaultSecond;
                }
                else
                {
                    dateTimeFlags |= MetadataDateTimeFlags.Second;
                }
            }

            var utcOffsetHours = MetadataDateTime.DefaultUtcOffsetHours;

            if (remainingPayload > 0)
            {
                utcOffsetHours = reader.ReadSByte();
                --remainingPayload;
                var offsetHoursRange = new Range <int>(-12, 12);
                if (!dateTimeFlags.HasFlag(MetadataDateTimeFlags.Second) || !offsetHoursRange.IsValueInRange(utcOffsetHours))
                {
                    utcOffsetHours = MetadataDateTime.DefaultUtcOffsetHours;
                }
                else
                {
                    dateTimeFlags |= MetadataDateTimeFlags.UtcOffset;
                }
            }

            var utcOffsetMinutes = MetadataDateTime.DefaultUtcOffsetMinutes;

            if (remainingPayload > 0)
            {
                utcOffsetMinutes = reader.ReadByte();
                --remainingPayload;
                if (!dateTimeFlags.HasFlag(MetadataDateTimeFlags.UtcOffset) || (utcOffsetMinutes > 59))
                {
                    utcOffsetMinutes = MetadataDateTime.DefaultUtcOffsetMinutes;
                }
                else
                {
                    dateTimeFlags |= MetadataDateTimeFlags.UtcOffset;
                }
            }

            if (remainingPayload > 0)
            {
                System.Diagnostics.Debug.WriteLine("Too many bytes left! Draining...");
                reader.BaseStream.Seek(remainingPayload, System.IO.SeekOrigin.Current);
            }

            var date = DateTimeOffset.MinValue;

            if (dateTimeFlags != MetadataDateTimeFlags.None)
            {
                var offset = dateTimeFlags.HasFlag(MetadataDateTimeFlags.UtcOffset) ? new TimeSpan(utcOffsetHours, utcOffsetMinutes, 0) : TimeSpan.Zero;
                date = new DateTimeOffset(year, month, day, hour, minute, second, offset);
            }

            return(new MetadataDateTime(date, dateTimeFlags));
        }
예제 #8
0
 /// <summary>
 /// Creates a new instance of a LuigiFileHeader by inflating it from a BinaryReader.
 /// </summary>
 /// <param name="reader">The binary reader containing the data to deserialize to create the object.</param>
 /// <returns>A new instance of a LuigiFileHeader.</returns>
 public static LuigiFileHeader Inflate(INTV.Core.Utility.BinaryReader reader)
 {
     return(Inflate <LuigiFileHeader>(reader));
 }