Thema: Delphi DCP Format

Einzelnen Beitrag anzeigen

Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.132 Beiträge
 
Delphi 12 Athens
 
#19

AW: DCP Format

  Alt 20. Sep 2022, 22:04
GExperts : Joar, mit paar Hindernissen, aber geht erstmal.

Die Liste ist unsortiert ... echt brutal dort was zu finden (drinnen suchen oder rauskopieren geht nicht)
und wenn man wissen will wo etwas drin ist und nicht nur ob dort etwas drin ist,
dann mußt du umständlich tausende DCPs öffnen und überall achsehn.

Ich denke mal die lesen einfach die PE-Ressourcen aus. Dort gibt es zwei/drei einfache Ressourcen, wo z.B. Info vom Compiler drin stehen und für die Lizenzierung (CE/Pro/Ent/Starter und indirekt auch die Version), also mit welchem Delphi kompiliert wurde.


Hab jetzt erstmal mit dem DCP-Parser angefangen (PE-Parser/Editor kommt später ... schon zu lange geplant).
Im ersten Schritt kommt eine JSON raus.

Später als Plugin im Delphi, bzw. eventuell ins IDE-Insight (F6), falls das von der Masse an Daten nicht zusammenbricht.
* welche BPL hängt wovon ab
* welche Unit ist wo drin
* [vielleicht auch] was ist in welcher Unit drin, bzw. wo ist was drin (Typen/Klassen/Methoden/............)

-> nach TEdit suchen und Unit + Package wird angezeigt
-> nach dateiname.bpl suchen und alle Packages werden angezeigt, welche es benötig (und was die nutzen usw.)


Die Unit-Infos hab ich noch nicht durch,
aber im Contains stehen wirklich nur die Contains drin, also was explizit an Units im Package ist (leider ohne das implizit Einkompilierte).


Die DCP-Verzeichnisse von Delphi und unsere Eigenen werden in Sekunden ausgelesen und aus paar hundert *.DCP entstechen entsprechende *.JSON
Diese Dateien hab ich mir einfach erstmal in ein Exportverzeichnis unserer DB-Synchro-Tabellen gelegt ... mit Strg+Shift+F wird das zusammen mit unseren DB-ErstellungsSQL, den Programmquellcodes, den Fremdkomponentencodes und anschießend noch die Delphi-Quellcodes durchsucht. (Suchen im Delphi und Alles wird gefunden )


