PDA

View Full Version : SDL_RWops -> TStream conversion?



masonwheeler
19-04-2008, 07:11 PM
I'm trying to use an archive that can work with multiple file types in an SDL-based program. I've got a routine to open the archive and retrieve individual files from it as PSDL_RWops pointers. Problem is, only certain file types are able to be read from a SDL_RWops. I'd like to be able to define custom loaders for other file types.

But the preferred method of working with files in Delphi isn't an SDL_RWops, it's a TStream. For compatibility purposes, I need a way to convert the one buffer to the other. Can anyone help me fill in the following function?

function rwToStream(rw: PSdl_RWops): TMemoryStream
begin
result := TMemoryStream.Create;
{insert functional code here}
end;

Robert Kosek
19-04-2008, 07:17 PM
No offense, but why not derive a new stream class that encapsulates RWops instead of converting it? Conversion is more of a hassle anyway. You have to somehow decipher the type of stream it is and make sure it's intercompatible with BOTH TStream and RWops. It's simpler to encapsulate:
type
TRWStream = class(TStream)
private
fOps: PSDL_RWops;
fOwnsOps: Boolean;
public
constructor Create(ops: PSDL_RWops; owns: boolean = true);
end;

And so on. Much simpler than attempting type conversion.

masonwheeler
19-04-2008, 07:20 PM
You know, that's a really good idea! I hadn't thought of that.

Thanks!

technomage
19-04-2008, 08:45 PM
JEDI-SDL already has a unit sdlstreams.pas which has all these functions written for you, there is no need to write you own!

masonwheeler
19-04-2008, 10:35 PM
Nope. Sdlstreams has a converter that goes the other way, taking an existing TStream and making a new PSDL_RWops out of it, but that's the opposite of what I'm looking for.

Here's my preliminary offering. If it's good enough, maybe it could get integrated into the sdlstreams unit.
unit SDL_rwStream;

interface
uses
classes,
SDL;

type
TRWStream = class(TStream)
private
FOps: PSDL_RWops;
FOwnsOps: Boolean;
public
constructor Create(ops: PSDL_RWops; owns: boolean = true);
destructor Destroy; override;
function Read(var Buffer; Count: Integer): Integer; override;
function Write(const Buffer; Count: Integer): Integer; override;
function Seek(Offset: Integer; Origin: Word): Integer; override;
end;

implementation

{ TRWStream }

constructor TRWStream.Create(ops: PSDL_RWops; owns: boolean);
begin
inherited Create;
if not assigned(ops) then
raise EStreamError.Create('No SDL_RWops available for TRWStream creation!');
FOps := ops;
FOwnsOps := owns;
end;

destructor TRWStream.Destroy;
begin
if FOwnsOps then
begin
FOps.close(FOps);
SDL_FreeRW(FOps);
end

//this is not strictly necessary, but it leaves the RWops in a known state,
//which is always nice
else self.Seek(0, soFromBeginning);
inherited Destroy;
end;

function TRWStream.Read(var Buffer; Count: Integer): Integer;
begin
result := FOps.read(FOps, @Buffer, 1, count);
end;

function TRWStream.Seek(Offset: Integer; Origin: Word): Integer;
begin
result := FOps.seek(FOps, offset, origin);
end;

function TRWStream.Write(const Buffer; Count: Integer): Integer;
begin
result := FOps.write(FOps, @buffer, 1, count);
end;

end.

EDIT: After poking around in SDL_rwops.c, it appears that I had some of the arguments to Read and Write backwards, causing unexpected return values. Fixed now.