Ejemplo n.º 1
0
        private void readChapters(BinaryReader source, long offset, long size)
        {
            source.BaseStream.Seek(offset, SeekOrigin.Begin);
            if (null == tagData.Chapters)
            {
                tagData.Chapters = new List <ChapterInfo>();
            }
            else
            {
                tagData.Chapters.Clear();
            }
            double cumulatedDuration = 0;
            int    idx = 1;

            while (source.BaseStream.Position < offset + size)
            {
                uint chapterSize   = StreamUtils.DecodeBEUInt32(source.ReadBytes(4));
                uint chapterOffset = StreamUtils.DecodeBEUInt32(source.ReadBytes(4));
                structureHelper.AddZone(chapterOffset, (int)chapterSize, "chp" + idx);
                structureHelper.AddIndex(source.BaseStream.Position - 4, chapterOffset, false, "chp" + idx);

                ChapterInfo chapter = new ChapterInfo();
                chapter.Title      = "Chapter " + idx++; // Chapters have no title metatada in the AA format
                chapter.StartTime  = (uint)Math.Round(cumulatedDuration);
                cumulatedDuration += chapterSize / (BitRate * 1000);
                chapter.EndTime    = (uint)Math.Round(cumulatedDuration);
                tagData.Chapters.Add(chapter);

                source.BaseStream.Seek(chapterSize, SeekOrigin.Current);
            }
        }
Ejemplo n.º 2
0
        private void readChannelLayoutChunk(BinaryReader source)
        {
            uint channelLayout = StreamUtils.DecodeBEUInt32(source.ReadBytes(4));

            // we don't need anything else

            if (channelsMapping.ContainsKey(channelLayout))
            {
                channelsArrangement = channelsMapping[channelLayout];
            }
        }
Ejemplo n.º 3
0
        // WARNING : EXPERIMENTAL / UNTESTED DUE TO THE LACK OF METADATA-RICH SAMPLE FILES
        private void readInfoChunk(BinaryReader source, bool readAllMetaFrames)
        {
            uint nbEntries = StreamUtils.DecodeBEUInt32(source.ReadBytes(4));

            for (int i = 0; i < nbEntries; i++)
            {
                string infoKey = StreamUtils.ReadNullTerminatedString(source, Encoding.UTF8);
                string infoVal = StreamUtils.ReadNullTerminatedString(source, Encoding.UTF8);
                SetMetaField(infoKey, infoVal, readAllMetaFrames);
            }
        }
Ejemplo n.º 4
0
        // ---------- SUPPORT METHODS

        private bool readFileHeader(BinaryReader source)
        {
            uint fileType = StreamUtils.DecodeBEUInt32(source.ReadBytes(4));

            if (fileType != CAF_MAGIC_NUMBER)
            {
                return(false);
            }

            source.BaseStream.Seek(4, SeekOrigin.Current); // Useless here

            return(true);
        }
Ejemplo n.º 5
0
        private void readAudioDescriptionChunk(BinaryReader source)
        {
            double sampleRate      = StreamUtils.DecodeBEDouble(source.ReadBytes(8)); // aka frames per second
            string formatId        = Utils.Latin1Encoding.GetString(source.ReadBytes(4));
            uint   formatFlags     = StreamUtils.DecodeBEUInt32(source.ReadBytes(4));
            uint   bytesPerPacket  = StreamUtils.DecodeBEUInt32(source.ReadBytes(4));
            uint   framesPerPacket = StreamUtils.DecodeBEUInt32(source.ReadBytes(4));

            channelsPerFrame = StreamUtils.DecodeBEUInt32(source.ReadBytes(4));
            uint bitsPerChannel = StreamUtils.DecodeBEUInt32(source.ReadBytes(4));

            this.sampleRate = (uint)Math.Round(sampleRate);

            // Compute audio duration
            if (bytesPerPacket > 0)
            {
                double secondsPerPacket = framesPerPacket / sampleRate;
                secondsPerByte = secondsPerPacket / bytesPerPacket;
                // Duration will be determined using the size of 'data' chunk
            }
            else
            {
                secondsPerByte = 0;
                isVbr          = true;
                // Duration will be dertermiend using data from the 'pakt' chunk
            }

            // Determine audio properties according to the format ID
            codecFamily = AudioDataIOFactory.CF_LOSSY;
            switch (formatId)
            {
            case ("lpcm"):
            case ("alac"):
                codecFamily = AudioDataIOFactory.CF_LOSSLESS;
                break;
            }

            // Determine format
            if (formatsMapping.ContainsKey(formatId))
            {
                containeeAudioFormat = formatsMapping[formatId];
            }
            else
            {
                containeeAudioFormat = formatsMapping["none"];
            }
        }
