I was chasing this problem (http://tracker.firebirdsql.org/browse/DNET-327) and was about to post to the list to try to find a solution when I found this http://blog.cincura.net/232192-ado-net-provider-2-6-0-for-firebird-released/ and in one of the comments (DEC 20, 2010) Jiri said:

"I was testing it with Mono 2.8.1 and 2.8.0 on Slackware, but maybe Mac version is missing some charsets. Simply comment out the line in FirebirdSql.Data.Common.Charset."

That tipped me off to an easy workaround so I started putting the #if (!MONO) around Charsets until I stopped getting the error. This solved my problem (for now, until I put my code on a different platform or version of my platform), but don't see this as a good solution for the Firebird provider project. In all I had to eliminate 15 character sets from that type initializer to get it to work, and it took the better part of a day to track down the root cause and do that elimination process.

So I'm posting to try to get an understanding of how this part of the code could work better, and contribute an enhancement. I'm not all that familiar with how the different OS, runtime and DB platforms deal with character sets, so I may be guilty of wishful thinking...so my question was: Is there a way to detect the character sets supported by the platform? We could then merge that with the character sets supported by Firebird and this provider and prevent this problem from reoccurring.

I tried a very straightforward approach using Encoding.GetEncodings and trying to search that list to eliminate unsupported encodings before problems were encountered, but that didn't work because accessing the EncodingInfo data (as returned from that method) throws an exception if the CodePage isn't supported, apparently because it is trying to initialize it's internal encoding when accessed*. So I mangled it to the less elegant version that I've attached. I've tested it here and it solves my problem without conditional compilation or commenting out unsupported encodings. Look for "InitializeSupportedCharsets". The old version is present, but commented out.

*This doesn't happen on MS.NET.  My environments are:

danno@puma:~/dev/firebird$ mono --version
Mono JIT compiler version 2.6.7 (Debian 2.6.7-5ubuntu1~dhx1)
Copyright (C) 2002-2010 Novell, Inc and Contributors. www.mono-project.com
        TLS:           __thread
        GC:            Included Boehm (with typed GC and Parallel Mark)
        SIGSEGV:       altstack
        Notifications: epoll
        Architecture:  amd64
        Disabled:      none

Firebird.NET Provider 2.6.0 (compiled on Ubuntu Desktop 10.04.2) testing on Ubuntu Server 10.04.2 (Lucid Lynx)

...and...

Windows.NET 2.0, Firebird.NET Provider 2.5.1 from download running on Windows XP (development and unit test with VS.NET 2005).


Also, one side note: when compiling 2.6.0 without the ENTITY_FRAMEWORK directive, I got errors on Entity.SSDLToFB.cs (added sometime after 2.5.2). Adding #if (NET_35 && ENTITY_FRAMEWORK) condition solved that problem. Is that missing conditional an oversight, or should I not need that conditional and is there something else wrong with my setup?

Cheers,
Danny


--
Danny Gorton II
Co-founder
Absolute Power and Control, LLC
www.absolutepowerandcontrol.com
/*
 *  Firebird ADO.NET Data provider for .NET and Mono 
 * 
 *     The contents of this file are subject to the Initial 
 *     Developer's Public License Version 1.0 (the "License"); 
 *     you may not use this file except in compliance with the 
 *     License. You may obtain a copy of the License at 
 *     http://www.firebirdsql.org/index.php?op=doc&id=idpl
 *
 *     Software distributed under the License is distributed on 
 *     an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either 
 *     express or implied.  See the License for the specific 
 *     language governing rights and limitations under the License.
 * 
 *  Copyright (c) 2002, 2007 Carlos Guzman Alvarez
 *  All Rights Reserved.
 *      
 *  Contributors:
 *    Jiri Cincura (j...@cincura.net)
 */

using System;
using System.Collections.Generic;
using System.Text;

namespace FirebirdSql.Data.Common
{
        internal sealed class Charset
        {
                #region · Static Fields ·

                private readonly static List<Charset> supportedCharsets = 
Charset.InitializeSupportedCharsets();
                

                
                #endregion

                #region · Static Properties ·

                public static Charset DefaultCharset
                {
                        get { return Charset.supportedCharsets[0]; }
                }

                #endregion

        #region · Static Methods ·

        public static Charset GetCharset(int charsetId)
        {
            foreach (Charset charset in supportedCharsets)
            {
                if (charset.Identifier == charsetId)
                    return charset;
            }
            return null;
        }

        public static Charset GetCharset(string charsetName)
        {
            foreach (Charset charset in supportedCharsets)
            {
                if (GlobalizationHelper.CultureAwareCompare(charset.Name, 
charsetName))
                    return charset;
            }
            return null;
        }

                private static List<Charset> InitializeSupportedCharsets()
        {
                        EncodingInfo[] systemEncodings = 
Encoding.GetEncodings();
                        
            List<Charset> charsets = new List<Charset>();

                        //these won't be in the system encodings and are 
handled differently.
            // NONE
            charsets.Add(new Charset(0, "NONE", 1, "NONE"));
            // OCTETS
            charsets.Add(new Charset(1, "OCTETS", 1, "OCTETS"));
                        
            
                        // American Standard Code for Information Interchange   
            addCharset(charsets, systemEncodings, 2, "ASCII", 1, "ascii");
                        
            // Eight-bit Unicode Transformation Format
            addCharset(charsets, systemEncodings, 3, "UNICODE_FSS", 3, "UTF-8");
            
                        // UTF8
            addCharset(charsets, systemEncodings, 4, "UTF8", 4, "UTF-8");

                        // Shift-JIS, Japanese
            addCharset(charsets, systemEncodings, 5, "SJIS_0208", 2, 
"shift_jis");

            // JIS X 0201, 0208, 0212, EUC encoding, Japanese
            addCharset(charsets, systemEncodings, 6, "EUCJ_0208", 2, "euc-jp");

                        // Windows Japanese     
            addCharset(charsets, systemEncodings, 7, "ISO2022-JP", 2, 
"iso-2022-jp");

            // MS-DOS United States, Australia, New Zealand, South Africa       
            addCharset(charsets, systemEncodings, 10, "DOS437", 1, "IBM437");
                        
            // MS-DOS Latin-1                           
            addCharset(charsets, systemEncodings, 11, "DOS850", 1, "ibm850");
                                     
            // MS-DOS Nordic    
            addCharset(charsets, systemEncodings, 12, "DOS865", 1, "IBM865");
                        
            // MS-DOS Portuguese        
            addCharset(charsets, systemEncodings, 13, "DOS860", 1, "IBM860");
                        
            // MS-DOS Canadian French   
            addCharset(charsets, systemEncodings, 14, "DOS863", 1, "IBM863");
                        
            // ISO 8859-1, Latin alphabet No. 1
            addCharset(charsets, systemEncodings, 21, "ISO8859_1", 1, 
"iso-8859-1");
                        
            // ISO 8859-2, Latin alphabet No. 2
            addCharset(charsets, systemEncodings, 22, "ISO8859_2", 1, 
"iso-8859-2");
                        
            // Windows Korean   
            addCharset(charsets, systemEncodings, 44, "KSC_5601", 2, 
"ks_c_5601-1987");

            // MS-DOS Icelandic 
            addCharset(charsets, systemEncodings, 47, "DOS861", 1, "ibm861");
                                   
            // Windows Eastern European
            addCharset(charsets, systemEncodings, 51, "WIN1250", 1, 
"windows-1250");
                        
                        // Windows Cyrillic
            addCharset(charsets, systemEncodings, 52, "WIN1251", 1, 
"windows-1251");
                                   
            // Windows Latin-1
            addCharset(charsets, systemEncodings, 53, "WIN1252", 1, 
"windows-1252");
                        
            // Windows Greek
            addCharset(charsets, systemEncodings, 54, "WIN1253", 1, 
"windows-1253");

            // Windows Turkish
            addCharset(charsets, systemEncodings, 55, "WIN1254", 1, 
"windows-1254");

            // Big5, Traditional Chinese
            addCharset(charsets, systemEncodings, 56, "BIG_5", 2, "big5");

            // GB2312, EUC encoding, Simplified Chinese 
            addCharset(charsets, systemEncodings, 57, "GB_2312", 2, "gb2312");

                        // Windows Hebrew
            addCharset(charsets, systemEncodings, 58, "WIN1255", 1, 
"windows-1255");

                        // Windows Arabic       
            addCharset(charsets, systemEncodings, 59, "WIN1256", 1, 
"windows-1256");

                        // Windows Baltic       
            addCharset(charsets, systemEncodings, 60, "WIN1257", 1, 
"windows-1257");

                        // UTF-16
            addCharset(charsets, systemEncodings, 61, "UTF16", 4, "utf-16");
            
                        // UTF-32
            addCharset(charsets, systemEncodings, 62, "UTF32", 4, "utf-32");
                        
            // Russian KOI8R
                        addCharset(charsets, systemEncodings, 63, "KOI8R", 2, 
"koi8-r");

            // Ukrainian KOI8U
            addCharset(charsets, systemEncodings, 64, "KOI8U", 2, "koi8-u");

            return charsets;
        }
                
                #region Old InitializeSupportedCharsets culled by dgorton

                /*
        private static List<Charset> InitializeSupportedCharsets()
        {
            List<Charset> charsets = new List<Charset>();

            // NONE
            charsets.Add(new Charset(0, "NONE", 1, "NONE"));
            // OCTETS
            charsets.Add(new Charset(1, "OCTETS", 1, "OCTETS"));
            // American Standard Code for Information Interchange       
            charsets.Add(new Charset(2, "ASCII", 1, "ascii"));
            // Eight-bit Unicode Transformation Format
            charsets.Add(new Charset(3, "UNICODE_FSS", 3, "UTF-8"));
            // UTF8
            charsets.Add(new Charset(4, "UTF8", 4, "UTF-8"));

                        // Shift-JIS, Japanese
            charsets.Add(new Charset(5, "SJIS_0208", 2, "shift_jis"));

            // JIS X 0201, 0208, 0212, EUC encoding, Japanese
            charsets.Add(new Charset(6, "EUCJ_0208", 2, "euc-jp"));

                        // Windows Japanese     
            charsets.Add(new Charset(7, "ISO2022-JP", 2, "iso-2022-jp"));
#endif

            // MS-DOS United States, Australia, New Zealand, South Africa       
            charsets.Add(new Charset(10, "DOS437", 1, "IBM437"));
            // MS-DOS Latin-1                           
            charsets.Add(new Charset(11, "DOS850", 1, "ibm850"));
            // MS-DOS Nordic    
            charsets.Add(new Charset(12, "DOS865", 1, "IBM865"));
            // MS-DOS Portuguese        
            charsets.Add(new Charset(13, "DOS860", 1, "IBM860"));
            // MS-DOS Canadian French   
            charsets.Add(new Charset(14, "DOS863", 1, "IBM863"));
            // ISO 8859-1, Latin alphabet No. 1
            charsets.Add(new Charset(21, "ISO8859_1", 1, "iso-8859-1"));
            // ISO 8859-2, Latin alphabet No. 2
            charsets.Add(new Charset(22, "ISO8859_2", 1, "iso-8859-2"));
#if (!MONO)
            // Windows Korean   
            charsets.Add(new Charset(44, "KSC_5601", 2, "ks_c_5601-1987"));
#endif
            // MS-DOS Icelandic 
            charsets.Add(new Charset(47, "DOS861", 1, "ibm861"));
            // Windows Eastern European
            charsets.Add(new Charset(51, "WIN1250", 1, "windows-1250"));
                        
#if (!MONO)             
                        // Windows Cyrillic
            charsets.Add(new Charset(52, "WIN1251", 1, "windows-1251"));
#endif
            // Windows Latin-1
            charsets.Add(new Charset(53, "WIN1252", 1, "windows-1252"));
            // Windows Greek
            charsets.Add(new Charset(54, "WIN1253", 1, "windows-1253"));
#if (!MONO)                             
            // Windows Turkish
            charsets.Add(new Charset(55, "WIN1254", 1, "windows-1254"));

            // Big5, Traditional Chinese
            charsets.Add(new Charset(56, "BIG_5", 2, "big5"));

            // GB2312, EUC encoding, Simplified Chinese 
            charsets.Add(new Charset(57, "GB_2312", 2, "gb2312"));

                        // Windows Hebrew
            charsets.Add(new Charset(58, "WIN1255", 1, "windows-1255"));

                        // Windows Arabic       
            charsets.Add(new Charset(59, "WIN1256", 1, "windows-1256"));

                        // Windows Baltic       
            charsets.Add(new Charset(60, "WIN1257", 1, "windows-1257"));

                        // UTF-16
            // Charset.Add(new Charset(61, "UTF16", 4, "utf-16"));
            // UTF-32
            // Charset.Add(new Charset(62, "UTF32", 4, "utf-32"));
            // Russian KOI8R
                        charsets.Add(new Charset(63, "KOI8R", 2, "koi8-r"));

            // Ukrainian KOI8U
            charsets.Add(new Charset(64, "KOI8U", 2, "koi8-u"));
#endif
            return charsets;
        }
*/
                #endregion Old InitializeSupportedCharsets culled by dgorton
                
                
                
                private static void addCharset(List<Charset> list, 
                                               EncodingInfo[] systemEncodings,
                                               int id, 
                                               string name, 
                                               int bytesPerCharacter, 
                                               string systemName)
                {
                        foreach(EncodingInfo ei in systemEncodings)
                        {
                                try
                                {
                                        if (ei.Name.Equals(systemName, 
StringComparison.OrdinalIgnoreCase))
                                        {

                                                list.Add(new Charset(id, name, 
bytesPerCharacter, systemName)); 
                                        }
                                }
                                catch
                                {
                                                /*I hate doing this, but eat 
it, and possibly log it out. 
                                                  However, note that the 
exception is thrown upon accessing ei.Name
                                                  (CodePage xx not supported), 
so it must be trying to access the 
                                                  encoding for internal 
reasons, which doesn't happen on MS.NET.
                                                  One way to clean this up 
might be to access the encodings by their
                                                  codepage rather than by name. 
 I'm not sure what the Charset.ID 
                                                  property means to Firebird, 
but it doesn't seem to correlate to 
                                                  codepage as I understand it, 
so this is about as far as I can go
                                                  without some collaborative 
input.
                                                */      
                                }
                        }
                }
                
        #endregion

                #region · Fields ·

                private int                 id;
                private int                 bytesPerCharacter;
                private string      name;
                private string      systemName;
        private Encoding    encoding;
        private object      syncObject;

                #endregion

                #region · Properties ·

                public int Identifier
                {
                        get { return this.id; }
                }

                public string Name
                {
                        get { return this.name; }
                }

                public int BytesPerCharacter
                {
                        get { return this.bytesPerCharacter; }
                }

        public bool IsOctetsCharset
        {
            get { return (this.id == Charset.GetCharset("OCTETS").Identifier); }
        }

                #endregion

                #region · Constructors ·

                public Charset(int id, string name, int bytesPerCharacter, 
string systemName)
                {
                        this.id                                 = id;
                        this.name                               = name;
                        this.bytesPerCharacter  = bytesPerCharacter;
                        this.systemName                 = systemName;
            this.syncObject         = new object();

#if (!NET_CF)
            this.GetEncoding();
#endif
                }

                #endregion

                #region · Methods ·

                public byte[] GetBytes(string s)
                {
#if (NET_CF)
                        return this.GetEncoding().GetBytes(s);
#else
            return this.encoding.GetBytes(s);
#endif
                }

                public int GetBytes(string s, int charIndex, int charCount, 
byte[] bytes, int byteIndex)
                {
#if (NET_CF)
                        return this.GetEncoding().GetBytes(s, charIndex, 
charCount, bytes, byteIndex);
#else
            return this.encoding.GetBytes(s, charIndex, charCount, bytes, 
byteIndex);
#endif
                }

                public string GetString(byte[] buffer)
                {
                        return this.GetString(buffer, 0, buffer.Length);
                }

                public string GetString(byte[] buffer, int index, int count)
                {
#if (NET_CF)
                        return this.GetEncoding().GetString(buffer, index, 
count);
#else
            return this.encoding.GetString(buffer, index, count);
#endif
                }

                #endregion

                #region · Private Methods ·

                private Encoding GetEncoding()
                {
            lock (this.syncObject)
            {
                if (this.encoding == null)
                {
                    switch (this.systemName)
                    {
                        case "NONE":
                            this.encoding = Encoding.Default;
                            break;

                        case "OCTETS":
                            this.encoding = new BinaryEncoding();
                            break;

                        default:
                            this.encoding = 
Encoding.GetEncoding(this.systemName);
                            break;
                    }
                }
            }

            return this.encoding;
                }

                #endregion
        }
}
------------------------------------------------------------------------------
Enable your software for Intel(R) Active Management Technology to meet the
growing manageability and security demands of your customers. Businesses
are taking advantage of Intel(R) vPro (TM) technology - will your software 
be a part of the solution? Download the Intel(R) Manageability Checker 
today! http://p.sf.net/sfu/intel-dev2devmar
_______________________________________________
Firebird-net-provider mailing list
Firebird-net-provider@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/firebird-net-provider

Reply via email to