3

I am using a TIdTcpServer component to implement a basic server side application. I have clients witch send strings to the server,ascii encoded, ending in these to characters #@.

eg :

this_is_a_sample#@ thisis_another_sample#@

My OnExecute method is the following :

procedure TLX8511.ProcessEvent(AContext: TIdContext);
var
  recv : String;
begin
    with AContext.Connection.IOHandler do
    begin
          CheckForDataOnSource(20);
          if not InputBufferIsEmpty then
          begin
              recv := ReadLn('#@');
              WriteLn(recv);
          end;
    end;
end

However when the ReadLn is executed I receive a wierd error : Buffer terminator must be specified

What I am doing wrong ?

LE : I am using Indy with lazarus on linux so this might be some porting issue

Thank you.

opc0de
  • 11,557
  • 14
  • 94
  • 187
  • 1
    In `TIdIOHandler.ReadLn`, this code `LTerm := ToBytes(ATerminator, AByteEncoding {$IFDEF STRING_IS_ANSI}, ADestEncoding{$ENDIF} );` is setting `LTerm` to a zero-length array. Not sure why mind you. You have the source to Indy, so you can just debug this. You know the text of the error. You can find the single place in the code that the error is raised. You can break there and look at the call stack. And then work out why that route was taken. – David Heffernan Aug 05 '13 at 10:15
  • LTerm get's nulled after the ToBytes function call. I will dig deeper.Thanks – opc0de Aug 05 '13 at 10:23
  • 1
    The only way `ToBytes()` can return an empty byte array for a non-empty input string is if the underlying character encoding engine (which in this case is iconv) fails to encode the input characters. Indy does have a slightly buggy/incomplete iconv implementation, so it is not unheard of to run into character encoding problems such as this on non-Windows platforms. Your use of `IIdTextEncoding` tells me you are using a recent Indy release that shipped with Delphi XE4, so be sure that you are using an up-to-date SVN snapshot so you have all of the latest bug fixes since XE4's initial release. – Remy Lebeau Aug 05 '13 at 17:12

1 Answers1

3

I don't like to answer my own questions but based of David Heffernan's suggestion I dug up the problem myself.

Turns out you must specify the encoding in order to avoid that exception so here is the solution:

procedure TLX8511.ProcessEvent(AContext: TIdContext);
var
  recv : String;
  encoding : IIdTextEncoding;
begin
    encoding := IndyTextEncoding_ASCII;
    with AContext.Connection.IOHandler do
    begin
          CheckForDataOnSource(20);
          if not InputBufferIsEmpty then
          begin
              recv := ReadLn('#@',encoding,encoding);
              WriteLn(recv);
          end;
    end;
end;  
opc0de
  • 11,557
  • 14
  • 94
  • 187
  • 1
    If you do not specify an encoding, Indy will simply use a default encoding, which is ASCII by default (based on the `IdGlobal.GIdDefaultTextEncoding` variable). The real issue is that on FPC/Linux, Indy uses the iconv library for its character encoding support, and Indy's use of iconv is still a little buggy/incomplete. But Indy's ASCII implementation does not use iconv, and since ASCII is Indy's default encoding, you should not have encountered this problem to begin with. So something else is going on. – Remy Lebeau Aug 05 '13 at 17:05
  • 3
    Since you are using FPC, you are using an Ansi-based RTL, so Indy would have set the `AByteEncoding` parameter of `ReadLn()` to ASCII by default, and the `ADestEncoding` parameter to an OS-default encoding. So either the ASCII->UTF16 conversion failed (not likely), or the UTF16->OS conversion failed (more likely). And that might be related to a bug that was recently fixed in the `TIdMBCSEncoding.Create()` constructor on systems that use iconv, where the `TIdMBCSEncoding.MaxCharSize` member was being set to 0 on charsets that do not support Unicode codepage U+10FFFF. That was fixed a week ago. – Remy Lebeau Aug 05 '13 at 17:17