Ejemplo n.º 6
0
        // ---------- SUPPORT METHODS

        private static bool readHeader(BinaryReader source, ref HeaderInfo Header)
        {
            bool result = true;

            // Read header and get file size
            Header.ID            = source.ReadChars(4);
            Header.Version       = source.ReadChars(8);
            Header.Size          = StreamUtils.DecodeBEUInt32(source.ReadBytes(4));
            Header.Common.ID     = Utils.Latin1Encoding.GetString(source.ReadBytes(4));
            Header.Common.Size   = StreamUtils.DecodeBEUInt32(source.ReadBytes(4));
            Header.ChannelMode   = StreamUtils.DecodeBEUInt32(source.ReadBytes(4));
            Header.BitRate       = StreamUtils.DecodeBEUInt32(source.ReadBytes(4));
            Header.SampleRate    = StreamUtils.DecodeBEUInt32(source.ReadBytes(4));
            Header.SecurityLevel = StreamUtils.DecodeBEUInt32(source.ReadBytes(4));

            return(result);
        }
Ejemplo n.º 7
0
        private void readTag(BinaryReader source, HeaderInfo Header, ReadTagParams readTagParams)
        {
            ChunkHeader chunk = new ChunkHeader();
            string      data;
            bool        first    = true;
            long        tagStart = -1;

            source.BaseStream.Seek(40, SeekOrigin.Begin);
            do
            {
                // Read chunk header (length : 8 bytes)
                chunk.ID   = Utils.Latin1Encoding.GetString(source.ReadBytes(4));
                chunk.Size = StreamUtils.DecodeBEUInt32(source.ReadBytes(4));

                // Read chunk data and set tag item if chunk header valid
                if (headerEndReached(chunk))
                {
                    break;
                }

                if (first)
                {
                    tagStart = source.BaseStream.Position - 8;
                    first    = false;
                }
                tagExists = true; // If something else than mandatory info is stored, we can consider metadata is present
                data      = Encoding.UTF8.GetString(source.ReadBytes((int)chunk.Size)).Trim();

                SetMetaField(chunk.ID, data, readTagParams.ReadAllMetaFrames);
            }while (source.BaseStream.Position < source.BaseStream.Length);

            if (readTagParams.PrepareForWriting)
            {
                // Metadata zone goes from the first field after COMM to the last field before DSIZ
                if (-1 == tagStart)
                {
                    structureHelper.AddZone(source.BaseStream.Position - 8, 0);
                }
                else
                {
                    structureHelper.AddZone(tagStart, (int)(source.BaseStream.Position - tagStart - 8));
                }
                structureHelper.AddSize(12, Header.Size);
            }
        }
