Example #1
0
        /// <summary>
        /// Parse a flipnote's raw bytes
        /// </summary>
        /// <param name="bytes">Raw Flipnote Bytes</param>
        public void Parse(byte[] bytes)
        {
            var br = new BinaryReader(new MemoryStream(bytes));

            if (!br.ReadChars(4).SequenceEqual(FileMagic))
            {
                throw new Exception("Unexpected file format");
            }
            AnimationDataSize   = br.ReadUInt32();
            SoundDataSize       = br.ReadUInt32();
            FrameCount          = (ushort)(br.ReadUInt16() + 1);
            FormatVersion       = br.ReadUInt16();
            IsLocked            = br.ReadUInt16() != 0;
            ThumbnailFrameIndex = br.ReadUInt16();
            string rootname    = br.ReadWChars(11);
            string parentname  = br.ReadWChars(11);
            string currentname = br.ReadWChars(11);
            ulong  parentid    = br.ReadUInt64();
            ulong  currentid   = br.ReadUInt64();

            ParentFilename  = br.ReadPPMFilename();
            CurrentFilename = br.ReadPPMFilename();
            ulong rootid = br.ReadUInt64();

            RootAuthor       = new PPMAuthor(rootname, rootid);
            ParentAuthor     = new PPMAuthor(parentname, parentid);
            CurrentAuthor    = new PPMAuthor(currentname, currentid);
            RootFileFragment = br.ReadPPMFileFragment();
            Timestamp        = br.ReadPPMTimestamp();
            br.ReadUInt16(); // 0x9E
            Thumbnail            = br.ReadPPMThumbnail();
            FrameOffsetTableSize = br.ReadUInt16();
            br.ReadUInt32(); //0x6A2 - always 0
            AnimationFlags = br.ReadUInt16();
            var oCnt = FrameOffsetTableSize / 4.0 - 1;

            _animationOffset = new uint[(int)oCnt + 1];
            Frames           = new PPMLib.PPMFrame[FrameCount];
            for (var x = 0; x <= oCnt; x++)
            {
                _animationOffset[x] = br.ReadUInt32();
            }
            long framePos0 = br.BaseStream.Position;
            var  offset    = framePos0; //&H6A8 + FrameOffsetTableSize

            for (var x = 0; x <= oCnt; x++)
            {
                if (offset + _animationOffset[x] == 4288480943)
                {
                    throw new Exception("Data corrupted (possible memory pit?)");
                }
                br.BaseStream.Seek(offset + _animationOffset[x], SeekOrigin.Begin);
                Frames[x] = br.ReadPPMFrame();
                Frames[x].AnimationIndex = Array.IndexOf(_animationOffset, _animationOffset[x]);
                if (x > 0)
                {
                    Frames[x].Overwrite(Frames[x - 1]);
                }
            }

            // Read Sound Data
            if (SoundDataSize == 0)
            {
                return;
            }

            offset = 0x6A0 + AnimationDataSize;
            br.BaseStream.Seek(offset, SeekOrigin.Begin);
            SoundEffectFlags = new byte[Frames.Length];
            Audio            = new PPMAudio();
            for (int i = 0; i < Frames.Length; i++)
            {
                SoundEffectFlags[i] = br.ReadByte();
            }
            offset += Frames.Length;

            // make the next offset dividable by 4
            br.ReadBytes((int)((4 - offset % 4) % 4));

            Audio.SoundData   = new _SoundData();
            Audio.SoundHeader = new _SoundHeader();

            Audio.SoundHeader.BGMTrackSize           = br.ReadUInt32();
            Audio.SoundHeader.SE1TrackSize           = br.ReadUInt32();
            Audio.SoundHeader.SE2TrackSize           = br.ReadUInt32();
            Audio.SoundHeader.SE3TrackSize           = br.ReadUInt32();
            Audio.SoundHeader.CurrentFramespeed      = (byte)(8 - br.ReadByte());
            Audio.SoundHeader.RecordingBGMFramespeed = (byte)(8 - br.ReadByte());

            //
            Framerate = PPM_FRAMERATES[Audio.SoundHeader.CurrentFramespeed];
            BGMRate   = PPM_FRAMERATES[Audio.SoundHeader.RecordingBGMFramespeed];
            br.ReadBytes(14);

            Audio.SoundData.RawBGM = br.ReadBytes((int)Audio.SoundHeader.BGMTrackSize);
            Audio.SoundData.RawSE1 = br.ReadBytes((int)Audio.SoundHeader.SE1TrackSize);
            Audio.SoundData.RawSE2 = br.ReadBytes((int)Audio.SoundHeader.SE2TrackSize);
            Audio.SoundData.RawSE3 = br.ReadBytes((int)Audio.SoundHeader.SE3TrackSize);

            // Read Signature (Will implement later)
            if (br.BaseStream.Position == br.BaseStream.Length)
            {
                // file is RSA unsigned -> do something...
            }
            else
            {
                // Next 0x80 bytes = RSA-1024 SHA-1 signature
                Signature = br.ReadBytes(0x80);
                var padding = br.ReadBytes(0x10);
                // Next 0x10 bytes are filled with 0
            }
        }
