Esempio n. 1
0
        /// <summary>
        /// Parses a GNU MO file from the given stream and loads all available data.
        /// </summary>
        /// <remarks>
        ///	http://www.gnu.org/software/gettext/manual/html_node/MO-Files.html
        /// </remarks>
        /// <param name="stream">Stream that contain binary data in the MO file format</param>
        public void Parse(Stream stream)
        {
            this._Init();
            Trace.WriteLine("Trying to parse a MO file stream...", "NGettext");

            if (stream == null || stream.Length < 20)
            {
                throw new ArgumentException("Stream can not be null of less than 20 bytes long.");
            }

            var reader = new BinaryReader(new ReadOnlyStreamWrapper(stream));
            try
            {
                var magicNumber = reader.ReadUInt32();
                if (magicNumber != MO_FILE_MAGIC)
                {
                    // System.IO.BinaryReader does not respect machine endianness and always uses little-endian
                    // So we need to detect and read big-endian files by ourselves
                    if (_ReverseBytes(magicNumber) == MO_FILE_MAGIC)
                    {
                        Trace.WriteLine("Big Endian file detected. Switching readers...", "NGettext");
                        this.IsBigEndian = true;
            #if DNXCORE50
                        reader.Dispose();
            #else
                        reader.Close();
            #endif
                        reader = new BigEndianBinaryReader(new ReadOnlyStreamWrapper(stream));
                    }
                    else
                    {
                        throw new ArgumentException("Invalid stream: can not find MO file magic number.");
                    }
                }

                var revision = reader.ReadInt32();
                this.FormatRevision = new Version(revision >> 16, revision & 0xffff);

                Trace.WriteLine(String.Format("MO File Revision: {0}.{1}.", this.FormatRevision.Major, this.FormatRevision.Minor), "NGettext");

                if (this.FormatRevision.Major > MAX_SUPPORTED_VERSION)
                {
                    throw new Exception(String.Format("Unsupported MO file major revision: {0}.", this.FormatRevision.Major));
                }

                var stringCount = reader.ReadInt32();
                var originalTableOffset = reader.ReadInt32();
                var translationTableOffset = reader.ReadInt32();

                // We don't support hash tables and system dependent segments.

                Trace.WriteLine(String.Format("MO File contains {0} strings.", stringCount), "NGettext");

                var originalTable = new StringOffsetTable[stringCount];
                var translationTable = new StringOffsetTable[stringCount];

                Trace.WriteLine(String.Format("Trying to parse strings using encoding \"{0}\"...", this.Encoding), "NGettext");

                reader.BaseStream.Seek(originalTableOffset, SeekOrigin.Begin);
                for (int i = 0; i < stringCount; i++)
                {
                    originalTable[i].Length = reader.ReadInt32();
                    originalTable[i].Offset = reader.ReadInt32();
                }

                reader.BaseStream.Seek(translationTableOffset, SeekOrigin.Begin);
                for (int i = 0; i < stringCount; i++)
                {
                    translationTable[i].Length = reader.ReadInt32();
                    translationTable[i].Offset = reader.ReadInt32();
                }

                for (int i = 0; i < stringCount; i++)
                {
                    var originalStrings = this._ReadStrings(reader, originalTable[i].Offset, originalTable[i].Length);
                    var translatedStrings = this._ReadStrings(reader, translationTable[i].Offset, translationTable[i].Length);

                    if (originalStrings.Length == 0 || translatedStrings.Length == 0) continue;

                    if (originalStrings[0].Length == 0)
                    {
                        // MO file metadata processing
                        foreach (var headerText in translatedStrings[0].Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries))
                        {
                            var header = headerText.Split(new[] { ':' }, 2);
                            if (header.Length == 2)
                            {
                                this.Headers.Add(header[0], header[1].Trim());
                            }
                        }

                        if (this.DetectEncoding && this.Headers.ContainsKey("Content-Type"))
                        {
                            try
                            {
                                var contentType = new ContentType(this.Headers["Content-Type"]);
                                if (!String.IsNullOrEmpty(contentType.CharSet))
                                {
                                    this.Encoding = Encoding.GetEncoding(contentType.CharSet);
                                    Trace.WriteLine(String.Format("File encoding switched to \"{0}\" (\"{1}\" requested).", this.Encoding, contentType.CharSet), "NGettext");
                                }
                            }
                            catch (Exception exception)
                            {
                                Trace.WriteLine(String.Format("Unable to change parser encoding using the Content-Type header: \"{0}\".", exception.Message), "NGettext");
                            }
                        }
                        if (this.Headers.ContainsKey("Plural-Forms"))
                        {
                            //TODO: Plural forms parsing.
                        }
                    }

                    this.Translations.Add(originalStrings[0], translatedStrings);
                }

                Trace.WriteLine("String parsing completed.", "NGettext");

            }
            finally
            {
            #if DNXCORE50
                reader.Dispose();
            #else
                reader.Close();
            #endif
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Read and load all translation strings from given MO file stream.
        /// </summary>
        /// <remarks>
        ///	http://www.gnu.org/software/gettext/manual/html_node/MO-Files.html
        /// </remarks>
        /// <param name="stream">Stream that contain binary data in the MO file format</param>
        /// <returns>Raw translations</returns>
        public Dictionary <string, string[]> GetTranslations(Stream stream)
        {
            Trace.WriteLine("Trying to parse a MO file stream...", "Lib.Gettext");

            if (stream == null || stream.Length < 20)
            {
                throw new ArgumentException("Stream can not be null of less than 20 bytes long.");
            }

            var  reader      = new BinaryReader(stream);
            uint magicNumber = reader.ReadUInt32();

            if (magicNumber != 0x950412de)
            {
                throw new ArgumentException("Invalid stream: can not find MO file magic number.");
            }

            uint revision = reader.ReadUInt32();

            Trace.WriteLine(String.Format("MO File Revision: {0}.{1}.", revision >> 16, revision & 0xffff),
                            "Lib.Gettext");

            if ((revision >> 16) > 1)
            {
                throw new Exception(String.Format("Unsupported MO file major revision: {0}.", revision >> 16));
            }

            int stringCount             = reader.ReadInt32();
            int originalTableOffset     = reader.ReadInt32();
            int translationlTableOffset = reader.ReadInt32();

            // We don't support hash tables and system dependent segments.

            Trace.WriteLine(String.Format("MO File contains {0} strings.", stringCount), "Lib.Gettext");


            var originalTable     = new StringOffsetTable[stringCount];
            var translationlTable = new StringOffsetTable[stringCount];

            Trace.WriteLine(String.Format("Trying to parse strings using encoding \"{0}\"...", Encoding), "Lib.Gettext");

            reader.BaseStream.Seek(originalTableOffset, SeekOrigin.Begin);
            for (int i = 0; i < stringCount; i++)
            {
                originalTable[i].Length = reader.ReadInt32();
                originalTable[i].Offset = reader.ReadInt32();
            }

            reader.BaseStream.Seek(translationlTableOffset, SeekOrigin.Begin);
            for (int i = 0; i < stringCount; i++)
            {
                translationlTable[i].Length = reader.ReadInt32();
                translationlTable[i].Offset = reader.ReadInt32();
            }


            var dict = new Dictionary <string, string[]>(stringCount);

            for (int i = 0; i < stringCount; i++)
            {
                string[] originalStrings   = _ReadStrings(reader, originalTable[i].Offset, originalTable[i].Length);
                string[] translatedStrings = _ReadStrings(reader, translationlTable[i].Offset,
                                                          translationlTable[i].Length);

                dict.Add(originalStrings[0], translatedStrings);
            }

            Trace.WriteLine("String parsing completed.", "Lib.Gettext");

            return(dict);
        }
Esempio n. 3
0
        /// <summary>
        /// Parses a GNU MO file from the given stream and loads all available data.
        /// </summary>
        /// <remarks>
        ///	http://www.gnu.org/software/gettext/manual/html_node/MO-Files.html
        /// </remarks>
        /// <param name="stream">Stream that contain binary data in the MO file format</param>
        /// <returns>Parsed file data.</returns>
        public MoFile Parse(Stream stream)
        {
#if !NETSTANDARD1_0
            Trace.WriteLine("Trying to parse a MO file stream...", "NGettext");
#endif

            if (stream == null || stream.Length < 20)
            {
                throw new ArgumentException("Stream can not be null of less than 20 bytes long.");
            }

            var bigEndian = false;
            var reader    = new BinaryReader(new ReadOnlyStreamWrapper(stream));
            try
            {
                var magicNumber = reader.ReadUInt32();
                if (magicNumber != MO_FILE_MAGIC)
                {
                    // System.IO.BinaryReader does not respect machine endianness and always uses LittleEndian
                    // So we need to detect and read BigEendian files by ourselves
                    if (_ReverseBytes(magicNumber) == MO_FILE_MAGIC)
                    {
#if !NETSTANDARD1_0
                        Trace.WriteLine("BigEndian file detected. Switching readers...", "NGettext");
#endif
                        bigEndian = true;
                        ((IDisposable)reader).Dispose();
                        reader = new BigEndianBinaryReader(new ReadOnlyStreamWrapper(stream));
                    }
                    else
                    {
                        throw new ArgumentException("Invalid stream: can not find MO file magic number.");
                    }
                }

                var revision   = reader.ReadInt32();
                var parsedFile = new MoFile(new Version(revision >> 16, revision & 0xffff), this.DefaultEncoding, bigEndian);

#if !NETSTANDARD1_0
                Trace.WriteLine(String.Format("MO File Revision: {0}.{1}.", parsedFile.FormatRevision.Major, parsedFile.FormatRevision.Minor), "NGettext");
#endif

                if (parsedFile.FormatRevision.Major > MAX_SUPPORTED_VERSION)
                {
                    throw new CatalogLoadingException(String.Format("Unsupported MO file major revision: {0}.", parsedFile.FormatRevision.Major));
                }

                var stringCount            = reader.ReadInt32();
                var originalTableOffset    = reader.ReadInt32();
                var translationTableOffset = reader.ReadInt32();

                // We don't support hash tables and system dependent segments.

#if !NETSTANDARD1_0
                Trace.WriteLine(String.Format("MO File contains {0} strings.", stringCount), "NGettext");
#endif

                var originalTable    = new StringOffsetTable[stringCount];
                var translationTable = new StringOffsetTable[stringCount];

#if !NETSTANDARD1_0
                Trace.WriteLine(String.Format("Trying to parse strings using encoding \"{0}\"...", parsedFile.Encoding), "NGettext");
#endif

                reader.BaseStream.Seek(originalTableOffset, SeekOrigin.Begin);
                for (int i = 0; i < stringCount; i++)
                {
                    originalTable[i].Length = reader.ReadInt32();
                    originalTable[i].Offset = reader.ReadInt32();
                }

                reader.BaseStream.Seek(translationTableOffset, SeekOrigin.Begin);
                for (int i = 0; i < stringCount; i++)
                {
                    translationTable[i].Length = reader.ReadInt32();
                    translationTable[i].Offset = reader.ReadInt32();
                }


                for (int i = 0; i < stringCount; i++)
                {
                    var originalStrings   = this._ReadStrings(reader, originalTable[i].Offset, originalTable[i].Length, parsedFile.Encoding);
                    var translatedStrings = this._ReadStrings(reader, translationTable[i].Offset, translationTable[i].Length, parsedFile.Encoding);

                    if (originalStrings.Length == 0 || translatedStrings.Length == 0)
                    {
                        continue;
                    }

                    if (originalStrings[0].Length == 0)
                    {
                        // MO file meta data processing
                        foreach (var headerText in translatedStrings[0].Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries))
                        {
                            var separatorIndex = headerText.IndexOf(':');
                            if (separatorIndex > 0)
                            {
                                var headerName  = headerText.Substring(0, separatorIndex);
                                var headerValue = headerText.Substring(separatorIndex + 1).Trim();
                                if (parsedFile.Headers.ContainsKey(headerName))
                                {
                                    parsedFile.Headers.Add(headerName, headerValue.Trim());
                                }
                            }
                        }

                        if (this.AutoDetectEncoding && parsedFile.Headers.ContainsKey("Content-Type"))
                        {
                            try
                            {
                                var contentType = new ContentType(parsedFile.Headers["Content-Type"]);
                                if (!String.IsNullOrEmpty(contentType.CharSet))
                                {
                                    parsedFile.Encoding = Encoding.GetEncoding(contentType.CharSet);
#if !NETSTANDARD1_0
                                    Trace.WriteLine(String.Format("File encoding switched to \"{0}\" (\"{1}\" requested).", parsedFile.Encoding, contentType.CharSet), "NGettext");
#endif
                                }
                            }
                            catch (Exception exception)
                            {
                                throw new CatalogLoadingException(String.Format("Unable to change parser encoding using the Content-Type header: \"{0}\".", exception.Message), exception);
                            }
                        }
                    }

                    parsedFile.Translations.Add(originalStrings[0], translatedStrings);
                }

#if !NETSTANDARD1_0
                Trace.WriteLine("String parsing completed.", "NGettext");
#endif
                return(parsedFile);
            }
            finally
            {
                ((IDisposable)reader).Dispose();
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Read and load all translation strings from given MO file stream.
        /// </summary>
        /// <remarks>
        ///	http://www.gnu.org/software/gettext/manual/html_node/MO-Files.html
        /// </remarks>
        /// <param name="stream">Stream that contain binary data in the MO file format</param>
        /// <returns>Raw translations</returns>
        public Dictionary<string, string[]> GetTranslations(Stream stream)
        {
            Trace.WriteLine("Trying to parse a MO file stream...", "Lib.Gettext");

            if (stream == null || stream.Length < 20)
            {
                throw new ArgumentException("Stream can not be null of less than 20 bytes long.");
            }

            var reader = new BinaryReader(stream);
            uint magicNumber = reader.ReadUInt32();

            if (magicNumber != 0x950412de)
            {
                throw new ArgumentException("Invalid stream: can not find MO file magic number.");
            }

            uint revision = reader.ReadUInt32();
            Trace.WriteLine(String.Format("MO File Revision: {0}.{1}.", revision >> 16, revision & 0xffff),
                            "Lib.Gettext");

            if ((revision >> 16) > 1)
            {
                throw new Exception(String.Format("Unsupported MO file major revision: {0}.", revision >> 16));
            }

            int stringCount = reader.ReadInt32();
            int originalTableOffset = reader.ReadInt32();
            int translationlTableOffset = reader.ReadInt32();

            // We don't support hash tables and system dependent segments.

            Trace.WriteLine(String.Format("MO File contains {0} strings.", stringCount), "Lib.Gettext");

            var originalTable = new StringOffsetTable[stringCount];
            var translationlTable = new StringOffsetTable[stringCount];

            Trace.WriteLine(String.Format("Trying to parse strings using encoding \"{0}\"...", Encoding), "Lib.Gettext");

            reader.BaseStream.Seek(originalTableOffset, SeekOrigin.Begin);
            for (int i = 0; i < stringCount; i++)
            {
                originalTable[i].Length = reader.ReadInt32();
                originalTable[i].Offset = reader.ReadInt32();
            }

            reader.BaseStream.Seek(translationlTableOffset, SeekOrigin.Begin);
            for (int i = 0; i < stringCount; i++)
            {
                translationlTable[i].Length = reader.ReadInt32();
                translationlTable[i].Offset = reader.ReadInt32();
            }

            var dict = new Dictionary<string, string[]>(stringCount);

            for (int i = 0; i < stringCount; i++)
            {
                string[] originalStrings = _ReadStrings(reader, originalTable[i].Offset, originalTable[i].Length);
                string[] translatedStrings = _ReadStrings(reader, translationlTable[i].Offset,
                                                          translationlTable[i].Length);

                dict.Add(originalStrings[0], translatedStrings);
            }

            Trace.WriteLine("String parsing completed.", "Lib.Gettext");

            return dict;
        }
Esempio n. 5
0
        /// <summary>
        /// Parses a GNU MO file from the given stream and loads all available data.
        /// </summary>
        /// <remarks>
        ///	http://www.gnu.org/software/gettext/manual/html_node/MO-Files.html
        /// </remarks>
        /// <param name="stream">Stream that contain binary data in the MO file format</param>
        /// <returns>Parsed file data.</returns>
        public MoFile Parse(Stream stream)
        {
            #if !NETSTANDARD1_0
            Trace.WriteLine("Trying to parse a MO file stream...", "NGettext");
            #endif

            if (stream == null || stream.Length < 20)
            {
                throw new ArgumentException("Stream can not be null of less than 20 bytes long.");
            }

            var bigEndian = false;
            var reader = new BinaryReader(new ReadOnlyStreamWrapper(stream));
            try
            {
                var magicNumber = reader.ReadUInt32();
                if (magicNumber != MO_FILE_MAGIC)
                {
                    // System.IO.BinaryReader does not respect machine endianness and always uses LittleEndian
                    // So we need to detect and read BigEendian files by ourselves
                    if (_ReverseBytes(magicNumber) == MO_FILE_MAGIC)
                    {
            #if !NETSTANDARD1_0
                        Trace.WriteLine("BigEndian file detected. Switching readers...", "NGettext");
            #endif
                        bigEndian = true;
                        ((IDisposable)reader).Dispose();
                        reader = new BigEndianBinaryReader(new ReadOnlyStreamWrapper(stream));
                    }
                    else
                    {
                        throw new ArgumentException("Invalid stream: can not find MO file magic number.");
                    }
                }

                var revision = reader.ReadInt32();
                var parsedFile = new MoFile(new Version(revision >> 16, revision & 0xffff), this.DefaultEncoding, bigEndian);

            #if !NETSTANDARD1_0
                Trace.WriteLine(String.Format("MO File Revision: {0}.{1}.", parsedFile.FormatRevision.Major, parsedFile.FormatRevision.Minor), "NGettext");
            #endif

                if (parsedFile.FormatRevision.Major > MAX_SUPPORTED_VERSION)
                {
                    throw new CatalogLoadingException(String.Format("Unsupported MO file major revision: {0}.", parsedFile.FormatRevision.Major));
                }

                var stringCount = reader.ReadInt32();
                var originalTableOffset = reader.ReadInt32();
                var translationTableOffset = reader.ReadInt32();

                // We don't support hash tables and system dependent segments.

            #if !NETSTANDARD1_0
                Trace.WriteLine(String.Format("MO File contains {0} strings.", stringCount), "NGettext");
            #endif

                var originalTable = new StringOffsetTable[stringCount];
                var translationTable = new StringOffsetTable[stringCount];

            #if !NETSTANDARD1_0
                Trace.WriteLine(String.Format("Trying to parse strings using encoding \"{0}\"...", parsedFile.Encoding), "NGettext");
            #endif

                reader.BaseStream.Seek(originalTableOffset, SeekOrigin.Begin);
                for (int i = 0; i < stringCount; i++)
                {
                    originalTable[i].Length = reader.ReadInt32();
                    originalTable[i].Offset = reader.ReadInt32();
                }

                reader.BaseStream.Seek(translationTableOffset, SeekOrigin.Begin);
                for (int i = 0; i < stringCount; i++)
                {
                    translationTable[i].Length = reader.ReadInt32();
                    translationTable[i].Offset = reader.ReadInt32();
                }

                for (int i = 0; i < stringCount; i++)
                {
                    var originalStrings = this._ReadStrings(reader, originalTable[i].Offset, originalTable[i].Length, parsedFile.Encoding);
                    var translatedStrings = this._ReadStrings(reader, translationTable[i].Offset, translationTable[i].Length, parsedFile.Encoding);

                    if (originalStrings.Length == 0 || translatedStrings.Length == 0) continue;

                    if (originalStrings[0].Length == 0)
                    {
                        // MO file meta data processing
                        foreach (var headerText in translatedStrings[0].Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries))
                        {
                            var separatorIndex = headerText.IndexOf(':');
                            if (separatorIndex > 0)
                            {
                                var headerName = headerText.Substring(0, separatorIndex);
                                var headerValue = headerText.Substring(separatorIndex + 1).Trim();
                                parsedFile.Headers.Add(headerName, headerValue.Trim());
                            }
                        }

                        if (this.AutoDetectEncoding && parsedFile.Headers.ContainsKey("Content-Type"))
                        {
                            try
                            {
                                var contentType = new ContentType(parsedFile.Headers["Content-Type"]);
                                if (!String.IsNullOrEmpty(contentType.CharSet))
                                {
                                    parsedFile.Encoding = Encoding.GetEncoding(contentType.CharSet);
            #if !NETSTANDARD1_0
                                    Trace.WriteLine(String.Format("File encoding switched to \"{0}\" (\"{1}\" requested).", parsedFile.Encoding, contentType.CharSet), "NGettext");
            #endif
                                }
                            }
                            catch (Exception exception)
                            {
                                throw new CatalogLoadingException(String.Format("Unable to change parser encoding using the Content-Type header: \"{0}\".", exception.Message), exception);
                            }
                        }
                    }

                    parsedFile.Translations.Add(originalStrings[0], translatedStrings);
                }

            #if !NETSTANDARD1_0
                Trace.WriteLine("String parsing completed.", "NGettext");
            #endif
                return parsedFile;
            }
            finally
            {
                ((IDisposable)reader).Dispose();
            }
        }