Esta código lê um arquivo no formato DFM (Delphi Form), na modalidade "texto plano" e extrai dele as propriedades e seus valores. Atualmente apenas as propriedades do form (raiz do DFM) são lidas. Para ler todo o arquivo DFM é necessário melhorar este código e usar recursividade. O código não é perfeito, mas dá uma boa ideia do que precisa ser feito

Formato
Delphi
Post date
2021-04-09 04:02
Publication Period
Unlimited
  1. procedure ReadTextDFM(ADFMFile: TFileName; List: TStrings);
  2. var
  3. FileStream: TFileStream;
  4. BinaryStream: TMemoryStream;
  5. AuxShortString: ShortString;
  6. AuxUTF8String: UTF8String;
  7. AuxInt8: Int8;
  8. AuxInt16: Int16;
  9. AuxInt32: Int32;
  10. AuxInt64: Int64;
  11. PropertyName: ShortString;
  12. PropertyValue: String;
  13. Buffer: PByte;
  14. begin
  15. List.Clear;
  16. FileStream := TFileStream.Create(ADFMFile, fmOpenRead);
  17. try
  18. BinaryStream := TMemoryStream.Create;
  19. try
  20. FileStream.Seek(0, sofrombeginning);
  21. ObjectTextToBinary(FileStream, BinaryStream);
  22. BinaryStream.Seek(0,soFromBeginning);
  23. // Signature (ShortString)
  24. // Numa ShortString o elemento zero é o tamanho da string e o elemento 1 é
  25. // o início da string propriamente dita! Eu sei que a string de assinatura
  26. // tem 4 bytes, logo, pra começar eu configuro o tamanho corretamente da
  27. // string em seguida eu copio os 4 bytes a partir do elemento 1 da string,
  28. // dessa forma eu terei uma ShortString bem formada que contém a
  29. // assinatura do arquivo (magic number)
  30. AuxShortString[0] := AnsiChar(4);
  31. BinaryStream.Read(AuxShortString[1],4);
  32. List.Add('Signature = ' + AuxShortString);
  33. // FormClassName (ShortString)
  34. // Primeiro obtém o tamanho, depos usa esse tamanho para obter o valor do
  35. // nome da classe do form
  36. BinaryStream.Read(AuxInt8,1);
  37. AuxShortString[0] := AnsiChar(AuxInt8);
  38. BinaryStream.Read(AuxShortString[1],AuxInt8);
  39. List.Add('Form Class Name = ' + AuxShortString);
  40. // FormName (ShortString)
  41. BinaryStream.Read(AuxInt8,1);
  42. AuxShortString[0] := AnsiChar(AuxInt8);
  43. BinaryStream.Read(AuxShortString[1],AuxInt8);
  44. List.Add('Form Name = ' + AuxShortString);
  45. // A partir desse ponto é a parte que varia de acordo com qual componente
  46. // está sendo lido do dfm.
  47. while BinaryStream.Position < BinaryStream.Size do
  48. begin
  49. // Cada loop vai ser responsável por ler uma propriedade, então no
  50. // inicio do loop eu sempre estarei lendo o tamanho do nome da
  51. // propriedade. Quando o byte lido aqui é zero, significa que um
  52. // componente vai começar, um componente colocado no form. Neste momento
  53. // a função atual tem que ser chamada desde o começo, porém a partir do
  54. // ponto onde estamos em BinaryStream. Não vou implementar isso... Se
  55. // vira! (Envolve recursividade)
  56. // NomeDaPropriedade
  57. BinaryStream.Read(AuxInt8,1);
  58. if AuxInt8 = 0 then
  59. Break;
  60. PropertyName[0] := AnsiChar(AuxInt8);
  61. BinaryStream.Read(PropertyName[1],AuxInt8);
  62. // Tipo da propriedade
  63. BinaryStream.Read(AuxInt8,1);
  64. case TValueType(AuxInt8) of
  65. vaInt8: begin //1 Byte
  66. BinaryStream.Read(AuxInt8,1);
  67. PropertyValue := AuxInt8.ToString;
  68. end;
  69. vaInt16: begin //2 Bytes
  70. BinaryStream.Read(AuxInt16,2);
  71. PropertyValue := AuxInt16.ToString;
  72. end;
  73. vaInt32: begin //4 Bytes
  74. BinaryStream.Read(AuxInt32,4);
  75. PropertyValue := AuxInt32.ToString;
  76. end;
  77. vaInt64: begin //8 Bytes
  78. BinaryStream.Read(AuxInt64,8);
  79. PropertyValue := AuxInt64.ToString;
  80. end;
  81. vaUTF8String: begin // String UTF8 (Esta algoritmo não está bom)
  82. BinaryStream.Read(AuxInt32,4);
  83. // Variáveis declaradas que não são ponteiros ou objetos são
  84. // inicializadas automaticamente pelo Delphi. Variáveis String, e
  85. // isso inclui UTF8String, são ponteiros que apontam para o local
  86. // real onde a string está. O tamanho da string está nos 4 bytes
  87. // anteriores ao endereço de onde está a string propriamente dita,
  88. // mais ou menos assim:
  89. // XX XX XX XX YY YY YY YY YY YY
  90. // Onde XX são os bytes que represetam o tamanho da string e YY são
  91. // os bytes da string propriamente dita. O valor de uma variável
  92. // string é um ponteiro que aponta para o primeiro Byte da string
  93. // (Primeiro YY no exemplo). Ao declarar uma variável string, a sua
  94. // memória já estará alocada, mas a memória da string propriamente
  95. // dita, não! Antes da primeira atribuição a string, ela aponta para
  96. // "nil" e é por isso que não podemos acessar o endereço da string
  97. // propriamente dita, porque ele contém nil. Ao fazer a primeira
  98. // atribuição a string é inicializada e passa a apontar para um
  99. // endereço válido, aliás, toda vez que se atribui um novo valor a
  100. // uma string, ela passa a apontar para outro local da memória,
  101. // sempre ocupando o tamanho da string em Bytes + 4 Bytes de tamanho
  102. // no offset negativo. O gerenciamento da memória das strings é
  103. // feito automaticamente pelo Delphi. Como abaixo eu quero acessar
  104. // os dados da string diretamente, eu preciso inicializar a string
  105. // com a quantidade de Bytes, para (re)inicializar a string de forma
  106. // que ela aponte para um endereço válido. O SetString em combinação
  107. // com DupeString resolvem esse problema! Após a linha a seguir
  108. // teremos um endereço válido de memória que poderá ser preenchido
  109. // diretamente
  110. SetString(AuxUTF8String,PChar(DupeString(#0,AuxInt32)),AuxInt32);
  111. BinaryStream.Read(Pointer(AuxUTF8String)^,AuxInt32);
  112. // Isso já resolve a conversão entre UTF-8 e Unicode automaticamente
  113. PropertyValue := String(AuxUTF8String);
  114. end;
  115. vaIdent, vaString: begin // Membro de uma enumeração ou ShortString (é shortstring mesmo)
  116. BinaryStream.Read(AuxInt8,1);
  117. AuxShortString[0] := AnsiChar(AuxInt8);
  118. BinaryStream.Read(AuxShortString[1],AuxInt8);
  119. PropertyValue := String(AuxShortString);
  120. end;
  121. vaExtended: begin
  122. // Não implementei
  123. end;
  124. vaBinary: begin
  125. // Não implementei
  126. end;
  127. vaSet: begin
  128. BinaryStream.Read(AuxInt8,1);
  129. if AuxInt8 > 0 then
  130. begin
  131. // Não implementei
  132. end
  133. else
  134. PropertyValue := '[]';
  135. end;
  136. vaFalse: begin
  137. // Não precisa ler nada, pois o valor é o tipo, no caso False
  138. PropertyValue := 'False';
  139. end;
  140. vaTrue: begin
  141. // Não precisa ler nada, pois o valor é o tipo, no caso True
  142. PropertyValue := 'True';
  143. end;
  144. end;
  145. List.Add(PropertyName + ' = ' + PropertyValue);
  146. end;
  147. finally
  148. BinaryStream.Free;
  149. end;
  150. finally
  151. FileStream.Free;
  152. end;
  153. end;
Download Printable view

URL of this paste

Embed with JavaScript

Embed with iframe

Raw text