Solved

Replace string in blob in Stream

Posted on 2011-03-11
9
1,586 Views
Last Modified: 2013-11-23
Hi
I have a .doc file stored in Oracle DB as Blob field. From Delphi I fetch it and store in
a BlobStream ... example :
    Field := OracleDataSet.FieldByName('FIELD');
    Stream := OracleDataSet.CreateBlobStream(Field, bmRead);
In the .doc file I have strings like ... #NAME#. I want to replace that with real value.
How can I do that without writing the .doc file to my hard drive.
Later I can open my Stream using OleContainer, but first I want to replace some strings.
Best regards:
Albert Elisson
0
Comment
Question by:Programm
  • 5
  • 4
9 Comments
 
LVL 25

Expert Comment

by:epasquier
Comment Utility
you can't do that directly, you will have to load your stream into a string first, then replace your #NAME# with your value, and put it back in a TMemoryStream to open it in the OleContainer

Procedure ReplaceAndLoadStream( Stream : TBlobStream ; OleContainer:TOleContainer );
Var
 BlobTxt:ANSIString;
 MemStream:TMemoryStream;
begin
 SetSize(BlobTxt,Stream.Size);
 Stream.ReadBuffer(BlobTxt[1],Stream.Size);
 BlobTxt:=StringReplace(BlobTxt,'#NAME#', 'NewName' , [rfReplaceAll]);
 MemStream:=TMemoryStream.Create;
 MemStream.WriteBuffer(BlobTxt[1],Length(BlobTxt));
 OleContainer.LoadFromStream(MemStream);
 MemStream.Free;
end;

Open in new window

0
 

Author Comment

by:Programm
Comment Utility
Hi epasquier
Sorry for my late response. I have been so busy in other assignments.
I couldn't get this to work for me.
1. I couldn't find the function SetSize... only SetLength. Was than then function you meant?
2. When I reach OleContainer.LoadFromStream(MemStream) I get an 'Stream read error' error. It crashes on the  'Stream.ReadBuffer(Header, SizeOf(Header));' line in the OleContainer class.
Any ideas?

Best regards:
Albert.
0
 
LVL 25

Expert Comment

by:epasquier
Comment Utility
yes, that is setLength

you need also to reset the position of the stream before reading from it :

 MemStream:=TMemoryStream.Create;
 MemStream.WriteBuffer(BlobTxt[1],Length(BlobTxt));
MemStream.Position:=0;
 OleContainer.LoadFromStream(MemStream);
0
 

Author Comment

by:Programm
Comment Utility
Hi epasquier
Now I get the error 'Invalid stream format' when I call OleContainer.LoadFromStream(MemStream).

I got this working with call to a new custom function in TOleContainerP whitch is a custom .pas file from another question I posted here and you solved with me brilliantly ( http://www.experts-exchange.com/Programming/Editors_IDEs/Delphi/Q_26861235.html ).
My code is:

 
procedure TfrmAttachmentsDOAStraumur.OpnaStraumEftirSnidmati(qry : TOracleDataSet);
var
  Stream : TStream;
  Field : TField;
  iSizeBefore : integer;
  BlobTxt:ANSIString;
  MemStream:TMemoryStream;
begin
  try

    m_qry := qry;
    Field := qry.FieldByName('BLOB_SNIDMAT');
    Stream := qry.CreateBlobStream(Field, bmRead);
    SetLength(BlobTxt,Stream.Size);
    Stream.ReadBuffer(BlobTxt[1],Stream.Size);
    BlobTxt := StringReplaceP(BlobTxt,'#ATVRNAFN#', 'NewName' , [rfReplaceAll]);
    MemStream := TMemoryStream.Create;
    MemStream.WriteBuffer(BlobTxt[1],Length(BlobTxt));
    MemStream.Position := 0;
    //OleContainerP1.LoadFromStream(MemStream);
    OleContainerP1.CreateObjectFromStream(MemStream);
    OleContainerP1.DoVerb(ovShow);
    Self.ShowModal;
  finally
    FreeAndNil(Stream);
    MemStream.Free;
  end;
end;

Open in new window


I had to customize the function StringReplace. It uses this line ' Offset := AnsiPos(Patt, SearchStr); ' whitch always returns 0. If I used  ' Offset := Pos(Patt, SearchStr); ' ... it worked.


This works great when the replacement string is equal in size to the original string, but if the replacement string is shorter than the original string I get the error:
'The doc file has been corrupted'.
What can I do? We are so close.....

Best regards:
Albert.
0
Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 

Author Comment

by:Programm
Comment Utility
Hi epasquier
I got you mixed up with ewangoya in my recent comment who solved my other question with me an I apologize for that.
0
 
LVL 25

Expert Comment

by:epasquier
Comment Utility
Hi, I think that working on the Doc stream is not a good idea. You would need the complete specification of .DOC file format, if obviously it has some length control of some data structures.

The better idea would be then to load the Doc as it is in the blob field, and use OLE automation to do a Word search & replace in the document
0
 

Author Comment

by:Programm
Comment Utility
Hi , that is my method today. But it is causing a problem for me because I then have to write my blob field to disk and read it from there. When I close the OleContainer the WINWORD.EXE process is still alive unless i kill it with quit(0). If I have other word documents open at the same time, they get shut down as well without save!!
This is the reason I am trying to open, edit and save my documents without writing them to hard disk.

I have my .doc files stored in blob field in the db as templates. In these templates I have some variables with ## at each side like #NAME#, #ADDRESS# etc.
I replace them with real values.
There must be some way to to this without writing the .doc files to hard disk.
0
 
LVL 25

Accepted Solution

by:
epasquier earned 250 total points
Comment Utility
if your problem is mainly of closing Word process only if there is no other open document, there is probably a way to check that before calling Quit

I'm about sure that Ole automation, while being a bit of a pain on some details like that, is still the best way of doing things with Office documents.
0
 

Author Closing Comment

by:Programm
Comment Utility
I did not get a soloution for my problem. That is why I select grade B. Maybe it is a bit harsh on my behalf if it is not possible to solve.
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Reference external folders in Visual Studio 4 70
Sending Gmail through Delphi 3 69
delphi exception 7 58
Run video youtube webbrowse 10 44
A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Programmer's Notepad is, one of the best free text editing tools available, simply because the developers appear to have second-guessed every weird problem or issue a programmer is likely to run into. One of these problems is selecting and deleti…
The viewer will learn how to use NetBeans IDE 8.0 for Windows to connect to a MySQL database. Open Services Panel: Create a new connection using New Connection Wizard: Create a test database called eetutorial: Create a new test tabel called ee…
The viewer will learn how to synchronize PHP projects with a remote server in NetBeans IDE 8.0 for Windows.

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now