Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > [ "Начинающим" ]
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 09.07.2020, 11:09
Alexandr_57 Alexandr_57 вне форума
Прохожий
 
Регистрация: 26.02.2016
Сообщения: 30
Версия Delphi: Delphi XE10
Репутация: 10
По умолчанию Именения данных в бинарном файле на большее, меньшее или равное количество

Здравствуйте. Повторюсь в в данном вопросе я ноль. Ибо не интересовался по работе с бинарным данными. Однако по ответам с друогих форумах имею представления что встроенного функционала на подобие функций Pos, Copy и Delete нету для работы с набором байтов.
Короче нужно 3 примера:
1. Замена байтов на такоеже количество.
2. Замена байт если длинна заменяемых данных больше длинны искомых.
3. Замена байт если длинна заменяемых данных меньше чем длина искомых. И да нужно именно заменить удалив лишнии

Что до 2 варианта о данные например такие:
Код:
PATTERN1: array [0..9] of Byte = ($03, $05, $00, $00, $00, $63, $69, $62, $3D, $31);
PATTERN2: array [0..11] of Byte = ($03, $07, $00, $00, $00, $63, $69, $62, $3D, $39, $39, $39);
Что до 3го варианта то данные например такие:
Код:
PATTERN1: array [0..10] of Byte = ($03, $06, $00, $00, $00, $63, $69, $62, $3D, $2D,  $31);
PATTERN2: array [0..9] of Byte = ($03, $05, $00, $00, $00, $63, $69, $62, $3D, $39);

Цитата:
И не по теме. Если правильно менять данные то файл работать будет. Я знаю какие данные на какие нужно менять. Я лишь не знаю как именно это делать на Delphi по сути нужно сделать хекс редактор на автоматический процесс замены.
Ответить с цитированием
  #2  
Старый 09.07.2020, 19:20
Аватар для dr. F.I.N.
dr. F.I.N. dr. F.I.N. вне форума
I Like it!
 
Регистрация: 12.12.2009
Адрес: Россия, г. Новосибирск
Сообщения: 660
Версия Delphi: D6/D7
Репутация: 26643
По умолчанию

Я бы работал с классом TFileStream. Считали блок данных размером с искомый паттерн, и посимвольно пробегаем в поиске первого байта паттерна. Если нашли, то запоминаем позицию (начало искомой последовательности) и проверяем следующий бай. Совпал - продолжаем с третьим и т.д. на всю длину паттерна. (если дошли до конца прочитанного блока, то дочитываем недостающую длину и продолжаем сверку). Если же ничего не нашлось, то снова считываем следующую партию байт и повторяем процесс пока не найдем всю последовательность.

А дальше бы уже прибегнул к дополнительному потоку (хоть TFileStream, хоть TMemoryStream). Копируем в дополнительный поток все что до начала искомого паттерна, потом записываем нужный паттерн (PATTERN2) и повторяем все действия до конца файла.

Если нужно, то переносите содержимое дополнительного потока в первый и сохраняете. Или же оригинальный файл переименовывем и сохраняем доп.поток в файл с прежним именем.

С таким подходом не будет никакой разницы какой, какой паттерн длиннее или короче, хоть вообще "удалять" искомый набор байт.
__________________
Грамотно поставленный вопрос содержит не менее 50% ответа.
Грамотно поставленная речь вызывает уважение, а у некоторых даже зависть.

Последний раз редактировалось dr. F.I.N., 09.07.2020 в 19:24.
Ответить с цитированием
  #3  
Старый 09.07.2020, 20:10
Alexandr_57 Alexandr_57 вне форума
Прохожий
 
Регистрация: 26.02.2016
Сообщения: 30
Версия Delphi: Delphi XE10
Репутация: 10
По умолчанию

