delphioxygeneremobjects

Load string from Delphi stream in Oxygene


I'm new to Oxygene and I want to read strings from a stream that was generated by Delphi. I receive this stream via TCP. Here is how I save strings to a stream on the client side:

procedure SaveStringToStream(AStream: TStream; AString: String);
var
  StringSize: Integer;
  StringToSave: AnsiString;
begin
  StringToSave := Utf8Encode(AString);
  StringSize := Length(StringToSave);
  AStream.WriteBuffer(StringSize, SizeOf(StringSize));
  AStream.WriteBuffer(Pointer(StringToSave)^, StringSize);
end;

As you can See I first add the size of the string to the stream and then the content. My existing method to load strings from a stream on the server side (Oxygene) looks like this:

function LoadStringFromStream(const aStream: NSInputStream): String;
begin
  var buf: array[1024] of uint8_t;
  var len: Integer:= 0;   
  len := aStream.&read(buf) maxLength(1024);
  if len > 0 then
  begin    
    nslog(len.stringValue);
    var data: NSMutableData := NSMutableData.alloc().initWithLength(0);
    data.appendBytes(@buf) length(buf[0]); 

    exit NSString.alloc().initWithData(data) encoding(NSStringEncoding.NSASCIIStringEncoding);             
  end;    
end;

But this returns the hole content and not the current part.

EDIT: Oh, I had a mistake in the server application... Now I'm able to read strings, but not to read integer values (only upto 256 bit). For Objective-C I found this code

- (int32_t)readInt32
{
    int32_t value = 0;

    if ([self read:(uint8_t *)&value maxLength:4] != 4)
    {
        NSlog(@"***** Couldn't read int32");
    }
    return value;
}

Thats the Oxygene code:

function readInt32(const aStream: NSInputStream): Integer;
begin
  var value: int32_t := 0;
  var tmp:= uint8_t(@value);
  if aStream.&read(@tmp) maxLength(4) <> 4 then
    NSLog('***** Couldn''t read int32');  
  exit value;
end;

But something goes wrong, I don't get any value. Do you guys know what I have to do?


Solution

  • I think you have converted the Objective-C code (slightly, but significantly) incorrectly:

    function readInt32(const aStream: NSInputStream): Integer;
    begin
      var value: int32_t := 0;
      var tmp:= uint8_t(@value);
      if aStream.&read(@tmp) maxLength(4) <> 4 then
        NSLog('***** Couldn''t read int32');  
      exit value;
    end;
    

    In the above code tmp is declared as a single byte and initialised using a type cast of the address of the value variable.

    So if the value variable is being stored at the memory address $12345678 (stupid example kept to 32-bit for brevity) then tmp will be initialised with the value $78. You then pass the address of the tmp variable to aStream.read() which tries to read 4 bytes into the location of the tmp variable. But tmp is only a 1 byte value!

    I think you need to change the declaration of tmp to make it a pointer to unit8_t, and then pass this directly to aStream.read():

      var value: int32_t := 0;
      var tmp:= ^uint8_t(@value);
      if aStream.&read(tmp) maxLength(4) <> 4 then
        NSLog('***** Couldn''t read int32'); 
    

    Or eliminate the tmp variable and pass the address of value directly, with an appropriate cast:

      var value: int32_t := 0;
      if aStream.&read(^uint8_t(@value)) maxLength(4) <> 4 then
        NSLog('***** Couldn''t read int32'); 
    

    This latter approach is more directly comparable to the Objective-C original.