//----------------------------------------------------------------------------
// ObjectComponents
// Copyright (c) 1994, 1996 by Borland International, All Rights Reserved
//
/// \file
/// Implementation of TOcDocument Class
//----------------------------------------------------------------------------
#include <ocf/pch.h>
#include <ocf/oleutil.h>
#include <ocf/ocstorag.h>
#include <ocf/ocdoc.h>
#include <ocf/ocpart.h>
#include <ocf/ocapp.h>
#include <ocf/ocremvie.h>
namespace ocf {
using namespace owl;
DIAG_DECLARE_GROUP(OcfRefCount);
const _TCHAR DocStreamName[] = _T("OcDocument");
//
//
//
TOcDocument::TOcDocument(TOcApp& app, LPCTSTR fileName)
:
OcApp(app),
Name(fileName?fileName:_T("")),
PartCollection(),
LinkCollection()
{
// Host support...
//
ActiveView = 0;
PartID = 0;
Storage = 0;
bool createNew = ToBool(!fileName || !fileName[0]);
Storage = new TOcStorage(fileName, createNew);
TRACEX(OcfRefCount, 1, "TOcDocument() @" << (void*)this);
}
//
//
//
TOcDocument::TOcDocument(TOcApp& app, LPCTSTR fileName, IStorage * storageI)
:
OcApp(app),
Name(fileName?fileName:_T("")),
PartCollection(),
LinkCollection()
{
// Host support...
//
ActiveView = 0;
PartID = 0;
Storage = 0;
OrgStorage = 0;
if (storageI) // Storage already created by host application
Storage = new TOcStorage(storageI);
else
Storage = 0; // No storage yet, wait until a SetStorage() is called
TRACEX(OcfRefCount, 1, "TOcDocument() @" << (void*)this);
}
//
//
//
TOcDocument::~TOcDocument()
{
delete Storage;
}
//----------------------------------------------------------------------------
//
/// Set the storage for this document
//
void
TOcDocument::SetStorage(IStorage* storage, bool remember)
{
if (Storage && storage == Storage->GetIStorage())
return;
if (remember) {
delete Storage;
OrgStorage = 0;
}
else
OrgStorage = Storage;
if (storage)
Storage = new TOcStorage(storage);
else
Storage = 0;
}
//
/// Set the storage for this document
//
void
TOcDocument::SetStorage(LPCTSTR path)
{
delete Storage;
Storage = new TOcStorage(path, false);
SetName(path); // new Storage now has path as a name
}
//
/// Restore the original root IStorage before the save operation
//
bool
TOcDocument::RestoreStorage()
{
if (OrgStorage) {
delete Storage;
Storage = OrgStorage;
OrgStorage = 0;
}
return true;
}
//
/// Perform saveas operation
//
bool
TOcDocument::SaveToFile(LPCTSTR newName)
{
PRECONDITION(newName);
TOcStorage newStorage(newName, true);
Name = newName;
return SaveParts(newStorage.GetIStorage(), false);
}
//
/// Save the embedded parts to the provided storage. 'remember' flag is not
/// really used here, as our save/restore is done outside here.
//
bool
TOcDocument::SaveParts(IStorage* storage, bool sameAsLoaded, bool remember)
{
if (!Storage)
return true;
TOcStorage* oldStorage = 0;
// If the storage passed is not the same as the one we loaded, wrap the new
// one & use it in here.
//
if (!sameAsLoaded) {
CHECK(storage);
// If we are switching storages, make sure parts all all pulled in now
//
for (TOcPartCollectionIter i(PartCollection); i; i++) {
TOcPart& part = *i.Current();
part.FinishLoading();
}
oldStorage = Storage;
Storage = new TOcStorage(storage);
}
// Create a stream for part information
//
STATSTG statstg;
if (!HRSucceeded(Storage->Stat(&statstg, STATFLAG_NONAME)))
return false;
TOcStream stream(*Storage, DocStreamName, true, statstg.grfMode);
// Write TOcDocument data into stream
//
ulong count;
bool ok;
ulong value = PartCollection.Count();
ok = ToBool(HRSucceeded(stream.Write(&PartID, sizeof PartID, &count)) &&
HRSucceeded(stream.Write(&value, sizeof value, &count)));
if (ok) {
for (TOcPartCollectionIter i(PartCollection); i; i++) {
TOcPart& part = *i.Current();
int16 len = int16(part.GetName().Length());
// Write the part name string, pascal style [len]+chars, no 0
//
ok = ToBool(HRSucceeded(stream.Write(&len, sizeof len, &count)) &&
HRSucceeded(stream.Write((_TCHAR *)part.GetName(), len, &count)) &&
part.Save(sameAsLoaded, remember));
if (!ok)
break;
}
}
// Deal with the alloc'd storage if there was one. Either put things back on
// failure, or keep the new storage around for a while
//
if (!sameAsLoaded) {
if (!ok) {
delete Storage;
Storage = oldStorage;
}
else
delete oldStorage;
}
return ok;
}
//
/// Loads the parts from the current storage into the PartCollection. Return
/// false if a serious error occurs. Having no part stream at all is OK.
//
bool
TOcDocument::LoadParts()
{
if (!Storage)
return true;
/// Clear the part collection
///
/// PartCollection.Clear(); ///DR clear before make a new one.
/// There is a case when clearing now causes a crash
// Open a stream with part information
//
STATSTG statstg;
if (!HRSucceeded(Storage->Stat(&statstg, STATFLAG_NONAME)))
return false;
try {
TOcStream stream(*Storage, DocStreamName, false, statstg.grfMode);
// Read TOcDocument data from stream. Return false if any of the data
// is missing--something must have been corrupted.
//
if (!HRSucceeded(stream.Read(&PartID, sizeof PartID)))
return false;
ulong value;
if (!HRSucceeded(stream.Read(&value, sizeof value)))
return false;
// Clear the part collection
//
PartCollection.Clear();
// Rebuild the part collection
//
for (int i = (int)value; i; i--) {
_TCHAR name[33];
int16 len;
// Read the part name string, pascal style [len]+chars, no 0
//
if (!HRSucceeded(stream.Read(&len, sizeof(len))))
return false;
if (len >= sizeof(name)) {
// NOTE: Should *never* happen!
//
return false;
}
if (!HRSucceeded(stream.Read(name, len)))
return false;
name[len] = 0; // 0 was not written
// !BB Something's wrong here for controls -- can't just create
// !BB a TOcPart for OCXes..
// !BB
new TOcPart(*this, name);
}
}
catch (TXObjComp&) {
// There is no part related info stream. Thats OK, we then have a document
// with no parts
}
return true;
}
//
//
//
void
TOcDocument::RenameParts(IBRootLinkable * bLDocumentI)
{
if (Name.empty())
return; // Temporary file does not have moniker
for (TOcPartCollectionIter i(PartCollection); i; i++) {
TOcPart& part = *i.Current();
IBLinkable * linkI;
if (HRSucceeded(part.QueryInterface(IID_IBLinkable, (LPVOID *)&linkI))) {
linkI->OnRename(bLDocumentI, part.GetName());
linkI->Release();
}
}
}
//
//
//
void
TOcDocument::Close()
{
for (TOcPartCollectionIter i(PartCollection); i; i++) {
TOcPart& part = *i.Current();
part.Close();
}
for (TOcLinkCollectionIter j((TPtrArray<TOcLinkView*>&)LinkCollection); j; j++) {
TOcLinkView& link = *j.Current();
link.Disconnect();
}
LinkCollection.Clear(); // Remove the link views now
}
//
//
//
void
TOcDocument::SetActiveView(TOcView* view)
{
ActiveView = view;
}
//
/// Notify container that doc pathname has changed
//
void
TOcDocument::SetName(const owl::tstring& newName)
{
Name = newName;
// Create a moniker for this document
//
if (!Name.empty() && ActiveView)
ActiveView->Rename();
}
} // OCF namespace
//==============================================================================
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: OrgStorage.
↑ V1004 The 'newName' pointer was used unsafely after it was verified against nullptr. Check lines: 135, 138.
↑ V1048 The 'Storage' variable was assigned the same value.
↑ V565 An empty exception handler. Silent suppression of exceptions can hide the presence of bugs in source code during testing.
↑ V803 Decreased performance. In case 'i' is iterator it's more effective to use prefix form of increment. Replace iterator++ with ++iterator.
↑ V803 Decreased performance. In case 'i' is iterator it's more effective to use prefix form of increment. Replace iterator++ with ++iterator.
↑ V803 Decreased performance. In case 'i' is iterator it's more effective to use prefix form of increment. Replace iterator++ with ++iterator.
↑ V803 Decreased performance. In case 'i' is iterator it's more effective to use prefix form of increment. Replace iterator++ with ++iterator.
↑ V803 Decreased performance. In case 'j' is iterator it's more effective to use prefix form of increment. Replace iterator++ with ++iterator.