Ejemplo n.º 8
0
        // Read header data
        private void readHeader(BinaryReader source)
        {
            uint fileSize    = StreamUtils.DecodeBEUInt32(source.ReadBytes(4));
            int  magicNumber = StreamUtils.DecodeBEInt32(source.ReadBytes(4));

            if (magicNumber != AA_MAGIC_NUMBER)
            {
                return;
            }

            tagExists       = true;
            AudioDataOffset = source.BaseStream.Position - 4;
            int tocSize = StreamUtils.DecodeBEInt32(source.ReadBytes(4));

            source.BaseStream.Seek(4, SeekOrigin.Current); // Even FFMPeg doesn't know what this integer is

            // The table of contents describes the layout of the file as triples of integers (<section>, <offset>, <length>)
            toc = new Dictionary <int, Tuple <uint, uint> >();
            for (int i = 0; i < tocSize; i++)
            {
                int  section            = StreamUtils.DecodeBEInt32(source.ReadBytes(4));
                uint tocEntryOffset     = StreamUtils.DecodeBEUInt32(source.ReadBytes(4));
                uint tocEntrySize       = StreamUtils.DecodeBEUInt32(source.ReadBytes(4));
                Tuple <uint, uint> data = new Tuple <uint, uint>(tocEntryOffset, tocEntrySize);
                toc[section] = data;
                structureHelper.AddZone(tocEntryOffset, (int)tocEntrySize, section.ToString());
                structureHelper.AddIndex(source.BaseStream.Position - 8, tocEntryOffset, false, section.ToString());
                if (TOC_AUDIO == section)
                {
                    AudioDataOffset = tocEntryOffset;
                    AudioDataSize   = tocEntrySize;
                }
                if (TOC_CONTENT_TAGS == section)
                {
                    structureHelper.AddSize(source.BaseStream.Position - 4, tocEntrySize, section.ToString());
                    structureHelper.AddSize(0, fileSize, section.ToString());
                }
                if (TOC_COVER_ART == section)
                {
                    structureHelper.AddSize(source.BaseStream.Position - 4, tocEntrySize, section.ToString());
                    structureHelper.AddIndex(source.BaseStream.Position - 8, tocEntryOffset, false, section.ToString());
                    structureHelper.AddSize(0, fileSize, section.ToString());
                }
            }
        }
Ejemplo n.º 9
0
        // WARNING : EXPERIMENTAL / UNTESTED DUE TO THE LACK OF METADATA-RICH SAMPLE FILES
        private void readStringsChunk(BinaryReader source)
        {
            uint nbEntries = StreamUtils.DecodeBEUInt32(source.ReadBytes(4));

            Dictionary <uint, long> stringIds = new Dictionary <uint, long>();

            for (int i = 0; i < nbEntries; i++)
            {
                uint stringId     = StreamUtils.DecodeBEUInt32(source.ReadBytes(4));
                long stringOffset = StreamUtils.DecodeBEInt64(source.ReadBytes(8));
                stringIds.Add(stringId, stringOffset);
            }
            long initialPos = source.BaseStream.Position;

            string stringValue;

            foreach (uint id in stringIds.Keys)
            {
                source.BaseStream.Seek(initialPos + stringIds[id], SeekOrigin.Begin);
                stringValue = StreamUtils.ReadNullTerminatedString(source, Encoding.UTF8);
                SetMetaField("str-" + id, stringValue, true);
            }
        }
Ejemplo n.º 10
0
        private static uint findPngChunk(Stream s, byte[] chunkID, long limit)
        {
            byte[] intData = new byte[4];
            uint   chunkSize;
            bool   foundChunk = false;

            while (s.Position < limit)
            {
                s.Read(intData, 0, 4); // Chunk Size
                chunkSize = StreamUtils.DecodeBEUInt32(intData);
                s.Read(intData, 0, 4); // Chunk ID
                foundChunk = StreamUtils.ArrEqualsArr(intData, chunkID);
                if (foundChunk)
                {
                    return(chunkSize);
                }
                else
                {
                    s.Seek(chunkSize + 4, SeekOrigin.Current);
                }
            }

            return(0);
        }
Ejemplo n.º 11
0
        private static UInt32 findPngChunk(Stream s, Byte[] chunkID, Int64 limit)
        {
            var    intData = new Byte[4];
            UInt32 chunkSize;
            var    foundChunk = false;

            while (s.Position < limit)
            {
                s.Read(intData, 0, 4); // Chunk Size
                chunkSize = StreamUtils.DecodeBEUInt32(intData);
                s.Read(intData, 0, 4); // Chunk ID
                foundChunk = StreamUtils.ArrEqualsArr(intData, chunkID);
                if (foundChunk)
                {
                    return(chunkSize);
                }
                else
                {
                    s.Seek(chunkSize + 4, SeekOrigin.Current);
                }
            }

            return(0);
        }