Die Unit-Infos parse ich noch nicht, aber für den Anfang
Code:
{
    "ReadStatus": "Disabled: ContainsData",
    "DataType": "DCP: Delphi Compiled Package",
    "FileMagic": "PKX0",
    "FileVersion": "0",
    "Counts": "req1 con50@47:3847 flg00400000 9 10",
    "FileName": "vcl280.bpl",
    "Requires": [
        "rtl"
    ],
    "Contains": {
        "Vcl.Consts": null,
        "Vcl.Graphics": null,
        "Vcl.ActnList": null,
        "Vcl.GraphUtil": null,
        "Vcl.Controls": null,
        "Vcl.StdCtrls": null,
        "Vcl.Mask": null,
        "Vcl.Printers": null,
        "Vcl.ToolWin": null,
        "Vcl.ListActns": null,
        "Vcl.ComStrs": null,
        "Vcl.StdActns": null,
        "Vcl.ComCtrls": null,
        "Vcl.Dialogs": null,
        "Vcl.ExtCtrls": null,
        "Vcl.Themes": null,
        "Vcl.ImgList": null,
        "Vcl.Menus": null,
        "Vcl.Forms": null,
        "Vcl.Clipbrd": null,
        "Vcl.Grids": null,
        "Vcl.ValEdit": null,
        "Vcl.OleConst": null,
        "Vcl.OleCtnrs": null,
        "Vcl.AxCtrls": null,
        "Vcl.OleCtrls": null,
        "Vcl.OleServer": null,
        "Vcl.Buttons": null,
        "Vcl.ExtDlgs": null,
        "Vcl.SvcMgr": null,
        "Vcl.AppEvnts": null,
        "Vcl.ExtActns": null,
        "Vcl.WinHelpViewer": null,
        "Vcl.HtmlHelpViewer": null,
        "Vcl.CmAdmCtl": null,
        "Vcl.XPMan": null,
        "Vcl.CategoryButtons": null,
        "Vcl.ButtonGroup": null,
        "Vcl.CaptionedDockTree": null,
        "Vcl.Tabs": null,
        "Vcl.DockTabSet": null,
        "Vcl.IMouse": null,
        "Vcl.ShellAnimations": null,
        "Vcl.Direct2D": null,
        "Vcl.ShareContract": null,
        "Vcl.SysStyles": null,
        "Vcl.Styles": null,
        "Vcl.Taskbar": null,
        "Vcl.JumpList": null,
        ".vcl": null
    }
}
bzw.
Code:
{
    "ReadStatus": null,
    "DataType": "DCP: Delphi Compiled Package",
    "FileMagic": "PKX0",
    "FileVersion": "0",
    "Counts": "req1 con50@47:3847 flg00400000 9 10",
    "FileName": "vcl280.bpl",
    "Requires": [
        "rtl"
    ],
    "Contains": {
        "Vcl.Consts": {
            "UnitHeader": "00000F36", "Flags": "FFFFFFFF", "FileFime": "DCF1E496", "bplCode": "00408060", "bplData": "00678138",
            "bplBSS": "0067A188", "X": "0067D04C", "H": "00000000", "I": "00000000", "J": "00000000", "K": "00000000",
            "L": "00000000", "M": "00000000", "N": "00000000", "O": "00000000", "Namespace": "Vcl"
        },
        "Vcl.Graphics": {
            "UnitHeader": "00013672", "Flags": "FFFFFFFF", "FileFime": "DCF1E496", "bplCode": "00408D88", "bplData": "00678140",
            "bplBSS": "0067A188", "X": "0067D050", "H": "00000000", "I": "00000000", "J": "00000000", "K": "00000000",
            "L": "00000000", "M": "00000000", "N": "00000000", "O": "00000000", "Namespace": "Vcl"
        },
        "Vcl.ActnList": {
            "UnitHeader": "00049AD9", "Flags": "FFFFFFFF", "FileFime": "DCF1E496", "bplCode": "0041E908", "bplData": "00678270",
            "bplBSS": "0067A404", "X": "0067D0D0", "H": "00000000", "I": "00000000", "J": "00000000", "K": "00000000",
            "L": "00000000", "M": "00000000", "N": "00000000", "O": "00000000", "Namespace": "Vcl"
        },
        ...

    }
}
und für Interessierte (oder Fehlersuche)
noch eine Textansicht des DCP-Inhalts, aus Infos/Schnittmarken der vollständigen JSON generiert


Code:
### 0: FileHeader\FileMagic ###
PKX0·01·00·00·002·00·00·00·07·0F·00·00/·00·00·00·00·00@·00·09·00·00·00·0A·00·00·00vcl280.bpl·00

### 43: Requires ###
rtl·00

