unit NewParser;

interface

uses generics.collections, System.SysUtils, mysetupapi, System.Types, parseinf,
  ulog;

type
  TOS_type_version = record
    os_kernel: word; // 0 ,50,51,52,60,61,62
    os_BIT: word; // 32 or 64
  end;

  Taltmarker = record
    ForcedMarker: boolean;
    StrictMarker: boolean;
  end;

  Thwid_inf = record
    DRV_infdir, DRV_filename, DRV_MFG, DRV_Date, DRV_Ver, DRV_NAME: ansistring;
  end;

  Thwids = TDictionary<ansistring, Thwid_inf>;
  Tinf_dict = TDictionary<ansistring, Thwids>;

function GetKernelVersion(var InputVersion: PAnsiChar): word;
function GetOsType_byMFG(inputMFG: ansistring): TOS_type_version;
function Analyze_markers(Folder: ansistring): integer;
function GetTypeOs(var Ostype: TOS_type_version; marker: integer;
  Altm: Taltmarker): ansistring;
function NewIndexInf(INF_folder, INF_filename: ansistring): Tinf_dict;

const
  Markers: array [1 .. 18] of ansistring = ('5X64', '5X86', '6X64', '6X86',
    '7X64', '7X86', '8X64', '8X86', 'NTX64', 'NTX86', 'ALLX64', 'ALLX86',
    'ALLXP', 'ALL6', 'ALL7', 'ALL8', 'WINALL', 'ALLNT');

  MarkersKernel: array [1 .. 18] of word = (51, 51, 60, 60, 61, 61, 62, 62, 6,
    6, 0, 0, 51, 60, 61, 62, 0, 6);

  MarkersBITS: array [1 .. 18] of word = (64, 32, 64, 32, 64, 32, 64, 32, 64,
    32, 64, 32, 0, 0, 0, 0, 0, 0);

  MarkersALT: array [1 .. 2] of ansistring = ('FORCED', 'STRICT');

implementation

uses unit1;

// GetKernelVersion will return

// 2L.NTX86.6.0		defined as  60
// 2L.NTX86.6.1		defined as  61
// 2L.NTX86.6.2		defined as  62
// 2WIRE		defined as PЊV  (has no X.Y description)
// 2WIRE.NT.5.1		defined as 51

// Function returns 0 ,50,51,52,60,61,62, if return ZERO that mean it could not find Kernel number aka '2WIRE'
function GetKernelVersion(var InputVersion: PAnsiChar): word;
var
  i: integer;
  XXversion: ansistring;
  NotDefined: boolean;
begin
  XXversion := '';
  NotDefined := True;
  i := pos('.', InputVersion);
  if i > 0 then
    inc(InputVersion, i - 1)
  else
  begin
    result := 0;
    exit;
  end;

  for i := 0 to length(InputVersion) - 1 do
    if InputVersion[i] in ['0' .. '9'] then
    begin
      XXversion := XXversion + InputVersion[i];
      NotDefined := false;
      if length(XXversion) = 2 then
        break;

    end;

  if length(XXversion) = 1 then
  begin
    if strtoint(XXversion) < 5 then
      XXversion := '0';
    // else
    // XXversion := XXversion + 'X';

  end;

  if length(XXversion) > 0 then
    result := strtoint(XXversion)
  else
    result := 0;

  if NotDefined then
    result := 0;

end;

// Function will analyze OS type by MANUFACTURER
// possible strings '64', 'X86', '.NT'
function GetOsType_byMFG(inputMFG: ansistring): TOS_type_version;
var
  PSTR: PAnsiChar;
  Ppos: integer; // позиция в которой нашли 64 или X86 или .NT
  NT_type: integer; // Тип ОС  это '64', 'X86', '.NT'
  os_type: word;
const
  OS_types: array [0 .. 2] of ansistring = ('64', 'X86', '.NT');
