Russian Qt Forum

Qt => Вопросы новичков => Тема начата: bsf от Ноябрь 26, 2012, 16:14



Название: Base64 в long double
Отправлено: bsf от Ноябрь 26, 2012, 16:14
Здравствуйте коллеги...
Есть значение uB6F61G4npAEQASSsG8nERHeBECDKkQA Это запись чисел из Delfi двух чисел типа Extended. Значение чисел 36.155 и 55.516667. Как прочитать это дело на Qt ?
Делаю так:
Код
C++ (Qt)
QByteArray arr = QByteArray::fromBase64("uB6F61G4npAEQASSsG8nERHeBECDKkQA");
QByteArray ba = arr.mid(0,12);
bool ok;
long double ld = ba.toLong(&ok,12);
// ok = false
 
В чём моя ошибка?
Спасибо за советы


Название: Re: Base64 в long double
Отправлено: mutineer от Ноябрь 26, 2012, 16:21
Код:
ba.toLong(&ok,12);
У тебя числа в 12-ричной системе счисления, чтоли?


Название: Re: Base64 в long double
Отправлено: bsf от Ноябрь 26, 2012, 16:22
Пробовал и 10ку... - без разницы


Название: Re: Base64 в long double
Отправлено: mutineer от Ноябрь 26, 2012, 16:23
Пробовал и 10ку... - без разницы
Так а зачем 12 ставить, что это даст?

а что у тебя находится в ba? Какой текст получился?


Название: Re: Base64 в long double
Отправлено: bsf от Ноябрь 26, 2012, 16:49
Насчет 12 - поехали, описка скорее
Какой текст? Это же набор байтов и текст крякозябры!


Название: Re: Base64 в long double
Отправлено: mutineer от Ноябрь 26, 2012, 16:52
Код:
QByteArray str("FF");
 bool ok;
 long hex = str.toLong(&ok, 16);   // hex == 255, ok == true
Данный пример наводит на мысли что toLong хочет на входе именно текстовое представление числа, а не кракозябры

Если из Base64 ты получешь уже бинарное представление числа, то берешь себе data() указатель и кастуешь куда нужно


Название: Re: Base64 в long double
Отправлено: xokc от Ноябрь 26, 2012, 17:13
Если из Base64 ты получешь уже бинарное представление числа, то берешь себе data() указатель и кастуешь куда нужно
К сожалению, тут не всё так просто. В Delphi Extended для Win32 - это 10 байтный тип данных, для которого прямого аналога в C++ нет. Для Win64 (как ни странно) - это 8 байтный long double.
Так что способ double *ptr = (double *)ba.data() прокатит только для Win64. Для Win32 нужно конвертировать ручками.
Подробнее можно почитать тут - http://www.linux.org.ru/forum/development/5990825.


Название: Re: Base64 в long double
Отправлено: bsf от Ноябрь 26, 2012, 18:57
О, спасибо xokc, это ближе к теме...а можно попросить пример записи и чтения в этот формат, а то я совсем запутался...


Название: Re: Base64 в long double
Отправлено: mutineer от Ноябрь 26, 2012, 18:59
О, спасибо xokc, это ближе к теме...а можно попросить пример записи и чтения в этот формат, а то я совсем запутался...

Примеры по указанной ссылке чем не нравятся?


Название: Re: Base64 в long double
Отправлено: bsf от Ноябрь 26, 2012, 20:02
xokc, спасибо! Всё получилось и всё работает... И возвращает нужные данные!
Код
C++ (Qt)
long double *ptr;
fp80le_to_fp64(ptr, ba.data());
 


Название: Re: Base64 в long double
Отправлено: bsf от Ноябрь 27, 2012, 15:55
Ребят, имея заголовок функции:
Код
C++ (Qt)
void fp64_to_fp80le(void *f80, const void *f64)
не могу сообразить, как сделать обратно записать в base64 в тип Extended
Пытаюсь записать так:
Код
C++ (Qt)
double *ld;
...
fp64_to_fp80le(x, ld);
Каким типом данным должен быть x? Чтобы я его запихнул в QByteArray?


Название: Re: Base64 в long double
Отправлено: Igors от Ноябрь 27, 2012, 16:01
Код
C++ (Qt)
char rebyat[10];
 