Ejemplo n.º 12
0
        // ---------- SUPPORT METHODS

        private bool readWAV(Stream source, ReadTagParams readTagParams)
        {
            bool result = true;
            uint riffChunkSize;
            long riffChunkSizePos;

            byte[] data = new byte[4];

            source.Seek(0, SeekOrigin.Begin);

            // Read header
            source.Read(data, 0, 4);
            string str = Utils.Latin1Encoding.GetString(data);

            if (str.Equals(HEADER_RIFF))
            {
                _isLittleEndian = true;
            }
            else if (str.Equals(HEADER_RIFX))
            {
                _isLittleEndian = false;
            }
            else
            {
                return(false);
            }

            // Force creation of FileStructureHelper with detected endianness
            structureHelper      = new FileStructureHelper(isLittleEndian);
            id3v2StructureHelper = new FileStructureHelper(isLittleEndian);

            riffChunkSizePos = source.Position;
            source.Read(data, 0, 4);
            if (isLittleEndian)
            {
                riffChunkSize = StreamUtils.DecodeUInt32(data);
            }
            else
            {
                riffChunkSize = StreamUtils.DecodeBEUInt32(data);
            }

            // Format code
            source.Read(data, 0, 4);
            str = Utils.Latin1Encoding.GetString(data);
            if (!str.Equals(FORMAT_WAVE))
            {
                return(false);
            }


            string subChunkId;
            uint   chunkSize;
            long   chunkDataPos;
            bool   foundSample = false;
            bool   foundBext   = false;
            bool   foundInfo   = false;
            bool   foundIXml   = false;

            // Sub-chunks loop
            while (source.Position < riffChunkSize + 8)
            {
                // Chunk ID
                source.Read(data, 0, 4);
                if (0 == data[0]) // Sometimes data segment ends with a parasite null byte
                {
                    source.Seek(-3, SeekOrigin.Current);
                    source.Read(data, 0, 4);
                }

                subChunkId = Utils.Latin1Encoding.GetString(data);

                // Chunk size
                source.Read(data, 0, 4);
                if (isLittleEndian)
                {
                    chunkSize = StreamUtils.DecodeUInt32(data);
                }
                else
                {
                    chunkSize = StreamUtils.DecodeBEUInt32(data);
                }

                chunkDataPos = source.Position;

                if (subChunkId.Equals(CHUNK_FORMAT))
                {
                    source.Read(data, 0, 2);
                    if (isLittleEndian)
                    {
                        formatId = StreamUtils.DecodeUInt16(data);
                    }
                    else
                    {
                        formatId = StreamUtils.DecodeBEUInt16(data);
                    }

                    source.Read(data, 0, 2);
                    if (isLittleEndian)
                    {
                        channelsArrangement = ChannelsArrangements.GuessFromChannelNumber(StreamUtils.DecodeUInt16(data));
                    }
                    else
                    {
                        channelsArrangement = ChannelsArrangements.GuessFromChannelNumber(StreamUtils.DecodeBEUInt16(data));
                    }

                    source.Read(data, 0, 4);
                    if (isLittleEndian)
                    {
                        sampleRate = StreamUtils.DecodeUInt32(data);
                    }
                    else
                    {
                        sampleRate = StreamUtils.DecodeBEUInt32(data);
                    }

                    source.Read(data, 0, 4);
                    if (isLittleEndian)
                    {
                        bytesPerSecond = StreamUtils.DecodeUInt32(data);
                    }
                    else
                    {
                        bytesPerSecond = StreamUtils.DecodeBEUInt32(data);
                    }

                    source.Seek(2, SeekOrigin.Current); // BlockAlign

                    source.Read(data, 0, 2);
                    if (isLittleEndian)
                    {
                        bitsPerSample = StreamUtils.DecodeUInt16(data);
                    }
                    else
                    {
                        bitsPerSample = StreamUtils.DecodeBEUInt16(data);
                    }
                }
                else if (subChunkId.Equals(CHUNK_DATA))
                {
                    headerSize = riffChunkSize - chunkSize;
                }
                else if (subChunkId.Equals(CHUNK_FACT))
                {
                    source.Read(data, 0, 4);
                    if (isLittleEndian)
                    {
                        sampleNumber = StreamUtils.DecodeInt32(data);
                    }
                    else
                    {
                        sampleNumber = StreamUtils.DecodeBEInt32(data);
                    }
                }
                else if (subChunkId.Equals(CHUNK_SAMPLE))
                {
                    structureHelper.AddZone(source.Position - 8, (int)(chunkSize + 8), subChunkId);
                    structureHelper.AddSize(riffChunkSizePos, riffChunkSize, subChunkId);

                    foundSample = true;
                    tagExists   = true;

                    SampleTag.FromStream(source, this, readTagParams);
                }
                else if (subChunkId.Equals(CHUNK_BEXT))
                {
                    structureHelper.AddZone(source.Position - 8, (int)(chunkSize + 8), subChunkId);
                    structureHelper.AddSize(riffChunkSizePos, riffChunkSize, subChunkId);

                    foundBext = true;
                    tagExists = true;

                    BextTag.FromStream(source, this, readTagParams);
                }
                else if (subChunkId.Equals(CHUNK_INFO))
                {
                    // Purpose of the list should be INFO
                    source.Read(data, 0, 4);
                    string purpose = Utils.Latin1Encoding.GetString(data, 0, 4);
                    if (purpose.Equals(InfoTag.PURPOSE_INFO))
                    {
                        structureHelper.AddZone(source.Position - 12, (int)(chunkSize + 8), subChunkId);
                        structureHelper.AddSize(riffChunkSizePos, riffChunkSize, subChunkId);

                        foundInfo = true;
                        tagExists = true;

                        InfoTag.FromStream(source, this, readTagParams, chunkSize);
                    }
                }
                else if (subChunkId.Equals(CHUNK_IXML))
                {
                    structureHelper.AddZone(source.Position - 8, (int)(chunkSize + 8), subChunkId);
                    structureHelper.AddSize(riffChunkSizePos, riffChunkSize, subChunkId);

                    foundIXml = true;
                    tagExists = true;

                    IXmlTag.FromStream(source, this, readTagParams, chunkSize);
                }
                else if (subChunkId.Equals(CHUNK_ID3))
                {
                    id3v2Offset = source.Position;

                    // Zone is already added by Id3v2.Read
                    id3v2StructureHelper.AddZone(id3v2Offset - 8, (int)(chunkSize + 8), subChunkId);
                    id3v2StructureHelper.AddSize(riffChunkSizePos, riffChunkSize, subChunkId);
                }

                source.Seek(chunkDataPos + chunkSize, SeekOrigin.Begin);
            }

            // Add zone placeholders for future tag writing
            if (readTagParams.PrepareForWriting)
            {
                if (!foundSample)
                {
                    structureHelper.AddZone(source.Position, 0, CHUNK_SAMPLE);
                    structureHelper.AddSize(riffChunkSizePos, riffChunkSize, CHUNK_SAMPLE);
                }
                if (!foundBext)
                {
                    structureHelper.AddZone(source.Position, 0, CHUNK_BEXT);
                    structureHelper.AddSize(riffChunkSizePos, riffChunkSize, CHUNK_BEXT);
                }
                if (!foundInfo)
                {
                    structureHelper.AddZone(source.Position, 0, CHUNK_INFO);
                    structureHelper.AddSize(riffChunkSizePos, riffChunkSize, CHUNK_INFO);
                }
                if (!foundIXml)
                {
                    structureHelper.AddZone(source.Position, 0, CHUNK_IXML);
                    structureHelper.AddSize(riffChunkSizePos, riffChunkSize, CHUNK_IXML);
                }
            }

            // ID3 zone should be set as the very last one for Windows to be able to read the LIST INFO zone properly
            if (-1 == id3v2Offset)
            {
                id3v2Offset = 0; // Switch status to "tried to read, but nothing found"

                if (readTagParams.PrepareForWriting)
                {
                    id3v2StructureHelper.AddZone(source.Position, 0, CHUNK_ID3);
                    id3v2StructureHelper.AddSize(riffChunkSizePos, riffChunkSize, CHUNK_ID3);
                }
            }

            return(result);
        }