begin
  inputMFG := UpperCase(inputMFG);
  PSTR := PAnsiChar(inputMFG);
  Ppos := 0;

  for NT_type := Low(OS_types) to High(OS_types) do
  begin
    Ppos := pos(OS_types[NT_type], PSTR);
    if Ppos > 0 then
      break;
  end;

  if Ppos = 0 then
    NT_type := 3;

  result.os_BIT := 0;
  case NT_type of
    0:
      begin
        inc(PSTR, Ppos + 1);
        result.os_BIT := 64;
      end;
    1:
      begin
        inc(PSTR, Ppos + 2);
        result.os_BIT := 32;
      end;
    2:
      begin
        inc(PSTR, Ppos + 2);
        result.os_BIT := 32;
      end;
  end;

  os_type := NT_type;
  result.os_kernel := GetKernelVersion(PSTR);

  // if Ppos > 0 then
  // if (result.Kernel > 0) then

  // if not(result.Kernel in [50 .. 70]) then

  begin
    // msg('NT' + IntToStr(result.os_kernel) + '_' + IntToStr(result.os_BIT) + #9 +
    // inputMFG + #9);

  end;


  // ShowMessage(PSTR);

end;

function Analyze_markers(Folder: ansistring): integer;
var
  i: integer;
  tmp: ansistring;
