Results 1 to 4 of 4

Thread: Access Violation when loading from TStream

  1. #1

    Access Violation when loading from TStream

    Hi, I've got a very annoying problem which I can't seem to solve by myself.

    I want to load a list of images of my own format (nothing fancy at all as you'll see). I get no error when saving (but there may very well be something in there) however when loading I get a strange AV error that I've not been able to find the cause of.

    Anyway I suck at describing things so here's the code that should be the cause of the problem:

    TDXImageList saving and loading:
    Code:
    procedure TDXImageList.SaveToStream(Stream: TStream);
    var
      i, len: Integer;
    begin
      len := FList.Count;
      Stream.WriteBuffer(len, SizeOf(len));
      for i := 0 to len -1 do
        TDXImage(FList.Items[i]).SaveToStream(Stream);
    end;
    
    procedure TDXImageList.LoadFromStream(Stream: TStream);
    var
      i, len: Integer;
      img: TDXImage;
    begin
      Clear; // clears of any images that already existed
      Stream.ReadBuffer(len, SizeOf(len));
      for i := 0 to len -1 do
      begin
        img := TDXImage.Create(Self);
        img.LoadFromStream(Stream);
      end;
    end;
    TDXImage saving and loading:
    Code:
    procedure TDXImage.SaveToStream(Stream: TStream);
    begin
      FImage.SaveToStream(Stream);
      Stream.WriteBuffer(FWidth, SizeOf(FWidth));
      Stream.WriteBuffer(FHeight, SizeOf(FHeight));
      Stream.WriteBuffer(FTileWidth, SizeOf(FTileWidth));
      Stream.WriteBuffer(FTileHeight, SizeOf(FTileHeight));
      Stream.WriteBuffer(FTransparent, SizeOf(FTransparent));
      Stream.WriteBuffer(FTransColor, SizeOf(FTransColor));
      WriteStr(FName, Stream);
    end;
    
    procedure TDXImage.LoadFromStream(Stream: TStream);
    begin
      if Assigned(FImage) then FImage.Free;
      if Assigned(FImageList) then
        FImage := TMyImage.Create(FImageList.FHWnd)
      else
        FImage := TMyImage.Create(0);
    
      FImage.LoadFromStream(Stream);
      Stream.ReadBuffer(FWidth, SizeOf(FWidth));
      
      Stream.ReadBuffer(FHeight, SizeOf(FHeight));
      Stream.ReadBuffer(FTileWidth, SizeOf(FTileWidth));
      Stream.ReadBuffer(FTileHeight, SizeOf(FTileHeight));
      Stream.ReadBuffer(FTransparent, SizeOf(FTransparent));
      Stream.ReadBuffer(FTransColor, SizeOf(FTransColor));
      ReadStr(FName, Stream);
    end;
    TMyImage saving and loading;
    Code:
    procedure TMyImage.SaveToStream(Stream: TStream);
    begin
      Stream.WriteBuffer(FWidth, SizeOf(FWidth));
      Stream.WriteBuffer(FHeight, SizeOf(FHeight));
      Stream.WriteBuffer(FPixels[0, 0], SizeOf(FPixels[0, 0])*FWidth*FHeight);
    end;
    
    procedure TMyImage.LoadFromStream(Stream: TStream);
    begin
      Stream.ReadBuffer(FWidth, SizeOf(FWidth));
      Stream.ReadBuffer(FHeight, SizeOf(FHeight));
      SetLength(FPixels, FWidth, FHeight);
      Stream.ReadBuffer(FPixels[0, 0], SizeOf(FPixels[0, 0])*FWidth*FHeight);
    end;
    Save/Load a string from a stream:
    Code:
    procedure ReadStr(var s: String; Stream: TStream);
    var
      len: Integer;
    begin
      Stream.Read(len, SizeOf(len));
      SetLength(s, len);
      Stream.Read(s[1], SizeOf(s[1]) * len);
    end;
    
    procedure WriteStr(const s: String; Stream: TStream);
    var
      len: Integer;
    begin
      len := Length(s);
      Stream.Write(len, SizeOf(len));
      Stream.Write(s[1], SizeOf(s[1]) * len);
    end;
    Signature:
    <br />This is a block of text that can be added to posts you make. There is a 255 character limit

  2. #2

    Access Violation when loading from TStream

    TStream is an abstract class, use a "TFileStream" or "TMemoryStream" instead when calling the functions. IE ReadStr(thestring,thefile); so to speak.

    [pascal]
    procedure ReadStr(var s: String; Stream: TStream);
    var
    len: Integer;
    begin
    Stream.Read(len, SizeOf(len));
    SetLength(s, len);
    Stream.Read(pchar(s)^, len);
    end;

    procedure WriteStr(const s: String; Stream: TStream);
    var
    len: Integer;
    begin
    len := Length(s);
    Stream.Write(len, SizeOf(len));
    Stream.Write(pchar(s)^, len);
    end; [/pascal]

    This should fix your problems. It was the only error I really noticed. Remember to place before you load you image an:

    [pascal]If imagesize = 0 then {blank image code}[/pascal] to prevent errors.

    If you still don't get it I'll post source to a small set of apps I made. Just so you know I am not a good commenter.

    Ok, another thing I noticed. Your using:
    [pascal]Stream.ReadBuffer(FWidth, SizeOf(FWidth));
    Stream.ReadBuffer(FHeight, SizeOf(FHeight));
    SetLength(FPixels, FWidth, FHeight);
    Stream.ReadBuffer(FPixels[0, 0], SizeOf(FPixels[0, 0])*FWidth*FHeight);[/pascal]

    use this instead:
    [pascal]Stream.ReadBuffer(FWidth,SizeOf(Integer)); // IE the SIZEOF the data type, not the variable
    //...
    Stream.ReadBuffer(FPixels[0, 0], SizeOf(YourDataType{ie integer, cardinal, record}));
    [/pascal]

    Robert

  3. #3

    Access Violation when loading from TStream

    Quote Originally Posted by Robert Kosek
    TStream is an abstract class, use a "TFileStream" or "TMemoryStream" instead when calling the functions. IE ReadStr(thestring,thefile); so to speak.
    Actually I use a TFileStream. By using a TStream in then SaveTo/LoadFromStream methods I can use whatever TStream descendant I want without any problems.

    [pascal]
    Stream.Read(pchar(s)^, len);
    [/pascal]
    This might work (I haven't tried it) but so does my other method. I've never had any problems using Stream.Read(s[1], len), might be different on different versions (I use Delphi 6). Anybody know if it works on Free Pascal?

    [pascal]If imagesize = 0 then {blank image code}[/pascal] to prevent errors.
    Hmm... not really sure where I'd put that or if I need it. Even without any image data it should (hopefully ) load without problems.

    If you still don't get it I'll post source to a small set of apps I made. Just so you know I am not a good commenter.
    Hehe, who is?

    Ok, another thing I noticed. Your using:
    [pascal]Stream.ReadBuffer(FWidth, SizeOf(FWidth));
    Stream.ReadBuffer(FHeight, SizeOf(FHeight));
    SetLength(FPixels, FWidth, FHeight);
    Stream.ReadBuffer(FPixels[0, 0], SizeOf(FPixels[0, 0])*FWidth*FHeight);[/pascal]

    use this instead:
    [pascal]Stream.ReadBuffer(FWidth,SizeOf(Integer)); // IE the SIZEOF the data type, not the variable
    //...
    Stream.ReadBuffer(FPixels[0, 0], SizeOf(YourDataType{ie integer, cardinal, record}));
    [/pascal]
    There shouldn't be any difference between SizeOf(<VarType>) and SizeOf(<VarName>). i use the latter because it allows me to change the type of VarName without having to worry about changing alot of SizeOf()'s.

    Thanks for trying to help though.
    Signature:
    <br />This is a block of text that can be added to posts you make. There is a 255 character limit

  4. #4

    Access Violation when loading from TStream

    Actually I use a TFileStream. By using a TStream in then SaveTo/LoadFromStream methods I can use whatever TStream descendant I want without any problems.
    I actualy was trying to say this.

    Well I'm a hobbiest and don't exactly know the best ways (I learned from books and by simply trying things).

    Writing a string as a pchar pointer:
    [pascal]Stream.Write(pchar(s)^, len);[/pascal]
    Writing on a perchar basis:
    [pascal]Stream.Write(s[1], SizeOf(s[1]) * len);[/pascal]

    I learned the writing strings and streams while messing with custom made solid archives (my own format). It took a while to come to the best method, yet I don't know if it's really the "best".

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •