private void UpdateHeader()
        {
            var dataOffset   = HcaInfo.DataOffset;
            var buffer       = new byte[dataOffset];
            var sourceStream = SourceStream;
            var outputStream = _outputStream;

            sourceStream.Seek(0, SeekOrigin.Begin);
            sourceStream.Read(buffer, 0, buffer.Length);
            sourceStream.Seek(0, SeekOrigin.Begin);

            uint v;

            // HCA
            v = sourceStream.PeekUInt32LE();
            if (MagicValues.IsMagicMatch(v, MagicValues.HCA))
            {
                ProcessHeaderSignature(sourceStream, buffer);
                sourceStream.Skip(Marshal.SizeOf(typeof(HcaHeader)));
            }
            // FMT
            v = sourceStream.PeekUInt32LE();
            if (MagicValues.IsMagicMatch(v, MagicValues.FMT))
            {
                ProcessHeaderSignature(sourceStream, buffer);
                sourceStream.Skip(Marshal.SizeOf(typeof(FormatHeader)));
            }
            // COMP / DEC
            v = sourceStream.PeekUInt32LE();
            if (MagicValues.IsMagicMatch(v, MagicValues.COMP))
            {
                ProcessHeaderSignature(sourceStream, buffer);
                sourceStream.Skip(Marshal.SizeOf(typeof(CompressHeader)));
            }
            else if (MagicValues.IsMagicMatch(v, MagicValues.DEC))
            {
                ProcessHeaderSignature(sourceStream, buffer);
                sourceStream.Skip(Marshal.SizeOf(typeof(DecodeHeader)));
            }
            // VBR
            v = sourceStream.PeekUInt32LE();
            if (MagicValues.IsMagicMatch(v, MagicValues.VBR))
            {
                ProcessHeaderSignature(sourceStream, buffer);
                sourceStream.Skip(Marshal.SizeOf(typeof(VbrHeader)));
            }
            // ATH
            v = sourceStream.PeekUInt32LE();
            if (MagicValues.IsMagicMatch(v, MagicValues.ATH))
            {
                ProcessHeaderSignature(sourceStream, buffer);
                sourceStream.Skip(Marshal.SizeOf(typeof(AthHeader)));
            }
            // LOOP
            v = sourceStream.PeekUInt32LE();
            if (MagicValues.IsMagicMatch(v, MagicValues.LOOP))
            {
                ProcessHeaderSignature(sourceStream, buffer);
                sourceStream.Skip(Marshal.SizeOf(typeof(LoopHeader)));
            }
            // CIPH
            v = sourceStream.PeekUInt32LE();
            if (MagicValues.IsMagicMatch(v, MagicValues.CIPH))
            {
                ProcessHeaderSignature(sourceStream, buffer);
                var cipherOffset = (int)(sourceStream.Position + 4);
                var u            = (ushort)_ccTo.CipherType;
                if (BitConverter.IsLittleEndian)
                {
                    u = DereToreHelper.SwapEndian(u);
                }
                var cipherTypeBytes = BitConverter.GetBytes(u);
                buffer[cipherOffset]     = cipherTypeBytes[0];
                buffer[cipherOffset + 1] = cipherTypeBytes[1];
            }
            // RVA
            v = sourceStream.PeekUInt32LE();
            if (MagicValues.IsMagicMatch(v, MagicValues.RVA))
            {
                ProcessHeaderSignature(sourceStream, buffer);
                sourceStream.Skip(Marshal.SizeOf(typeof(RvaHeader)));
            }
            // COMM
            v = sourceStream.PeekUInt32LE();
            if (MagicValues.IsMagicMatch(v, MagicValues.COMM))
            {
                ProcessHeaderSignature(sourceStream, buffer);
                sourceStream.Skip(Marshal.SizeOf(typeof(CommentHeader)));
                byte tmpByte;
                do
                {
                    tmpByte = (byte)sourceStream.ReadByte();
                } while (tmpByte != 0);
            }
            // PAD (undocumented)
            v = sourceStream.PeekUInt32LE();
            if (MagicValues.IsMagicMatch(v, MagicValues.PAD))
            {
                ProcessHeaderSignature(sourceStream, buffer);
                sourceStream.Skip(4);
            }

            FixDataBlock(buffer);
            outputStream.Write(buffer, 0, buffer.Length);
        }
