Esempio n. 1
0
        private string readPSFLine(Stream source, Encoding encoding)
        {
            long lineStart = source.Position;
            long lineEnd;
            bool hasEOL = true;

            if (StreamUtils.FindSequence(source, new byte[1] {
                LINE_FEED
            }))
            {
                lineEnd = source.Position;
            }
            else
            {
                lineEnd = source.Length;
                hasEOL  = false;
            }

            source.Seek(lineStart, SeekOrigin.Begin);

            byte[] data = new byte[lineEnd - lineStart];
            source.Read(data, 0, data.Length);

            for (int i = 0; i < data.Length; i++)
            {
                if (data[i] < SPACE)
                {
                    data[i] = SPACE;                                               // According to spec : "All characters 0x01-0x20 are considered whitespace"
                }
            }
            return(encoding.GetString(data, 0, data.Length - (hasEOL?1:0)).Trim()); // -1 because we don't want to include LINE_FEED in the result
        }
Esempio n. 2
0
        private void audio_X_AAC_MP4_Atom(string atom, string atomCaption = null)
        {
            if (null == atomCaption)
            {
                atomCaption = atom;
            }

            ArrayLogger log              = new ArrayLogger();
            string      resource         = "AAC/mp4.m4a";
            string      location         = TestUtils.GetResourceLocationRoot() + resource;
            string      testFileLocation = TestUtils.GetTempTestFile(resource);

            using (FileStream fs = new FileStream(testFileLocation, FileMode.Open, FileAccess.ReadWrite, FileShare.Read))
            {
                StreamUtils.FindSequence(fs, Utils.Latin1Encoding.GetBytes(atom));
                fs.Seek(-1, SeekOrigin.Current);
                fs.WriteByte(0);

                Track           theTrack = new Track(fs, ".mp4");
                IList <LogItem> logItems = log.GetAllItems(Log.LV_ERROR);
                Assert.AreEqual(1, logItems.Count);
                Assert.AreEqual(atomCaption + " atom could not be found; aborting read", logItems[0].Message);
            }

            // Get rid of the working copy
            File.Delete(testFileLocation);
        }
Esempio n. 3
0
        private void checkTrackDiscZeroes(FileStream fs)
        {
            using (BinaryReader r = new BinaryReader(fs))
            {
                byte[] bytes = new byte[20];
                fs.Seek(0, SeekOrigin.Begin);
                Assert.IsTrue(StreamUtils.FindSequence(fs, Utils.Latin1Encoding.GetBytes("TRACKNUMBER=")));
                String s = StreamUtils.ReadNullTerminatedString(r, System.Text.Encoding.ASCII);
                Assert.AreEqual("06", s.Substring(0, s.Length - 1));

                fs.Seek(0, SeekOrigin.Begin);
                Assert.IsTrue(StreamUtils.FindSequence(fs, Utils.Latin1Encoding.GetBytes("TRACKTOTAL=")));
                s = StreamUtils.ReadNullTerminatedString(r, System.Text.Encoding.ASCII);
                Assert.AreEqual("06", s.Substring(0, s.Length - 1));

                fs.Seek(0, SeekOrigin.Begin);
                Assert.IsTrue(StreamUtils.FindSequence(fs, Utils.Latin1Encoding.GetBytes("DISCNUMBER=")));
                s = StreamUtils.ReadNullTerminatedString(r, System.Text.Encoding.ASCII);
                Assert.AreEqual("03", s.Substring(0, s.Length - 1));

                fs.Seek(0, SeekOrigin.Begin);
                Assert.IsTrue(StreamUtils.FindSequence(fs, Utils.Latin1Encoding.GetBytes("DISCTOTAL=")));
                s = StreamUtils.ReadNullTerminatedString(r, System.Text.Encoding.ASCII);
                Assert.AreEqual("04", s.Substring(0, s.Length - 1));
            }
        }
Esempio n. 4
0
        public void TagIO_RW_ID3v2_CommentFields()
        {
            ConsoleLogger log = new ConsoleLogger();

            // Source : MP3 with existing tag incl. comment fields (iTunNORM, iTunPGAP)
            String           testFileLocation = TestUtils.GetTempTestFile("MP3/id3v2.2_iTunNORM-iTunPGAP.mp3");
            AudioDataManager theFile          = new AudioDataManager(AudioData.AudioDataIOFactory.GetInstance().GetFromPath(testFileLocation));

            // Check if the two fields are indeed accessible
            Assert.IsTrue(theFile.ReadFromFile(false, true));
            Assert.IsNotNull(theFile.ID3v2);
            Assert.IsTrue(theFile.ID3v2.Exists);

            Assert.AreEqual(4, theFile.ID3v2.AdditionalFields.Count);

            int found = 0;

            foreach (KeyValuePair <string, string> field in theFile.ID3v2.AdditionalFields)
            {
                if (field.Key.Equals("iTunNORM"))
                {
                    Assert.AreEqual(" 00000099 000000A2 000002F0 000002F4 0000002E 0000002E 00002E6E 00002C5C 00000017 00000017", field.Value); // Why an empty space at the beginning ?!
                    found++;
                }
                else if (field.Key.Equals("iTunPGAP"))
                {
                    Assert.AreEqual("1", field.Value);
                    found++;
                }
            }
            Assert.AreEqual(2, found);


            // Check if they are persisted as comment fields when editing the tag
            TagData theTag = new TagData();

            Assert.IsTrue(theFile.UpdateTagInFile(theTag, MetaDataIOFactory.TAG_ID3V2));

            // For this we need to open the file in binary mode and check that the two fields belong to a comment field
            byte[] readBytes = new byte[4];
            byte[] expected  = Utils.Latin1Encoding.GetBytes("COMM");

            using (FileStream fs = new FileStream(testFileLocation, FileMode.Open, FileAccess.Read))
            {
                Assert.IsTrue(StreamUtils.FindSequence(fs, Utils.Latin1Encoding.GetBytes("iTunNORM")));
                fs.Seek(-22, SeekOrigin.Current);
                fs.Read(readBytes, 0, 4);
                Assert.IsTrue(StreamUtils.ArrEqualsArr(expected, readBytes));

                fs.Seek(0, SeekOrigin.Begin);
                Assert.IsTrue(StreamUtils.FindSequence(fs, Utils.Latin1Encoding.GetBytes("iTunPGAP")));
                fs.Seek(-22, SeekOrigin.Current);
                fs.Read(readBytes, 0, 4);
                Assert.IsTrue(StreamUtils.ArrEqualsArr(expected, readBytes));
            }

            // Get rid of the working copy
            File.Delete(testFileLocation);
        }
