unit UnitMF;

interface

uses
  math,ShlObj, Vcl.Dialogs,Vcl.StdCtrls,
  System.StrUtils, System.SysUtils, System.Classes, System.IOUtils;

  function GetFileHead(const FName: string): string;
  function GetFileSize(const FileName: string): Int64;
  function GetFileHex(FName: string; MeStart, MeLen: Longint): string;
  function BytesToStr(const i64Size: Int64): string;
  function IsNumber(const S: string): Boolean;
  function GDP:string;
  procedure DoCAP(const strFileName: string);
  procedure ListToolFolders(ListBox:TListBox);
  function HexToChar(const HexStr: string): Char;
  function ReadBytesAfterPosition(Position: Integer): string;
  function FindBytesInFile(const FileName: string; const SearchBytes: TBytes): Int64;
  function HexToBytes(const HexStr: string): TBytes;

implementation
  uses BiosEditMainForm;
//开始

procedure ListToolFolders(ListBox:TListBox);
var
  RootPath: string;
  FolderName: string;
begin
  ListBox.Items.Clear;
  RootPath := 'C:\BIOS';
  // 检查目录是否存在，防止报错
  if not TDirectory.Exists(RootPath) then exit;
  try
    for FolderName in TDirectory.GetDirectories(RootPath, '*', TSearchOption.soTopDirectoryOnly) do
    begin
      if Pos('TOOLS',UpperCase( ExtractFileName(FolderName))) > 0 then
      begin
        ListBox.Items.Add(ExtractFileName(FolderName));
      end;
    end;
  except
  end;
end;

function GetFileHead(const FName: string): string;
var
  FileStream: TFileStream;
  Buffer: TBytes;
  BytesToRead: Int64;
  i: Integer;
  HexVal: string;
begin
  Result := '';
  if FName = '' then
    Exit;
  if not FileExists(FName) then
    Exit;

  BytesToRead := 80; // 对应 VB 中的 nFileLen = 80

  try
    FileStream := TFileStream.Create(FName, fmOpenRead or fmShareDenyWrite);
    try
      if FileStream.Size < BytesToRead then
        BytesToRead := FileStream.Size;
      if BytesToRead <= 0 then
        Exit;
      SetLength(Buffer, BytesToRead);
      FileStream.ReadBuffer(Buffer, BytesToRead);
    finally
      FileStream.Free;
    end;
  except
  end;
  // 预分配结果字符串长度
  SetLength(Result, BytesToRead * 2);
  // 修正后的循环：通过索引直接赋值字符
  for i := 0 to Length(Buffer) - 1 do
  begin
    HexVal := IntToHex(Buffer[i], 2);
    Result[i * 2 + 1] := HexVal[1];
    Result[i * 2 + 2] := HexVal[2];
  end;
end;

function GetFileSize(const FileName: string): Int64;
var
  SearchRec: TSearchRec;
begin
  Result := -1;
  if FindFirst(FileName, faAnyFile, SearchRec) = 0 then
  begin
    Result := SearchRec.Size;
    FindClose(SearchRec);
  end;
end;


function GetFileHex(FName: string; MeStart, MeLen: Longint): string;
var
  FileStream: TFileStream;
  Buffer: array of Byte;
  i: Integer;
  HexStr: string;
begin
  Result := '';
  try
    FileStream := TFileStream.Create(FName, fmOpenRead or fmShareDenyWrite);
    try
      if FileStream.Size < (MeStart + MeLen) then
        Exit;

      FileStream.Position := MeStart;

      SetLength(Buffer, MeLen);
      FileStream.ReadBuffer(Buffer[0], MeLen);

      HexStr := '';
      for i := 0 to MeLen - 1 do
      begin
        HexStr := HexStr + IntToHex(Buffer[i], 2);
      end;

      Result := HexStr;
    finally
      FileStream.Free;
    end;
  except
    on E: Exception do
      Result := '';
  end;
end;

function BytesToStr(const i64Size: Int64): string;
const
  i64GB = 1024 * 1024 * 1024;
  i64MB = 1024 * 1024;
  i64KB = 1024;
begin
  if i64Size div i64GB > 0 then
    Result := Format('%.2f GB', [i64Size / i64GB])
  else if i64Size div i64MB > 0 then
    Result := Format('%.2f MB', [i64Size / i64MB])
  else if i64Size div i64KB > 0 then
    Result := Format('%.2f KB', [i64Size / i64KB])
  else
    Result := IntToStr(i64Size) + ' Byte';
end;

function IsNumber(const S: string): Boolean;
var
  LVal: Double;
begin
  Result := TryStrToFloat(S, LVal);
end;

function GDP: string;
begin
  result:=TPath.GetDesktopPath;
end;


