{*******************************************************} { } { Tocsg.Hex } { } { Copyright (C) 2022 Sunk } { } {*******************************************************} unit Tocsg.Hex; interface uses System.Classes, System.SysUtils, Winapi.Windows; function ConvBinToStr(pBuf: PAnsiChar; dwSize: DWORD): AnsiString; function ConvBinToDelphiStr(pBuf: PAnsiChar; dwSize: DWORD): AnsiString; function ConvStrToBin(str: String; var pBuf: TBytes): Integer; function ConvStrToBinStream(const sBinStr: String; aStream: TStream): Boolean; function ConvStrToBinStreamForce(sBinStr: String; aStream: TStream): Boolean; procedure hexDump_to_list(pBuf: PBYTE; dwLen: DWORD; var lstDump: TStringList); function PosBin(const pFind, pDestBuf: TBytes; nBeginOffset: Integer = 0): Integer; implementation uses Tocsg.Safe, Tocsg.Strings; function ConvBinToStr(pBuf: PAnsiChar; dwSize: DWORD): AnsiString; var i: Integer; begin Result := ''; for i := 0 to dwSize - 1 do Result := Result + Format('%.2x', [Integer(pBuf[i])]); end; function ConvBinToDelphiStr(pBuf: PAnsiChar; dwSize: DWORD): AnsiString; var i: Integer; begin Result := ''; for i := 0 to dwSize - 1 do Result := Result + Format('$%.2x', [Integer(pBuf[i])]); end; // $뒤에 2자리까지 짤라서 리스트에 넣어준다. function SplitHexToStringList(sText: String; var lstString: TStringList; bDelphiHex: Boolean): Integer; var nPos : Integer; sTemp : String; begin lstString.Clear; Result := 0; if bDelphiHex then begin while sText <> '' do if sText[1] = '$' then begin sTemp := Copy(sText, 1, 3); lstString.Add(sTemp); Delete(sText, 1, 3); Inc(Result); end else begin nPos := Pos('$', sText); if nPos <> 0 then begin sTemp := Copy(sText, 1, nPos-1); lstString.Add(sTemp); Delete(sText, 1, Length(sTemp)); Inc(Result, Length(sTemp)); end else begin lstString.Add(sText); Inc(Result, Length(sText)); break; end; end; end else begin while sText <> '' do begin sTemp := Copy(sText, 1, 2); lstString.Add(sTemp); Delete(sText, 1, 2); Inc(Result); end; end; end; function ConvStrToBin(str: String; var pBuf: TBytes): Integer; var lstStr: TStringList; i: Integer; begin // c 스타일의 16진수 표시 문자 바꾸기 // str := StringReplace(str, '\x', '$', [rfReplaceAll]); // 길이가 짝수가 아니라면 맨앞에 0을 붙혀준다 14_1222 14:25:10 sunk if (Length(str) mod 2) <> 0 then str := '0' + str; Guard(lstStr, TStringList.Create); Result := SplitHexToStringList(str, lstStr, false); if Result <= 0 then exit; // pBuf := AllocMem(Result); SetLength(pBuf, Result); for i := 0 to lstStr.Count - 1 do pBuf[i] := StrToIntDef('$'+lstStr[i], 0); end; function ConvStrToBinStream(const sBinStr: String; aStream: TStream): Boolean; var lstTemp: TStringList; i: Integer; arrBin: array of Byte; begin Result := false; aStream.Size := 0; aStream.Position := 0; Guard(lstTemp, TStringList.Create); lstTemp.CommaText := sBinStr; SetLength(arrBin, lstTemp.Count); for i := 0 to lstTemp.Count - 1 do try arrBin[i] := StrToInt('$'+lstTemp[i]); except exit; end; aStream.Write(arrBin[0], Length(arrBin)); Result := true; end; function ConvStrToBinStreamForce(sBinStr: String; aStream: TStream): Boolean; var lstTemp: TStringList; i: Integer; pBuf: TBytes; begin aStream.Size := 0; aStream.Position := 0; sBinStr := StringReplace(sBinStr, ' ', '', [rfReplaceAll]); sBinStr := InsertPointString(',', sBinStr, 2); Guard(lstTemp, TStringList.Create); lstTemp.CommaText := sBinStr; SetLength(pBuf, lstTemp.Count); for i := 0 to lstTemp.Count - 1 do pBuf[i] := StrToIntDef('$'+lstTemp[i], 0); aStream.Write(pBuf[0], Length(pBuf)); Result := true; end; procedure hexDump_to_list(pBuf: PBYTE; dwLen: DWORD; var lstDump: TStringList); var pStart, pEnd : PBYTE; i, dwRemainder : DWORD; sLine : String; b : BYTE; begin // 시작과 끝을 잡아주고.. pStart := pBuf; pEnd := PBYTE(LongInt(pBuf)+dwLen); dwRemainder := dwLen mod 16; // 16Byte씩 보여주기 while LongInt(pStart)+16 <= LongInt(pEnd) do begin // offset 출력 sLine := Format('0x%.8x ', [LongInt(pStart)-LongInt(pBuf)]); // 16Byte 단위로 내용출력 for i := 0 to 15 do begin CopyMemory(@b, PBYTE(LongInt(pStart)+i), SizeOf(BYTE)); sLine := sLine + Format('%.2x ', [Integer(b)]); end; sLine := sLine + ' '; for i := 0 to 15 do begin CopyMemory(@b, PBYTE(LongInt(pStart)+i), SizeOf(BYTE)); if (Integer(b) >= 32) and (Integer(b) <= 125 )then sLine := sLine + Format('%s', [Char(b)]) else sLine := sLine + '.'; end; pStart := PBYTE(LongInt(pStart)+16); lstDump.Add(sLine); end; // 나머지 if dwRemainder > 0 then begin // offset 출력 sLine := Format('0x%.8x ', [LongInt(pStart)-LongInt(pBuf)]); // 16Byte 단위로 출력하고 남은 것 출력 for i := 0 to 15 do begin CopyMemory(@b, PBYTE(LongInt(pStart)+i), SizeOf(BYTE)); sLine := sLine + Format('%.2x ', [LongInt(pStart)+i]); end; for i := 0 to 155 - dwRemainder do sLine := sLine + ' '; sLine := sLine + ' '; for i := 0 to 15 do begin CopyMemory(@b, PBYTE(LongInt(pStart)+i), SizeOf(BYTE)); if (Integer(b) >= 32) and (Integer(b) <= 125 )then sLine := sLine + Format('%s', [Char(b)]) else sLine := sLine + '.'; end; for i := 0 to 15 - dwRemainder do sLine := sLine + ' '; lstDump.Add(sLine) end; end; function PosBin(const pFind, pDestBuf: TBytes; nBeginOffset: Integer = 0): Integer; var i, j, lp, ld: integer; begin lp := Length(pFind); ld := Length(pDestBuf); Result := -1; if (lp > ld) or (nBeginOffset >= ld) then Exit; for i := nBeginOffset to ld-lp-1 do begin for j := 0 to lp -1 do begin if pFind[j] <> pDestBuf[i + j] then Break; if j = lp-1 then Result := i; end; if Result <> -1 then Break; end; end; end.