Esempio n. 5
0
 /// Mandatory override of PlaylistIO.getFiles
 protected override void getFiles(FileStream fs, IList <string> result)
 {
     while (StreamUtils.FindSequence(fs, FILE_IDENTIFIER))
     {
         string filePath = StreamUtils.ReadNullTerminatedString(fs, UTF8_NO_BOM);
         result.Add(decodeLocation(filePath));
     }
 }
Esempio n. 6
0
        };                                                                                      // "file://"


        protected override void getFiles(FileStream fs, IList <string> result)
        {
            string filePath;
            string playlistPath = System.IO.Path.GetDirectoryName(fs.Name) + System.IO.Path.DirectorySeparatorChar;

            while (StreamUtils.FindSequence(fs, FILE_IDENTIFIER))
            {
                filePath = StreamUtils.ReadNullTerminatedString(fs, Encoding.UTF8);
                if (!System.IO.Path.IsPathRooted(filePath))
                {
                    filePath = playlistPath + filePath;
                }
                result.Add(filePath);
            }
        }
Esempio n. 7
0
        private void checkTrackDiscZeroes(FileStream fs)
        {
            using (BinaryReader r = new BinaryReader(fs))
            {
                byte[] bytes = new byte[20];
                fs.Seek(0, SeekOrigin.Begin);
                Assert.IsTrue(StreamUtils.FindSequence(fs, Utils.Latin1Encoding.GetBytes("TPOS")));
                fs.Seek(7, SeekOrigin.Current);
                String s = StreamUtils.ReadNullTerminatedString(r, System.Text.Encoding.ASCII);
                Assert.AreEqual("03/04", s);

                fs.Seek(0, SeekOrigin.Begin);
                Assert.IsTrue(StreamUtils.FindSequence(fs, Utils.Latin1Encoding.GetBytes("TRCK")));
                fs.Seek(7, SeekOrigin.Current);
                s = StreamUtils.ReadNullTerminatedString(r, System.Text.Encoding.ASCII);
                Assert.AreEqual("06/06", s);
            }
        }
        private void audio_X_MP4_Atom(string resourceName, string atom, int logLevel = Log.LV_ERROR, string atomCaption = null)
        {
            if (null == atomCaption)
            {
                atomCaption = atom;
            }

            ArrayLogger log              = new ArrayLogger();
            string      resource         = "MP4/" + resourceName;
            string      testFileLocation = TestUtils.CopyAsTempTestFile(resource);

            using (FileStream fs = new FileStream(testFileLocation, FileMode.Open, FileAccess.ReadWrite, FileShare.Read))
            {
                StreamUtils.FindSequence(fs, Utils.Latin1Encoding.GetBytes(atom));
                fs.Seek(-1, SeekOrigin.Current);
                fs.WriteByte(0);
                if (StreamUtils.FindSequence(fs, Utils.Latin1Encoding.GetBytes(atom)))
                {
                    fs.Seek(-1, SeekOrigin.Current);
                    fs.WriteByte(0);
                }

                new Track(fs, ".mp4");
                IList <LogItem> logItems = log.GetAllItems(logLevel);
                Assert.IsTrue(logItems.Count > 0);
                bool found = false;
                foreach (LogItem l in logItems)
                {
                    if (l.Message.Contains(atomCaption + " atom could not be found"))
                    {
                        found = true;
                    }
                }
                Assert.IsTrue(found);
            }

            // Get rid of the working copy
            if (Settings.DeleteAfterSuccess)
            {
                File.Delete(testFileLocation);
            }
        }
Esempio n. 9
0
        public void TagIO_RW_ID3v2_UrlFrames()
        {
            ConsoleLogger log = new ConsoleLogger();

            // Source : MP3 with existing tag incl. chapters
            String           testFileLocation = TestUtils.GetTempTestFile("MP3/chapters.mp3");
            AudioDataManager theFile          = new AudioDataManager(AudioData.AudioDataIOFactory.GetInstance().GetFromPath(testFileLocation));

            // Check if the two fields are indeed accessible
            Assert.IsTrue(theFile.ReadFromFile(false, true));
            Assert.IsNotNull(theFile.ID3v2);
            Assert.IsTrue(theFile.ID3v2.Exists);

            Assert.IsTrue(theFile.ID3v2.AdditionalFields.ContainsKey("WPUB"));
            Assert.AreEqual(theFile.ID3v2.AdditionalFields["WPUB"], "http://auphonic.com/");

            // Check if URLs are persisted properly, i.e. without encoding byte
            TagData theTag = new TagData();

            Assert.IsTrue(theFile.UpdateTagInFile(theTag, MetaDataIOFactory.TAG_ID3V2));

            Assert.IsTrue(theFile.ReadFromFile(false, true));

            // 1/ Check value through ATL
            Assert.IsTrue(theFile.ID3v2.AdditionalFields.ContainsKey("WPUB"));
            Assert.AreEqual(theFile.ID3v2.AdditionalFields["WPUB"], "http://auphonic.com/");

            // 2/ Check absence of encoding field in the file itself
            byte[] readBytes = new byte[4];
            byte[] expected  = Utils.Latin1Encoding.GetBytes("WPUB");

            using (FileStream fs = new FileStream(testFileLocation, FileMode.Open, FileAccess.Read))
            {
                Assert.IsTrue(StreamUtils.FindSequence(fs, Utils.Latin1Encoding.GetBytes("WPUB")));
                fs.Seek(6, SeekOrigin.Current);
                Assert.IsTrue(fs.ReadByte() > 10); // i.e. byte is not a 'text encoding descriptor'
            }

            // Get rid of the working copy
            File.Delete(testFileLocation);
        }