begin
  tmp := UpperCase(Folder);
  for i := Low(Markers) to High(Markers) do
    if pos(Markers[i] + '\', tmp) > 0 then
    begin
      result := i;
      exit;

    end;
  result := 0;

end;

function Analyze_markersALT(Folder: ansistring): Taltmarker;
var
  i: integer;
  tmp: ansistring;
begin
  tmp := UpperCase(Folder);
  result.ForcedMarker := false;
  result.StrictMarker := false;

  if pos(MarkersALT[1] + '\', tmp) > 0 then
    result.ForcedMarker := True;

  if pos(MarkersALT[2] + '\', tmp) > 0 then
    result.StrictMarker := True;
end;

function GetTypeOs(var Ostype: TOS_type_version; marker: integer;
  Altm: Taltmarker): ansistring;
begin

  if Altm.ForcedMarker then
  begin
    Ostype.os_kernel := MarkersKernel[marker];
    Ostype.os_BIT:= MarkersBITS[marker];

  end
  else
  begin

    if Ostype.os_kernel = 0 then
      Ostype.os_kernel := MarkersKernel[marker];

    if Ostype.os_BIT = 0 then
      Ostype.os_BIT := MarkersBITS[marker];

  end;

  if Ostype.os_BIT = 0 then
    Ostype.os_BIT := 32;

  if Ostype.os_kernel > 0 then
    result := 'NT' + IntToStr(Ostype.os_kernel) + '_' + IntToStr(Ostype.os_BIT)
  else
    result := 'ALL_' + IntToStr(Ostype.os_BIT);

end;

function NewIndexInf(INF_folder, INF_filename: ansistring): Tinf_dict;
label GETNEXTLINE;
Var
  hinf1: Pointer;
  aContext: INFCONTEXT;

  aReturnBuffer: array [0 .. 128] of ansichar;
  aReturnBuffer2: array [0 .. 128] of ansichar;

  aReturnBufferSize: DWORD;
  needsize: DWORD;

  TNAME, Thwid: ansistring;
  DRV_Ver: ansistring;
  DRV_Date: ansistring;
  Tinffilename: ansistring;
  Tinfdir: ansistring;

  Manucount: integer;
  FielCount: integer;
  i, L: integer;

  FirstMFG, CurMFG: ansistring;
  ConHWID: INFCONTEXT;
  ConHWID2: INFCONTEXT;
  IsHWNext: boolean;

  sectionWR: ansistring;
  I_sec, KB: integer;

  MarkerOS: integer; // Marker by whom we analyze type of Operating system
  MarkerALT: Taltmarker;
  os_type: TOS_type_version;
  Hwid_count: integer;
  ST_typeos: ansistring;
  Hwids: Thwids;
  Hwid: Thwid_inf;
begin

  ulog.LogFileName := ExtractFilePath(GetModuleName(HInstance)) +
    'TaskManager.log';

  Tinffilename := ExtractFileName(INF_filename);
  Tinfdir := ExtractFilePath(INF_filename);

  MarkerOS := 0;
  MarkerOS := Analyze_markers(Tinfdir);
  MarkerALT := Analyze_markersALT(Tinfdir);

  // form1.memo2.lines.add(IntToStr(markeros)+'__'+Tinfdir);

  // Form1.Memo1.Lines.Add(INF_folder);
  // Form1.Memo1.Lines.Add(INF_folder + INF_filename);
  hinf1 := SetupOpenInfFileA(PAnsiChar(INF_folder + INF_filename), nil,
    INF_STYLE_WIN4, nil);
  if (DWORD(hinf1) = INVALID_HANDLE_VALUE) then
  begin
    // ShowMessage('EROR OPEN');
    exit;
  end;

  result := Tinf_dict.Create;

  if SetupFindFirstLineA(hinf1, _Version, _DriverVer, aContext) then
  begin
    DRV_Date := '';
    aReturnBufferSize := 128;
    SetupGetStringFieldA(aContext, 1, @aReturnBuffer[0],
      aReturnBufferSize, nil);
    if aReturnBufferSize > 0 then
      DRV_Date := aReturnBuffer;
    DRV_Ver := '';
    SetupGetStringFieldA(aContext, 2, @aReturnBuffer[0],
      aReturnBufferSize, nil);
    if aReturnBufferSize > 0 then
      DRV_Ver := aReturnBuffer;

  end;

  if SetupFindFirstLineA(hinf1, _Manufacturer, nil, ConHWID) then
  begin
    Manucount := SetupGetLineCountA(hinf1, _Manufacturer);

    for i := 0 to Manucount - 1 do
    begin
      FielCount := SetupGetFieldCount(ConHWID);
      For L := 1 to FielCount do
      begin
        aReturnBufferSize := 127;
        SetupGetStringFieldA(ConHWID, L, @aReturnBuffer[0],
          aReturnBufferSize, nil);

        if L > 1 then
          CurMFG := FirstMFG + '.' + aReturnBuffer
        else
        begin
          CurMFG := aReturnBuffer;
          FirstMFG := aReturnBuffer;
        end;

        os_type := GetOsType_byMFG(CurMFG);

        Hwid_count := SetupGetLineCountA(hinf1, PAnsiChar(CurMFG));

        ST_typeos := '';
        ST_typeos := GetTypeOs(os_type, MarkerOS, MarkerALT);
        // Form1.Memo1.Lines.Add('M' + IntToStr(MarkerOS) + '___' + ST_typeos +
        // '  ' + CurMFG);

        if result.ContainsKey(ST_typeos) then
          Hwids := result.Items[ST_typeos]
        else

          if Hwid_count > 0 then
        begin
          Hwids := Thwids.Create;
          result.Add(ST_typeos, Hwids);
        end;

        IsHWNext := SetupFindFirstLineA(hinf1, PAnsiChar(CurMFG), nil,
          ConHWID2);

        if MarkerALT.ForcedMarker and IsHWNext then
        begin
          sLog('', #9 + CurMFG + #9 + INF_folder + INF_filename);

        end;

        KB := 0;

        while IsHWNext do
        begin
          aReturnBufferSize := 127;
          needsize := 0;
          SetupGetStringFieldA(ConHWID2, 2, @aReturnBuffer2, aReturnBufferSize,
            @needsize);
          if needsize < 3 then
            SetupGetStringFieldA(ConHWID2, 3, @aReturnBuffer2,
              aReturnBufferSize, @needsize);

          if needsize < 3 then
            goto GETNEXTLINE;

          Thwid := aReturnBuffer2;

          SetupGetStringFieldA(ConHWID2, 0, @aReturnBuffer,
            aReturnBufferSize, nil);
          TNAME := aReturnBuffer;

          if not(Hwids.ContainsKey(Thwid)) then
          begin
            Hwid.DRV_infdir := Tinfdir;
            Hwid.DRV_filename := Tinffilename;
            Hwid.DRV_MFG := CurMFG;
            Hwid.DRV_Date := DRV_Date;
            Hwid.DRV_Ver := DRV_Ver;
            Hwid.DRV_NAME := TNAME;

            Hwids.Add(Thwid, Hwid);
            // Hwids.Add(Thwid, Thwid + #9 + Tinfdir + #9 + Tinffilename + #9 +
            // CurMFG + #9 + DRV_Date + #9 + DRV_Ver + #9 + TNAME + #9);
          end;
          // Необходимость отпадает так как теперь будет возвращатся не стринглисты а
          // ALStrings[KB].Add(
          // THWID + #0 + Tinfdir + #0 + Tinffilename + #0 + CurMFG + #0 + DRV_Date
          // + #0 + DRV_Ver + #0 + TNAME + #0);

        GETNEXTLINE:
          IsHWNext := SetupFindNextLine(ConHWID2, ConHWID2);
        end;

      end;
      SetupFindNextLine(ConHWID, ConHWID);
    end;

  end;

  SetupCloseInfFile(hinf1);

end;

end.
