зеркало из https://github.com/mozilla/gecko-dev.git
266 строки
8.1 KiB
C++
266 строки
8.1 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
|
|
/*======================================================================================
|
|
AUTHOR: Ted Morris <tmorris@netscape.com> - 12 DEC 96
|
|
|
|
MODIFICATIONS:
|
|
|
|
Date Person Description
|
|
---- ------ -----------
|
|
======================================================================================*/
|
|
|
|
|
|
/*====================================================================================*/
|
|
#pragma mark INCLUDE FILES
|
|
/*====================================================================================*/
|
|
|
|
#include "URobustCreateWindow.h"
|
|
|
|
#include <LWindow.h>
|
|
#include <LCommander.h>
|
|
#include <LControl.h>
|
|
#include <LDataStream.h>
|
|
#include <LString.h>
|
|
#include <UMemoryMgr.h>
|
|
|
|
#include "fredmem.h"
|
|
|
|
// Necessary stuff from <UReanimator.cp>
|
|
|
|
typedef Int32 TagID;
|
|
|
|
enum {
|
|
tag_ObjectData = 'objd',
|
|
tag_BeginSubs = 'begs',
|
|
tag_EndSubs = 'ends',
|
|
tag_Include = 'incl',
|
|
tag_UserObject = 'user',
|
|
tag_ClassAlias = 'dopl',
|
|
tag_Comment = 'comm',
|
|
tag_End = 'end.',
|
|
|
|
object_Null = 'null'
|
|
};
|
|
|
|
#pragma options align=mac68k
|
|
|
|
typedef struct {
|
|
Int16 numberOfItems;
|
|
PaneIDT itemID[1];
|
|
} SResList, *SResListP;
|
|
|
|
#pragma options align=reset
|
|
|
|
|
|
#pragma mark -
|
|
/*====================================================================================*/
|
|
#pragma mark CLASS IMPLEMENTATIONS
|
|
/*====================================================================================*/
|
|
|
|
#pragma mark -
|
|
/*======================================================================================
|
|
Return a newly created Window object initialized from a PPob resource. Raise an
|
|
exception if the window cannot be created. If no exception is raised, this method
|
|
will ALWAYS return a valid LWindow object.
|
|
======================================================================================*/
|
|
|
|
LWindow *URobustCreateWindow::CreateWindow(ResIDT inWindowID, LCommander *inSuperCommander)
|
|
{
|
|
ThrowIf_(Memory_MemoryIsLow());
|
|
LCommander::SetDefaultCommander(inSuperCommander);
|
|
LAttachable::SetDefaultAttachable(nil);
|
|
LWindow *theWindow = nil;
|
|
OSErr error = noErr;
|
|
|
|
URobustCreateWindow::ReadObjects('PPob', inWindowID, &theWindow, &error);
|
|
ThrowIfOSErr_(error); // theWindow not valid yet, don't bother trying to delete it.
|
|
|
|
theWindow->FinishCreate();
|
|
if ( theWindow->HasAttribute(windAttr_ShowNew) )
|
|
theWindow->Show();
|
|
|
|
return theWindow;
|
|
}
|
|
|
|
|
|
/*======================================================================================
|
|
Much more robust object creation. Create new objects from the data resource.
|
|
Return a pointer to the first object created, or nil if no objects were created.
|
|
If a non-nil value is returned, check the outErr value to see if the object
|
|
is valid (i.e. no exceptions were thrown during creation); if outErr returns something
|
|
other than noErr, the object is invalid (which means don't try to delete it).
|
|
======================================================================================*/
|
|
|
|
void URobustCreateWindow::ReadObjects(OSType inResType, ResIDT inResID, void **outFirstObject,
|
|
OSErr *outErr) {
|
|
|
|
*outFirstObject = nil;
|
|
*outErr = noErr;
|
|
|
|
Try_ {
|
|
StResource objectRes(inResType, inResID);
|
|
::HLockHi(objectRes.mResourceH);
|
|
|
|
LDataStream objectStream(*objectRes.mResourceH, ::GetHandleSize(objectRes.mResourceH));
|
|
|
|
Int16 ppobVersion;
|
|
objectStream.ReadData(&ppobVersion, sizeof(Int16));
|
|
|
|
ThrowIf_(ppobVersion != 2);
|
|
|
|
URobustCreateWindow::ObjectsFromStream(&objectStream, outFirstObject);
|
|
}
|
|
Catch_(inErr) {
|
|
*outErr = inErr;
|
|
// No throw, catch the exception and return error
|
|
}
|
|
EndCatch_
|
|
}
|
|
|
|
|
|
/*======================================================================================
|
|
Same as the UReanimator::ObjectsFromStream(), but returns the first object, if it
|
|
is created.
|
|
======================================================================================*/
|
|
|
|
void *URobustCreateWindow::ObjectsFromStream(LStream *inStream, void **outFirstObject) {
|
|
|
|
void *firstObject = nil;
|
|
ClassIDT aliasClassID = 'null';
|
|
|
|
// Save current defaults
|
|
LCommander *defaultCommander = LCommander::GetDefaultCommander();
|
|
LView *defaultView = LPane::GetDefaultView();
|
|
|
|
Boolean readingTags = true;
|
|
do {
|
|
void *currentObject = nil; // Object created by current tag
|
|
TagID theTag = tag_End;
|
|
inStream->ReadData(&theTag, sizeof(TagID));
|
|
|
|
switch (theTag) {
|
|
|
|
case tag_ObjectData: {
|
|
// Restore default Commander and View
|
|
LCommander::SetDefaultCommander(defaultCommander);
|
|
LPane::SetDefaultView(defaultView);
|
|
|
|
// Object data consists of a byte length, class ID,
|
|
// and then the data for the object. We use the
|
|
// byte length to manually set the stream marker
|
|
// after creating the object just in case the
|
|
// object constructor doesn't read all the data.
|
|
|
|
Int32 dataLength;
|
|
inStream->ReadData(&dataLength, sizeof(Int32));
|
|
Int32 dataStart = inStream->GetMarker();
|
|
ClassIDT classID;
|
|
inStream->ReadData(&classID, sizeof(ClassIDT));
|
|
|
|
if (aliasClassID != 'null') {
|
|
// The previous tag specified an Alias for
|
|
// the ID of this Class
|
|
classID = aliasClassID;
|
|
}
|
|
|
|
currentObject = URegistrar::CreateObject(classID, inStream);
|
|
inStream->SetMarker(dataStart + dataLength, streamFrom_Start);
|
|
|
|
aliasClassID = 'null'; // Alias is no longer in effect
|
|
|
|
#ifdef Debug_Signal
|
|
if (currentObject == nil && classID != 'null') {
|
|
LStr255 msg("\pUnregistered ClassID: ");
|
|
msg.Append(&classID, sizeof(classID));
|
|
SignalPStr_(msg);
|
|
}
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
case tag_BeginSubs:
|
|
currentObject = URobustCreateWindow::ObjectsFromStream(inStream, outFirstObject);
|
|
break;
|
|
|
|
case tag_EndSubs:
|
|
case tag_End:
|
|
readingTags = false;
|
|
break;
|
|
|
|
case tag_UserObject: {
|
|
|
|
// The UserObject tag is only needed for the Constructor
|
|
// view editing program. It tells Constructor to treat
|
|
// the following object as if it were an object of the
|
|
// specified superclass (which must be a PowerPlant
|
|
// class that Constructor knows about). We don't need
|
|
// this information here, so we just read and ignore
|
|
// the superclass ID.
|
|
|
|
ClassIDT superClassID;
|
|
inStream->ReadData(&superClassID, sizeof(ClassIDT));
|
|
break;
|
|
}
|
|
|
|
case tag_ClassAlias:
|
|
|
|
// The ClassAlias tag defines the ClassID the for
|
|
// the next object in the Stream. This allows you
|
|
// to define an object which belongs to a subclass
|
|
// of another class, but has the same data as that
|
|
// other class.
|
|
|
|
inStream->ReadData(&aliasClassID, sizeof(ClassIDT));
|
|
break;
|
|
|
|
case tag_Comment: {
|
|
|
|
// The Comment tag denotes data used by PPob editors
|
|
// that PowerPlant ignores. Format is a long word
|
|
// byte count followed by arbitrary hex data.
|
|
|
|
Int32 commentLength;
|
|
inStream->ReadData(&commentLength, sizeof(commentLength));
|
|
inStream->SetMarker(commentLength, streamFrom_Marker);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
SignalPStr_("\pUnrecognized Tag");
|
|
readingTags = false;
|
|
break;
|
|
}
|
|
|
|
if (firstObject == nil) {
|
|
firstObject = currentObject;
|
|
if ( *outFirstObject == nil ) { // This if statement if the only modified code in
|
|
// this method from the UReanimator::ObjectsFromStream()
|
|
// method.
|
|
*outFirstObject = firstObject; // Store the first created object in case an
|
|
// exception is thrown
|
|
}
|
|
}
|
|
|
|
} while (readingTags);
|
|
|
|
return firstObject;
|
|
}
|
|
|
|
|