Ejemplo n.º 13
0
        protected override bool read(BinaryReader source, MetaDataIO.ReadTagParams readTagParams)
        {
            bool result = false;
            long position;

            resetData();
            source.BaseStream.Seek(0, SeekOrigin.Begin);

            if (AIFF_CONTAINER_ID.Equals(Utils.Latin1Encoding.GetString(source.ReadBytes(4))))
            {
                // Container chunk size
                long containerChunkPos  = source.BaseStream.Position;
                int  containerChunkSize = StreamUtils.DecodeBEInt32(source.ReadBytes(4));

                if (containerChunkPos + containerChunkSize + 4 != source.BaseStream.Length)
                {
                    LogDelegator.GetLogDelegate()(Log.LV_WARNING, "Header size is incoherent with file size");
                }

                // Form type
                format = Utils.Latin1Encoding.GetString(source.ReadBytes(4));

                if (format.Equals(FORMTYPE_AIFF) || format.Equals(FORMTYPE_AIFC))
                {
                    isValid = true;

                    StringBuilder commentStr         = new StringBuilder("");
                    long          soundChunkPosition = 0;
                    long          soundChunkSize     = 0; // Header size included
                    bool          nameFound          = false;
                    bool          authorFound        = false;
                    bool          copyrightFound     = false;
                    bool          commentsFound      = false;
                    long          limit = Math.Min(containerChunkPos + containerChunkSize + 4, source.BaseStream.Length);

                    int annotationIndex = 0;
                    int commentIndex    = 0;

                    while (source.BaseStream.Position < limit)
                    {
                        ChunkHeader header = seekNextChunkHeader(source, limit);

                        position = source.BaseStream.Position;

                        if (header.ID.Equals(CHUNKTYPE_COMMON))
                        {
                            short channels = StreamUtils.DecodeBEInt16(source.ReadBytes(2));
                            switch (channels)
                            {
                            case 1: channelsArrangement = MONO; break;

                            case 2: channelsArrangement = STEREO; break;

                            case 3: channelsArrangement = ISO_3_0_0; break;

                            case 4: channelsArrangement = ISO_2_2_0; break;     // Specs actually allow both 2/2.0 and LRCS

                            case 6: channelsArrangement = LRLcRcCS; break;

                            default: channelsArrangement = UNKNOWN; break;
                            }

                            numSampleFrames = StreamUtils.DecodeBEUInt32(source.ReadBytes(4));
                            sampleSize      = (uint)StreamUtils.DecodeBEInt16(source.ReadBytes(2)); // This sample size is for uncompressed data only
                            byte[] byteArray = source.ReadBytes(10);
                            Array.Reverse(byteArray);
                            double aSampleRate = StreamUtils.ExtendedToDouble(byteArray);

                            if (format.Equals(FORMTYPE_AIFC))
                            {
                                compression = Utils.Latin1Encoding.GetString(source.ReadBytes(4));
                            }
                            else // AIFF <=> no compression
                            {
                                compression = COMPRESSION_NONE;
                            }

                            if (aSampleRate > 0)
                            {
                                sampleRate = (int)Math.Round(aSampleRate);
                                duration   = (double)numSampleFrames * 1000.0 / sampleRate;

                                if (!compression.Equals(COMPRESSION_NONE)) // Sample size is specific to selected compression method
                                {
                                    if (compression.ToLower().Equals("fl32"))
                                    {
                                        sampleSize = 32;
                                    }
                                    else if (compression.ToLower().Equals("fl64"))
                                    {
                                        sampleSize = 64;
                                    }
                                    else if (compression.ToLower().Equals("alaw"))
                                    {
                                        sampleSize = 8;
                                    }
                                    else if (compression.ToLower().Equals("ulaw"))
                                    {
                                        sampleSize = 8;
                                    }
                                }
                                if (duration > 0)
                                {
                                    bitrate = sampleSize * numSampleFrames * channelsArrangement.NbChannels / duration;
                                }
                            }
                        }
                        else if (header.ID.Equals(CHUNKTYPE_SOUND))
                        {
                            soundChunkPosition = source.BaseStream.Position - 8;
                            soundChunkSize     = header.Size + 8;
                        }
                        else if (header.ID.Equals(CHUNKTYPE_NAME) || header.ID.Equals(CHUNKTYPE_AUTHOR) || header.ID.Equals(CHUNKTYPE_COPYRIGHT))
                        {
                            structureHelper.AddZone(source.BaseStream.Position - 8, header.Size + 8, header.ID);
                            structureHelper.AddSize(containerChunkPos, containerChunkSize, header.ID);

                            tagExists = true;
                            if (header.ID.Equals(CHUNKTYPE_NAME))
                            {
                                nameFound = true;
                            }
                            if (header.ID.Equals(CHUNKTYPE_AUTHOR))
                            {
                                authorFound = true;
                            }
                            if (header.ID.Equals(CHUNKTYPE_COPYRIGHT))
                            {
                                copyrightFound = true;
                            }

                            SetMetaField(header.ID, Utils.Latin1Encoding.GetString(source.ReadBytes(header.Size)), readTagParams.ReadAllMetaFrames);
                        }
                        else if (header.ID.Equals(CHUNKTYPE_ANNOTATION))
                        {
                            annotationIndex++;
                            structureHelper.AddZone(source.BaseStream.Position - 8, header.Size + 8, header.ID + annotationIndex);
                            structureHelper.AddSize(containerChunkPos, containerChunkSize, header.ID + annotationIndex);

                            if (commentStr.Length > 0)
                            {
                                commentStr.Append(Settings.InternalValueSeparator);
                            }
                            commentStr.Append(Utils.Latin1Encoding.GetString(source.ReadBytes(header.Size)));
                            tagExists = true;
                        }
                        else if (header.ID.Equals(CHUNKTYPE_COMMENTS))
                        {
                            commentIndex++;
                            structureHelper.AddZone(source.BaseStream.Position - 8, header.Size + 8, header.ID + commentIndex);
                            structureHelper.AddSize(containerChunkPos, containerChunkSize, header.ID + commentIndex);

                            tagExists     = true;
                            commentsFound = true;

                            ushort numComs = StreamUtils.DecodeBEUInt16(source.ReadBytes(2));

                            for (int i = 0; i < numComs; i++)
                            {
                                CommentData cmtData = new CommentData();
                                cmtData.Timestamp = StreamUtils.DecodeBEUInt32(source.ReadBytes(4));
                                cmtData.MarkerId  = StreamUtils.DecodeBEInt16(source.ReadBytes(2));

                                // Comments length
                                ushort        comLength = StreamUtils.DecodeBEUInt16(source.ReadBytes(2));
                                MetaFieldInfo comment   = new MetaFieldInfo(getImplementedTagType(), header.ID + commentIndex);
                                comment.Value        = Utils.Latin1Encoding.GetString(source.ReadBytes(comLength));
                                comment.SpecificData = cmtData;
                                tagData.AdditionalFields.Add(comment);

                                // Only read general purpose comments, not those linked to a marker
                                if (0 == cmtData.MarkerId)
                                {
                                    if (commentStr.Length > 0)
                                    {
                                        commentStr.Append(Settings.InternalValueSeparator);
                                    }
                                    commentStr.Append(comment.Value);
                                }
                            }
                        }
                        else if (header.ID.Equals(CHUNKTYPE_ID3TAG))
                        {
                            id3v2Offset = source.BaseStream.Position;

                            // Zone is already added by Id3v2.Read
                            id3v2StructureHelper.AddZone(id3v2Offset - 8, header.Size + 8, CHUNKTYPE_ID3TAG);
                            id3v2StructureHelper.AddSize(containerChunkPos, containerChunkSize, CHUNKTYPE_ID3TAG);
                        }

                        source.BaseStream.Position = position + header.Size;

                        if (header.ID.Equals(CHUNKTYPE_SOUND) && header.Size % 2 > 0)
                        {
                            source.BaseStream.Position += 1;                                                           // Sound chunk size must be even
                        }
                    }

                    tagData.IntegrateValue(TagData.TAG_FIELD_COMMENT, commentStr.ToString().Replace("\0", " ").Trim());

                    if (-1 == id3v2Offset)
                    {
                        id3v2Offset = 0; // Switch status to "tried to read, but nothing found"

                        if (readTagParams.PrepareForWriting)
                        {
                            id3v2StructureHelper.AddZone(soundChunkPosition + soundChunkSize, 0, CHUNKTYPE_ID3TAG);
                            id3v2StructureHelper.AddSize(containerChunkPos, containerChunkSize, CHUNKTYPE_ID3TAG);
                        }
                    }

                    // Add zone placeholders for future tag writing
                    if (readTagParams.PrepareForWriting)
                    {
                        if (!nameFound)
                        {
                            structureHelper.AddZone(soundChunkPosition, 0, CHUNKTYPE_NAME);
                            structureHelper.AddSize(containerChunkPos, containerChunkSize, CHUNKTYPE_NAME);
                        }
                        if (!authorFound)
                        {
                            structureHelper.AddZone(soundChunkPosition, 0, CHUNKTYPE_AUTHOR);
                            structureHelper.AddSize(containerChunkPos, containerChunkSize, CHUNKTYPE_AUTHOR);
                        }
                        if (!copyrightFound)
                        {
                            structureHelper.AddZone(soundChunkPosition, 0, CHUNKTYPE_COPYRIGHT);
                            structureHelper.AddSize(containerChunkPos, containerChunkSize, CHUNKTYPE_COPYRIGHT);
                        }
                        if (!commentsFound)
                        {
                            structureHelper.AddZone(soundChunkPosition, 0, CHUNKTYPE_COMMENTS);
                            structureHelper.AddSize(containerChunkPos, containerChunkSize, CHUNKTYPE_COMMENTS);
                        }
                    }

                    result = true;
                }
            }

            return(result);
        }