Esempio n. 10
0
        public void StreamUtils_FindSequence()
        {
            string sequence1 = "ftypmp42";
            string sequence2 = "trak";
            string sequence3 = "jstsd";

            using (FileStream fs = new FileStream(TestUtils.GetResourceLocationRoot() + "AAC/mp4.m4a", FileMode.Open, FileAccess.Read))
            {
                Assert.AreEqual(true, StreamUtils.FindSequence(fs, Utils.Latin1Encoding.GetBytes(sequence1)));
                Assert.AreEqual(12, fs.Position);

                Assert.AreEqual(true, StreamUtils.FindSequence(fs, Utils.Latin1Encoding.GetBytes(sequence2)));
                Assert.AreEqual(156, fs.Position);

                Assert.AreEqual(true, StreamUtils.FindSequence(fs, Utils.Latin1Encoding.GetBytes(sequence3)));
                Assert.AreEqual(416, fs.Position);

                fs.Seek(20, SeekOrigin.Begin);

                Assert.AreEqual(false, StreamUtils.FindSequence(fs, Utils.Latin1Encoding.GetBytes(sequence3), 100));
            }
        }
Esempio n. 11
0
        private bool getInfo(BufferedBinaryReader source, FileInfo info, ReadTagParams readTagParams)
        {
            // Get info from file
            bool result        = false;
            bool isValidHeader = false;

            // Check for ID3v2 (NB : this case should not even exist since OGG has its own native tagging system, and is not deemed compatible with ID3v2 according to the ID3 FAQ)
            source.Seek(sizeInfo.ID3v2Size, SeekOrigin.Begin);

            // Read global file header
            info.IdentificationHeader.ReadFromStream(source);

            if (info.IdentificationHeader.IsValid())
            {
                source.Seek(sizeInfo.ID3v2Size + info.IdentificationHeader.Segments + 27, SeekOrigin.Begin); // 27 being the size from 'ID' to 'Segments'

                // Read Vorbis or Opus stream info
                long position = source.Position;

                String headerStart = Utils.Latin1Encoding.GetString(source.ReadBytes(3));
                source.Seek(position, SeekOrigin.Begin);
                if (VORBIS_HEADER_ID.StartsWith(headerStart))
                {
                    contents = CONTENTS_VORBIS;
                    info.VorbisParameters.ID = Utils.Latin1Encoding.GetString(source.ReadBytes(7));
                    isValidHeader            = VORBIS_HEADER_ID.Equals(info.VorbisParameters.ID);

                    info.VorbisParameters.BitstreamVersion = source.ReadBytes(4);
                    info.VorbisParameters.ChannelMode      = source.ReadByte();
                    info.VorbisParameters.SampleRate       = source.ReadInt32();
                    info.VorbisParameters.BitRateMaximal   = source.ReadInt32();
                    info.VorbisParameters.BitRateNominal   = source.ReadInt32();
                    info.VorbisParameters.BitRateMinimal   = source.ReadInt32();
                    info.VorbisParameters.BlockSize        = source.ReadByte();
                    info.VorbisParameters.StopFlag         = source.ReadByte();
                }
                else if (OPUS_HEADER_ID.StartsWith(headerStart))
                {
                    contents = CONTENTS_OPUS;
                    info.OpusParameters.ID = Utils.Latin1Encoding.GetString(source.ReadBytes(8));
                    isValidHeader          = OPUS_HEADER_ID.Equals(info.OpusParameters.ID);

                    info.OpusParameters.Version            = source.ReadByte();
                    info.OpusParameters.OutputChannelCount = source.ReadByte();
                    info.OpusParameters.PreSkip            = source.ReadUInt16();
                    //info.OpusParameters.InputSampleRate = source.ReadUInt32();
                    info.OpusParameters.InputSampleRate = 48000; // Actual sample rate is hardware-dependent. Let's assume for now that the hardware ATL runs on supports 48KHz
                    source.Seek(4, SeekOrigin.Current);
                    info.OpusParameters.OutputGain = source.ReadInt16();

                    info.OpusParameters.ChannelMappingFamily = source.ReadByte();

                    if (info.OpusParameters.ChannelMappingFamily > 0)
                    {
                        info.OpusParameters.StreamCount        = source.ReadByte();
                        info.OpusParameters.CoupledStreamCount = source.ReadByte();

                        info.OpusParameters.ChannelMapping = new byte[info.OpusParameters.OutputChannelCount];
                        for (int i = 0; i < info.OpusParameters.OutputChannelCount; i++)
                        {
                            info.OpusParameters.ChannelMapping[i] = source.ReadByte();
                        }
                    }
                }

                if (isValidHeader)
                {
                    info.CommentHeaderStart = source.Position;
                    IList <long> pagePos = new List <long>();

                    // Reads all related Vorbis pages that describe Comment and Setup headers
                    // and concatenate their content into a single, continuous data stream
                    bool loop  = true;
                    bool first = true;
                    using (MemoryStream s = new MemoryStream())
                    {
                        // Reconstruct the whole Comment header from OGG pages to a MemoryStream
                        while (loop)
                        {
                            info.SetupHeaderEnd              = source.Position; // When the loop stops, cursor is starting to read a brand new page located after Comment _and_ Setup headers
                            info.CommentHeader.ID            = Utils.Latin1Encoding.GetString(source.ReadBytes(4));
                            info.CommentHeader.StreamVersion = source.ReadByte();
                            info.CommentHeader.TypeFlag      = source.ReadByte();
                            // 0 marks a new page
                            if (0 == info.CommentHeader.TypeFlag)
                            {
                                loop = first;
                            }
                            if (loop)
                            {
                                info.CommentHeader.AbsolutePosition = source.ReadUInt64();
                                info.CommentHeader.Serial           = source.ReadInt32();
                                info.CommentHeader.PageNumber       = source.ReadInt32();
                                info.CommentHeader.Checksum         = source.ReadUInt32();
                                info.CommentHeader.Segments         = source.ReadByte();
                                info.CommentHeader.LacingValues     = source.ReadBytes(info.CommentHeader.Segments);
                                s.Write(source.ReadBytes(info.CommentHeader.GetPageLength()), 0, info.CommentHeader.GetPageLength());
                                pagePos.Add(info.SetupHeaderEnd);
                            }
                            first = false;
                        }

                        if (readTagParams.PrepareForWriting) // Metrics to prepare writing
                        {
                            if (pagePos.Count > 1)
                            {
                                source.Position = pagePos[pagePos.Count - 2];
                            }
                            else
                            {
                                source.Position = pagePos[0];
                            }

                            // Determine the boundaries of 3rd header (Setup header) by searching from last-but-one page
                            if (StreamUtils.FindSequence(source, Utils.Latin1Encoding.GetBytes(VORBIS_SETUP_ID)))
                            {
                                info.SetupHeaderStart = source.Position - VORBIS_SETUP_ID.Length;
                                info.CommentHeaderEnd = info.SetupHeaderStart;

                                if (pagePos.Count > 1)
                                {
                                    int firstSetupPage = -1;
                                    for (int i = 1; i < pagePos.Count; i++)
                                    {
                                        if (info.CommentHeaderEnd < pagePos[i])
                                        {
                                            info.CommentHeaderSpanPages = i - 1;
                                            firstSetupPage = i - 1;
                                        }
                                        if (info.SetupHeaderEnd < pagePos[i])
                                        {
                                            info.SetupHeaderSpanPages = i - firstSetupPage;
                                        }
                                    }
                                    /// Not found yet => comment header takes up all pages, and setup header is on the end of the last page
                                    if (-1 == firstSetupPage)
                                    {
                                        info.CommentHeaderSpanPages = pagePos.Count;
                                        info.SetupHeaderSpanPages   = 1;
                                    }
                                }
                                else
                                {
                                    info.CommentHeaderSpanPages = 1;
                                    info.SetupHeaderSpanPages   = 1;
                                }
                            }
                        }

                        // Get total number of samples
                        info.Samples = getSamples(source);

                        // Read metadata from the reconstructed Comment header inside the memoryStream
                        if (readTagParams.ReadTag)
                        {
                            BinaryReader msr = new BinaryReader(s);
                            s.Seek(0, SeekOrigin.Begin);

                            string tagId;
                            bool   isValidTagHeader = false;
                            if (contents.Equals(CONTENTS_VORBIS))
                            {
                                tagId            = Utils.Latin1Encoding.GetString(msr.ReadBytes(7));
                                isValidTagHeader = (VORBIS_TAG_ID.Equals(tagId));
                            }
                            else if (contents.Equals(CONTENTS_OPUS))
                            {
                                tagId            = Utils.Latin1Encoding.GetString(msr.ReadBytes(8));
                                isValidTagHeader = (OPUS_TAG_ID.Equals(tagId));
                            }

                            if (isValidTagHeader)
                            {
                                vorbisTag.Clear();
                                vorbisTag.Read(msr, readTagParams);
                            }
                        }
                    } // using MemoryStream

                    result = true;
                }
            }

            return(result);
        }
