It looks like I have found a bug with TOraXml data storing.
Let take a look at the TOraXML.LoadFromStream procedure. It loads xml data from the source stream to the internal buffer. If the source stream has 10 bytel length, then internal buffer will be allocated for 10 bytes storing. Then try to get the xml data back with TOraXML.SaveToStream procedure. For some reason you will get 11+ bytes length xml data.
When exploring the issue I have found the folowing:
1) the TOraXML.SaveToStream procedure is expecting than xml data ends with zero-value byte (like any null-terminated string):
2) the TOraXML.LoadFromStream procedure does not append zero-value byte to the xml data stored as expected;
3) the TOraXML.SaveToStream procedure saves the xml-data to stream from the internal buffer begin till the zero-value byte (including zero byte) even if the internal data buffer does not contain zero byte at all, so it can append many garbage to the xml data end and can cause access violation memory error.
Below is my workaround. It is not perfect, but please check it and address the issue.
Code: Select all
procedure TOraXML.LoadFromStream(Stream: TStream);
var
Remainder, Readed: integer;
BufLen: integer;
Buffer: TBytes;
Ptr: IntPtr;
begin
CheckType;
FreeObject;
Stream.Seek(0, soFromBeginning);
Remainder := Stream.Size;
Readed := 0;
while Remainder > 0 do begin
if Remainder > 10000 then
BufLen := 10000
else
BufLen := Remainder;
SetLength(Buffer, BufLen);
Stream.ReadBuffer(Buffer{$IFNDEF CLR}[0]{$ENDIF}, BufLen);
if Readed + BufLen 0 then begin
Ptr := Marshal.AllocHGlobal(Readed + BufLen + 1); // added +1 to allocate place for zero byte
FillChar(Ptr, Readed + BufLen + 1, 0); // memory clear with zero for any case
if Readed 0 then
CopyBuffer(CacheValue, Ptr, Readed);
Marshal.Copy(Buffer, 0, IntPtr(Integer(Ptr) + Readed), BufLen);
if CacheValue nil then
Marshal.FreeHGlobal(CacheValue);
CacheValue := Ptr;
end;
Dec(Remainder, BufLen);
Inc(Readed, BufLen);
end;
end;
procedure TOraXML.SaveToStream(Stream: TStream);
var
Buffer: TBytes;
Len: integer;
begin
// if CacheIsNull then begin
// if ObjectIsNull then
// Exit;
// ReadXML;
// end;
if CacheValue = nil then
Len := 0
else
Len := StrLen(CacheValue);
SetLength(Buffer, Len); // removed +1 to exclude zero byte
if CacheValue nil then
Marshal.Copy(CacheValue, Buffer, 0 , Len); // removed +1 to exclude zero byte
Stream.WriteBuffer(Buffer{$IFNDEF CLR}[0]{$ENDIF}, Len); // removed +1 to exclude zero byte
end;--
Eugene