Ejemplo n.º 14
0
        public void StreamUtils_Exceptions()
        {
            Assert.IsFalse(StreamUtils.ArrEqualsArr(new byte[1], new byte[2]));
            Assert.IsFalse(StreamUtils.StringEqualsArr(".", new char[2]));

            try
            {
                StreamUtils.DecodeBEUInt16(new byte[1]);
                Assert.Fail();
            }
            catch { }

            try
            {
                StreamUtils.DecodeUInt16(new byte[1]);
                Assert.Fail();
            }
            catch { }

            try
            {
                StreamUtils.DecodeInt16(new byte[1]);
                Assert.Fail();
            }
            catch { }

            try
            {
                StreamUtils.DecodeBEInt16(new byte[1]);
                Assert.Fail();
            }
            catch { }


            try
            {
                StreamUtils.DecodeBEInt24(new byte[2]);
                Assert.Fail();
            }
            catch { }

            try
            {
                StreamUtils.DecodeBEUInt24(new byte[2]);
                Assert.Fail();
            }
            catch { }

            try
            {
                StreamUtils.EncodeBEUInt24(0x01FFFFFF);
                Assert.Fail();
            }
            catch { }


            try
            {
                StreamUtils.DecodeBEUInt32(new byte[3]);
                Assert.Fail();
            }
            catch { }

            try
            {
                StreamUtils.DecodeUInt32(new byte[3]);
                Assert.Fail();
            }
            catch { }

            try
            {
                StreamUtils.DecodeBEInt32(new byte[3]);
                Assert.Fail();
            }
            catch { }

            try
            {
                StreamUtils.DecodeInt32(new byte[3]);
                Assert.Fail();
            }
            catch { }


            try
            {
                StreamUtils.DecodeUInt64(new byte[7]);
                Assert.Fail();
            }
            catch { }

            try
            {
                StreamUtils.DecodeBEInt64(new byte[7]);
                Assert.Fail();
            }
            catch { }


            try
            {
                StreamUtils.DecodeSynchSafeInt(new byte[6]);
                Assert.Fail();
            }
            catch { }

            try
            {
                StreamUtils.DecodeSynchSafeInt32(new byte[6]);
                Assert.Fail();
            }
            catch { }

            try
            {
                StreamUtils.EncodeSynchSafeInt(1, 0);
                Assert.Fail();
            }
            catch { }

            try
            {
                StreamUtils.EncodeSynchSafeInt(1, 6);
                Assert.Fail();
            }
            catch { }

            try
            {
                StreamUtils.ReadBits(new BinaryReader(new MemoryStream()), 0, 0);
                Assert.Fail();
            }
            catch { }

            try
            {
                StreamUtils.ReadBits(new BinaryReader(new MemoryStream()), 0, 33);
                Assert.Fail();
            }
            catch { }
        }