Example #2
0
        internal void ParseHeaders()
        {
            var  stream = SourceStream;
            uint v;
            var  hcaInfo = new HcaInfo();

            // HCA
            v = stream.PeekUInt32LE();
            if (MagicValues.IsMagicMatch(v, MagicValues.HCA))
            {
                HcaHeader header;
                stream.Read(out header);
                hcaInfo.Version    = DereToreHelper.SwapEndian(header.Version);
                hcaInfo.DataOffset = DereToreHelper.SwapEndian(header.DataOffset);
            }
            else
            {
                throw new HcaException("Missing HCA signature.", ActionResult.MagicNotMatch);
            }
            // FMT
            v = stream.PeekUInt32LE();
            if (MagicValues.IsMagicMatch(v, MagicValues.FMT))
            {
                FormatHeader header;
                stream.Read(out header);
                hcaInfo.ChannelCount = header.Channels;
                hcaInfo.SamplingRate = DereToreHelper.SwapEndian(header.SamplingRate << 8);
                hcaInfo.BlockCount   = DereToreHelper.SwapEndian(header.Blocks);
                hcaInfo.FmtR01       = DereToreHelper.SwapEndian(header.R01);
                hcaInfo.FmtR02       = DereToreHelper.SwapEndian(header.R02);
                if (hcaInfo.ChannelCount < 1 || hcaInfo.ChannelCount > 16)
                {
                    throw new HcaException($"Channel count should be between 1 and 16, read {hcaInfo.ChannelCount}.", ActionResult.InvalidFieldValue);
                }
                if (hcaInfo.SamplingRate < 1 || hcaInfo.SamplingRate > 0x7fffff)
                {
                    throw new HcaException($"Sampling rate should be between 1 and {0x7fffffff}, read {hcaInfo.SamplingRate}.", ActionResult.InvalidFieldValue);
                }
            }
            else
            {
                throw new HcaException("Missing FMT signature.", ActionResult.MagicNotMatch);
            }
            // COMP / DEC
            v = stream.PeekUInt32LE();
            if (MagicValues.IsMagicMatch(v, MagicValues.COMP))
            {
                CompressHeader header;
                stream.Read(out header);
                hcaInfo.BlockSize = DereToreHelper.SwapEndian(header.BlockSize);
                hcaInfo.CompR01   = header.R01;
                hcaInfo.CompR02   = header.R02;
                hcaInfo.CompR03   = header.R03;
                hcaInfo.CompR04   = header.R04;
                hcaInfo.CompR05   = header.R05;
                hcaInfo.CompR06   = header.R06;
                hcaInfo.CompR07   = header.R07;
                hcaInfo.CompR08   = header.R08;
                if ((hcaInfo.BlockSize < 8 || hcaInfo.BlockSize > 0xffff) && hcaInfo.BlockSize != 0)
                {
                    throw new HcaException($"Block size should be between 8 and {0xffff}, read {hcaInfo.BlockSize}.", ActionResult.InvalidFieldValue);
                }
                if (!(hcaInfo.CompR01 <= hcaInfo.CompR02 && hcaInfo.CompR02 <= 0x1f))
                {
                    throw new HcaException($"CompR01 should be less than or equal to CompR02, and CompR02 should be less than or equal to {0x1f}, read {hcaInfo.CompR01} and {hcaInfo.CompR02}.", ActionResult.InvalidFieldValue);
                }
            }
            else if (MagicValues.IsMagicMatch(v, MagicValues.DEC))
            {
                DecodeHeader header;
                stream.Read(out header);
                hcaInfo.CompR01 = header.R01;
                hcaInfo.CompR02 = header.R02;
                hcaInfo.CompR03 = header.R04;
                hcaInfo.CompR04 = header.R03;
                hcaInfo.CompR05 = (ushort)(header.Count1 + 1);
                hcaInfo.CompR06 = (ushort)((header.EnableCount2 ? header.Count2 : header.Count1) + 1);
                hcaInfo.CompR07 = (ushort)(hcaInfo.CompR05 - hcaInfo.CompR06);
                hcaInfo.CompR08 = 0;
                if ((hcaInfo.BlockSize < 8 || hcaInfo.BlockSize > 0xffff) && hcaInfo.BlockSize != 0)
                {
                    throw new HcaException($"Block size should be between 8 and {0xffff}, read {hcaInfo.BlockSize}.", ActionResult.InvalidFieldValue);
                }
                if (!(hcaInfo.CompR01 <= hcaInfo.CompR02 && hcaInfo.CompR02 <= 0x1f))
                {
                    throw new HcaException($"CompR01 should be less than or equal to CompR02, and CompR02 should be less than or equal to {0x1f}, read {hcaInfo.CompR01} and {hcaInfo.CompR02}.", ActionResult.InvalidFieldValue);
                }
                if (hcaInfo.CompR03 == 0)
                {
                    hcaInfo.CompR03 = 1;
                }
            }
            else
            {
                throw new HcaException("Missing COMP/DEC signature.", ActionResult.MagicNotMatch);
            }
            // VBR
            v = stream.PeekUInt32LE();
            if (MagicValues.IsMagicMatch(v, MagicValues.VBR))
            {
                VbrHeader header;
                stream.Read(out header);
                hcaInfo.VbrR01 = DereToreHelper.SwapEndian(header.R01);
                hcaInfo.VbrR02 = DereToreHelper.SwapEndian(header.R02);
                if (!(hcaInfo.BlockSize == 0 && hcaInfo.VbrR01 < 0x01ff))
                {
                    throw new HcaException($"VbrR01 should be less than {0x01ff} in VBR HCA.", ActionResult.InvalidFieldValue);
                }
            }
            else
            {
                hcaInfo.VbrR01 = hcaInfo.VbrR02 = 0;
            }
            // ATH
            v = stream.PeekUInt32LE();
            if (MagicValues.IsMagicMatch(v, MagicValues.ATH))
            {
                AthHeader header;
                stream.Read(out header);
                hcaInfo.AthType = header.Type;
            }
            else
            {
                hcaInfo.AthType = (ushort)(hcaInfo.Version < 0x0200 ? 1 : 0);
            }
            // LOOP
            v = stream.PeekUInt32LE();
            if (MagicValues.IsMagicMatch(v, MagicValues.LOOP))
            {
                LoopHeader header;
                stream.Read(out header);
                hcaInfo.LoopStart = DereToreHelper.SwapEndian(header.LoopStart);
                hcaInfo.LoopEnd   = DereToreHelper.SwapEndian(header.LoopEnd);
                hcaInfo.LoopR01   = DereToreHelper.SwapEndian(header.R01);
                hcaInfo.LoopR02   = DereToreHelper.SwapEndian(header.R02);
                hcaInfo.LoopFlag  = true;
            }
            else
            {
                hcaInfo.LoopStart = 0;
                hcaInfo.LoopEnd   = 0;
                hcaInfo.LoopR01   = 0;
                hcaInfo.LoopR02   = 0x400;
                hcaInfo.LoopFlag  = false;
            }
            // CIPH
            v = stream.PeekUInt32LE();
            if (MagicValues.IsMagicMatch(v, MagicValues.CIPH))
            {
                CipherHeader header;
                stream.Read(out header);
                hcaInfo.CipherType = (CipherType)DereToreHelper.SwapEndian(header.Type);
            }
            else
            {
                hcaInfo.CipherType = CipherType.NoChipher;
            }
            // RVA
            v = stream.PeekUInt32LE();
            if (MagicValues.IsMagicMatch(v, MagicValues.RVA))
            {
                RvaHeader header;
                stream.Read(out header);
                hcaInfo.RvaVolume = DereToreHelper.SwapEndian(header.Volume);
            }
            else
            {
                hcaInfo.RvaVolume = 1;
            }
            // COMM
            v = stream.PeekUInt32LE();
            if (MagicValues.IsMagicMatch(v, MagicValues.COMM))
            {
                CommentHeader header;
                stream.Read(out header);
                hcaInfo.CommentLength = header.Length;
                var  tmpCommentCharList = new List <byte>();
                byte tmpByte;
                do
                {
                    tmpByte = (byte)stream.ReadByte();
                    tmpCommentCharList.Add(tmpByte);
                } while (tmpByte != 0);
                hcaInfo.Comment = tmpCommentCharList.ToArray();
            }
            else
            {
                hcaInfo.CommentLength = 0;
                hcaInfo.Comment       = null;
            }
            // PAD (undocumented)
            v = stream.PeekUInt32LE();
            if (MagicValues.IsMagicMatch(v, MagicValues.PAD))
            {
                stream.Skip(4); // Length of 'pad '
            }

            if (hcaInfo.CompR03 == 0)
            {
                hcaInfo.CompR03 = 1;
            }

            if (hcaInfo.CompR01 != 1 || hcaInfo.CompR02 != 0xf)
            {
                throw new HcaException($"Expected CompR01=1, CompR02=15, read {hcaInfo.CompR01}, {hcaInfo.CompR02}.", ActionResult.InvalidFieldValue);
            }
            hcaInfo.CompR09 = HcaHelper.Ceil2((uint)(hcaInfo.CompR05 - (hcaInfo.CompR06 + hcaInfo.CompR07)), hcaInfo.CompR08);
            HcaInfo         = hcaInfo;
        }