Название: Re: Base64 в long double
Отправлено: bsf от Ноябрь 27, 2012, 20:01
Спасибо, я уже сомневаться стал...но всё именно так, как у меня. Я вот случайно обнаружил, что исходная строка содержит 24 байта, первые два на Extended, остальные 4 не могу идентифицировать. Собственно в этом и проблема. Вопрос теперь другой, возможно ли ка нибудь идентифицировать эти 4 байта и преобразовать к какому нибудь типу? Известно только что это массив типа record с двумя переменными типа Extended... Ту длинную строку которую я приводил - это массив с одним элементом...


Название: Re: Base64 в long double
Отправлено: xokc от Ноябрь 28, 2012, 09:18
Что-то ты тут сумбур развёл. Отвечаю ровно на те вопросы, которые ты задал.
Вопрос теперь другой, возможно ли ка нибудь идентифицировать эти 4 байта и преобразовать к какому нибудь типу?
Можно. К любому типу данных размером в 4 байта. Например, к quint32. Или char[4]. Или short[2].
Если нужно больше конкретики, конкретизируй вопрос.


Название: Re: Base64 в long double
Отправлено: bsf от Ноябрь 28, 2012, 16:02
Мне тип данных неизвестен, поэтому я не знаю к чему делать cast. Методом тыка пробовал к int double - не выходит. Так что скорее всего это утопия. Надо смотреть как происходит сериализация. А этой возможности нет. Знаю точно, что это массив Дельфёвый структур. В структуре - 2 переменные типа Extended. Я их читаю, всё замечательно. А записать назад - не могу, не хватает этих преславутых 4 байтов.


Название: Re: Base64 в long double
Отправлено: Igors от Ноябрь 28, 2012, 16:13
Мне тип данных неизвестен, поэтому я не знаю к чему делать cast. Методом тыка пробовал к int double - не выходит. Так что скорее всего это утопия. Надо смотреть как происходит сериализация. А этой возможности нет. Знаю точно, что это массив Дельфёвый структур. В структуре - 2 переменные типа Extended. Я их читаю, всё замечательно. А записать назад - не могу, не хватает этих преславутых 4 байтов.
Забудьте Вы эти академические термины long/int double. На практике есть double (8 байт) и float (4 байтв), остальное - дань истории "сопроцессоров". Делаете так

Код
C++ (Qt)
#pragma pack (push, 4)
struct CTest {
char rebyat1[10]; // первый урод (10 байт)
char rebyat2[10]; // второй
union {
  int rebyatenok_I;
  float rebyatenok_F;
};
};
#pragma pack (pop)
 
CTest test;
ba.read(&test, sizeof(test));
printf("int = %d, float = %f\n", test.rebyatenok_I, test.rebyatenok_F);
 
И смотрите какое значение разумное int или float

[/offtop]
"пресловутый" - от слова "слово", а не "слава"  :)


Название: Re: Base64 в long double
Отправлено: bsf от Ноябрь 28, 2012, 20:38
Я извиняюсь, но QByteArray  нет метода read()


Название: Re: Base64 в long double
Отправлено: Igors от Ноябрь 28, 2012, 21:04
Я извиняюсь, но QByteArray  нет метода read()
Ну не все же дается под copy/paste  :) Из Ваших слов следует что есть блок данных 24 байта - ну и считайте его в эту структуру доступными средствами. Откуда-то де Вы данные берете


Название: Re: Base64 в long double
Отправлено: xokc от Ноябрь 28, 2012, 21:32
Мне тип данных неизвестен, поэтому я не знаю к чему делать cast. Методом тыка пробовал к int double - не выходит. Так что скорее всего это утопия. Надо смотреть как происходит сериализация. А этой возможности нет. Знаю точно, что это массив Дельфёвый структур. В структуре - 2 переменные типа Extended. Я их читаю, всё замечательно. А записать назад - не могу, не хватает этих преславутых 4 байтов.
Я правильно понимаю, что нужно реализовать какой-то обмен данными с Дельфи приложением и теперь читать из дельфового буфера получается, а обратно записывать - нет? Если - да, то для начала я бы оставил ровно те значения, которые которые там в этих 4 байтах и лежат. Если не прокатит - пробовать методом тыка - накапливать статистику и пытаться угадать, что именно там лежит. Дело в том, что того, что называется "массивом" в Delphi есть великое множество - начиная с банального array of и заканчивая TDynArray и т.п. Что именно применяется в данном конкретном случае и как оно сериализовалось - это вообще неочевидно. Кроме того, поскольку речь идёт массиве структур - то, с учётом неизвестного выравнивания этих структур, вообще можно мозг сломать.
P.S. Последние 4 байта из исходной последовательности дают 0x00442A83 или 4467331. Ничего разумного я в этом значении не нахожу - информации мало.


