C++ to Delphi

Тема в разделе "WASM.WIN32", создана пользователем Searcher, 4 дек 2004.

  1. Searcher

    Searcher New Member

    Публикаций:
    0
    Регистрация:
    28 окт 2004
    Сообщения:
    24
    Помогите перевести следующие функции на язык дельфи, это функции чтения-записи в файл.
    Код (Text):
    1. PboEntry::PboEntry()
    2. {
    3.    filename[0]=0;
    4.    size=0;
    5.    memset(unknown,0,16);
    6. }
    7.  
    8. int      PboEntry::Read(FILE *f)
    9. {  
    10.    while(1)
    11.    {
    12.       char c=fgetc(f);
    13.  
    14.       if (c==char(0))
    15.          break;        
    16.  
    17.       filename+=c;
    18.    }
    19.  
    20.    fread(unknown,1,16,f);
    21.  
    22.    fread(&size,1,4,f);
    23.  
    24.    if (size==0)
    25.       return 0;
    26.  
    27.    return 1;
    28. }
    29.  
    30.  
    31. int      PboEntry::Write(FILE *f)
    32. {
    33.    fwrite(filename.c_str(),1,filename.size(),f);
    34.  
    35.    fputc(char(0),f);
    36.  
    37.    fwrite(unknown,1,16,f);
    38.  
    39.    fwrite(&size,1,4,f);
    40.  
    41.    return 1;
    42. }
    43.  


    На всякий случай, программа на С++ лежит тут

    Хочу написать подобную, но на Дельфи.
     
  2. Quantum

    Quantum Паладин дзена

    Публикаций:
    0
    Регистрация:
    6 янв 2003
    Сообщения:
    3.143
    Адрес:
    Ukraine
    Брр...



    В Дельфи можно и API использовать: CreateFile(), ReadFile(), WriteFile().
     
  3. Pavia

    Pavia Well-Known Member

    Публикаций:
    0
    Регистрация:
    17 июн 2003
    Сообщения:
    2.409
    Адрес:
    Fryazino
    Quantum

    Конечно можно.

    Searcher

    Проще самому написать чем переводить.Мог перевести с ошибками.

    constructor PboEntry.creat;

    begin

    filename[0]:=0;

    size:=0;

    fillchar(unknown,16,0);

    end;



    function PboEntry.Read(f:FILE of byte):integer;

    begin

    while (true) do

    begin

    system.read(f,c);



    if (c=chr(0)) then

    break;



    filename:=filename+chr(c);

    end;



    blockread(f,unknown,16);



    blockread(f,size,4);



    if (size=0) then

    result:=0;



    result:=1;

    end;





    function PboEntry.Write(f:FILE of byte):integer;

    begin

    blockwrite(f,filename.c_str,filename.size);



    system.write(f,byte(0));



    blockwrite(f,unknown^,16);



    blockwrite(f,size,4,);



    result:=1;

    end;
     
  4. yureckor

    yureckor New Member

    Публикаций:
    0
    Регистрация:
    25 фев 2004
    Сообщения:
    494
    Адрес:
    Russia
    Как я рад что не знаю Дельфи.

    ASM Forever!
     
  5. Searcher

    Searcher New Member

    Публикаций:
    0
    Регистрация:
    28 окт 2004
    Сообщения:
    24
    Pavia

    Спасибо за ответ, попробую написать так.
     
  6. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Searcher > "попробую написать так"

    Попробуй-попробуй, надеюсь ты знаком с Delphi и сам исправишь кучу ошибок "перевода" Pavia:



    1) конструктор переопределять не нужно вообще, т.к. наследуемый от TObject автоматом зануляет все поля.

    2) переменная типа file передается всегда как var параметр, т.е. Read(var f:file) и Write(var f:file)

    3) на system.read(f,..) и system.write(f,..) компилятор выдаст ошибку, т.к. эти функции - для работы с текстовыми файлами и консолью, а для двоичных файлов нужно использовать blockread(f,..)

    4) в дельфах result - это просто обозначение переменной результата и никакого ret она не делает, поэтому в функции read результат надо определять так if size = 0 then result:=0 else result:=1 или без else переставить присвоение единицы до проверки size.

    5) если filename это string, то в дельфах никаких мемберов через точку указать нельзя и write надо делать так:

    blockwrite(f,filename[1],length(filename)), а еще лучше length()+1, тогда не нужно будет отдельно записывать завершающий ноль;

    6) ну и мелкие незуразности: если в read переменная с:Char, то Сhr(c) - это масло масляное; в write крышка у unknown^ не нужна (хотя может и прокатит)



    Что касается, формата записываемого файла - не проще ли в начале записывать длину filename, а то while в поисках конца строки выглядит как-то некрасиво, если не сказать глупо.



    PS: volodya наверное спит, иначе бы этой темы здесь не было. Helheim & Delphi в одном флаконе - это перебор :)
     
  7. CyberManiac

    CyberManiac New Member

    Публикаций:
    0
    Регистрация:
    2 сен 2003
    Сообщения:
    2.473
    Адрес:
    Russia
    А еще нужно очистить свое сознание от предрассудков, которые скрывает от духовного зрения тот простой факт, что filename - это строка, а строки в Delphi

    1. начинаются с _первого_ элемента

    2. являются полноценными динамическими переменными



    Поэтому filename:='', несомненно, поможет благородному дону.



    Короче, вместо того, чтобы лабать изначально дефективный "перевод", есть смысл понять, что эта программа делает (судя по приведенному куску - ничего особо сложного) и написать ее именно на Delphi, а не на языке "Объектный Сикаль".
     
  8. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    Просветите чукчу (меня) - что, в самом деле существует язык программирования Delphi ?



    leo >




    IMHO не проще. В таком случае при копировании строки будет использоваться счётчик (регистр), а в случае с "посимвольным копированием до завершающего нуля" код будет более эффективным. А выглядит некрасиво, потому что следовало бы делать так:
    Код (Text):
    1.  
    2.    while(char c=fgetc(f))
    3.        filename+=c;
    4.  
     
  9. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    S_T_A_S_

    > "в случае с "посимвольным копированием до завершающего нуля" код будет более эффективным"

    Это в каком смысле более эффективным ?



    1) если filename это динамическая строка "произвольного" размера, то наверное понятно что будет, когда мы делаем filename+=c; если не понятно, то поясняю - если при очередном добавлении символа не хватает размера выделенной памяти, то происходит realloc со всеми вытекающими отсюда последствиями. За подробностями обращяться в getmem.inc на дельфах или heap.cpp на С++.

    2) чтение\копирование блоков памяти и в оси, и в любых компиляторах производится не по байту, а как минимум по 4 и только остаток 1-3 байта по одному.



    Если размер строки известен, то на дельфах сразу выделяется строка нужного размера и грузится из файла целиком через ReadFile:
    Код (Text):
    1.     setlength(filename,L);
    2.     blockread(f,filename[1],L); //тут можно прочитать и завержающий 0, если еспользовать L+1
    PS: В дельфах blockread это просто обертка для ReadFilе с проверкой валидности хэндла, хранещегося в переменной f:TFileRec, и генерацией исключений при GetLastError <> 0.
     
  10. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    leo



    1) Разве виндос поддерживает имена файлов "произвольного" размера ?



    2) Может лучше тогда уж MMX + prefetchnta использовать.

    Для копирования имени файла =))



    >




    Откуда он будет известен? Его так же придётся загружать из файла - это одна операция чтения.

    Далее, либо цикл по этому счётчику (который где-то нужно хранить), либо
    - 2я операция чтения.



    Если же мы будем просто брать по 1му байту (из буфера, куда fgetc прочитает сразу 4K данных, из отображённого файла, из ...) пока не встретим 0, то потребуется одна операция чтения. Счётчик цикла не нужен. В результате имеем более компактный и простой код.
     
  11. Searcher

    Searcher New Member

    Публикаций:
    0
    Регистрация:
    28 окт 2004
    Сообщения:
    24
    Действительно "попробовал" :)

    Работает наполовину, пытался кучу всего исправить, так и не смог.

    Теперь попробую по новым добавленным советам портировать эти функции в Дельфи.

    Спасибо вам, программеры. Если есть еще варианты как это написать в Дельфи, пишите. :)
     
  12. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    S_T_A_S_

    Твои рассуждения насчет преимущества fgetc перед ReadFile ИМХО ошибочны.



    Во-первых, по твоему получается, что fgetc это что-то типа инлайнового mov al,byte [Buf]. На самом деле это далеко не так. Вот минимум того, что должна делать fgetc (на примере дельфийской internal функции _readchar):

    1) проверить валидность операции (чтобы с дуру не выдать мусор и не нарваться на исключение)

    2) проверить валидность текущей позиции буфера (позиция не вышла за пределы буфера и не соответствет концу файла EOF)

    если все ОК, то

    3) MOV символ в AL

    4) инкремент позиции буфера

    5) ret

    6) здесь разные варианты если после 1 или 2 не ОК

    Умножаем все эти излишества на число символов filename (с учетом latency call и ret) и радуемся "простоте и компактности кода".



    Во-вторых, а чем принципиально отличается ReadFile от fgetc ? Если отбросить экзотический вариант с FILE_FLAG_NO_BUFFERING, то ИМХО ReadFile работает примерно также как и fgetc, т.е. даные читаются с диска в системный буфер (файловый кэш) теми же 4K, откуда затем и копируются в наш буфер с теми же проверками, что и в fgetc. Единственное тут могут добавляться системные проверки, связанные с синхронизацией IO при ShareMode <> 0 или FILE_FLAG_OVERLAPPED. Но зато мы вызываем ReadFile для чтения строки только один раз и дополнительно экономим время на пересылке байтов в строку.



    > "Разве виндос поддерживает имена файлов "произвольного" размера ?"

    Под "произвольной" длиной filename я конечно имел ввиду не "бесконечную", а от "нескольких" символов до многих десятков (ну к примеру "C:\Program Files\Microsoft Office\Шаблоны\Дизайны презентаций\Высокое напряжение.pot").



    > "в самом деле существует язык программирования Delphi"

    Прикалываешься ? В Delphi используется язык прогаммирования Object Pascal. Но когда мы используем библиотечные функции, то возникает интересный вопрос, а "чьи" это функции - некоего стандарта языка Pascal или системы программирования Delphi ? Чтобы не забивать себе голову этими вопросами, проще говорить, что программа написана не на Object Pascal, а на Delphi такой-то версии, и возможно ее не удастся без проблем скомпилировать в младших версиях или каких-то других компиляторах.
     
  13. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    leo >




    Обязательно ли делать "подмену ценностей" ?

    Моё мнение было о разнице в применении zero-terminated и паскалевских строк в данном конкретном случае.



    >




    Я не теоретик.

    Откомпилировал болванку и пробежался отладчиком - это даже быстрее, чем рыться в сорцах ;)



    >




    А вот это мне нравицца =)

    Если
    , то fgetc - .....?



    Это та же самая обёртка!

    Но нет, при "модификации" моих рассуждений о строчках, откуда ни возьмись, берётся fgetc vs ReadFile (даже не blockread ;).

    Естесственно, любой человек, находясь в трезвом уме и здравой памяти, скажет, что ReadFile - это более быстрый путь получить данные из файла.

    Но утверждал ли я обратное



    ?
     
  14. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    S_T_A_S_

    Извини, но ты меня запутал окончательно. Из последнего поста я-тупой не понял ничего.



    Я рассуждаю просто - и blockread и fgetc\_readchar кроме чтения\копирования данных выполняют вспомогательные операции. Поэтому 2 операции "чтения" размера строки и самой строки должны занимать меньшее время, чем N чтений по одному байту. Плюс к этому "ускоренное" копирование строки по 4 байта (или фиг знает по сколько). Минус проблемы с неизвестной зарезервированной длиной filename (резервировать MaxPath на все случаи жизни ?).



    Если ты считаешь иначе, то хотелось бы услышать вразумительно-доходчивые аргументы. Только про счетчик не вспоминай, т.к. я его в явном виде никогда и не предлагал использовать.
     
  15. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    Как говорят теоретики, 90% кода программы выполняется в течении 10% времени её работы.

    IMHO они не правы.

    Правильное соотношение - как минимум 80% / 20%.

    Потомучто эти 90% нужно оптимизировать по размеру !



    Использование одной операции чтения вместо 2х, и/или отказ от счётчика ведёт к уменьшению размера кода.

    Ну зачем это оптимизировать по скорости ? (и можно ли это сделать вообще ;)
     
  16. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Понял. Оптимизация по скорости здесь конечно под большим вопросом (впрочем как и по коду). Так что давай "замнем" на этом для ясности.
     
  17. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    В самом деле, винты же бесконечные ;)
     
  18. Searcher

    Searcher New Member

    Публикаций:
    0
    Регистрация:
    28 окт 2004
    Сообщения:
    24
    Итак, эти функции я переконвертил в дельфи, теперь есть еще вопрос насчет считывания и записи поблочно. В Си это делается через векторы, а в дельфи помедленнее у меня выходит. В общем, есть процедура:
    Код (Text):
    1.  
    2. Procedure UnpackPBO(FName:string);
    3. const
    4.   N = 63579;
    5. var
    6.   FromF, ToF: file;
    7.   NumRead, NumWritten, i, j, CountFiles: Integer;
    8.   BufName: array [1..1] of Char;
    9.   Buf: array [1..1] of Char;
    10.   BufUnknown: array[1..16] of Char;
    11.   BufSize: array [1..4] of byte;
    12.   rec:^Trec;
    13.   str,preFname,dir:string[255];
    14. begin
    15.   GetMem(rec, N*sizeof(PboEntry));
    16.   AssignFile(FromF, FName);
    17.   Reset(FromF, 1); { Record size = 1 }
    18.   j:=0;
    19.   Repeat
    20.   j:=j+1;
    21.   str:='';
    22.   Repeat
    23.     BlockRead(FromF, BufName, SizeOf(BufName), NumRead);
    24.     If Char(BufName)<>chr(0) then
    25.       str:=str+Char(BufName);
    26.   Until Char(BufName)=chr(0);
    27.   rec^[j].FPN:=str;
    28.   BlockRead(FromF, BufUnknown, SizeOf(BufUnknown), NumRead);
    29.   BlockRead(FromF, BufSize, SizeOf(BufSize), NumRead);
    30.   str:='';
    31.   For i:=4 downto 1 do
    32.     str:=str+IntToHex(BufSize[i],2);
    33.   rec^[j].size:=HexToInt(str);
    34.   Until rec^[j].size=0;
    35.   CountFiles:=j-1;
    36.   preFname:='';
    37.   For i:=1 to Length(FName)-4 do
    38.     preFname:=preFname+FName[i];
    39.   For j:=1 to CountFiles do
    40.     begin
    41.       dir:=preFname+'\'+ExtractFilePath(rec^[j].FPN);
    42.       if ForceDirectories(dir) then
    43.         begin
    44.           Assign(ToF,preFname+'\'+rec^[j].FPN);
    45.           Rewrite(ToF,1);
    46.           For i:=1 to rec^[j].size do
    47.             begin
    48.               BlockRead(FromF, Buf, SizeOf(Buf), NumRead);
    49.               BlockWrite(ToF, Buf, NumRead, NumWritten);
    50.             end;
    51.           CloseFile(ToF);
    52.         end
    53.       else
    54.         showmessage('Cann''t create '+dir);
    55.     end;
    56.   CloseFile(FromF);
    57.   {$IFDEF VER80}
    58.   FreeMem(rec, N*sizeof(PboEntry));
    59.   {$ELSE}
    60.   FreeMem(rec);
    61.   {$ENDIF}
    62. end;
    63.  


    Так вот, можно ли как то во время работы программы изменять длину(размер) буфера Buf? Чтобы считывать не по одному символу, а сразу помногу? Пробовал Buf как динамический массив, но не работает, выдает ошибку.
     
  19. volodya

    volodya wasm.ru

    Публикаций:
    0
    Регистрация:
    22 апр 2003
    Сообщения:
    1.169
    Не, ну я уже злиться начинаю... Сказано же в правилах - дельфи - ересь. Это тебе что, форум по дельфям, блин?
     
  20. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754