sexta-feira, 18 de fevereiro de 2011

Criando um arquivo unicode com BOM a partir do Delphi 7

Hoje um colega que leu meu post sobre quebra de linhas no Delphi 7 e no Delphi novo teve uma dúvida: Ele não estava conseguindo criar um arquivo de conexão UDL válido. Todos eles davam erro ao abrir.

Ele me disse que usar widestring não resolveu.

Fiquei surpreso do porque ele precisaria gerar o udl pelo Delphi, já que é possível apenas criar um arquivo de texto vazio, renomear ara .udl, e o arquivo será criado normalmente. Mas, ele tinha essa necessidade.

Uma das coisas que descobri hoje é que este arquivo, além de começar com [oledb], deve obrigatoriamente ter o "comentário" abaixo. Ou seja, não é apenas um comentario.

[oledb]
; Everything after this line is an OLE DB initstring

O conteúdo deve ser idêntico a esse. Mas não é apenas o conteúdo. Mesmo que se grave os cabeçalhos corretamente e as strings de conexão, e mesmo que as strings sejam widestrings de dois bytes (unicode) o arquivo em si ainda precisa de alguma coisa.

Essa alguma coisa é o BOM: Abrindo um arquivo que funcione em um editor hexadecimal verá que o arquivo começa com os bytes FF e FE.

Esse FF FE se chama BOM, Byte order mark, (http://en.wikipedia.org/wiki/Byte_order_mark) e diz para o programa que estiver lendo o arquivo qual é o formato (unicode ou não) e qual a orientação (big endian ou litle endian).

O BOM em si é um único char, um widechar de 2 bytes. Como você sabe o tamanho do BOM de cara fica fácil escrever ele no stream: o tamanho será 2, ou 1 * sizeof(widechar). Não concatene o BOM, nem "tipe" ele, pois ele será deformado. Grave-o como um puro array de 2 bytes.

Há alguns programas que não precisam do BOM, pois tentam inferir o tipo de arquivo pelo conteudo. Mas outros, como o programinha do windows que le/edita os udl ou o proprio notepad++ salvam o arquivo já com o BOM, e precisam dele para ler.

Faça o seguinte: crie uma const chamada BOM e grave essa constante no arquivo antes de gravar o restante do conteudo. Repare que o problema não é a quebra de linha, mas sim o BOM.


Mas atenção: não é apenas só por causa do BOM.

Como ja dissemos antes o arquivo deve ter inicialmente 3 linhas onde a primeira é [oledb] e a segunda deve ter exatamente 52 caracteres e deve ser exatamente: "; Everything after this line is an OLE DB initstring"

Exemplo de arquivo udl que se conecta em bases dbase.
[oledb]
; Everything after this line is an OLE DB initstring
Provider=MSDASQL.1;Persist Security Info=False;Data Source=dBASE Files

Exemplo de código usando const ou array de bytes. Perceba que um char pode ser representado pelo seu valor hexadecimal contanto que seja precedido de #$. O BOM é #$FF#$FE.
procedure TForm1.Button1Click(Sender: TObject);
var
  teste: WideString;
const
//  BOM = #$FF#$FE;
    BOM: array[1..2] of Byte = ($ff, $fe); 
begin

  with TFileStream.Create(ExtractFilePath(Application.ExeName)+'\teste.udl', fmCreate) do
  try
    teste :=
      '[oledb]'+#13#10+
      '; Everything after this line is an OLE DB initstring'+#13#10+
      'Provider=MSDASQL.1;Persist Security Info=False;Data Source=dBASE Files';
    //você sabe que o BOM tem um tamanho fixo, que é 2 bytes. O bom é um único widechar de 2 bytes
    Write(BOM, 1 * sizeof(widechar)); //2
    Write(Pointer(teste)^, Length(teste)*SizeOf(WideChar));
  finally
    Free;
  end;

end;


faça o download do exemplo.

Have fun ;)

Um comentário:

  1. Cara.... Muito obrigado pela dica. Estava precisando somente disso para finalizar meu SETUP para SQL SERVER. Muito bom mesmo! Fico te devendo essa.

    ResponderExcluir

Postagens populares

Marcadores

delphi (60) C# (31) poo (21) Lazarus (19) Site aos Pedaços (15) sql (13) Reflexões (10) .Net (9) Humor (9) javascript (9) ASp.Net (8) api (8) Básico (6) Programação (6) ms sql server (5) Web (4) banco de dados (4) HTML (3) PHP (3) Python (3) design patterns (3) jQuery (3) livros (3) metaprogramação (3) Ajax (2) Debug (2) Dicas Básicas Windows (2) Pascal (2) games (2) linguagem (2) música (2) singleton (2) tecnologia (2) Anime (1) Api do Windows (1) Assembly (1) Eventos (1) Experts (1) GNU (1) Inglês (1) JSON (1) SO (1) datas (1) developers (1) dicas (1) easter egg (1) firebird (1) interfaces (1) introspecção (1) memo (1) oracle (1) reflexão (1)