Esempio n. 12
0
        // ---------------------------------------------------------------------------

        // Read total samples of OGG file, which are located on the very last page of the file
        private ulong getSamples(BufferedBinaryReader source)
        {
            OggHeader header = new OggHeader();

            string headerId;
            byte   typeFlag;

            byte[] lacingValues   = new byte[255];
            byte   nbLacingValues = 0;
            long   nextPageOffset = 0;

            // TODO - fine tune seekSize value
            int seekSize = (int)Math.Round(MAX_PAGE_SIZE * 0.75);

            if (seekSize > source.Length)
            {
                seekSize = (int)Math.Round(source.Length * 0.5);
            }
            source.Seek(-seekSize, SeekOrigin.End);
            if (!StreamUtils.FindSequence(source, Utils.Latin1Encoding.GetBytes(OGG_PAGE_ID)))
            {
                LogDelegator.GetLogDelegate()(Log.LV_ERROR, "No OGG header found; aborting read operation"); // Throw exception ?
                return(0);
            }
            source.Seek(-4, SeekOrigin.Current);

            // Iterate until last page is encountered
            do
            {
                if (source.Position + nextPageOffset + 27 > source.Length) // End of stream about to be reached => last OGG header did not have the proper type flag
                {
                    break;
                }

                source.Seek(nextPageOffset, SeekOrigin.Current);

                headerId = Utils.Latin1Encoding.GetString(source.ReadBytes(4));

                if (headerId.Equals(OGG_PAGE_ID))
                {
                    source.Seek(1, SeekOrigin.Current);
                    typeFlag = source.ReadByte();
                    source.Seek(20, SeekOrigin.Current);
                    nbLacingValues = source.ReadByte();
                    nextPageOffset = 0;
                    source.Read(lacingValues, 0, nbLacingValues);
                    for (int i = 0; i < nbLacingValues; i++)
                    {
                        nextPageOffset += lacingValues[i];
                    }
                }
                else
                {
                    LogDelegator.GetLogDelegate()(Log.LV_ERROR, "Invalid OGG header found while looking for total samples; aborting read operation"); // Throw exception ?
                    return(0);
                }
            } while (0 == (typeFlag & 0x04)); // 0x04 marks the last page of the logical bitstream


            // Stream is positioned at the end of the last page header; backtracking to read AbsolutePosition field
            source.Seek(-nbLacingValues - 21, SeekOrigin.Current);

            return(source.ReadUInt64());
        }