Название: Re: Base64 в long double
Отправлено: bsf от Ноябрь 28, 2012, 21:35
Есть программа, писанная на Дельфях, я думаю вы все её знаете - SASPlanet. Она сохраняет метки в формате XML. В одном из параметров координата(ы) меток сериализуется в Base64. Благодаря добрым людям я научился читать координаты, а вот писать не получается эти координаты не получается. Полагаю, что эти 4 байта - это что то такое, что без них программа отказывается эту метку поднимать...
Вот что сделано, пусть и через *опу. Файл main.cpp

Код
C++ (Qt)
#include <QtGui/QApplication>
 
#include <QtCore/QTextCodec>
#include <QtCore/QDebug>
 
 
#if __BYTE_ORDER == __LITTLE_ENDIAN
 
#define MAN1OFFSET  0
#define MAN2OFFSET  4
#define EXP_OFFSET  6
#define lecpy       memcpy
 
#elif __BYTE_ORDER == __BIG_ENDIAN
 
#define MAN1OFFSET  4
#define MAN2OFFSET  0
#define EXP_OFFSET  0
 
static inline void *lecpy(char *dst, const char *src, size_t size) {
       dst += size;
       while (size--)
               *--dst = *src++;
       return dst;
}
 
#endif /* __BYTE_ORDER */
 
 
void fp80le_to_fp64(void *f64, const void *f80) {
       uint32_t man1, man2;
       uint16_t exp;
 
       lecpy((char *) &man1, (const char *) f80, 4);
       lecpy((char *) &man2, (const char *) f80 + 4, 4);
       lecpy((char *) &exp, (const char *) f80 + 8, 2);
 
       man1 >>= 11;
       man1 |= (man2 & 0x7ff) << 21;
       man2 >>= 11;
       man2 &= 0x000fffff;
       man2 |= (uint32_t) (exp & 0x8000) << 16;
       exp &= 0x7fff;
       exp = (uint16_t)(exp - 0x3c00);
       man2 |= (uint32_t) (exp & 0x7ff) << 20;
 
       memcpy((char *) f64 + MAN1OFFSET, &man1, 4);
       memcpy((char *) f64 + MAN2OFFSET, &man2, 4);
}
 
void fp64_to_fp80le(void *f80, const void *f64) {
       uint32_t man1, man2;
       uint16_t exp;
 
       memcpy(&man1, (const char *) f64 + MAN1OFFSET, 4);
       memcpy(&man2, (const char *) f64 + MAN2OFFSET, 4);
       memcpy(&exp,  (const char *) f64 + EXP_OFFSET, 2);
 
       man2 = ((man2 << 11) & 0x7ffff800)
            | ((man1 >> 21) & 0x000007ff);
       if (man1 || man2)
               man2 |= 0x80000000;
 
       man1 <<= 11;
       if (man1 & 0x800)
               man1 |= 0x7ff;
 
       exp = (uint16_t)(((((exp >> 4) & 0x7ff) + 0x3c00) & 0x7fff) | (exp & 0x8000));
 
       lecpy((char *) f80, (const char *) &man1, 4);
       lecpy((char *) f80 + 4, (const char *) &man2, 4);
       lecpy((char *) f80 + 8, (const char *) &exp, 2);
}
 
 
int main(int argc, char *argv[])
{
   QApplication a(argc, argv);
   QTextCodec::setCodecForTr(QTextCodec::codecForName("CP1251"));
 
   QByteArray decodeString = QByteArray::fromBase64("uB6F61G4npAEQASSsG8nERHeBECDKkQA");
 
   QByteArray ba = decodeString.mid(0,10);
   QByteArray bb = decodeString.mid(10,10);
   QByteArray bc = decodeString.mid(20,4);
 
   double *ld;
   double *lw;
 
   fp80le_to_fp64(ld, ba.data());
   fp80le_to_fp64(lw, bb.data());
 
   qDebug() << "size=" << decodeString.count();
   qDebug() << "1 - double=" << *ld;
   qDebug() << "2 - double=" << *lw;
   qDebug() << "3 - unknown=" << bc.data();
 
   char a1[10];
   char a2[10];
   fp64_to_fp80le(a1, ld);
   fp64_to_fp80le(a2, lw);
 
 
   QByteArray arr;
   arr.append(a1);
   arr.append(a2);
   arr.append(bc.data());
   arr = arr.toBase64();
 
   qDebug() << arr.data();
 
   return 0;
}
Результат естественно иной, во-первых, что то теряется при переводе типов, во-вторых, эти 4 байта, что в них? Загадка... Явный cast ни к чему не привёл...


