Прочесть variant из потока (i386>x86_64)

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

Прочесть variant из потока (i386>x86_64)

Сообщение Ichthyander » 24.02.2018 01:42:41

Вопрос. В потоке (TFileStream или TMemoryStream) размещена переменная тип Variant, записанная там из кода, скомпилированного в 32-битном режиме FPC. Как прочесть этот же блок памяти из под 64-битного кода FreePascal.
Сложность. ;) Variant в коде, скомпилированном в 32-битном FPC хранится в 16 байтах памяти. Variant 64-битный - 24 байтах
Есть варианты попроще и красивее?
Аватара пользователя
Ichthyander
энтузиаст
 
Сообщения: 668
Зарегистрирован: 04.04.2007 08:32:43
Откуда: Астрахань

Re: Прочесть variant из потока (i386>x86_64)

Сообщение olegy123 » 24.02.2018 18:05:39

Что мешает серилизировать данные?
Свести к стандартам (Byte,Integer,Double)?
Variant это не совсем стандарт.
olegy123
долгожитель
 
Сообщения: 1643
Зарегистрирован: 25.02.2016 12:10:20

Re: Прочесть variant из потока (i386>x86_64)

Сообщение runewalsh » 24.02.2018 18:11:17

Насколько я (не) нагуглил, стандартных функций нет..?

Сохранение и загрузка Variant как сырого куска памяти — это неправильно и в общем случае работать не будет. Если работала, значит, там были простые типы — типа varSingle, varLongWord (даже varString не должен работать). Для них раскладка в памяти, скорее всего, осталась такой же, так что (возможно) сработает просто чтение в первые 16 байт Variant'а.

А вообще правильнее записывать и читать по case VarType(...) and VarTypeMask of, т. к. там может быть, например, массив (в том числе многомерный массив других Variant!).
Последний раз редактировалось runewalsh 24.02.2018 18:11:49, всего редактировалось 1 раз.
Аватара пользователя
runewalsh
энтузиаст
 
Сообщения: 578
Зарегистрирован: 27.04.2010 00:15:25

Re: Прочесть variant из потока (i386>x86_64)

Сообщение Ichthyander » 24.02.2018 18:11:23

Сохранять Variant в Stream как есть - это плохо. И сама задача тому доказательство. Но вопрос задачи немного другой.

Добавлено спустя 1 минуту 53 секунды:
Чуть не успел раньше Вас написать про то, что конечно же сохранять варианты в поток некрасиво. Я вообще думал, что написал об этом в первом посте топика. Но пропустил и тем самым суть дискуссии уводится не туда

Добавлено спустя 1 минуту 12 секунд:
Если работала, значит, там были простые типы — типа varSingle, varLongWord (даже varString не должен работать)

Да, конечно, Вы правы. Там были только простые типы. Ни строк, ни массивов, ни указателей и объектов.

Добавлено спустя 1 минуту 17 секунд:
Для них раскладка в памяти, скорее всего, осталась такой же, так что (возможно) сработает просто чтение в первые 16 байт Variant'а.

Интересно предположение, но вряд ли... В любом случае не очень нравится такое решение. Но! для такого случае может и нет красивого решения!

Добавлено спустя 19 минут 8 секунд:
Решение, которое поможет это разбор внутренней структуры Variant, то есть
Код: Выделить всё
   tvardata = packed record
      vtype : tvartype;
      case integer of
         0:(res1 : word;
            case integer of
               0:
                 (res2,res3 : word;
                  case word of
                     varsmallint : (vsmallint : smallint);
                     varinteger : (vinteger : longint);
{$ifndef FPUNONE}
                     varsingle : (vsingle : single);
                     vardouble : (vdouble : double);
                     vardate : (vdate : tdatetime);
{$endif}
                     varcurrency : (vcurrency : currency);
                     varolestr : (volestr : pwidechar);
                     vardispatch : (vdispatch : pointer);
                     varerror : (verror : hresult);
                     varboolean : (vboolean : wordbool);
                     varunknown : (vunknown : pointer);
                     // vardecimal : ( : );
                     varshortint : (vshortint : shortint);
                     varbyte : (vbyte : byte);
                     varword : (vword : word);
                     varlongword : (vlongword : dword);
                     varint64 : (vint64 : int64);
                     varqword : (vqword : qword);
                     varword64 : (vword64 : qword);
                     varstring : (vstring : pointer);
                     varany :  (vany : pointer);
                     vararray : (varray : pvararray);
                     varbyref : (vpointer : pointer);
{$ifdef FPC_HASFIXED64BITVARIANT}
                     { unused so far, only to fill up space }
                     varrecord : (vrecord : pointer;precinfo : pointer);
{$endif FPC_HASFIXED64BITVARIANT}
                );
               1:
                 (vlongs : array[0..2] of longint);
           );
         1:(vwords : array[0..6] of word);
         2:(vbytes : array[0..13] of byte);
      end;                                 