Esempio n. 13
0
        /// <inheritdoc/>
        protected override bool read(BinaryReader source, MetaDataIO.ReadTagParams readTagParams)
        {
            byte[] header;
            string trigger;

            IList <MidiTrack> tracks = new List <MidiTrack>();

            resetData();

            // Ignores everything (comments) written before the MIDI header
            StreamUtils.FindSequence(source.BaseStream, Utils.Latin1Encoding.GetBytes(MIDI_FILE_HEADER));

            // Ready to read header data...
            header = source.ReadBytes(10);
            if ((header[0] != 0) ||
                (header[1] != 0) ||
                (header[2] != 0) ||
                (header[3] != 6)
                )
            {
                Logging.LogDelegator.GetLogDelegate()(Log.LV_ERROR, "Wrong MIDI header");
                return(false);
            }
            type = header[5];

            // MIDI STRUCTURE TYPE
            // 0 - single-track
            // 1 - multiple tracks, synchronous
            // 2 - multiple tracks, asynchronous
            if (type > 1)
            {
                Logging.LogDelegator.GetLogDelegate()(Log.LV_WARNING, "SMF type 2 MIDI files are partially supported; results may be approximate");
            }

            tagExists = true;

            timebase = (header[8] << 8) + header[9];

            tempo = 0; // maybe (hopefully!) overwritten by parseTrack

            int trackSize;
            int nbTrack = 0;

            comment = new StringBuilder("");

            AudioDataOffset = source.BaseStream.Position;
            AudioDataSize   = sizeInfo.FileSize - AudioDataOffset;

            // Ready to read track data...
            while (source.BaseStream.Position < sizeInfo.FileSize - 4)
            {
                trigger = Utils.Latin1Encoding.GetString(source.ReadBytes(4));

                if (trigger != MIDI_TRACK_HEADER)
                {
                    source.BaseStream.Seek(-3, SeekOrigin.Current);
                    if (!StreamUtils.FindSequence(source.BaseStream, Utils.Latin1Encoding.GetBytes(MIDI_TRACK_HEADER)))
                    {
                        break;
                    }
                }

                // trackSize is stored in big endian -> needs inverting
                trackSize = StreamUtils.DecodeBEInt32(source.ReadBytes(4));

                tracks.Add(parseTrack(source.ReadBytes(trackSize), nbTrack));
                nbTrack++;
            }

            this.tracks = tracks;

            if (comment.Length > 0)
            {
                comment.Remove(comment.Length - 1, 1);
            }
            tagData.IntegrateValue(TagData.TAG_FIELD_COMMENT, comment.ToString());

            duration = getDuration();
            bitrate  = (double)sizeInfo.FileSize / duration;

            return(true);
        }
Esempio n. 14
0
        public void TagIO_RW_ID3v2_Chapters_CTOCEdgeCases()
        {
            ConsoleLogger log = new ConsoleLogger();

            // Source : empty MP3
            String           testFileLocation = TestUtils.GetTempTestFile(emptyFile);
            AudioDataManager theFile          = new AudioDataManager(AudioData.AudioDataIOFactory.GetInstance().GetFromPath(testFileLocation));

            // Case 1. Setting Track.ChaptersTableDescription alone without setting any chapter shouldn't write any CTOC frame
            Assert.IsTrue(theFile.ReadFromFile(true, true));
            Assert.IsNotNull(theFile.ID3v2);
            Assert.IsFalse(theFile.ID3v2.Exists);

            TagData theTag = new TagData();

            theTag.ChaptersTableDescription = "aaa";
            theTag.Chapters = new List <ChapterInfo>();

            // Check if they are persisted properly
            Assert.IsTrue(theFile.UpdateTagInFile(theTag, MetaDataIOFactory.TAG_ID3V2));

            Assert.IsTrue(theFile.ReadFromFile(true, true));
            Assert.IsNotNull(theFile.ID3v2);
            Assert.IsFalse(theFile.ID3v2.Exists);

            // Read the file itself and check that no CTOC frame has been written
            using (FileStream fs = new FileStream(testFileLocation, FileMode.Open))
            {
                Assert.IsFalse(StreamUtils.FindSequence(fs, Utils.Latin1Encoding.GetBytes("CTOC")));
            }


            //Case 2. If Settings.ID3v2_alwaysWriteCTOCFrame to true and at least 1 chapter without setting Track.ChaptersTableDescription shouldn't write any TIT2 subframe

            // Set a chapter but no description
            ChapterInfo ch = new ChapterInfo();

            ch.StartTime   = 123;
            ch.StartOffset = 456;
            ch.EndTime     = 789;
            ch.EndOffset   = 101112;
            ch.UniqueID    = "";
            ch.Subtitle    = "bbb";
            theTag.ChaptersTableDescription = "";
            theTag.Chapters.Add(ch);

            // Check if they are persisted properly
            Assert.IsTrue(theFile.UpdateTagInFile(theTag, MetaDataIOFactory.TAG_ID3V2));

            Assert.IsTrue(theFile.ReadFromFile(true, true));
            Assert.IsNotNull(theFile.ID3v2);
            Assert.IsTrue(theFile.ID3v2.Exists);

            // Read the file itself
            using (FileStream fs = new FileStream(testFileLocation, FileMode.Open))
            {
                Assert.IsTrue(StreamUtils.FindSequence(fs, Utils.Latin1Encoding.GetBytes("CTOC")));
                Assert.IsFalse(StreamUtils.FindSequence(fs, Utils.Latin1Encoding.GetBytes("TIT2")));
            }

            // Get rid of the working copy
            File.Delete(testFileLocation);
        }
