OberonCore
https://forum.oberoncore.ru/

Аналог fread
https://forum.oberoncore.ru/viewtopic.php?f=2&t=2006
Страница 1 из 1

Автор:  Rafi [ Среда, 04 Ноябрь, 2009 03:16 ]
Заголовок сообщения:  Аналог fread

Скажите, никто, случаем, не писал процедуру, через которую разом можно было бы перенести из файла в запись кусок объёмом SIZE(запись). И возможно ли вообще поместить скопом байты в запись без явной инициализации её полей?

Автор:  Иван Кузьмицкий [ Среда, 04 Ноябрь, 2009 12:14 ]
Заголовок сообщения:  Re: Аналог fread

Много ли полей в записи?

Автор:  Rafi [ Среда, 04 Ноябрь, 2009 12:53 ]
Заголовок сообщения:  Re: Аналог fread

Например, такая запись:
Код:
TgaHeader = RECORD;
   idLength: BYTE;
   colorMapType: BYTE;
   imageTypeCode: BYTE;
   colorMapSpec: ARRAY 5 OF BYTE;
   xOrigin: SHORTINT;
   yOrigin: SHORTINT;
   width: SHORTINT;
   height: SHORTINT;
   bpp: BYTE;
   imageDesc: BYTE
END;


Занести байты в поля с помощью rd.ReadByte и rd.ReadSInt не такая уж и проблема, но всё равно трудоёмко. Наверняка ведь можно сделать обобщённый вариант для всех записей. Или нет?

Автор:  Илья Ермаков [ Среда, 04 Ноябрь, 2009 12:54 ]
Заголовок сообщения:  Re: Аналог fread

Прошу:

Код:
MODULE назовите-как-хотите;
   IMPORT S := SYSTEM, Kernel, Files;

   TYPE
      Bytes = ARRAY [untagged] 1000000000 OF BYTE;

   PROCEDURE SizeOf* (IN rec: ANYREC): INTEGER;
      VAR type: Kernel.Type;
   BEGIN
      type := S.VAL(Kernel.Type, S.TYP(rec));
      RETURN type.size
   END SizeOf;

   PROCEDURE RecWithoutPtrFields* (IN rec: ANYREC): BOOLEAN;
      VAR t: Kernel.Type;
   BEGIN
      t := S.VAL(Kernel.Type, S.TYP(rec));
      RETURN t.ptroffs[0] < 0
   END RecWithoutPtrFields;

   PROCEDURE RecToBytes* (IN rec: ANYREC; VAR bytes: ARRAY OF BYTE; VAR pos: INTEGER);
      VAR t: Kernel.Type;
   BEGIN
      t := S.VAL(Kernel.Type, S.TYP(rec));
      ASSERT(t.ptroffs[0] < 0, 20);
      ASSERT(pos + t.size <= LEN(bytes), 21);
      IF Kernel.littleEndian THEN
         S.MOVE(S.ADR(rec), S.ADR(bytes) + pos, t.size);
         INC(pos, t.size)
      ELSE
         HALT(126)
      END
   END RecToBytes;

   PROCEDURE RecFromBytes* (VAR rec: ANYREC; IN bytes: ARRAY OF BYTE; VAR pos: INTEGER);
      VAR t: Kernel.Type;
   BEGIN
      t := S.VAL(Kernel.Type, S.TYP(rec));
      ASSERT(t.ptroffs[0] < 0, 20);
      ASSERT(pos + t.size <= LEN(bytes), 21);
      IF Kernel.littleEndian THEN
         S.MOVE(S.ADR(bytes) + pos, S.ADR(rec), t.size);
         INC(pos, t.size)
      ELSE
         HALT(126)
      END
   END RecFromBytes;

   PROCEDURE RecToFile* (IN rec: ANYREC; wr: Files.Writer);
      VAR t: Kernel.Type;
   BEGIN
      t := S.VAL(Kernel.Type, S.TYP(rec));
      ASSERT(t.ptroffs[0] < 0, 20);
      IF Kernel.littleEndian THEN
         wr.WriteBytes(S.VAL(Bytes, rec), 0, t.size)
      ELSE
         HALT(126)
      END
   END RecToFile;

   PROCEDURE RecFromFile* (VAR rec: ANYREC; rd: Files.Reader);
      VAR t: Kernel.Type;
   BEGIN
      t := S.VAL(Kernel.Type, S.TYP(rec));
      ASSERT(t.ptroffs[0] < 0, 20);
      IF Kernel.littleEndian THEN
         rd.ReadBytes(S.VAL(Bytes, rec), 0, t.size)
      ELSE
         HALT(126)
      END
   END RecFromFile;

   PROCEDURE New* (IN sameType: ANYREC): ANYPTR;
   BEGIN
      RETURN S.VAL(ANYPTR, Kernel.NewRec(S.TYP(sameType)))
   END New;

   PROCEDURE CopyBase* (IN src: ANYREC; VAR dest: ANYREC);