procedure DoCAP(const strFileName: string);
var
  newf: string;
  f1, f2: file of Byte; // 使用 typed file 方便 BlockRead/Write
  S1: array of Byte;
  fileSize, startOffset, bytesToRead, bytesRead, bytesWritten: Integer;
  fileNameOnly: string;
begin
  fileNameOnly := ExtractFileName(strFileName);
  newf :=GDP+ '\' + fileNameOnly + '.BIN';

  fileSize := TFile.GetSize(strFileName);
  startOffset := fileSize mod 1048576;

  if (startOffset = 2048) or (startOffset = 4096) then begin
    AssignFile(f1, strFileName);
    Reset(f1);
    try
      AssignFile(f2, newf);
      Rewrite(f2);
      try
        bytesToRead := fileSize - startOffset;
        if bytesToRead > 0 then
        begin
          SetLength(S1, bytesToRead);
          Seek(f1, startOffset);
          BlockRead(f1, S1[0], bytesToRead, bytesRead);
          BlockWrite(f2, S1[0], bytesRead, bytesWritten);
        end;
      finally
        CloseFile(f2);
      end;
    finally
      CloseFile(f1);
    end;
    ShowMessage('桌面生成 ' + fileNameOnly + '.BIN 文件成功!');
    BiosFileNM:=newf;
    mf.LBBiosFile.Caption  :=newf;
  end;
end;



//读取内容
function ReadBytesAfterPosition(Position: Integer): string;
var
  FileStream: TFileStream;
  Buffer: array of Byte;
  ReadBytes: Integer;
  i: Integer;
  Len:integer;
begin
  Result := '';
  Len:=29;
  if Position < 0 then Exit;
  FileStream := TFileStream.Create(BiosFileNM, fmOpenRead or fmShareDenyWrite);
  try
    FileStream.Position := Position;
    SetLength(Buffer,len);
    ReadBytes := FileStream.Read(Buffer[0], Len);
    for i := 0 to ReadBytes - 1 do
    begin
      if i > 0 then Result := Result ;
      Result := Result + IntToHex(Buffer[i], 2);
    end;
  finally
    FileStream.Free;
  end;
end;

function HexToChar(const HexStr: string): Char;
var
  Value: Integer;
begin
  if Length(HexStr) <> 2 then
    raise Exception.Create('无效的16进制字符串');
  Value := StrToInt('$' + HexStr);
  if (Value < 0) or (Value > 255) then
    raise Exception.Create('16进制值超出字符范围');
  Result := Chr(Value);
end;

function HexToBytes(const HexStr: string): TBytes;
var
  I: Integer;
begin
  if Length(HexStr) mod 2 <> 0 then
    raise Exception.Create('Invalid hex string length');
  SetLength(Result, Length(HexStr) div 2);
  for I := 0 to Length(Result) - 1 do
    Result[I] := StrToInt('$' + Copy(HexStr, I*2+1, 2));
end;

function FindBytesInFile(const FileName: string; const SearchBytes: TBytes): Int64;
const
  BufferSize = 65536; // 64KB 缓冲区
var
  Stream: TFileStream;
  Buffer, Overlap: TBytes;
  BytesRead, SearchLen, OverlapSize: Integer;
  TotalRead: Int64;
begin
  Result := -1;
  SearchLen := Length(SearchBytes);
  if SearchLen = 0 then Exit;

  Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone);
  try
    SetLength(Buffer, BufferSize + SearchLen - 1);
    SetLength(Overlap, 0);
    TotalRead := 0;

    while True do
    begin
      BytesRead := Stream.Read(Buffer[Length(Overlap)], BufferSize);
      if BytesRead = 0 then Break;

      // 合并重叠数据与新数据
      SetLength(Buffer, Length(Overlap) + BytesRead);
      if Length(Overlap) > 0 then
        Move(Overlap[0], Buffer[0], Length(Overlap));

      // 在合并缓冲区中搜索
      for var I := 0 to Length(Buffer) - SearchLen do
      begin
        var Match := True;
        for var J := 0 to SearchLen - 1 do
          if Buffer[I + J] <> SearchBytes[J] then
          begin
            Match := False;
            Break;
          end;
        if Match then
        begin
          Result := TotalRead - Length(Overlap) + I;
          Exit;
        end;
      end;

      // 保留尾部数据用于下一块重叠
      OverlapSize := Min(SearchLen - 1, Length(Buffer));
      SetLength(Overlap, OverlapSize);
      if OverlapSize > 0 then
        Move(Buffer[Length(Buffer) - OverlapSize], Overlap[0], OverlapSize);

      TotalRead := TotalRead + BytesRead;
      SetLength(Buffer, BufferSize + SearchLen - 1); // 重置缓冲区大小
    end;
  finally
    Stream.Free;
  end;
end;
end.