Esempio n. 15
0
        public void TagIO_RW_ID3v2_FieldCodev22Tov24()
        {
            ConsoleLogger log = new ConsoleLogger();

            // Source : MP3 with existing unsupported fields : RVA & TBP
            String           testFileLocation = TestUtils.GetTempTestFile("MP3/id3v2.2_iTunNORM-iTunPGAP.mp3");
            AudioDataManager theFile          = new AudioDataManager(AudioData.AudioDataIOFactory.GetInstance().GetFromPath(testFileLocation));

            // Check if the two fields are indeed accessible
            Assert.IsTrue(theFile.ReadFromFile(false, true));
            Assert.IsNotNull(theFile.ID3v2);
            Assert.IsTrue(theFile.ID3v2.Exists);

            Assert.AreEqual("1997", theFile.ID3v2.Year);

            int    found    = 0;
            string rvaValue = "";
            string tbpValue = "";

            foreach (KeyValuePair <string, string> field in theFile.ID3v2.AdditionalFields)
            {
                if (field.Key.Equals("RVA"))
                {
                    rvaValue = field.Value;
                    found++;
                }
                else if (field.Key.Equals("TBP"))
                {
                    tbpValue = field.Value;
                    found++;
                }
            }
            Assert.AreEqual(2, found);

            // Check if they are persisted with proper ID3v2.4 field codes when editing the tag
            TagData theTag = new TagData();

            Assert.IsTrue(theFile.UpdateTagInFile(theTag, MetaDataIOFactory.TAG_ID3V2));

            Assert.IsTrue(theFile.ReadFromFile(false, true));

            // 1/ Check if values are the same
            found = 0;
            foreach (KeyValuePair <string, string> field in theFile.ID3v2.AdditionalFields)
            {
                if (field.Key.Equals("RVA2"))
                {
                    Assert.AreEqual(rvaValue, field.Value);
                    found++;
                }
                else if (field.Key.Equals("TBPM"))
                {
                    Assert.AreEqual(tbpValue, field.Value);
                    found++;
                }
            }
            Assert.AreEqual(2, found);

            Assert.AreEqual("1997", theFile.ID3v2.Year);


            // 2/ Check if they are indeed persisted as "classic" ID3v2 fields, and not as sub-codes inside a TXXX field
            byte[] readBytes = new byte[4];
            byte[] expected  = Utils.Latin1Encoding.GetBytes("TXXX");

            using (FileStream fs = new FileStream(testFileLocation, FileMode.Open, FileAccess.Read))
            {
                Assert.IsTrue(StreamUtils.FindSequence(fs, Utils.Latin1Encoding.GetBytes("RVA2")));
                fs.Seek(-15, SeekOrigin.Current);
                fs.Read(readBytes, 0, 4);
                Assert.IsFalse(StreamUtils.ArrEqualsArr(expected, readBytes));

                fs.Seek(0, SeekOrigin.Begin);


                expected = Utils.Latin1Encoding.GetBytes("TDRC");

                Assert.IsTrue(StreamUtils.FindSequence(fs, Utils.Latin1Encoding.GetBytes("1997")));
                fs.Seek(-15, SeekOrigin.Current);
                fs.Read(readBytes, 0, 4);
                Assert.IsTrue(StreamUtils.ArrEqualsArr(expected, readBytes));
            }

            // Get rid of the working copy
            File.Delete(testFileLocation);
        }
