- BORLAND/: Borland C++ 4.52 (chosen over 4.5 by byte-match: CODE/RP/CW32.LIB
is identical to 4.52's install lib). BCC32/TLINK32/TLIB/MAKE run natively on
Win11; CODE/BT/OPT.MAK is the shipped BTL4OPT.EXE's exact flag recipe
(extender = Borland PowerPack DPMI32, not Phar Lap TNT).
- restoration/source410/: the literal 1995-form reconstruction of the missing
BT game source (never mixed into CODE/). Round 1-3 state:
* 6 of 10 surviving original TUs COMPILE CLEAN under the period toolchain
(BTMSSN, BTCNSL, BTSCNRL, BTTEAM, BTL4MODE, BTL4ARND) - first builds
since 1996.
* BT_L4/BTL4APP.CPP pilot reconstruction: 12/12 functions, Fail() lands on
its binary-recorded line 400 exactly.
* BT/BTCNSL.HPP: console wire IDs recovered from the binary's ctors
(Killed=9, Damaged=10, ScoreUpdate=13, DeathWithoutHonor=15 [T1];
TeamScore=12 flagged [T4]).
* MUNGA/: 8 engine-header backfills back-dated from the BT412 WinTesla tree
(VDATA numbering decomp-verified; AUDREND's OpenAL-era virtual removed -
the period compiler is the drift detector).
* Tooling: backdate.py (WinTesla->1995 header transform), compile410.sh
(per-TU verification sweep under authentic OPT.MAK flags).
* README: corrected roadmap - MECH.HPP is the capstone grown with the mech
TU reconstructions; BTREG.CPP green = the header-family milestone.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
880 lines
20 KiB
C++
880 lines
20 KiB
C++
//----------------------------------------------------------------------------
|
|
// ObjectWindows
|
|
// (C) Copyright 1993, 1994 by Borland International, All Rights Reserved
|
|
//
|
|
// Implements classes TDocument, TView, TWindowView
|
|
//----------------------------------------------------------------------------
|
|
#pragma hdrignore SECTION
|
|
#include <owl/owlpch.h>
|
|
#include <owl/docmanag.h>
|
|
#include <owl/appdict.h>
|
|
#include <owl/docview.rh>
|
|
#include <string.h>
|
|
|
|
DIAG_DECLARE_GROUP(OwlDocView); // General Doc/View diagnostic group
|
|
|
|
#if !defined(SECTION) || SECTION == 1
|
|
|
|
const uint MinUniqueViewId = 0x8000;
|
|
uint TView::NextViewId = MinUniqueViewId;
|
|
int TDocument::UntitledIndex = 0;
|
|
|
|
//----------------------------------------------------------------------------
|
|
// class TDocument
|
|
//
|
|
|
|
TDocument*
|
|
TDocument::List::Next(const TDocument* doc)
|
|
{
|
|
return doc ? doc->NextDoc : DocList;
|
|
}
|
|
|
|
bool
|
|
TDocument::List::Insert(TDocument* doc)
|
|
{
|
|
TDocument* pdoc;
|
|
for (pdoc = DocList; pdoc; pdoc = pdoc->NextDoc)
|
|
if (pdoc == doc)
|
|
return false;
|
|
doc->NextDoc = DocList;
|
|
DocList = doc;
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
TDocument::List::Remove(TDocument* doc)
|
|
{
|
|
TDocument** ppdoc;
|
|
for (ppdoc = &DocList; *ppdoc; ppdoc = &(*ppdoc)->NextDoc) {
|
|
if (*ppdoc == doc) {
|
|
*ppdoc = doc->NextDoc;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void
|
|
TDocument::List::Destroy()
|
|
{
|
|
while (DocList)
|
|
delete DocList; // removes it entry from destructor
|
|
}
|
|
|
|
TDocument::TDocument(TDocument* parent)
|
|
:
|
|
ParentDoc(parent), NextDoc(0), OpenMode(0),
|
|
Title(0), Template(0), ViewList(0), Tag(0), StreamList(0),
|
|
DocPath(0), DirtyFlag(false), Embedded(false)
|
|
{
|
|
if (parent) {
|
|
DocManager = parent->DocManager;
|
|
if (parent->ParentDoc == parent) {// a dummy parent
|
|
ParentDoc = 0;
|
|
DocManager->DocList.Insert(this);
|
|
}
|
|
else
|
|
parent->ChildDoc.Insert(this);
|
|
}
|
|
else {
|
|
TApplication* app = GetApplicationObject();
|
|
if ((DocManager = app->DocManager) == 0)
|
|
THROW( TXOwl(IDS_NODOCMANAGER) ); // no doc manager to catch this one
|
|
DocManager->DocList.Insert(this);
|
|
}
|
|
}
|
|
|
|
TDocument::~TDocument()
|
|
{
|
|
if (ParentDoc == this) // a dummy doc
|
|
return;
|
|
|
|
ChildDoc.Destroy(); // destroy children first, otherwise unnecessary
|
|
Close(); // force close (not virtual at this point!)
|
|
|
|
// delete all attached views, data has already been flushed
|
|
//
|
|
SetTemplate(0); // unref tpl, prevent self autodelete when deleting views
|
|
while (ViewList)
|
|
delete ViewList; // ~View() calls DetachView, which removes it from list
|
|
|
|
// delete all streams, should only be present if abort or coding error
|
|
//
|
|
while (StreamList)
|
|
delete StreamList;
|
|
|
|
// detach from parent and doc manager
|
|
//
|
|
if (ParentDoc) {
|
|
ParentDoc->ChildDoc.Remove(this);
|
|
}
|
|
else {
|
|
DocManager->PostEvent(dnClose, *this);
|
|
DocManager->DocList.Remove(this);
|
|
}
|
|
|
|
delete [] Title;
|
|
delete [] DocPath;
|
|
}
|
|
|
|
static char* PropNames[] = {
|
|
"Document Class", // DocumentClass
|
|
"Template Name", // TemplateName
|
|
"View Count", // ViewCount
|
|
"Storage Path", // StoragePath
|
|
"Document Title", // DocTitle
|
|
};
|
|
|
|
static int PropFlags[] = {
|
|
pfGetText|pfConstant, // DocumentClass
|
|
pfGetText, // TemplateName
|
|
pfGetBinary|pfGetText, // ViewCount
|
|
pfGetText|pfSettable, // StoragePath
|
|
pfGetText|pfSettable, // DocTitle
|
|
};
|
|
|
|
const char*
|
|
TDocument::PropertyName(int index)
|
|
{
|
|
if (index <= PrevProperty)
|
|
return 0;
|
|
else if (index < NextProperty)
|
|
return PropNames[index-PrevProperty-1];
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
TDocument::PropertyFlags(int index)
|
|
{
|
|
if (index <= PrevProperty)
|
|
return 0;
|
|
else if (index < NextProperty)
|
|
return PropFlags[index-PrevProperty-1];
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
TDocument::FindProperty(const char far* name)
|
|
{
|
|
int i;
|
|
for (i=0; i < NextProperty-PrevProperty-1; i++)
|
|
if (strcmp(PropNames[i], name) == 0)
|
|
return i+PrevProperty+1;
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
TDocument::GetProperty(int prop, void far* dest, int textlen)
|
|
{
|
|
const char far* src;
|
|
char numBuf[6];
|
|
switch (prop) {
|
|
case DocumentClass:
|
|
src = _TYPENAME(this);
|
|
break;
|
|
case TemplateName:
|
|
src = Template ? Template->GetDescription() : 0;
|
|
break;
|
|
case ViewCount: {
|
|
int cnt;
|
|
TView* view;
|
|
for (view=ViewList, cnt=0; view != 0; view=view->NextView, cnt++) ;
|
|
if (!textlen) {
|
|
*(int far*)dest = cnt;
|
|
return sizeof(int);
|
|
}
|
|
wsprintf(numBuf, "%d", cnt);
|
|
src = numBuf;
|
|
break;
|
|
}
|
|
case StoragePath:
|
|
src = DocPath;
|
|
break;
|
|
case DocTitle:
|
|
src = Title;
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
if (!textlen)
|
|
return 0;
|
|
int srclen = src ? strlen(src) : 0;
|
|
if (textlen > srclen)
|
|
textlen = srclen;
|
|
if (textlen)
|
|
memcpy(dest, src, textlen);
|
|
*((char far*)dest + textlen) = 0;
|
|
return srclen;
|
|
}
|
|
|
|
bool
|
|
TDocument::SetProperty(int prop, const void far* src)
|
|
{
|
|
switch (prop) {
|
|
case DocTitle:
|
|
SetTitle((const char far*)src);
|
|
break;
|
|
case StoragePath:
|
|
return SetDocPath((const char far*)src);
|
|
default:
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
TDocument&
|
|
TDocument::RootDocument()
|
|
{
|
|
TDocument* pdoc = this;
|
|
while (pdoc->ParentDoc)
|
|
pdoc = pdoc->ParentDoc;
|
|
return *pdoc;
|
|
}
|
|
|
|
void
|
|
TDocument::SetDocManager(TDocManager& dm)
|
|
{
|
|
if (!ParentDoc) {
|
|
if (DocManager) // test needed for TDocManager::Streamer::Read()
|
|
DocManager->DocList.Remove(this);
|
|
dm.DocList.Insert(this);
|
|
}
|
|
DocManager = &dm;
|
|
}
|
|
|
|
bool
|
|
TDocument::SetDocPath(const char far* path)
|
|
{
|
|
// path has been set already
|
|
//
|
|
if (path && (path == DocPath))
|
|
return true;
|
|
|
|
delete DocPath;
|
|
DocPath = (path && *path) ? strnewdup(path) : 0;
|
|
|
|
char title[256];
|
|
if (!DocPath || ::GetFileTitle(DocPath, title, sizeof title) != 0) {
|
|
int len = DocManager->Application->LoadString(IDS_UNTITLED, title, sizeof title);
|
|
if (DocManager->IsFlagSet(dmMDI))
|
|
wsprintf(title+len, "%d", ++UntitledIndex);
|
|
}
|
|
SetTitle(title);
|
|
return true; // derived classes may validate path
|
|
}
|
|
|
|
void
|
|
TDocument::SetTitle(const char far* title)
|
|
{
|
|
delete Title;
|
|
Title = title ? strnewdup(title) : 0;
|
|
ReindexFrames();
|
|
}
|
|
|
|
bool
|
|
TDocument::SetTemplate(TDocTemplate* tpl)
|
|
{
|
|
if (Template)
|
|
DocManager->UnRefTemplate(*Template);
|
|
if (tpl)
|
|
DocManager->RefTemplate(*tpl);
|
|
Template = tpl;
|
|
return true;
|
|
}
|
|
|
|
void
|
|
TDocument::ReindexFrames()
|
|
{
|
|
TView* view;
|
|
int seq;
|
|
|
|
for (seq = -1, view = ViewList; view != 0; view = view->NextView) {
|
|
seq -= view->SetDocTitle(Title, seq); // decrement if title displayed
|
|
if (seq == -3) // need only check if more than one title displayed
|
|
break;
|
|
}
|
|
if (seq == -1)
|
|
return;
|
|
seq = (seq == -2 ? 0 : 1);
|
|
for (view = ViewList; view != 0; view = view->NextView) {
|
|
seq += view->SetDocTitle(Title, seq); // increment if title displayed
|
|
}
|
|
}
|
|
|
|
void
|
|
TDocument::AttachStream(TStream& strm)
|
|
{
|
|
strm.NextStream = StreamList;
|
|
StreamList = &strm;
|
|
}
|
|
|
|
void
|
|
TDocument::DetachStream(TStream& strm)
|
|
{
|
|
TStream** plist = &StreamList;
|
|
for ( ; *plist; plist = &(*plist)->NextStream) {
|
|
if (*plist == &strm) {
|
|
*plist = strm.NextStream;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
TStream*
|
|
TDocument::NextStream(const TStream* strm)
|
|
{
|
|
return strm ? strm->NextStream : StreamList;
|
|
}
|
|
|
|
TView*
|
|
TDocument::NextView(const TView* view)
|
|
{
|
|
return view ? view->NextView : ViewList;
|
|
}
|
|
|
|
void
|
|
TDocument::AttachView(TView& view)
|
|
{
|
|
TView** ppview;
|
|
|
|
for (ppview = &ViewList; *ppview; ppview = &(*ppview)->NextView)
|
|
;
|
|
*ppview = &view; // insert at end of list
|
|
view.NextView = 0;
|
|
view.Doc = this;
|
|
NotifyViews(vnViewOpened, (long)&view, &view);
|
|
}
|
|
|
|
TView*
|
|
TDocument::InitView(TView* view)
|
|
{
|
|
if (!view) // test if new TView failed
|
|
return 0;
|
|
if (!view->IsOK()) { // test if constructor failed
|
|
delete view;
|
|
return 0;
|
|
}
|
|
DocManager->PostEvent(dnCreate, *view);
|
|
if (!view->IsOK()) { // if failed in creation
|
|
delete view;
|
|
return 0;
|
|
}
|
|
ReindexFrames();
|
|
if (++TView::NextViewId < MinUniqueViewId)
|
|
TView::NextViewId = MinUniqueViewId;
|
|
return view;
|
|
}
|
|
|
|
bool
|
|
TDocument::DetachView(TView& view)
|
|
{
|
|
TView** plist = &ViewList;
|
|
for (; *plist; plist = &(*plist)->NextView) {
|
|
if (*plist == &view) {
|
|
DocManager->PostEvent(dnClose, view);
|
|
*plist = view.NextView;
|
|
NotifyViews(vnViewClosed, (long)&view, &view);
|
|
if (!ViewList) { // all views for this doc are now gone
|
|
if (Template && (Template->Flags & dtAutoDelete)) {
|
|
if (IsOpen())
|
|
Close(); // close the document streams
|
|
return view.IsOK(); // delete doc UNLESS failure in creation
|
|
}
|
|
}
|
|
else {
|
|
ReindexFrames();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
TDocument::Commit(bool force)
|
|
{
|
|
TDocument* pdoc = 0;
|
|
while ((pdoc = ChildDoc.Next(pdoc)) != 0) {
|
|
if (!pdoc->Commit(force))
|
|
return false;
|
|
}
|
|
|
|
// should we test here for DocPath==0 , or should caller have checked?
|
|
//
|
|
return NotifyViews(vnCommit, force);
|
|
}
|
|
|
|
bool
|
|
TDocument::Revert(bool clear)
|
|
{
|
|
TDocument* pdoc = 0;
|
|
while ((pdoc = ChildDoc.Next(pdoc)) != 0) {
|
|
if (!pdoc->Revert(clear))
|
|
return false;
|
|
}
|
|
return NotifyViews(vnRevert, clear);
|
|
}
|
|
|
|
bool
|
|
TDocument::NotifyViews(int event, long item, TView* exclude)
|
|
{
|
|
bool answer = true;
|
|
TEventHandler::TEventInfo eventInfo(WM_OWLNOTIFY, event);
|
|
|
|
TDocument* pdoc = 0;
|
|
while ((pdoc = ChildDoc.Next(pdoc)) != 0)
|
|
answer = ToBool(answer && pdoc->NotifyViews(event, item, exclude));
|
|
|
|
for (TView* view = ViewList; view != 0; view = view->NextView)
|
|
if (view != exclude && view->Find(eventInfo))
|
|
answer = ToBool(answer && view->Dispatch(eventInfo, 0, item));
|
|
return answer;
|
|
}
|
|
|
|
TView*
|
|
TDocument::QueryViews(int event, long item, TView* exclude)
|
|
{
|
|
TView* view;
|
|
TDocument* pdoc = 0;
|
|
while ((pdoc = ChildDoc.Next(pdoc)) != 0)
|
|
if ((view = pdoc->QueryViews(event, item, exclude)) != 0)
|
|
return view;
|
|
|
|
TEventHandler::TEventInfo eventInfo(WM_OWLNOTIFY, event);
|
|
for (view = ViewList; view != 0; view = view->NextView)
|
|
if (view != exclude && view->Find(eventInfo)
|
|
&& view->Dispatch(eventInfo, 0, item))
|
|
return view; // return first acknowledger
|
|
|
|
return 0; // if no takers
|
|
}
|
|
|
|
bool
|
|
TDocument::IsDirty()
|
|
{
|
|
if (DirtyFlag)
|
|
return true;
|
|
|
|
TDocument* pdoc = 0;
|
|
while ((pdoc = ChildDoc.Next(pdoc)) != 0)
|
|
if (pdoc->IsDirty())
|
|
return true;
|
|
|
|
return QueryViews(vnIsDirty) != 0;
|
|
}
|
|
|
|
bool
|
|
TDocument::HasFocus(HWND hwnd)
|
|
{
|
|
TDocument* pdoc = 0;
|
|
while ((pdoc = ChildDoc.Next(pdoc)) != 0)
|
|
if (pdoc->HasFocus(hwnd))
|
|
return true;
|
|
|
|
return QueryViews(vnIsWindow, (long)hwnd) != 0;
|
|
}
|
|
|
|
bool
|
|
TDocument::CanClose()
|
|
{
|
|
TDocument* pdoc = 0;
|
|
while ((pdoc = ChildDoc.Next(pdoc)) != 0)
|
|
if (!pdoc->CanClose())
|
|
return false;
|
|
|
|
return DocManager->FlushDoc(*this); // do the UI in the doc manager
|
|
}
|
|
|
|
bool
|
|
TDocument::Close()
|
|
{
|
|
TDocument* pdoc = 0;
|
|
while ((pdoc = ChildDoc.Next(pdoc)) != 0)
|
|
if (!pdoc->Close())
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
uint
|
|
TDocument::PostError(uint sid, uint choice)
|
|
{
|
|
return DocManager->PostDocError(*this, sid, choice);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// class TView
|
|
//
|
|
|
|
TView::TView(TDocument& doc)
|
|
:
|
|
Tag(0), ViewMenu(0)
|
|
{
|
|
ViewId = NextViewId;
|
|
doc.AttachView(*this);
|
|
}
|
|
|
|
TView::~TView()
|
|
{
|
|
delete ViewMenu;
|
|
if (Doc->DetachView(*this)) {
|
|
delete Doc;
|
|
}
|
|
}
|
|
|
|
void
|
|
TView::SetViewMenu(TMenuDescr* menu)
|
|
{
|
|
delete ViewMenu;
|
|
ViewMenu = menu;
|
|
TDocTemplate* tpl = Doc->GetTemplate();
|
|
if (tpl && ViewMenu && *ViewMenu->GetModule() == *tpl->GetModule())
|
|
ViewMenu->SetModule(tpl->GetModule());// force same module alias as template
|
|
}
|
|
|
|
static char* TView_PropertyNames[] = {
|
|
"View Class", // ViewClass
|
|
"View Name", // ViewName
|
|
};
|
|
|
|
static int TView_PropertyFlags[] = {
|
|
pfGetText|pfConstant, // ViewClass
|
|
pfGetText|pfConstant, // ViewName
|
|
};
|
|
|
|
const char*
|
|
TView::PropertyName(int index)
|
|
{
|
|
if (index <= PrevProperty)
|
|
return 0;
|
|
else if (index < NextProperty)
|
|
return TView_PropertyNames[index-PrevProperty-1];
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
TView::PropertyFlags(int index)
|
|
{
|
|
if (index <= PrevProperty)
|
|
return 0;
|
|
else if (index < NextProperty)
|
|
return TView_PropertyFlags[index-PrevProperty-1];
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
TView::FindProperty(const char far* name)
|
|
{
|
|
int i;
|
|
for (i=0; i < NextProperty-PrevProperty-1; i++)
|
|
if (strcmp(TView_PropertyNames[i], name) == 0)
|
|
return i+PrevProperty+1;
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
TView::GetProperty(int prop, void far* dest, int textlen)
|
|
{
|
|
const char far* src;
|
|
switch (prop) {
|
|
case ViewClass:
|
|
src = _TYPENAME(this);
|
|
break;
|
|
case ViewName:
|
|
src = GetViewName();
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
if (!textlen)
|
|
return 0;
|
|
int srclen = src ? strlen(src) : 0;
|
|
if (textlen > srclen)
|
|
textlen = srclen;
|
|
if (textlen)
|
|
memcpy(dest, src, textlen);
|
|
*((char far*)dest + textlen) = 0;
|
|
return srclen;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// class TWindowView
|
|
//
|
|
|
|
DEFINE_RESPONSE_TABLE1(TWindowView, TWindow)
|
|
EV_VN_ISWINDOW,
|
|
END_RESPONSE_TABLE;
|
|
|
|
TWindowView::TWindowView(TDocument& doc, TWindow* parent)
|
|
: TView(doc), TWindow(parent, 0, doc.GetDocManager().GetApplication())
|
|
{
|
|
}
|
|
|
|
//
|
|
// Does a given HWND belong to this view? Yes if it is us, or a child of us
|
|
//
|
|
bool
|
|
TWindowView::VnIsWindow(HWND hWnd)
|
|
{
|
|
return hWnd == HWindow || IsChild(hWnd);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// class TDateTime (eventually)
|
|
//
|
|
|
|
int _OWLFUNC FormatFileTime(FILETIME* pft, void far* dest, int textlen)
|
|
{
|
|
char buf[40];
|
|
int len;
|
|
|
|
if (!textlen) {
|
|
*(FILETIME FAR*)dest = *pft;
|
|
return sizeof(FILETIME);
|
|
}
|
|
#if defined(BI_PLAT_WIN32)
|
|
SYSTEMTIME dt;
|
|
FileTimeToSystemTime(pft, &dt);
|
|
len = wsprintf(buf,"%d/%d/%d %02d:%02d:%02d.%02d",
|
|
dt.wMonth, dt.wDay, dt.wYear,
|
|
dt.wHour, dt.wMinute, dt.wSecond, dt.wMilliseconds/10);
|
|
#else
|
|
struct time filet;
|
|
struct date filed;
|
|
if (!(FileTimeToDateTime(pft, &filed, &filet)))
|
|
return false;
|
|
len = wsprintf(buf,"%d/%d/%d %02d:%02d:%02d.%02d",
|
|
filed.da_mon,filed.da_day,filed.da_year,
|
|
filet.ti_hour,filet.ti_min,filet.ti_sec,filet.ti_hund);
|
|
#endif
|
|
if (textlen > len)
|
|
textlen = len;
|
|
memcpy(dest, buf, textlen);
|
|
*((char far*)dest + textlen) = 0;
|
|
return len;
|
|
}
|
|
|
|
#if !defined(BI_PLAT_WIN32)
|
|
//
|
|
// Win32/OLE2 compatible FILETIME support for 16-bit applications
|
|
// these functions to be incorporated into TDateTime class
|
|
//
|
|
|
|
int FormatDateTime(struct date filed, struct time filet, void far* dest, int textlen)
|
|
{
|
|
char buf[40];
|
|
if (!textlen) {
|
|
DateTimeToFileTime(&filed, &filet, (FILETIME FAR*)dest);
|
|
return sizeof(FILETIME);
|
|
}
|
|
int len = wsprintf(buf,"%d/%d/%d %02d:%02d:%02d.%02d",
|
|
filed.da_mon,filed.da_day,filed.da_year,
|
|
filet.ti_hour,filet.ti_min,filet.ti_sec,filet.ti_hund);
|
|
if (textlen > len)
|
|
textlen = len;
|
|
memcpy(dest, buf, textlen);
|
|
*((char far*)dest + textlen) = 0;
|
|
return len;
|
|
}
|
|
|
|
// Convert date and time structures to 64-bit FILETIME structure
|
|
// multiply seconds by 10^7 and adjust offset to Jan. 1, 1601
|
|
// adjustment from Jan.1, 1970 = 116,444,736,000,000,000 = 0x019DB1DED53E8000
|
|
// This code is for Win32 and OLE2 compatibility when using Win16
|
|
|
|
#include <dos.h>
|
|
|
|
void DateTimeToFileTime(struct date* dosd, struct time* dost, FILETIME FAR* pft)
|
|
{
|
|
union {
|
|
long udt;
|
|
int w[2];
|
|
} u;
|
|
u.udt = dostounix(dosd, dost);
|
|
_BL = dost->ti_hund;
|
|
_AX = u.w[0];
|
|
_CX = u.w[1];
|
|
asm mov di,200
|
|
asm mul di
|
|
asm mov bh,0
|
|
asm add bx,bx
|
|
asm add ax,bx
|
|
asm adc dl,dh
|
|
asm xchg ax,cx
|
|
asm mov bx,dx
|
|
asm mul di
|
|
asm add bx,ax
|
|
asm mov si,0
|
|
asm adc si,dx
|
|
asm les di,pft
|
|
asm mov ax,50000
|
|
asm xchg ax,cx
|
|
asm mul cx
|
|
asm add ax,0x8000
|
|
asm adc dx,0
|
|
asm mov es:[di],ax
|
|
asm xchg ax,dx
|
|
asm xchg ax,bx
|
|
asm mul cx
|
|
asm add ax,bx
|
|
asm adc dx,0
|
|
asm add ax,0xD53E
|
|
asm adc dx,0
|
|
asm mov es:[di+2],ax
|
|
asm xchg ax,dx
|
|
asm xchg ax,si
|
|
asm mul cx
|
|
asm add ax,si
|
|
asm adc dx,0
|
|
asm add ax,0xB1DE
|
|
asm adc dx,0x019D
|
|
asm mov es:[di+4],ax
|
|
asm mov es:[di+6],dx
|
|
}
|
|
|
|
|
|
//
|
|
// Convert FILETIME structure to date and time structures
|
|
//
|
|
|
|
bool FileTimeToDateTime(FILETIME FAR* pft, struct date* dosd, struct time* dost)
|
|
{
|
|
union {
|
|
long udt;
|
|
int w[2];
|
|
} u;
|
|
asm les di,pft
|
|
asm mov dx,es:[di+6]
|
|
asm mov ax,es:[di+4]
|
|
asm sub ax,0xB1DE
|
|
asm sbb dx,0x019D
|
|
asm jnc OK
|
|
return false;
|
|
OK:
|
|
asm mov cx,50000
|
|
asm div cx
|
|
asm xchg bx,ax
|
|
asm mov ax,es:[di+2]
|
|
asm sub ax,0xD53E
|
|
asm sbb dx,0
|
|
asm div cx
|
|
asm xchg si,ax
|
|
asm mov ax,es:[di]
|
|
asm sub ax,(0x8000-5000)
|
|
asm sbb dx,0
|
|
asm div cx
|
|
asm mov dx,bx
|
|
asm xchg ax,si
|
|
asm mov cx,200
|
|
asm div cx
|
|
asm xchg ax,si
|
|
asm div cx
|
|
asm shr dx,1
|
|
asm push dx
|
|
u.w[0] = _AX;
|
|
u.w[1] = _SI;
|
|
unixtodos(u.udt, dosd, dost);
|
|
asm pop ax
|
|
dost->ti_hund = _AL;
|
|
return true;
|
|
}
|
|
#endif // !defined(BI_PLAT_WIN32)
|
|
|
|
#endif
|
|
//----------------------------------------------------------------------------
|
|
#if !defined(SECTION) || SECTION == 2
|
|
|
|
IMPLEMENT_ABSTRACT_STREAMABLE(TView);
|
|
|
|
void*
|
|
TView::Streamer::Read(ipstream& is, uint32 /*version*/) const
|
|
{
|
|
TView* o = GetObject();
|
|
bool hasViewMenu = is.readByte();
|
|
if (hasViewMenu) {
|
|
o->ViewMenu = new TMenuDescr;
|
|
is >> *o->ViewMenu;
|
|
}
|
|
else
|
|
o->ViewMenu = 0;
|
|
is >> o->ViewId;
|
|
is >> o->Doc;
|
|
is >> o->NextView;
|
|
return o;
|
|
}
|
|
|
|
void
|
|
TView::Streamer::Write(opstream& os) const
|
|
{
|
|
TView* o = GetObject();
|
|
os.writeByte(int16(o->ViewMenu ? 1 : 0));
|
|
if (o->ViewMenu)
|
|
os << *o->ViewMenu;
|
|
os << o->ViewId;
|
|
os << o->Doc;
|
|
os << o->NextView;
|
|
}
|
|
|
|
|
|
IMPLEMENT_ABSTRACT_STREAMABLE(TDocument);
|
|
|
|
void*
|
|
TDocument::Streamer::Read(ipstream& is, uint32 /*version*/) const
|
|
{
|
|
TDocument* o = GetObject();
|
|
|
|
o->NextDoc = 0;
|
|
o->StreamList = 0;
|
|
o->DocManager = 0;
|
|
o->DirtyFlag = false;
|
|
|
|
is >> o->OpenMode;
|
|
o->DocPath = is.freadString();
|
|
o->Title = is.freadString();
|
|
is >> o->Template; // static templates must have been already streamed
|
|
is >> o->ParentDoc;
|
|
o->ViewList = 0; // must init, does not get set until after view streamed
|
|
is >> o->ViewList;
|
|
is >> TView::NextViewId; // static, but must get set by at least 1 document
|
|
|
|
return o;
|
|
}
|
|
|
|
void
|
|
TDocument::Streamer::Write(opstream& os) const
|
|
{
|
|
TDocument* o = GetObject();
|
|
|
|
while (!o->CanClose()) // can't permit cancel here
|
|
;
|
|
os << o->OpenMode;
|
|
os.fwriteString(o->DocPath);
|
|
os.fwriteString(o->Title);
|
|
os << o->Template; // templates already streamed, must be so if static
|
|
os << o->ParentDoc;
|
|
os << o->ViewList; // each view streams out the next
|
|
os << TView::NextViewId; // insure that this static var gets set on reload
|
|
}
|
|
|
|
IMPLEMENT_STREAMABLE2(TWindowView, TWindow, TView);
|
|
void*
|
|
TWindowView::Streamer::Read(ipstream& is, uint32 /*version*/) const
|
|
{
|
|
ReadBaseObject((TWindow*)GetObject(), is);
|
|
ReadBaseObject((TView*)GetObject(), is);
|
|
return GetObject();
|
|
}
|
|
|
|
void
|
|
TWindowView::Streamer::Write(opstream& os) const
|
|
{
|
|
WriteBaseObject((TWindow*)GetObject(), os);
|
|
WriteBaseObject((TView*)GetObject(), os);
|
|
}
|
|
|
|
#endif
|