PPMを解析するクラス

先日作ったC#用のうごメモPPMファイルを解析するクラスです。
アニメーションデータサイズなどの触れる必要のないものは隠蔽してしまいます。
また、新しく作る必要がないので、コンストラクタはprotected、書き換える必要もないのでプロパティはすべてgetアクセサのみ実装です。
最初がPARAになっていないファイルはNotUgoMemoFile例外を出します。
チェックは適当。

        class NotUgoMemoFile : Exception
        {
            public NotUgoMemoFile() : base("このファイルはうごメモPPMファイルではありません。") { }
        }

        class UgoMemo
        {
            protected UgoMemo() { } //コンストラクタは公開されない

            //private
            uint magicNumber;       //ファイルタイプ。常に「PARA」が指定されていなければならない
            uint animationSize;     //アニメーションデータサイズ
            uint soundSize;         //音声データのサイズ
            ushort frameLength;     //フレーム数(ページ-1)
            ushort unKnow;          //不明なデータ(0x2400で固定)
            ushort locked;          //ロック(0でなし。1でロック)
            ushort savedFrame;      //サムネイル表示されているページ番号
            char[] originalAuthorName;  //原作者名
            char[] parentAuthorName;    //親作者名
            char[] userName;            //作者名
            ulong parentAuthorID;       //親作者ID
            ulong userAuthorID;         //作者ID
            byte[] parentMemoID;        //親作ID
            byte[] memoID;              //このメモのID
            ulong originalAuthorID;     //原作者ID
            byte[] partialFileName;     //?不明
            uint timeStamp;             //最終変更日(2000年からの経過秒)
            ushort filter;              //フィルタ。0x0000

            //static
            static int PARA = 0x41524150;   //うごメモPPMファイル識別子

            //public property (GetOnly)
            /// <summary>
            /// フレーム数。ページ数-1
            /// </summary>
            public int FrameLength { get { return frameLength; } }
            /// <summary>
            /// ロック状態(ロックでtrue)
            /// </summary>
            public bool Locked { get { return locked == 1; } }
            /// <summary>
            /// 最後に保存されたフレーム。サムネイルのページ
            /// </summary>
            public int SavedFrame { get { return savedFrame; } }
            /// <summary>
            /// 原作者名
            /// </summary>
            public string OriginalAuthorName { get { return new string(originalAuthorName).Trim(); } }
            /// <summary>
            /// 親作者名
            /// </summary>
            public string ParetAuthorName { get { return new string(parentAuthorName).Trim(); } }
            /// <summary>
            /// 作者名
            /// </summary>
            public string UserName { get { return new string(userName).Trim(); } }
            /// <summary>
            /// 更新日
            /// </summary>
            public DateTime TimeStamp { get { var dt = new DateTime(2000, 1, 1); return dt.AddSeconds(timeStamp);} }
        /// <summary>
        /// 作者ID
        /// </summary>
        public string UserAuthorID { get { return this.userAuthorID.ToString("X16"); } }
        /// <summary>
        /// 親作者ID
        /// </summary>
        public string ParentAuthorID { get { return this.parentAuthorID.ToString("X16"); } }
        /// <summary>
        /// 原作者ID
        /// </summary>
        public string OriginalAuthorID { get { return this.originalAuthorID.ToString("X16"); } }
            /// <summary>
            /// このメモのファイル名
            /// </summary>
            public string MemoFileName
            {
                get
                {
                    return memoID[0x0].ToString("X2") + memoID[0x1].ToString("X2") + memoID[0x2].ToString("X2")
                        + "_" + Encoding.ASCII.GetString(memoID, 3, 13) + "_" + (memoID[0x10] + (memoID[0x11] * 10)).ToString("000") + ".ppm";
                }
            }
            /// <summary>
            /// 親作品のファイル名
            /// </summary>
            public string ParentFileName
            {
                get
                {
                    return parentMemoID[0x0].ToString("X2") + parentMemoID[0x1].ToString("X2") + parentMemoID[0x2].ToString("X2")
                        + "_" + Encoding.ASCII.GetString(parentMemoID, 3, 13) + "_" + (parentMemoID[0x10] + (parentMemoID[0x11] * 10)).ToString("000") + ".ppm";
                }
            }

            //public method

            public static UgoMemo LoadFile(string FileName)
            {
                using (FileStream fs = new FileStream(FileName, FileMode.Open, FileAccess.Read))
                {
                    return LoadFile(fs);
                }
            }

            /// <summary>
            /// PPMファイルを読み込む
            /// </summary>
            /// <param name="s">PPMファイルのストリーム</param>
            /// <returns>読み込まれたUgoMemoクラスのインスタンス</returns>
            public static UgoMemo LoadFile(Stream s)
            {
                using (BinaryReader br = new BinaryReader(s, Encoding.Unicode))
                {
                    UgoMemo u = new UgoMemo();

                    u.magicNumber = br.ReadUInt32();
                    u.soundSize = br.ReadUInt32();
                    if (u.magicNumber != PARA) throw new NotUgoMemoFile();  //マジックナンバーチェックで例外
                    u.animationSize = br.ReadUInt32();
                    u.frameLength = br.ReadUInt16();
                    u.unKnow = br.ReadUInt16();
                    u.locked = br.ReadUInt16();
                    u.savedFrame = br.ReadUInt16();
                    u.originalAuthorName = br.ReadChars(11);
                    u.parentAuthorName = br.ReadChars(11);
                    u.userName = br.ReadChars(11);
                    u.parentAuthorID = br.ReadUInt64();
                    u.userAuthorID = br.ReadUInt64();
                    u.parentMemoID = br.ReadBytes(18);
                    u.memoID = br.ReadBytes(18);
                    u.originalAuthorID = br.ReadUInt64();
                    u.partialFileName = br.ReadBytes(8);
                    u.timeStamp = br.ReadUInt32();
                    u.filter = br.ReadUInt16();

                    return u;
                }
            }


        }


ところで、PPMファイルには、「ページ透過」というなぞの指定が。いったいなんだ?これ。このころはバージョン1で、上紙を消すということもないはずだし。
・・・というか、上紙、下紙の表示情報はどこだ?もしや0x9Eのあたりか!?
確認せねば。

2011/4/30 : ID関係の間違いを修正