Esempio n. 16
0
        public static void FromStream(Stream source, MetaDataIO meta, ReadTagParams readTagParams)
        {
            string str;

            byte[] data = new byte[256];

            // Description
            source.Read(data, 0, 256);
            str = Utils.StripEndingZeroChars(Utils.Latin1Encoding.GetString(data).Trim());
            if (str.Length > 0)
            {
                meta.SetMetaField("bext.description", str, readTagParams.ReadAllMetaFrames);
            }

            // Originator
            source.Read(data, 0, 32);
            str = Utils.StripEndingZeroChars(Utils.Latin1Encoding.GetString(data, 0, 32).Trim());
            if (str.Length > 0)
            {
                meta.SetMetaField("bext.originator", str, readTagParams.ReadAllMetaFrames);
            }

            // OriginatorReference
            source.Read(data, 0, 32);
            str = Utils.StripEndingZeroChars(Utils.Latin1Encoding.GetString(data, 0, 32).Trim());
            if (str.Length > 0)
            {
                meta.SetMetaField("bext.originatorReference", str, readTagParams.ReadAllMetaFrames);
            }

            // OriginationDate
            source.Read(data, 0, 10);
            str = Utils.StripEndingZeroChars(Utils.Latin1Encoding.GetString(data, 0, 10).Trim());
            if (str.Length > 0)
            {
                meta.SetMetaField("bext.originationDate", str, readTagParams.ReadAllMetaFrames);
            }

            // OriginationTime
            source.Read(data, 0, 8);
            str = Utils.StripEndingZeroChars(Utils.Latin1Encoding.GetString(data, 0, 8).Trim());
            if (str.Length > 0)
            {
                meta.SetMetaField("bext.originationTime", str, readTagParams.ReadAllMetaFrames);
            }

            // TimeReference
            source.Read(data, 0, 8);
            ulong timeReference = StreamUtils.DecodeUInt64(data);

            meta.SetMetaField("bext.timeReference", timeReference.ToString(), readTagParams.ReadAllMetaFrames);

            // BEXT version
            source.Read(data, 0, 2);
            int intData = StreamUtils.DecodeUInt16(data);

            meta.SetMetaField("bext.version", intData.ToString(), readTagParams.ReadAllMetaFrames);

            // UMID
            source.Read(data, 0, 64);
            str = "";

            int usefulLength = 32; // "basic" UMID

            if (data[12] > 19)
            {
                usefulLength = 64;                // data[12] gives the size of remaining UMID
            }
            for (int i = 0; i < usefulLength; i++)
            {
                str = str + data[i].ToString("X2");
            }

            meta.SetMetaField("bext.UMID", str, readTagParams.ReadAllMetaFrames);

            // LoudnessValue
            source.Read(data, 0, 2);
            intData = StreamUtils.DecodeInt16(data);
            meta.SetMetaField("bext.loudnessValue", (intData / 100.0).ToString(), readTagParams.ReadAllMetaFrames);

            // LoudnessRange
            source.Read(data, 0, 2);
            intData = StreamUtils.DecodeInt16(data);
            meta.SetMetaField("bext.loudnessRange", (intData / 100.0).ToString(), readTagParams.ReadAllMetaFrames);

            // MaxTruePeakLevel
            source.Read(data, 0, 2);
            intData = StreamUtils.DecodeInt16(data);
            meta.SetMetaField("bext.maxTruePeakLevel", (intData / 100.0).ToString(), readTagParams.ReadAllMetaFrames);

            // MaxMomentaryLoudness
            source.Read(data, 0, 2);
            intData = StreamUtils.DecodeInt16(data);
            meta.SetMetaField("bext.maxMomentaryLoudness", (intData / 100.0).ToString(), readTagParams.ReadAllMetaFrames);

            // MaxShortTermLoudness
            source.Read(data, 0, 2);
            intData = StreamUtils.DecodeInt16(data);
            meta.SetMetaField("bext.maxShortTermLoudness", (intData / 100.0).ToString(), readTagParams.ReadAllMetaFrames);

            // Reserved
            source.Seek(180, SeekOrigin.Current);

            // CodingHistory
            long initialPos = source.Position;

            if (StreamUtils.FindSequence(source, new byte[2] {
                13, 10
            } /* CR LF */))
            {
                long endPos = source.Position - 2;
                source.Seek(initialPos, SeekOrigin.Begin);

                if (data.Length < (int)(endPos - initialPos))
                {
                    data = new byte[(int)(endPos - initialPos)];
                }
                source.Read(data, 0, (int)(endPos - initialPos));

                str = Utils.StripEndingZeroChars(Utils.Latin1Encoding.GetString(data, 0, (int)(endPos - initialPos)).Trim());
                if (str.Length > 0)
                {
                    meta.SetMetaField("bext.codingHistory", str, readTagParams.ReadAllMetaFrames);
                }
            }
        }