### 47: Contains ### 
### 47: Contains\Vcl.Consts ###
6·0F·00·00·FF·FF·FF·FF·96·E4·F1·DC`·80@·008·81g·00·88·A1g·00L·D0g·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00Vcl.Consts·00Vcl·00

### 122: Contains\Vcl.Graphics ###
r6·01·00·FF·FF·FF·FF·96·E4·F1·DC·88·8D@·00@·81g·00·88·A1g·00P·D0g·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00Vcl.Graphics·00Vcl·00

...

### 3828: Contains\.vcl ###
E1r·00·FF·FF·FF·FF·98·E4·F1·DC·08Kg·00·D8·9Fg·00·1C·C2g·00t·0Di·000·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·00·03·00·00·00.vcl·00·00

### 3894: Units ### 
### 3894: Units\Vcl.Consts ###
M·03·00#<'·01·00·FF·FF·FF·FF·96·E4·F1·DC·00·02·03Vcl·FE·13·FF·F3·96·00·06<p·0EVcl.Consts.pas·CC·B6·D0T·00d·06System·00·00
...
bissl ausgezogene Spaghetti, welche jene Ausgaben verbrockt haben (hier nur die neuen Compiler seit 2009, also ohne D2-D7)
Delphi-Quellcode:
var FileName := 'C:\Program Files (x86)\Embarcadero\Studio\22.0\lib\win32\debug\vcl.dcp';
var FileMem := TFile.ReadAllBytes(FileName);
var ReadCheck: TBytes := nil;
SetLength(ReadCheck, Length(FileMem));

var JResult := TJSONObject.Create;
var FileData := TDataReader.Create(JResult, 255, 0, @FileMem[0], @ReadCheck[0], Length(FileMem));
JSONAddOrUpdate(JResult, 'ReadStatus', NULL);
JSONAddOrUpdate(JResult, 'DataType', 'DCP: Delphi Compiled Package');

{ Header :
  INT:PKX? (IF isMSIL)INT:MSIL
  INT:cntRequires INT:cntContains INT:sizeContains INT:posContains
  WORD:cntWord5a WORD:cntWord5b INT:cntInt6 INT:cntInt7
  PCHAR:Filename
}


var Magic := FileData.ReadChar;
JSONAddOrUpdate(JResult, 'FileMagic', string(Magic));
if Copy(Magic, 1, 3) <> 'PKXthen
  JSONSetAndAbort(JResult, 'ReadStatus', 'invalid file magic');

var FileVersion := Magic[3];
JSONAddOrUpdate(JResult, 'FileVersion', FileVersion);
if not (Magic[3] in ['0', '4', '5', '7', '9']) then
  JSONSetAndAbort(JResult, 'ReadStatus', 'invalid file version');

var isMSIL := EndsText('L', FileName);
if isMSIL then
  JSONAddOrUpdate(JResult, 'Platform', 'MSIL');

if isMSIL then FileData.ReadInt;
var cntRequires := FileData.ReadInt;
var cntContains := FileData.ReadInt;
var sizeContains := FileData.ReadInt;
var posContains := FileData.ReadInt;
var cntInt5 := FileData.ReadInt;
var cntInt6 := FileData.ReadInt;
var cntInt7 := FileData.ReadInt;
JSONAddOrUpdate(JResult, 'Counts', Format('req%d con%d@%d:%d flg%.8x %d %d',
  [cntRequires, cntContains, posContains, sizeContains,
   cntInt5, cntInt6, cntInt7]));

JSONAddOrUpdate(JResult, 'FileName', FileData.Read0Str);

if (cntRequires < 0) or (cntContains < 0) or (posContains < 0) or (sizeContains < 0) then
  JSONSetAndAbort(JResult, 'ReadStatus', 'out of range');

var posRequires := FileData.CurPos;
var posUnits := posContains + sizeContains;
var sizeUnits := Length(FileMem) - posUnits;

{ Requires :
  (LOOP cntRequires(
    PCHAR:Package
  )
}


var List := TJSONArray.Create;
JSONAddOrUpdate(JResult, 'Requires', List);
for var i := 0 to cntRequires-1 do
  JSONAddOrUpdate(List, '@', FileData.Read0Str);

{ HeaderCheck }

if FileData.CurPos < posContains then begin
  var Len := posContains - FileData.CurPos;
  var Data: TBytes;
  var SData := string.Create(#0, Len * 2);
  SetLength(Data, Len);
  FileData.Read(Data[0], Len);
  BinToHex(Data[0], PChar(SData), Len);
  JSONAddOrUpdate(JResult, 'UnknownHeader', SData);
end;

{ Contains :
  (LOOP cntContains(
    UnitHeader Flags FileFime bplCode bplData
    (IF Ver<>4)INT:bplBSS (IF Ver=0,9 or MSIL)INT:X
    INT:H INT:I INT:J INT:K INT:L
    (IF Ver=0)INT:M INT:N INT:O
    PCHAR:Unit PCHAR:Package
  )
}


var ContainsData := FileData.GetBlock(sizeContains, posContains);
var List := TJSONObject.Create;
var Values: TJSONValue;
JSONAddOrUpdate(JResult, 'Contains', List);
for var i := 0 to cntContains-1 do begin
  var _Cont := ContainsData.RealPos;
  var _Unit := {@UnitHeader}ContainsData.PeakInt;
  Values := TJSONObject.Create;
  JSONAddOrUpdate(Values, '@UnitHeader', ContainsData.ReadHex4);
  JSONAddOrUpdate(Values, 'UnitHeader', '');
  JSONAddOrUpdate(Values, 'Flags', ContainsData.ReadHex4);
  JSONAddOrUpdate(Values, 'FileFime', ContainsData.ReadHex4);
  JSONAddOrUpdate(Values, 'bplCode', ContainsData.ReadHex4);
  JSONAddOrUpdate(Values, 'bplData', ContainsData.ReadHex4);
  if FileVersion <> '4then
    JSONAddOrUpdate(Values, 'bplBSS', ContainsData.ReadHex4);
  if (FileVersion in ['0', '9']) or isMSIL then
    JSONAddOrUpdate(Values, 'X', ContainsData.ReadHex4);
  JSONAddOrUpdate(Values, 'H', ContainsData.ReadHex4);
  JSONAddOrUpdate(Values, 'I', ContainsData.ReadHex4);
  JSONAddOrUpdate(Values, 'J', ContainsData.ReadHex4);
  JSONAddOrUpdate(Values, 'K', ContainsData.ReadHex4);
  JSONAddOrUpdate(Values, 'L', ContainsData.ReadHex4);
  if FileVersion = '0then begin
    JSONAddOrUpdate(Values, 'M', ContainsData.ReadHex4);
    JSONAddOrUpdate(Values, 'N', ContainsData.ReadHex4);
    JSONAddOrUpdate(Values, 'O', ContainsData.ReadHex4);
  end;
  var Unitname := ContainsData.Read0Str;
  var Namespace := '';
  if Length(Unitname) > 255 then
    JSONSetAndAbort(JResult, 'ReadStatus', 'unit name to long');
  if FileVersion in ['0', '9'] then begin
    Namespace := ContainsData.Read0Str;
    if Unitname = 'then begin
      if (Namespace <> '') and (Namespace[1] <> '.') then
        Namespace := '~' + Namespace;
      Unitname := Namespace;
    end;
  end;
  if (Values is TJSONObject) and (Namespace <> '') then
    JSONAddOrUpdate(Values, 'Namespace', Namespace);
  JSONAddOrUpdate(List, Unitname, Values);
end;

if ContainsData.CurPos < sizeContains then begin
  var Len := sizeContains - ContainsData.CurPos;
  var Data: TBytes;
  var SData := string.Create(#0, Len * 2);
  SetLength(Data, Len);
  ContainsData.Read(Data[0], Len);
  BinToHex(Data[0], PChar(SData), Len);
  JSONAddOrUpdate(JResult, 'UnknownContains', SData);
end;

{ Units : }

var UnitsData := FileData.GetBlock(sizeUnits, posUnits);
...

{if UnitsData.CurPos < sizeUnits then begin
  var Len := sizeUnits - UnitsData.CurPos;
  var Data: TBytes;
  var SData := string.Create(#0, Len * 2);
  SetLength(Data, Len);
  UnitsData.Read(Data[0], Len);
  BinToHex(Data[0], PChar(SData), Len);
  JSONAddOrUpdate(JResult, 'UnknownUnits', SData);
end;}

Jemand meinte, dass die DCUs in der DCP (teilweise) drin seien ... stimmt so nicht ganz,
aber ich denke mal, dass der Teil mit den Definitionen (Typen/Kontstanten/Variablen/Klassen/Methodendeklaration/...) in DCU und DCP die gleichen sind, welche benötigt werden, damit der Compiler daraus/damit etwas kompilieren/verlinken kann.


[add]
https://www.delphipraxis.net/184987-...rmationen.html
https://memnarch.bplaced.net/blog/20...om-a-dcp-file/
https://github.com/rfrezino/DCU32INT...r/DCP.pas#L126
Angehängte Dateien
Dateityp: 7z vcl.7z (2,07 MB, 3x aufgerufen)
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu (20. Sep 2022 um 23:19 Uhr)
  Mit Zitat antworten Zitat