Цитата:
Сообщение от dr. F.I.N.
Я бы работал с классом TFileStream. Считали блок данных размером с искомый паттерн, и посимвольно пробегаем в поиске первого байта паттерна. Если нашли, то запоминаем позицию (начало искомой последовательности) и проверяем следующий бай. Совпал - продолжаем с третьим и т.д. на всю длину паттерна. (если дошли до конца прочитанного блока, то дочитываем недостающую длину и продолжаем сверку). Если же ничего не нашлось, то снова считываем следующую партию байт и повторяем процесс пока не найдем всю последовательность.

А дальше бы уже прибегнул к дополнительному потоку (хоть TFileStream, хоть TMemoryStream). Копируем в дополнительный поток все что до начала искомого паттерна, потом записываем нужный паттерн (PATTERN2) и повторяем все действия до конца файла.

Если нужно, то переносите содержимое дополнительного потока в первый и сохраняете. Или же оригинальный файл переименовывем и сохраняем доп.поток в файл с прежним именем.

С таким подходом не будет никакой разницы какой, какой паттерн длиннее или короче, хоть вообще "удалять" искомый набор байт.

Нужно учитывать что позиция где эти байты находятся находится неизвестно. И более того находиться они будут всегда в разном месте всеже это не программа.

Плюс размер файла большой - 10 - 50 МБ. Число варьируется между этим отрезком. Так что побайтовое чтение будет долгим. Да и мнебы пример. А точнее примеры 3 штуки на 3 варианта.
Ответить с цитированием
  #4  
Старый 09.07.2020, 20:41
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,004
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

1. Если работать через TFileStream - то без разницы по байту ты читаешь или по несколько - там все-равно все идет через буфер.
2. Делал в свое время такую штуку (правда не через TFfileStream). Там код довольно сложный получается, если ты не хочешь дублировать файл. 10-50мб это не так и много, так что проще сделать через временный файл. Т.е. читаем исходный файл, меняем данные, если нашли паттерн, и пишем во временный. Потом заменяем файл целиком.
Ответить с цитированием
  #5  
Старый 10.07.2020, 09:11
Alexandr_57 Alexandr_57 вне форума
Прохожий
 
Регистрация: 26.02.2016
Сообщения: 30
Версия Delphi: Delphi XE10
Репутация: 10
По умолчанию

Да лин. Может кто приме мне сделать. Например поменять:
PATTERN1: array [0..9] of Byte = ($03, $05, $00, $00, $00, $63, $69, $62, $3D, $31);
на
PATTERN2: array [0..11] of Byte = ($03, $07, $00, $00, $00, $63, $69, $62, $3D, $39, $39, $39);
и
PATTERN1: array [0..10] of Byte = ($03, $06, $00, $00, $00, $63, $69, $62, $3D, $2D, $31);
на
PATTERN2: array [0..9] of Byte = ($03, $05, $00, $00, $00, $63, $69, $62, $3D, $39);
Буду очень благодарен. Ну или если уже есть это то дайте ссылку.
Ответить с цитированием
  #6  
Старый 19.07.2020, 07:02
Аватар для Kailon
Kailon Kailon вне форума
Активный
 
Регистрация: 06.06.2010
Сообщения: 339
Версия Delphi: 10.4
Репутация: 429
Сообщение

Код:
//Функция поиска шаблона
function PatternSearch(aPattern: TBytes; aFileName: String): LongInt;
var
  F: TMemoryStream;
  Buf: TBytes;
  Len, Step: LongInt;
begin
  F := TMemoryStream.Create;
  F.LoadFromFile(aFileName);
  try
    Len := Length(aPattern);
    SetLength(Buf, Len);
    Step := 0;
    try
      repeat
        F.Seek(Step, soFromBeginning);
        F.ReadBuffer(Buf, Len);
        Inc(Step);
      until CompareMem(Buf, aPattern, Len);
      Result := F.Position;
    except
      Result := -1;
    end;
  finally
    F.Free;
  end;
end;

Код:
//Процедура замены одного шаблона на другой
procedure ReplacePattern(aFileName: String; aOffset: LongInt;
  OldPattern, NewPattern: TBytes);