(* Берёт "общий знаменатель" двух записей и копирует из src в dest *)
      VAR ts, td: Kernel.Type;
            i: INTEGER;
   BEGIN
      ASSERT(S.ADR(src) # S.ADR(dest), 20);
      ts := S.VAL(Kernel.Type, S.TYP(src));
      td := S.VAL(Kernel.Type, S.TYP(dest));
      i := 0;
      WHILE (ts.base[i] # NIL) & (ts.base[i] = td.base[i]) DO
         INC(i)
      END;
      IF i > 0 THEN
         S.MOVE(S.ADR(src), S.ADR(dest), ts.base[i-1].size) 
      END
   END CopyBase;


Автор:  Илья Ермаков [ Среда, 04 Ноябрь, 2009 12:57 ]
Заголовок сообщения:  Re: Аналог fread

Получаем аналог паскалёвого file of record, но принципиально более мощный за счёт того, что это динамика, а не статика.

Рискну утверждать, от своего опыта, что Files.File и пара процедур RecToFile и RecFromFile способна закрыть целый пучок задач с хранением данных - хоть на диске, хоть в памяти (можно - и даже нужно :) - ведь и с оперативной памятью работать через соотв. реализацию File).

Автор:  Rafi [ Среда, 04 Ноябрь, 2009 13:13 ]
Заголовок сообщения:  Re: Аналог fread

Илья, большое спасибо!)
Я тогда уж в целях избегания изобретения велосипедов, спрошу: не писал ли кто-нибудь процедурку загрузки tga?)

Автор:  Валерий Лаптев [ Среда, 04 Ноябрь, 2009 13:16 ]
Заголовок сообщения:  Re: Аналог fread

Илья Ермаков писал(а):
Получаем аналог паскалёвого file of record, но принципиально более мощный за счёт того, что это динамика, а не статика.

Рискну утверждать, от своего опыта, что Files.File и пара процедур RecToFile и RecFromFile способна закрыть целый пучок задач с хранением данных - хоть на диске, хоть в памяти (можно - и даже нужно :) - ведь и с оперативной памятью работать через соотв. реализацию File).

Ага!!!! Это как раз то, что я хочу в обучающем языке. Одна структура данных - контейнер. А внешний он или внутренний, нумерованный или нет - это его атрибуты... :)

Автор:  Александр Ильин [ Среда, 04 Ноябрь, 2009 14:55 ]
Заголовок сообщения:  Re: Аналог fread

Rafi писал(а):
Я тогда уж в целях избегания изобретения велосипедов, спрошу: не писал ли кто-нибудь процедурку загрузки tga?)
Если речь идёт о графическом формате, то см. FreeImage.dll.

Автор:  Rafi [ Среда, 04 Ноябрь, 2009 21:29 ]
Заголовок сообщения:  Re: Аналог fread

Илья, а что это за Bytes такой?..

Код:
PROCEDURE RecFromFile* (VAR rec: ANYREC; rd: Files.Reader);
      VAR t: Kernel.Type;
   BEGIN
      t := S.VAL(Kernel.Type, S.TYP(rec));
      ASSERT(t.ptroffs[0] < 0, 20);
      IF Kernel.littleEndian THEN
         rd.ReadBytes(S.VAL(Bytes, rec), 0, t.size)
      ELSE
         HALT(126)
      END
   END RecFromFile;

Автор:  Илья Ермаков [ Четверг, 05 Ноябрь, 2009 00:02 ]
Заголовок сообщения:  Re: Аналог fread

Пардон.
Добавил. См. выше.

Автор:  Роман М. [ Понедельник, 16 Ноябрь, 2009 23:42 ]
Заголовок сообщения:  Re: Аналог fread

Маленький пример использования кто-нибудь может написать? На примере записи, состоящей из двух INTEGER.
А то сложно как-то. Меня смущает тот факт, что в BP7 всё на порядок проще. Или я не с той стороны смотрю. :oops:

Автор:  Евгений Темиргалеев [ Понедельник, 16 Ноябрь, 2009 23:58 ]
Заголовок сообщения:  Re: Аналог fread

Вовсе не сложно.
Код:
TYPE MyRec = RECORD ... END;

VAR wr: Files.Writer; rd: Files.Reader; f: Files.File; x: MyRec;
f := Files.dir. ... ЧИТАЕМ ДОКУМЕНТАЦИЮ Files
wr := f.NewWriter(NIL); wr.SetPos(0);
назовите-как-хотите.RecToFile(x, wr);
rd := f.NewReader(NIL); rd.SetPos(0);
назовите-как-хотите.RecFromFile(x, rd);

Автор:  Comdiv [ Воскресенье, 17 Июнь, 2018 23:32 ]
Заголовок сообщения:  Re: Аналог fread

Илья Ермаков писал(а):
Код:
MODULE назовите-как-хотите;
...
   PROCEDURE RecToBytes* (IN rec: ANYREC; VAR bytes: ARRAY OF BYTE; VAR pos: INTEGER);
      VAR t: Kernel.Type;
   BEGIN
      t := S.VAL(Kernel.Type, S.TYP(rec));
      ASSERT(t.ptroffs[0] < 0, 20);
      ASSERT(pos + t.size <= LEN(bytes), 21);
      IF Kernel.littleEndian THEN
         S.MOVE(S.ADR(rec), S.ADR(bytes) + pos, t.size);
         INC(pos, t.size)
      ELSE
         HALT(126)
      END
   END RecToBytes;

Этот код используется где-то?
Вот эта проверка
Код:
ASSERT(pos + t.size <= LEN(bytes), 21);
Ошибочно пройдёт при отрицательном pos или pos > MAX(INTEGER) - t.size
После того, как в мире Си внезапно обнаружили, что нужно контролировать целостность буфера, для уязвимостей стали использовать ошибки в проверках, зачастую, основанных на неконтролируемом арифметическом переполнении.

Если трогать SYSTEM, то нужно всё проверять по 10 раз, но лучше не трогать.

Автор:  Илья Ермаков [ Понедельник, 18 Июнь, 2018 14:42 ]
Заголовок сообщения:  Re: Аналог fread

Код уже кочевал в другие либы сто раз, надо проверить!

Спасибо за указание!

Страница 1 из 1 Часовой пояс: UTC + 3 часа
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/