Конференция "Сети" » Получить UTF8 строку из TMemoryStream
 
  • denkop (06.02.12 14:50) [0]
    Есть кусок кода который получает от PHP какой-то текст в UTF8.
    Получаю данные вот таким образом:

       HTTPRecvBuffer: array [0..512] of char;

    ......................
             while True do
             begin
               // Check for data ready
               Retries:=0;
               repeat
                 lSucc:= InternetQueryDataAvailable(hFile, BytesRead, 0, 0);
                 if NOT lSucc then Sleep(SleepTime);
                 Inc(Retries);
               until lSucc OR (Retries <= Attempts);
               // Read data
               InternetReadFile(hFile, @HTTPRecvBuffer, BufferSize, BytesRead);
               if BytesRead = 0 then break;
               FOutStream.WriteBuffer(HTTPRecvBuffer, BytesRead);
               ProgBytesReaded:=ProgBytesReaded+BytesRead;
               if Assigned(OnProgress) then
                 OnProgress(Self, ProgBytesReaded, ProgTotalBytes);
               if FTerminate then Break;
             end;


    из потока пытаюсь читать вот так:

    function StreamToString(aStream: TStream): string;
    var
     SS: TStringStream;
    begin
     if aStream <> nil then
     begin
       SS := TStringStream.Create('');
       try
         SS.CopyFrom(aStream, 0);
         Result := SS.DataString;
       finally
         SS.Free;
       end;
     end else Result := '';
    end;
    ......................
    ShowMessage(StreamToString(FOutStream));
    ......................


    Но в результате русского текста не вижу, корявые символы получаются..

    вот ещё на всякий случай результаты снифа полученной инфы:
    HTTP/1.1 200 OK\r\n
    Date: Mon, 06 Feb 2012 10:21:39 GMT\r\n  
    Content-Type: text/html\r\n
    Connection: keep-alive\r\n
    Content-Length: 151\r\n

    Line-based text data: text/html
     
    <errcode>101</errcode>\n
    [truncated] <errmsg>\320\240\320\265\320\263\320\270\321\201\321\202\321\200\320\260\321\206 \320\270\320\276\320\275\320\275\321\213\320\271 \320\272\320\273\321\216\321\207 \321\203\320\266\320\265 \320\270\321\201\320\277\320\276\320\273  



    Если урл вбить в адресной строке браузера и поставить вручную кодировку UTF8, то вижу именно то что отправил из PHP скрипта, т.е. с серверной частью проблем нет.
  • denkop (06.02.12 14:52) [1]
    Добавлю ещё одно уточнение, код нормально работает с ANSI кодировкой, но сейчас возникла необходимость добавить мультиязыковую поддержку, поэтому переходим на UTF кодировку с которой и вылезли все вышеперечисленные проблемы.
  • denkop (06.02.12 15:02) [2]
    Исходное сообщение которое не могу получить:
    <errcode>101</errcode>
    <errmsg>Регистрационный ключ уже используется на другом компьютере.</errmsg>
  • sniknik © (06.02.12 15:10) [3]
    > Result := SS.DataString;
    Result := Utf8ToAnsi(SS.DataString);
    ?

    > Если урл вбить в адресной строке браузера и поставить вручную кодировку UTF8, то вижу именно то что отправил из PHP скрипта, т.е. с серверной частью проблем нет.
    как раз есть, если приходится вручную кодировку указывать значит сервер не отдает в какой кодировке контент.
  • sniknik © (06.02.12 15:12) [4]
    > HTTPRecvBuffer: array [0..512] of char;
    ? unf8 для русского текста раза в 3 длиннее.
  • denkop (06.02.12 15:44) [5]
    как раз есть, если приходится вручную кодировку указывать значит сервер не отдает в какой кодировке контент.


    а каким образом он об этом сообщает? как такого текста html нет, серверная и клиентская часть общается между собой подобием xml
    Result := Utf8ToAnsi(SS.DataString);


    не помогает
    ? unf8 для русского текста раза в 3 длиннее


    данные блочно получаются, 512 размер блока
            while True do
            begin
    ....
    читаем по 512 байт, если больше нечего получать, выходим из цикла
               if BytesRead = 0 then break;
  • Anatoly Podgoretsky © (06.02.12 16:00) [6]

    > sniknik ©   (06.02.12 15:12) [4]
    > > HTTPRecvBuffer: array [0..512] of char;
    > ? unf8 для русского текста раза в 3 длиннее.

    Может и в 6, как карты лягут. Не говоря уже о том, что массив статический.
  • sniknik © (06.02.12 16:08) [7]
    > Result := Utf8ToAnsi(SS.DataString);
    > не помогает
    значит преобразование уже было. поможет только для реально unf8, а не с уже попыткой, неправильной, его в юникод например преобразовать.

    > Может и в 6
    специально написал, для "русского текста", он насколько помню 3х-максимум 4х символьный.
  • Anatoly Podgoretsky © (06.02.12 16:34) [8]
    Это что за числа?
  • denkop (06.02.12 16:42) [9]
    Не пойму в чём вопрос по поводу длины.. Допустим я с сервера отправляю текст в 60 раз длинее чем 512, т.е. 30720 байт. Блоками по 512 байт за 60 итераций цикла, я сохраняю всё сообщение в поток FOutStream (WriteBuffer(HTTPRecvBuffer, BytesRead)), а потом всё 30720 байт пытаюсь сконвертировать из UTF8. В чём вопрос объясните? Проблема не в том как мне это прочитать, читается всё нормально там, вопрос в том как получить читаемый текст. Даже если всего лишь 512 байт прочитаются я получу хотя бы несколько букв моей посылки
  • Sha © (06.02.12 16:44) [10]
    > denkop  
    > Result := Utf8ToAnsi(SS.DataString); не помогает

    версия Delphi какая?

    > sniknik
    > специально написал, для "русского текста", он насколько помню 3х-максимум 4х символьный.

    буквы 2x-симвоьные
  • sniknik © (06.02.12 16:52) [11]
    > Блоками по 512 байт
    а массив типа char... не всегда равно.
  • denkop (06.02.12 16:54) [12]
    > версия Delphi какая?
    Delphi XE

    > а массив типа char... не всегда равно.
    что именно не всегда равно? и причём массив char?
  • denkop (06.02.12 16:54) [13]
    > версия Delphi какая?
    Delphi XE

    > а массив типа char... не всегда равно.
    что именно не всегда равно? и причём массив char?
  • Sha © (06.02.12 17:06) [14]
    > denkop
    в ХЕ char string и, наверно, stringstream в 2 раза жирнее,
    тебе не нужен stringsteam, надо любым способом сырые байты
    перегнать в string или ansistring.
  • sniknik © (06.02.12 17:06) [15]
    > что именно не всегда равно?
    byte = 1 байт, char = 2 байта.
    например.

    > Delphi XE
    тогда у тебя все к юникоду, если ничего не делать, преобразовывается. и utf8 насколько понимаю (до сих пор на D7) автоматом поддерживается.
  • Sha © (06.02.12 17:07) [16]
    В смысле конвертировать, например, можно попробовать этим:
    http://guildalfa.ru/alsha/sites/default/files/ShaUnicode_0.pas
  • denkop (06.02.12 17:15) [17]
    проблема решена, вместо:
    >    SS := TStringStream.Create('');
    нужно было явно указать кодировку для TStringStream:
    >    SS := TStringStream.Create('', CP_UTF8);

    > byte = 1 байт, char = 2 байта.
    не имеет абсолютно никакого отношения к вопросу, т.к. в конечном итоге мы получили в одной строке именно 30720 байт, ровно столько, сколько отправил сервер, а какой размер буфера использовался чтобы получить эти 30720 байт от сервера в моём вопросе не имеет никакого значения

    > тогда у тебя все к юникоду, если ничего не делать, преобразовывается. и utf8 насколько понимаю (до сих пор на D7) автоматом поддерживается.
    при этом без CP_UTF8 работать не стало! автоматом в том случае когда есть явный контекст в виде используемых переменных ранее, а здесь данные приходят с сервера который может хоть на китайском прислать результат и автоматом одним здесь не обойдёшься
  • Anatoly Podgoretsky © (06.02.12 17:17) [18]
    > Sha  (06.02.2012 16:44:10)  [10]

    Двухсимволные если их первых 64К Юникода, дальше в силу вступают 3 и 4
    символьные, и так до миллиона первых символов Юникода
  • Anatoly Podgoretsky © (06.02.12 17:18) [19]
    > denkop  (06.02.2012 16:54:13)  [13]

    А то что в твоем случае жно 512 символов.
  • Anatoly Podgoretsky © (06.02.12 17:19) [20]
    > sniknik  (06.02.2012 17:06:15)  [15]

    Автоматом 2009+, даже думать не нужно, есть такой тип ка UTFString, а вот
    пытаться преобразовать в ANSI это откровенная глупость
  • Sha © (06.02.12 20:29) [21]
    > Anatoly Podgoretsky ©   (06.02.12 17:17) [18]
    > Двухсимволные если их первых 64К Юникода, дальше в силу вступают 3 и 4

    в первых 64к есть 1-, 2- и 3-символьные,
    а русские буквы - строго 2-символьные
 
Конференция "Сети" » Получить UTF8 строку из TMemoryStream
Есть новые Нет новых   [134435   +16][b:0][p:0.002]