Example #2
0
        public static PPMFile Create(PPMAuthor author, List <PPMFrame> frames, byte[] audio, bool ignoreMetadata = false)
        {
            var file = new PPMFile();

            file.FrameCount    = (ushort)(frames.Count - 1);
            file.FormatVersion = 0x24;

            if (!ignoreMetadata)
            {
                file.RootAuthor    = author;
                file.ParentAuthor  = author;
                file.CurrentAuthor = author;

                string mac6 = string.Join("", BitConverter.GetBytes(author.Id).Take(3).Reverse().Select(t => t.ToString("X2")));
                var    asm  = Assembly.GetEntryAssembly().GetName().Version;
                var    dt   = DateTime.UtcNow;
                var    fnVM = ((byte)asm.Major).ToString("X2");
                var    fnVm = ((byte)asm.Minor).ToString("X2");
                var    fnYY = (byte)(dt.Year - 2009);
                var    fnMD = dt.Month * 32 + dt.Day;
                var    fnTi = (((dt.Hour * 3600 + dt.Minute * 60 + dt.Second) % 4096) >> 1) + (fnMD > 255 ? 1 : 0);
                fnMD = (byte)fnMD;
                var fnYMD = (fnYY << 9) + fnMD;
                var H6_9  = fnYMD.ToString("X4");
                var H89   = ((byte)fnMD).ToString("X2");
                var HABC  = fnTi.ToString("X3");

                string _13str   = $"80{fnVM}{fnVm}{H6_9}{HABC}";
                string nEdited  = 0.ToString().PadLeft(3, '0');
                var    filename = $"{mac6}_{_13str}_{nEdited}.ppm";


                var rawfn = new byte[18];
                for (int i = 0; i < 3; i++)
                {
                    rawfn[i] = byte.Parse("" + mac6[2 * i] + mac6[2 * i + 1], System.Globalization.NumberStyles.HexNumber);
                }
                for (int i = 3; i < 16; i++)
                {
                    rawfn[i] = (byte)_13str[i - 3];
                }
                rawfn[16] = rawfn[17] = 0;

                file.ParentFilename  = new PPMFilename(rawfn);
                file.CurrentFilename = new PPMFilename(rawfn);

                var ByteRootFileFragment = new byte[8];
                for (int i = 0; i < 3; i++)
                {
                    ByteRootFileFragment[i] =
                        byte.Parse("" + mac6[2 * i] + mac6[2 * i + 1], System.Globalization.NumberStyles.HexNumber);
                }
                for (int i = 3; i < 8; i++)
                {
                    ByteRootFileFragment[i] =
                        (byte)((byte.Parse("" + _13str[2 * (i - 3)], System.Globalization.NumberStyles.HexNumber) << 4)
                               + byte.Parse("" + _13str[2 * (i - 3) + 1], System.Globalization.NumberStyles.HexNumber));
                }

                file.RootFileFragment = new PPMFileFragment(ByteRootFileFragment);

                file.Timestamp           = new PPMTimestamp((uint)((dt - new DateTime(2000, 1, 1, 0, 0, 0)).TotalSeconds));
                file.Thumbnail           = new PPMThumbnail(new byte[0x600]);
                file.ThumbnailFrameIndex = 0;
            }
            // write the audio data

            uint animDataSize = (uint)(8 + 4 * frames.Count);

            file.AnimationFlags       = 0x43;
            file.FrameOffsetTableSize = (ushort)(4 * frames.Count);

            file.Frames = new PPMFrame[frames.Count];
            //SoundEffectFlags = new byte[frames.Count];

            for (int i = 0; i < frames.Count; i++)
            {
                file.Frames[i] = frames[i];


                animDataSize += (uint)file.Frames[i].ToByteArray().Length;
            }
            while ((animDataSize & 0x3) != 0)
            {
                animDataSize++;
            }
            file.AnimationDataSize = animDataSize;

            file.Audio = new PPMAudio();
            file.Audio.SoundData.RawBGM         = audio;
            file.Audio.SoundHeader.BGMTrackSize = (uint)file.Audio.SoundData.RawBGM.Length;
            file.Audio.SoundHeader.SE1TrackSize = 0;
            file.Audio.SoundHeader.SE2TrackSize = 0;
            file.Audio.SoundHeader.SE2TrackSize = 0;
            file.SoundDataSize = (uint)file.Audio.SoundData.RawBGM.Length;

            file.Audio.SoundHeader.CurrentFramespeed      = 0;
            file.Audio.SoundHeader.RecordingBGMFramespeed = 0;

            return(file);
        }