var
  InF, OutF: TMemoryStream;
  OldLen, NewLen: LongInt;
  FirstFilePart, SecondFilePart: TBytes;
begin
  OldLen := Length(OldPattern);
  NewLen := Length(NewPattern);
  InF := TMemoryStream.Create;
  OutF := TMemoryStream.Create;
  InF.LoadFromFile(aFileName);
  RenameFile(aFileName, aFileName + '.bak');
//  DeleteFile(aFileName);
  try
    if OldLen = NewLen then
    begin
      InF.Seek(aOffset, soFromBeginning);
      InF.WriteBuffer(NewPattern, NewLen);
      InF.SaveToFile(aFileName);
    end
    else
    begin
      SetLength(FirstFilePart, aOffset);
      InF.ReadBuffer(FirstFilePart, aOffset);
      InF.Seek(OldLen, soFromCurrent);
      SetLength(SecondFilePart, InF.Size - Length(FirstFilePart) - OldLen);
      InF.ReadBuffer(SecondFilePart, Length(SecondFilePart));
      OutF.WriteBuffer(FirstFilePart, Length(FirstFilePart));
      OutF.WriteBuffer(NewPattern, Length(NewPattern));
      OutF.WriteBuffer(SecondFilePart, Length(SecondFilePart));
      OutF.SaveToFile(aFileName);
    end;
  finally
    InF.Free;
    OutF.Free;
    SetLength(FirstFilePart, 0);
    SetLength(SecondFilePart, 0);
  end;
end;

Код:
//Пример использования
procedure TForm1.Button1Click(Sender: TObject);
const
  aFileName = 'd:\Test.pdf';
  Buf1: TBytes = [$65, $0A, $2F, $58, $4F, $62, $6A, $65, $63, $74, $2F, $4C, $65, $6E, $67, $74];
  Buf2: TBytes = [$FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF];
var
  Offset: LongInt;
begin
  Offset := PatternSearch(Buf1, aFileName);
  if Offset >= 0 then
    ReplacePattern(aFileName, Offset, Buf1, Buf2);
end;

Хотелось бы узнать результаты проверки в боевых условиях.
__________________
Всегда пишите код так, будто сопровождать его будет склонный к насилию психопат, который знает, где вы живете.

Последний раз редактировалось Kailon, 20.07.2020 в 06:34.
Ответить с цитированием
  #7  
Старый 19.07.2020, 08:58
Аватар для dr. F.I.N.
dr. F.I.N. dr. F.I.N. вне форума
I Like it!
 
Регистрация: 12.12.2009
Адрес: Россия, г. Новосибирск
Сообщения: 660
Версия Delphi: D6/D7
Репутация: 26643
По умолчанию

Kailon, функция поиска паттерна работать у Вас не будет. Пример:
Файл: #FF #0F #AE #12 #00...e.t.c.
Паттерн для поиска: #0F #AE

Работа Вашего алгоритма (опустим загрузки файла и т.п.):
Считываем из файла в буфер (длина буфера = длине паттерна = 2)
Содержимое буфера: #FF #0F
Сравниваем буфер с паттерном: #FF #F0 <> #0F #AE, повторяем чтение буфера
Содержимое буфера: #AE #12
... и т.д.

Как можете заметить, после первого сравнения Ваш алгоритм проскакивает мимо искомого паттерна.
__________________
Грамотно поставленный вопрос содержит не менее 50% ответа.
Грамотно поставленная речь вызывает уважение, а у некоторых даже зависть.
Ответить с цитированием
Этот пользователь сказал Спасибо dr. F.I.N. за это полезное сообщение:
Kailon (19.07.2020)
  #8  
Старый 19.07.2020, 12:09
Аватар для Kailon
Kailon Kailon вне форума
Активный
 
Регистрация: 06.06.2010
Сообщения: 339
Версия Delphi: 10.4
Репутация: 429
Сообщение