Esempio n. 17
0
        public static ImageProperties GetImageProperties(byte[] imageData, ImageFormat format = ImageFormat.Undefined)
        {
            ImageProperties props = new ImageProperties();

            if (ImageFormat.Undefined.Equals(format))
            {
                format = GetImageFormatFromPictureHeader(imageData);
            }

            if (format.Equals(ImageFormat.Unsupported))
            {
                return(props);
            }

            props.NumColorsInPalette = 0;
            props.Format             = format;

            using (MemoryStream s = new MemoryStream(imageData))
                using (BinaryReader r = new BinaryReader(s))
                {
                    long limit = (long)Math.Round(s.Length * 0.25); // TODO - test and adjust limit

                    switch (format)
                    {
                    case (ImageFormat.Tiff):
                        bool isBigEndian = (0x4D == r.ReadByte());
                        s.Seek(3, SeekOrigin.Current); // Skip the rest of the signature
                        long IFDOffset = readInt32(r, isBigEndian);

                        s.Seek(IFDOffset, SeekOrigin.Begin);

                        int nbIFDEntries = readInt16(r, isBigEndian);

                        long initialPos = s.Position;
                        int  IFDtag, IFDFieldType, IFDNbValues, IFDValue;
                        int  photometricInterpretation = 0;
                        int  bitsPerSample             = 0;
                        int  samplesPerPixel           = 0;

                        for (int i = 0; i < nbIFDEntries; i++)
                        {
                            IFDtag       = readInt16(r, isBigEndian);
                            IFDFieldType = readInt16(r, isBigEndian);
                            IFDNbValues  = readInt32(r, isBigEndian);
                            IFDValue     = readInt32(r, isBigEndian);

                            switch (IFDtag)
                            {
                            // Common properties
                            case (0x0100):
                                props.Width = IFDValue;
                                break;

                            case (0x0101):
                                props.Height = IFDValue;
                                break;

                            // Specific properties
                            case (0x0106):                      // PhotometricInterpretation
                                photometricInterpretation = IFDValue;
                                if (IFDValue < 2)
                                {
                                    props.ColorDepth = 1;                           // Bilevel image
                                }
                                else if (2 == IFDValue)
                                {
                                    props.ColorDepth = 24;                          // RGB full color image
                                }
                                // NB : A value of 3 would indicate a palette-color image, but has no effect here
                                break;

                            case (0x0102):                      // BitsPerSample
                                bitsPerSample = IFDValue;
                                break;

                            case (0x0115):                      // SamplesPerPixel
                                samplesPerPixel = IFDValue;
                                break;
                            }
                        }

                        if (photometricInterpretation < 2) // Bilevel
                        {
                            props.ColorDepth = bitsPerSample;
                        }
                        else if (2 == photometricInterpretation) // RGB
                        {
                            props.ColorDepth = 8 * samplesPerPixel;
                        }
                        else if (3 == photometricInterpretation) // Palette
                        {
                            props.ColorDepth         = 8 * samplesPerPixel;
                            props.NumColorsInPalette = bitsPerSample;
                        }


                        break;

                    case (ImageFormat.Gif):
                        byte[] GraphicControlExtensionBlockSignature = new byte[2] {
                            0x21, 0xf9
                        };

                        props.ColorDepth = 24;         // 1 byte for each component

                        s.Seek(3, SeekOrigin.Current); // Skip GIF signature

                        string version = Utils.Latin1Encoding.GetString(r.ReadBytes(3));

                        s.Seek(4, SeekOrigin.Current); // Skip logical screen descriptors

                        byte globalPaletteUse = r.ReadByte();
                        if (((globalPaletteUse & 0x80) >> 7) > 0) // File uses a global color palette
                        {
                            props.NumColorsInPalette = 2 << (globalPaletteUse & 0x07);
                        }

                        /*
                         * v89a means that the first image block should follow the first graphic control extension block
                         * (which may in turn be located after an application extension block if the GIF is animated)
                         *
                         * => The simplest way to get to the 1st image block is to look for the 1st
                         * graphic control extension block, and to skip it
                         */
                        if ("89a".Equals(version))
                        {
                            initialPos = s.Position;
                            if (StreamUtils.FindSequence(s, GraphicControlExtensionBlockSignature))
                            {
                                s.Seek(6, SeekOrigin.Current);
                            }
                            else
                            {
                                LogDelegator.GetLogDelegate()(Log.LV_WARNING, "Invalid v89a GIF file; no graphic control extension block found");
                                // GIF is malformed; trying to find the image block directly
                                s.Seek(initialPos, SeekOrigin.Begin);
                                if (StreamUtils.FindSequence(s, new byte[1] {
                                    0x2c
                                }))
                                {
                                    s.Seek(-1, SeekOrigin.Current);
                                }
                            }
                        }

                        // At this point, we should be at the very beginning of the first image block
                        if (0x2c == r.ReadByte())
                        {
                            s.Seek(4, SeekOrigin.Current); // Skip image position descriptors
                            props.Width  = r.ReadInt16();
                            props.Height = r.ReadInt16();

                            // No global palette is set => try and find information in the local palette of the 1st image block
                            if (0 == props.NumColorsInPalette)
                            {
                                props.NumColorsInPalette = (int)Math.Pow(2, ((globalPaletteUse & 0x0F) << 4) + 1);
                            }
                        }
                        else
                        {
                            LogDelegator.GetLogDelegate()(Log.LV_WARNING, "Error parsing GIF file; image block not found");
                        }

                        break;

                    case (ImageFormat.Bmp):

                        // Skip useless information
                        s.Seek(18, SeekOrigin.Begin);

                        props.Width  = r.ReadInt32();
                        props.Height = r.ReadInt32();
                        s.Seek(2, SeekOrigin.Current); // Planes
                        props.ColorDepth = r.ReadInt16();

                        // No support for BMP color palettes, as they seem to be exotic (and ATL has no use of this information)

                        break;

                    case (ImageFormat.Png):
                        byte[] intData               = new byte[4];
                        byte[] IHDRChunkSignature    = Utils.Latin1Encoding.GetBytes("IHDR");
                        byte[] PaletteChunkSignature = Utils.Latin1Encoding.GetBytes("PLTE");

                        // Skip header
                        s.Seek(8, SeekOrigin.Begin);

                        // Scroll chunks until we find IHDR (that should be the first one to appear, but who knows...)
                        if (0 == findPngChunk(s, IHDRChunkSignature, limit))
                        {
                            LogDelegator.GetLogDelegate()(Log.LV_WARNING, "Invalid PNG file; no IHDR chunk found");
                        }
                        else
                        {
                            // Read IHDR chunk
                            s.Read(intData, 0, 4);
                            props.Width = StreamUtils.DecodeBEInt32(intData);
                            s.Read(intData, 0, 4);
                            props.Height     = StreamUtils.DecodeBEInt32(intData);
                            props.ColorDepth = r.ReadByte();
                            int colorType = r.ReadByte();
                            if (3 == colorType)                // PNG file uses a palette
                            {
                                s.Seek(7, SeekOrigin.Current); // 3 last useful data + ending chunk CRC
                                uint paletteChunkSize = findPngChunk(s, PaletteChunkSignature, limit);
                                if (0 == paletteChunkSize)
                                {
                                    LogDelegator.GetLogDelegate()(Log.LV_WARNING, "Invalid PNG file; palette declared, but no PLTE chunk found");
                                }
                                else
                                {
                                    props.NumColorsInPalette = (int)Math.Floor(paletteChunkSize / 3.0);
                                }
                            }
                            else
                            {
                                props.NumColorsInPalette = 0;
                            }
                        }

                        break;

                    case (ImageFormat.Jpeg):
                        byte[] shortData          = new byte[2];
                        byte[] SOF0FrameSignature = new byte[2] {
                            0xFF, 0xC0
                        };

                        /*
                         * We just need to reach the SOF0 frame descripting the actual picture
                         *
                         * In order to handle JPEG files that contain multiple SOF0 frames (see test suite),
                         * the simplest way of proceeding is to look for all SOF0 frames in the first 25% of the file,
                         * and then read the very last one
                         */
                        long lastPos = 0;

                        while (StreamUtils.FindSequence(s, SOF0FrameSignature, limit))
                        {
                            lastPos = s.Position;
                        }

                        if (0 == lastPos)
                        {
                            LogDelegator.GetLogDelegate()(Log.LV_WARNING, "Invalid JPEG file; no SOF0 frame found");
                        }
                        else
                        {
                            // Skip frame length
                            s.Seek(2, SeekOrigin.Current);
                            bitsPerSample = r.ReadByte();
                            s.Read(shortData, 0, 2);
                            props.Height = StreamUtils.DecodeBEUInt16(shortData);
                            s.Read(shortData, 0, 2);
                            props.Width = StreamUtils.DecodeBEUInt16(shortData);
                            byte nbComponents = r.ReadByte();
                            props.ColorDepth = bitsPerSample * nbComponents;
                        }

                        break;
                    }
                }

            return(props);
        }