Название: Re: Base64 в long double
Отправлено: V1KT0P от Ноябрь 28, 2012, 22:43
Результат естественно иной, во-первых, что то теряется при переводе типов, во-вторых, эти 4 байта, что в них? Загадка... Явный cast ни к чему не привёл...
По идеи если есть три числа являющиеся координатами, и первые два это широта и долгота. То по идеи третье должно быть высота( скорее всего в метрах но может и в сантиметрах ).
А для того чтоб не терялось советую использовать long double.

добавлено:
Вот быстренько набросал две функции конвертации:
Код
C++ (Qt)
#include <QtCore/QDebug>
 
bool getPositionFromBase64( const QString &string, long double &longitude, long double &latitude, int &altitude )
{
   QByteArray data = QByteArray::fromBase64( string.toAscii() );
 
   if( data.size() != 24 ) {
       return false;
   }
 
   longitude = 0;
   latitude = 0;
 
   memcpy( &longitude, data.data(), 10 );
   memcpy( &latitude, data.data() + 10, 10 );
   memcpy( &altitude, data.data() + 20, 4 );
 
   return true;
}
 
QString getBase64FromPosition( const long double &longitude, const long double &latitude, const int &altitude )
{
   char data[24] = { 0 };
 
   memcpy( data, &longitude, 10 );
   memcpy( data + 10, &latitude, 10 );
   memcpy( data + 20, &altitude, 4 );
 
   return QString::fromAscii( QByteArray( data, 24 ).toBase64() );
}
 
int main(int argc, char *argv[])
{
   long double longitude;
   long double latitude;
   int altitude;
 
   if( getPositionFromBase64( "uB6F61G4npAEQASSsG8nERHeBECDKkQA", longitude, latitude, altitude ) ) {
       qDebug() << "Longitude:" << (double)longitude;
       qDebug() << "Latitude:" << (double)latitude;
       qDebug() << "Altitude:" << altitude;
       qDebug() << "Generate Base64:" << getBase64FromPosition( longitude, latitude, altitude );
   } else {
       qDebug() << "Wrong string";
   }
 
   return 0;
}
 
Вот вывод:
Цитировать
Longitude: 36.155
Latitude: 55.5167
Altitude: 4467331
Generate Base64: "uB6F61G4npAEQASSsG8nERHeBECDKkQA"
Как видно если правильно использовать С++ то получается компактно, правильно и красиво. А не та каша кода что у тебя =).


Название: Re: Base64 в long double
Отправлено: bsf от Ноябрь 29, 2012, 09:11
Спасибо, буду пробовать! Много нового для себя открыл! Я новичок в этой области и учусь! А что касается высоты - то странная она какая - то! Да и СасПланета вряд-ли ее умеет определять. Это что то иное. Буду пробовать...


Название: Re: Base64 в long double
Отправлено: xokc от Ноябрь 29, 2012, 10:58
По идеи если есть три числа являющиеся координатами, и первые два это широта и долгота. То по идеи третье должно быть высота( скорее всего в метрах но может и в сантиметрах ).
Как-то лихо Вы привязки делаете. Если так уж пальцем в небо тыкать, то я бы не int рассматривал, а float в качестве высоты. Вообще, автор СасПланета вроде адекватен вполне. Может прямо у него и спросить?


Название: Re: Base64 в long double
Отправлено: bsf от Ноябрь 29, 2012, 11:18
Как-то лихо Вы привязки делаете. Если так уж пальцем в небо тыкать, то я бы не int рассматривал, а float в качестве высоты. Вообще, автор СасПланета вроде адекватен вполне. Может прямо у него и спросить?
Спрашивали люди неоднократно, а получены уклончивые ответы, с типом Extended, ну и на том спасибо!


Название: Re: Base64 в long double
Отправлено: bsf от Ноябрь 29, 2012, 12:59
Потестил, всё отлично экспортируется и импортируется SAS-ом. V1KT0P спасибо за помощь, то что нужно!