О, действительно. Что-то я как-то совсем не подумал об этом. Вот почему важен взгляд со стороны и тестирование. Дополнил немного функцию в моём предыдущем посте.
__________________
Всегда пишите код так, будто сопровождать его будет склонный к насилию психопат, который знает, где вы живете.
Ответить с цитированием
  #9  
Старый 19.07.2020, 12:57
Аватар для dr. F.I.N.
dr. F.I.N. dr. F.I.N. вне форума
I Like it!
 
Регистрация: 12.12.2009
Адрес: Россия, г. Новосибирск
Сообщения: 660
Версия Delphi: D6/D7
Репутация: 26643
По умолчанию

Все равно ошибка
Цитата:
Сообщение от Kailon
Код:
//Функция поиска шаблона
function PatternSearch(aPattern: TBytes; aFileName: String): LongInt;
var
  F: TMemoryStream;
  Buf: TBytes;
  Len, Step: LongInt;
begin
  F := TMemoryStream.Create;
  F.LoadFromFile(aFileName);
  try
    Len := Length(aPattern);
    SetLength(Buf, Len);
    Step := 0;
    try
      repeat
        F.Seek(Step, soFromBeginning);
        F.ReadBuffer(Buf, Len);
        Inc(Step);
      until CompareMem(Buf, aPattern, Len);
      Result := F.Position; // <--- Позиция курсора в файле показывает на начало паттерна или нет? :D 
    except
      Result := -1;
    end;
  finally
    F.Free;
  end;
end;

И по примеру использования: А кто сказал, что паттерн не может располагаться в самом начале файла (Offset= 0)?
Стоит возвращать (-1) если паттерн не найден. А если найден, то уже значение от 0 до ... Аналогично функции Pos().

Вы не подумайте, что я критикую и не предлагаю. Я предложил решение первым ответом. Imikle внес замечания. По сути алгоритм есть, нужно только написать. Мне лень писать, но читать чужой код я люблю
__________________
Грамотно поставленный вопрос содержит не менее 50% ответа.
Грамотно поставленная речь вызывает уважение, а у некоторых даже зависть.

Последний раз редактировалось dr. F.I.N., 19.07.2020 в 13:04.
Ответить с цитированием
  #10  
Старый 20.07.2020, 06:34
Аватар для Kailon
Kailon Kailon вне форума
Активный
 
Регистрация: 06.06.2010
Сообщения: 339
Версия Delphi: 10.4
Репутация: 429
Сообщение

Цитата:
Сообщение от dr. F.I.N.
Все равно ошибка
Нет там никакой ошибки И да, позиция курсора в файле показывает на начало паттерна, а если он не найден, то возвращается -1. Аналогично функции Pos(), хоть она и возвращает 0 если ничего не нашла.
Цитата:
Сообщение от dr. F.I.N.
И по примеру использования: А кто сказал, что паттерн не может располагаться в самом начале файла (Offset= 0)?
Согласен. Изменим чуть-чуть условие (с больше на больше или равно )
Цитата:
Сообщение от dr. F.I.N.
Вы не подумайте, что я критикую и не предлагаю.
Да я и не думал... Общими усилиями мы доведем решение задачи до ума.
Цитата:
Сообщение от dr. F.I.N.
По сути алгоритм есть, нужно только написать.
Так я уже написал. Как по мне, так все прекрасно и быстро работает. Вот только автору поста это видимо уже не интересно.
Цитата:
Сообщение от dr. F.I.N.
Мне лень писать, но читать чужой код я люблю
Лень - двигатель прогресса. Читайте на здоровье.
__________________
Всегда пишите код так, будто сопровождать его будет склонный к насилию психопат, который знает, где вы живете.

Последний раз редактировалось Kailon, 20.07.2020 в 06:44.
Ответить с цитированием
  #11  
Старый 20.07.2020, 09:29
Аватар для dr. F.I.N.
dr. F.I.N. dr. F.I.N. вне форума
I Like it!
 