Создать свой тип на основе этого, который бы не зависел от ключей компиляции и читать данные из stream прямо в него. Вообщем, я об это думал изначально, но вдруг это можно было сделать проще и элементарно. Но, видимо, нет. Что опять таки понять можно )

Добавлено спустя 35 минут 7 секунд:
Короче, я реально ступил. Все просто оказалось. Интересно, что я это проверял, но в первый раз не получилось второпях это сделать правильно...
runewalsh, прав: значащие только первые 16 байтов.
Поэтому
Тупо и смело считываем только первые 16 байтов, то есть
ASomeStream.ReadBuffer(AVariantVar, 16);
Аватара пользователя
Ichthyander
энтузиаст
 
Сообщения: 668
Зарегистрирован: 04.04.2007 08:32:43
Откуда: Астрахань

Re: Прочесть variant из потока (i386>x86_64)

Сообщение olegy123 » 24.02.2018 19:54:30

Ichthyander писал(а): но вдруг это можно было сделать проще и элементарно. Но, видимо, нет.
Ichthyander писал(а):Тупо и смело считываем только первые 16 байтов
если с обычными типами как то прокатить, то с о всякими указателями, объектными типами, массивами можно вполне словить эксепшен..
Даже ключами оптимизации как пример выравнивания памяти.
Кто знает что в AVariantVar лежит, тип VarInteger или массив, его 16 байтами не запищишь.. нужно раскрывать.
olegy123
долгожитель
 
Сообщения: 1643
Зарегистрирован: 25.02.2016 12:10:20

Re: Прочесть variant из потока (i386>x86_64)

Сообщение Ichthyander » 24.02.2018 20:18:13

olegy123все так. Более того, их и сохранить как Variant "в лоб" в потоке таким способом не удастся. Имел ввиду, конечно, с самого начала что Variant содержит простой тип типа Float, Integer, Boolean, Ordinal, а не строки, указатели, объекты или массивы
Аватара пользователя
Ichthyander
энтузиаст
 
Сообщения: 668
Зарегистрирован: 04.04.2007 08:32:43
Откуда: Астрахань

Re: Прочесть variant из потока (i386>x86_64)

Сообщение Mirage » 25.02.2018 00:12:02

В данном случае правильнее всего - создать свой тип. Типа такого:
Код: Выделить всё
TMyVariant = record
    ValueType: VType;
    case VType of
      vtInteger: (ValueI: Integer);
      vtSingle: (ValueS: Single);
      ...
  end;

И вот его уже сохранять, точно зная сколько там байт значащих.
А для Variant это скорее всего нигде не гарантируется и в следующей версии компилятора может перестать работать.
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

Re: Прочесть variant из потока (i386>x86_64)

Сообщение runewalsh » 25.02.2018 17:24:27

Variant официально можно кастовать к TVarData, а она, в свою очередь, packed, причём VType и другие поля, предшествующие хранимому значению/указателю, имеют фиксированные размеры (VType: Word), как и само значение в оговорённых случаях, отсюда относительная работоспособность хака про 16 байт.
Аватара пользователя
runewalsh
энтузиаст
 
Сообщения: 578
Зарегистрирован: 27.04.2010 00:15:25

Re: Прочесть variant из потока (i386>x86_64)

Сообщение LearnMagic » 01.03.2018 22:19:55

Ichthyander писал(а):Вопрос. В потоке (TFileStream или TMemoryStream) размещена переменная тип Variant, записанная там из кода, скомпилированного в 32-битном режиме FPC. Как прочесть этот же блок памяти из под 64-битного кода FreePascal.

На основе variant из исходников 32-битного FPC, создаём свой тип с заменой разряднозависимых типов (pointer и т.д.) из 64-бит на типы, соответствующие 32-битным, читаем из потока, а потом присваиваем в 64-битный variant
LearnMagic
новенький
 
Сообщения: 66
Зарегистрирован: 10.11.2016 23:13:38


Вернуться в Free Pascal Compiler

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 26

Рейтинг@Mail.ru