Страница 1 из 1

Мистика Copy

СообщениеДобавлено: 14.03.2016 13:32:33
lordgray
err_copy.png
Здравствуйте! Спасите от сумасшествия, почти сутки бьюсь над загадкой "детской", где ее и быть не должно!
На скриншоте отладка кода и окно слежения за переменными.
Мистика в строке 1470. Там Copy ! Значение исходной строки t := 'locale=409', копируется первых 7 символов, и получается 'loca' ! Это как? :shock:
1) в 'locale=407' все символы английские;
2) никаких потоков, которые могли бы что-то изменить, нет;
3) Win7x64, Lazarus 1.6x64 (не RC2, а нормальный, последний), fpc 3.0.0, программа компилится в 32 бита.
4) Вариант, что отладчик не показывает строку полностью, не проходит, т.к. следующая строка - IF, который подтверждает, что значение 'loca'
Что делать? Менял Copy(t, 1, i) на Copy(t, 1, 7), результат тот же.
Капец, этих Copy по программе, штук 20, если не больше, и везде работают нормально, а тут - хрень какая-то.

Re: Мистика Copy

СообщениеДобавлено: 14.03.2016 14:23:59
wavebvg
Можно предположить, что строка хранится в UnicodeString или чем-то подобном.
А умная среда разработки Вам помогает и не заставляет думать о кодировках.

Попробуйте SetCodePage над строчкой перед сравнением.

Re: Мистика Copy

СообщениеДобавлено: 14.03.2016 14:28:37
DYUMON
что лежит в paramname ?

Re: Мистика Copy

СообщениеДобавлено: 14.03.2016 14:32:35
lordgray
DYUMON писал(а):что лежит в paramname ?


Код: Выделить всё
const
  ParamName = {$ifdef windows}'locale'{$else}'llocale'{$endif};


Добавлено спустя 5 минут 43 секунды:
wavebvg писал(а):Можно предположить, что строка хранится в UnicodeString или чем-то подобном.
А умная среда разработки Вам помогает и не заставляет думать о кодировках.

Попробуйте SetCodePage над строчкой перед сравнением.

1) String заменил на UTF8String - безрезультатно
2) Вернул на String. Вызов SetCodePage ругается на несоответствие типов: нужен RawByteString, а передается AnsiString

Re: Мистика Copy

СообщениеДобавлено: 14.03.2016 18:53:34
wavebvg
Я предполагаю, что кодировка в ParamName - однобайтовая, а в Loc - двубайтовая.
Для решения проблемы необходимо переконвертировать все строки с одну кодировку.
Учтите магию из вот этой статьй:

http://www.freepascal.ru/article/freepa ... 0718142000
А именно:
Код: Выделить всё
r1:=ac1;            // ac1 65001 -> r1 65001
r1:=ac1+ac3;     // ac1 65001 ac3 1251 -> r1 1251 при начальной инициализации
r1:=ac1+ac3;     // r1 65001 ac1 65001 ac3 1251 -> r1 65001 при повторном присвоении

Re: Мистика Copy

СообщениеДобавлено: 14.03.2016 18:59:25
lordgray
wavebvg писал(а):Можно предположить, что строка хранится в UnicodeString


Спасибо!!!
Функция Copy перегружаемая, и есть вариант под юникод. Видать, компилятор решил взять именно его (с каких делов?).
Объявил переменную t как UnicodeString, и все заработало.
Я, конечно, рад, что решилось, но изначально, до суток мучений, было:
Код: Выделить всё
Loc := Lang.Values['locale']

И это всегда возвращало пустую строку, не смотря на то, что строка 'locale=409', в Lang присутствовала.
Это уже разбираясь, что к чему, обвешал все переменными, повторяя поведение свойства Values, чтоб можно было отдебажить.
Что "перемкнуло" компилятор в данной функции, остается загадкой. И, буду надеяться, в других местах кода, его так не глюканет.

Re: Мистика Copy

СообщениеДобавлено: 14.03.2016 20:59:06
bormant
lordgray писал(а):Значение исходной строки t := 'locale=409', копируется первых 7 символов, и получается 'loca' ! Это как?

Если у вас перед 'locale=409' был BOM, то он в UTF-8 занимает как раз 3 байта...

Re: Мистика Copy

СообщениеДобавлено: 14.03.2016 21:30:35
lordgray
bormant писал(а):Если у вас перед 'locale=409' был BOM, то он в UTF-8 занимает как раз 3 байта...

Знаете, мне тоже приходила такая мысль. Да, BOM есть. Но! Если бы я работал напрямую с текстовым файлом, то да, это было бы верно. Но файл грузит TStringList. Он определяет BOM, и обрезает его. Кроме того, для Lang[1], Lang[2] все тоже самое происходит! Тут уже на BOM не спишешь.

Я все думал, в чем разница этого кода, и всего остального, раскиданного по программе, где все работает как надо. И заметил одно отличие: этот код (процедура), вызывается из Initialization секции. Вполне возможно, что этот Initialization вызван раньше, чем Initialization модуля, где инициализируется StringManager. Мне кажется логичным такой вариант. Буду проверять. Как вариант, поставить модуть последним в USES, либо код перенести в OnCreate модуля данных. Как проверю, отпишусь. Быстрее всего, уже завтра.

Спустя 2 часа:
Перестановка модуля в USES, не дала результата, вызов функции из OnCreate модуля данных, тоже ничего не изменил.
Я в шоке: объявлял все строковые переменные, как AnsiString, UTF8String, String, даже ShortString, пофигу, Copy обрабатывает как 2-х байтную строку. Пытался Copy(AnsiString(t),... тоже не помогло. Открыл окно ассемблера, и это меня поставило в полный тупик: ассемблер показывает вызов fpc_ansistr_copy.
На этом мысли останавливаются.

Re: Мистика Copy

СообщениеДобавлено: 15.03.2016 03:58:40
SSerge
lordgray писал(а):Он определяет BOM, и обрезает его


Вы уверены? Я как-то в целях эксперимента с удивлением выяснил, что BOM прекрасно приписывается к строкам при чтении файлов

Re: Мистика Copy

СообщениеДобавлено: 15.03.2016 09:19:08
lordgray
SSerge писал(а):
lordgray писал(а):Он определяет BOM, и обрезает его


Вы уверены? Я как-то в целях эксперимента с удивлением выяснил, что BOM прекрасно приписывается к строкам при чтении файлов


Финиш. Сделал через LoadFromStream.
Copy заработал. Упростил до начального варианта, через свойство Value, и оно заработало.

Код: Выделить всё
var Loader: TFileStream;
    Lang: TStringList;
    Loc: String;
begin
  Lang := TStringList.Create;
  //Lang.LoadFromFile(aSt);
  Loader := TFileStream.Create(aSt, fmOpenRead);
  Loader.Position := 3;//skip BOM
  Lang.LoadFromStream(Loader);
  Loc := Lang.Value['locale'];


Спасибо, Вы мой спаситель.
Я попутал с BOM. Это Delphi его отслеживает. Сейчас глянул в исходник TStrings.LoadFromFile(LoadFromStream), там и намека на проверку BOM нет.
А что ж я напутал с Lang[2], Lang[3]? Блин, каша в голове.
Всем спасибо! Давно таких "приколов" не попадалось.