Регистрация: 12.12.2009
Адрес: Россия, г. Новосибирск
Сообщения: 660
Версия Delphi: D6/D7
Репутация: 26643
По умолчанию

Все же Вы не правы. После выполнения TStream.Read позиция курсора меняется и уже указывает не на начало последовательности, а на её конец. Проведите эксперимент:
Содержимое файла [123456789]
Паттерн [23]
Какой результат вернет Ваша функция? Отвечаю: 3. А все потому, что нашли паттерн в позиции 1 (как и полагается), произвели чтение паттерна длиною в 2 байта. Итого 2+1 = 3.
Поправить можно так:
Код:
function PatternSearch(aPattern: TBytes; aFileName: String): LongInt;
var
  F: TMemoryStream;
  Buf: TBytes;
  Len, Step: LongInt;
begin
  F := TMemoryStream.Create;
  F.LoadFromFile(aFileName);
  try
    Len := Length(aPattern);
    SetLength(Buf, Len);
    Step := -1;
    try
      repeat
        Inc(Step);
        F.Seek(Step, soFromBeginning);
        F.ReadBuffer(Buf, Len);
      until CompareMem(Buf, aPattern, Len);
      Result := Step;
    except
      Result := -1;
    end;
  finally
    F.Free;
  end;
end;
Да и как-то грубо использовать эксепшен для завершения функции - не находите? Что Вам мешает отслеживать размер файла, количество считанных байт, позицию курсора?
__________________
Грамотно поставленный вопрос содержит не менее 50% ответа.
Грамотно поставленная речь вызывает уважение, а у некоторых даже зависть.

Последний раз редактировалось dr. F.I.N., 20.07.2020 в 09:33.
Ответить с цитированием
  #12  
Старый 21.07.2020, 12:18
Аватар для Vayrus
Vayrus Vayrus вне форума
Исполняемый Ретровирус
 
Регистрация: 09.08.2008
Адрес: Umbrella Corporation
Сообщения: 743
Репутация: 1293
По умолчанию

Автор, вот еще пример, дорабатывайте на разные размеры исходных и конечных данных + прикрутите отлов исключений:

Код:
const
  OriginalByte: array [0 .. 55] of Byte = ($64, $69, $6E, $67, $20, $6D, $65,
    $20, $68, $69, $73, $00, $00, $00, $00, $27, $00, $00, $28, $00, $00, $00,
    $21, $00, $00, $00, $63, $6F, $6D, $70, $75, $74, $65, $72, $2E, $00, $00,
    $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $27, $00, $00, $28,
    $00, $00, $00, $00);

  BytetoWrite: array [0 .. 55] of Byte = ($63, $68, $6F, $67, $20, $6D, $65,
    $20, $68, $69, $73, $00, $00, $00, $00, $27, $00, $00, $28, $00, $00, $00,
    $21, $00, $00, $00, $63, $6F, $6D, $70, $75, $74, $65, $72, $2E, $00, $00,
    $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $27, $00, $00, $28,
    $00, $00, $00, $06);

procedure DoMyPatch(const FileName: String);
var
  i: Int64;
  FileName: string;
  input: TFileStream;
  FileByteArray, ExtractedByteArray: Tbytes;
begin
  input := TFileStream.Create(FileName, fmOpenReadWrite);
  try
  input.Position := 0;
  SetLength(FileByteArray, input.size);
  input.Read(FileByteArray[0], Length(FileByteArray));
  for i := Low(FileByteArray) to High(FileByteArray) do
  begin
    ExtractedByteArray := Copy(FileByteArray, i, Length(OriginalByte));
    if CompareMem(@FileByteArray[i], @OriginalByte[0], Length(OriginalByte)) = True then
    begin
      input.Seek(i, SoFromBeginning);
      input.Write(BytetoWrite[0], Length(BytetoWrite));
    end;
  end;
  finally
    FreeAndNil(input);
  end;
end;
Ответить с цитированием
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 01:47.


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2023

ВКонтакте   Facebook   Twitter