mac-rom/Toolbox/DataPubsMgr/dpSectionIO.inc.p
Elliot Nunn 4325cdcc78 Bring in CubeE sources
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included.

The Tools directory, containing mostly junk, is also excluded.
2017-12-26 09:52:23 +08:00

583 lines
18 KiB
OpenEdge ABL

{
File: dpSectionIO.inc.p
Written by: Nick Kledzik
Copyright: © 1989-1990 by Apple Computer, Inc., all rights reserved.
This file is used in these builds: BigBang
Change History (most recent first):
<13> 12/14/90 ngk <RC>Use new PBxxSync calls. Stop subscribers from writing.
<12> 7/30/90 ngk fix zero length read of zero length buffer.
<11> 7/6/90 ngk Fixed bug in dp_ReadOrWrite, where current mark not being
updated.
<10> 7/2/90 ngk Fixed dpStandardReadFormat to return buffLen=0 if nothing read
and return eofErr if trying to read from end of format.
<9> 5/31/90 ngk Check for valid mark in ReadEdition. Combine ReadEdition and
WriteEdition into one routine. Set default mark to be 0 instead
of -1. Combine Add and FindFormat into GetFormat. Using more
WITH's more code savings.
<8> 4/7/90 ngk Make number of formats growable. Use dynamic arrays for
SIOCBRecord, format list, and allocation map. Use new failure
handling.
<7> 3/10/90 ngk Moved locking and unlocking of package to dispatcher.
<6> 2/4/90 ngk Fix dpStandardReadFormat to correctly reading 'fmts' and return
length read for all formats.
<5> 1/12/90 ngk Fixed bug where mark not being set first time
<4> 1/8/90 ngk add fmts
<2+> 1/7/90 ngk special 'fmts' in dpStandardLookUpFormat and dpStandardReadFormat
<2> 1/6/90 ngk Converted to BBS. Added FormatIO bottle necks. Moved StandardIO
routines into this file.
<1.6> 11/13/89 ngk Added Locking and restoring of Pack11 in all public routines
<1.5> 10/2/89 ngk Updated to new API
<1.4> 8/29/89 ngk Renamed XetEditionPos to XetEditionMark. Used new IO stategy.
<1.3> 8/8/89 ngk Fixed bug in GetEditionMark not returning dpBadPosErr. Used new
error codes. qDebug -> qCatchFailures
<1.2> 6/11/89 ngk Added dpHasEditionFormat and more debugging checks
<1.1> 5/29/89 ngk Change ReadEdition to call ReadFormat and WriteEdition to call
WriteFormat
<1.0> 5/19/89 ngk Submitted for first time
To Do:
}
{============================= low level =============================}
{------------- dpCreateSIOCBRecord -------------}
FUNCTION dpCreateSIOCBRecord(itsSectionH: SectionHandle;
itsRefNum: LONGINT;
itsProc: FormatIOProcPtr;
VAR sectCB: SIOCBHandle): OSErr;
VAR
i: INTEGER;
fi: FailInfo;
BEGIN
{ sectCB is never in a register because it is a VAR parameter }
sectCB := NIL;
{ set up failure handling }
IF IsFailure(fi, dpCreateSIOCBRecord) THEN
BEGIN
IF sectCB <> NIL
THEN DisposHandle(Handle(sectCB));
sectCB := NIL;
EXIT(dpCreateSIOCBRecord);
END; {if}
{$IFC qRangeCheck }
FailOSErr(dpCheckSection(itsSectionH));
{$ENDC }
{ allocate Section I/O Control block }
FailOSErr(dpNewDynamicArray(SizeOf(SIOCBRecord), {headerSize}
SizeOf(FormatPositionInfo), {slotSize}
kInitialFormats, {initialSlots}
NewHandle, {MyNewHandle} { in app heap }
DyanmicArrayHandle(sectCB))); {VAR arrayH}
{ initialize it }
WITH sectCB^^ DO
BEGIN
section := itsSectionH;
ioRefNum := itsRefNum;
ioProc := itsProc;
END;
{ set sectionH to point to it }
SIOCBHandle(itsSectionH^^.refNum) := sectCB;
Success(fi);
END; { dpCreateSIOCBRecord }
{------------- dpGetFormat -------------}
{ returns an index and pointer into the sectCB FormatPositionInfo array }
FUNCTION dpGetFormat(sectCB: SIOCBHandle; whichFormat: FormatType; canCreate: BOOLEAN;
VAR SIOCBIndex: INTEGER; VAR SIOCBPtr: FormatPositionInfoPtr): OSErr;
VAR
selector: FormatIOVerb;
params: FormatIOParamBlock;
FUNCTION MatchFormat(index: INTEGER; elemPtr: FormatPositionInfoPtr): BOOLEAN;
BEGIN
MatchFormat := LONGINT(elemPtr^.format) = LONGINT(whichFormat);
END; { MatchFormat }
BEGIN
{ if I can't find format in sectCB list, then try to create it }
IF NOT dpFindElement(DyanmicArrayHandle(sectCB), SizeOf(SIOCBRecord), MatchFormat, SIOCBIndex, SIOCBPtr) THEN
BEGIN
{ need to ask I/O proc to make it }
params.ioRefNum := sectCB^^.ioRefNum;
params.format := whichFormat;
IF canCreate
THEN selector := ioNewFormat
ELSE selector := ioHasFormat;
FailOSErr(dp_CallFormatIOProc(selector, params, sectCB^^.ioProc));
{ and add it to my list of known types }
FailOSErr(dpAddDynamicArrayEntry(DyanmicArrayHandle(sectCB), SizeOf(SIOCBRecord), SIOCBIndex, SIOCBPtr));
WITH SIOCBPtr^ DO
BEGIN
format := whichFormat;
mark := 0;
index := params.formatIndex;
length := params.buffLen;
END;
END; {if}
dpGetFormat := noErr;
END; { dpGetFormat }
{=============================== standard routines ==================================}
{------------- dpStandardLookUpFormat -------------}
FUNCTION dpStandardLookUpFormat(thePubCB: PubCBHandle; whichFormat: FormatType;
VAR mapIndex: LONGINT; VAR formatSize: Size): OSErr;
VAR
foundPtr: FormatPtr;
foundAt: INTEGER;
FUNCTION MatchFormat(index: INTEGER; elemPtr: FormatPtr): BOOLEAN;
BEGIN
MatchFormat := LONGINT(elemPtr^.theType) = LONGINT(whichFormat);
END; { MatchFormat }
BEGIN
dpStandardLookUpFormat := noErr;
{ special case 'fmts' }
IF LONGINT(whichFormat) = LONGINT(kFormatListFormat) THEN
BEGIN
mapIndex := 0;
formatSize := thePubCB^^.formats^^.lastUsedSlot * SizeOf(Format);
END ELSE
BEGIN
IF dpFindElement(thePubCB^^.formats, 0, MatchFormat, foundAt, foundPtr) THEN
BEGIN
mapIndex := foundAt;
formatSize := foundPtr^.theLength;
END ELSE
BEGIN
dpStandardLookUpFormat := noTypeErr;
END;
END; {if}
END; { dpStandardLookUpFormat }
{------------- dpStandardCreateNewFormat -------------}
FUNCTION dpStandardCreateNewFormat(thePubCB: PubCBHandle; newFormat: FormatType;
VAR mapIndex: LONGINT): OSErr;
VAR
newElementPtr: FormatPtr;
addErr: OSErr;
index: INTEGER;
BEGIN
addErr := dpAddDynamicArrayEntry(thePubCB^^.formats, 0, index, newElementPtr);
IF addErr = noErr THEN
BEGIN
mapIndex := index;
WITH newElementPtr^ DO
BEGIN
theType := newFormat;
theLength := 0;
END; {with}
END;
dpStandardCreateNewFormat := addErr;
END; { dpStandardCreateNewFormat }
{------------- dpStandardWriteFormat -------------}
FUNCTION dpStandardWriteFormat(thePubCB: PubCBHandle; buffPtr: Ptr; buffLen: Size;
whichFormat: FormatType; mapIndex: LONGINT; offset: LONGINT): OSErr;
VAR
theMap: AllocationMapHandle;
theRefNum: INTEGER;
PB: ParamBlockRec;
canReUse: BOOLEAN;
fPtr: FormatPtr;
alPtr: AllocationRecordPtr;
aSlot: INTEGER;
BEGIN
{ use PubCB to get theMap & theRefNum }
WITH thePubCB^^ DO
BEGIN
theMap := {thePubCB^^.}allocMap;
theRefNum := {thePubCB^^.}fileRefNum;
END;
{ write data to end of file, then update the map }
IF buffLen <> 0 THEN
BEGIN
WITH PB DO
BEGIN
ioRefNum := theRefNum;
ioBuffer := buffPtr;
ioReqCount := buffLen;
ioPosMode := fsFromStart;
ioPosOffset := thePubCB^^.fileMark;
FailOSErr(PBWriteSync(@PB));
IF ioActCount <> buffLen THEN FailOSErr(dskFulErr); {when would this ever happen?}
END; {with}
END; {if}
{ since when writing, we appended to the end of the file, }
{ we can reuse the last allocation record if the app has been appending a single format }
aSlot := theMap^^.lastUsedSlot;
IF aSlot > 0 THEN
BEGIN
FailOSErr(dpGetDynamicArrayEntry(theMap, 0, aSlot, alPtr));
WITH alPtr^ DO
BEGIN
canReUse := (LONGINT(theType) = LONGINT(whichFormat)) & (logicalStart+logicalLen = offset);
END; {with}
END
ELSE canReUse := FALSE;
IF canReUse THEN
BEGIN
{ can reuse last allocation record, because app is appending }
WITH alPtr^ DO
BEGIN
logicalLen := logicalLen + buffLen;
END; {with}
END ELSE
BEGIN
{ can't reuse one, so make new allocation entry, using current file pos }
FailOSErr(dpAddDynamicArrayEntry(theMap, 0, aSlot, alPtr));
WITH alPtr^ DO
BEGIN
theType := whichFormat;
logicalStart := offset; { new allocation begins at clients current mark }
logicalLen := buffLen;
fileOffset := thePubCB^^.fileMark; { put it at end of file }
END; {with}
END; {if}
FailOSErr(dpGetDynamicArrayEntry(thePubCB^^.formats, 0, mapIndex, fPtr));
WITH fPtr^ DO
BEGIN
{ if increased the length of a format, then bump format length }
IF theLength < offset+buffLen THEN
BEGIN
theLength := offset+buffLen;
END;
END; {with}
WITH thePubCB^^ DO
BEGIN
fileMark := fileMark + buffLen;
END;
dpStandardWriteFormat := noErr;
END; { dpStandardWriteFormat }
{------------- Intersection -------------}
{ compares two ranges and returns their intersection }
{ the ranges are specified by start and length }
{ use by ReadEdition when walking the allocation table }
FUNCTION Intersection(R1start,R1len, R2start,R2len: LONGINT;
VAR Istart,Ilen: LONGINT): BOOLEAN;
BEGIN
Intersection := FALSE;
Ilen := 0;
IF (R1start <= R2start+R2len) & (R1start+R1len > R2start) THEN
BEGIN
IF R1start > R2start
THEN Istart := R1start
ELSE Istart := R2start;
IF R1start+R1len > R2start+R2len
THEN Ilen := R2start+R2len-Istart
ELSE Ilen := R1start+R1len-Istart;
Intersection := TRUE;
END;
END; { Intersection }
{------------- dpStandardReadFormat -------------}
FUNCTION dpStandardReadFormat(thePubCB: PubCBHandle; buffPtr: Ptr; VAR buffLen: Size;
whichFormat: FormatType; mapIndex: LONGINT;
offsetIntoFormat: LONGINT): OSErr;
VAR
fmtsStart: LONGINT;
fmtsLen: LONGINT;
fmtsEnd: LONGINT;
maxOffsetInfoFormat: LONGINT;
theRefNum: INTEGER;
ignoreIndex: INTEGER;
ignorePtr: Ptr;
formatEntryPtr: FormatPtr;
FUNCTION ReadIfIntersects(allocIndex: INTEGER; allocPtr: AllocationRecordPtr): BOOLEAN;
VAR
interStart: LONGINT;
interLen: LONGINT;
PB: ParamBlockRec;
BEGIN
WITH allocPtr^ DO
BEGIN
IF (LONGINT(theType) = LONGINT(whichFormat)) THEN
IF Intersection(logicalStart,logicalLen, offsetIntoFormat,buffLen, interStart,interLen) THEN
WITH PB DO
BEGIN { if it contains data to be read }
ioRefNum := theRefNum;
ioBuffer := Pointer(ORD(buffPtr)+interStart-offsetIntoFormat);
ioReqCount := interLen;
ioPosMode := fsFromStart;
ioPosOffset := interStart+fileOffset-logicalStart;
FailOSErr(PBReadSync(@PB));
IF ioActCount <> interLen THEN FailOSErr(eofErr); {is this redundant?}
{ save off how far we have touched in format }
IF interStart+interLen > maxOffsetInfoFormat
THEN maxOffsetInfoFormat := interStart+interLen;
END; {with}
END; {with}
ReadIfIntersects := FALSE;
END; { ReadIfIntersects }
BEGIN
IF LONGINT(whichFormat) = LONGINT(kFormatListFormat) THEN
BEGIN
{ special case 'fmts' }
WITH thePubCB^^ DO
BEGIN
fmtsEnd := formats^^.lastUsedSlot * SizeOf(Format);
IF offsetIntoFormat > fmtsEnd { ### should be an unsigned comparison }
THEN FailOSErr(eofErr);
IF offsetIntoFormat = fmtsEnd {&} THEN IF buffLen <> 0 { only OK to read nothing }
THEN FailOSErr(eofErr);
IF Intersection(0,fmtsEnd, offsetIntoFormat,buffLen, fmtsStart,fmtsLen)
THEN BlockMove(Ptr(ORD(formats^)+SizeOf(DyanmicArray)+fmtsStart), buffPtr, fmtsLen);
END; {with}
buffLen := fmtsLen;
END ELSE
BEGIN
{ check if trying to read out of past end of format }
FailOSErr(dpGetDynamicArrayEntry(thePubCB^^.formats, 0, mapIndex, formatEntryPtr));
IF offsetIntoFormat > formatEntryPtr^.theLength { ### should be an unsigned comparison }
THEN FailOSErr(eofErr);
IF offsetIntoFormat = formatEntryPtr^.theLength {&} THEN IF buffLen <> 0 { only OK to read nothing }
THEN FailOSErr(eofErr);
{ use PubCB to get theMap & theRefNum }
theRefNum := thePubCB^^.fileRefNum;
{ read stuff if requested }
IF buffLen <> 0 THEN
BEGIN
{ for each intersection of table block and read range, copy to buffer }
maxOffsetInfoFormat := offsetIntoFormat;
IF dpFindElement(thePubCB^^.allocMap, 0, ReadIfIntersects, ignoreIndex, ignorePtr) THEN;
{ return amount read in buffLen }
buffLen := maxOffsetInfoFormat - offsetIntoFormat;
END;
END;
dpStandardReadFormat := noErr;
END; { dpStandardReadFormat }
{------------- dpStandardIO -------------}
FUNCTION dpStandardIO(selector: FormatIOVerb; VAR PB: FormatIOParamBlock): OSErr;
VAR
thePubCB: PubCBHandle;
fi: FailInfo;
BEGIN
{ set up failure handling }
IF IsFailure(fi, dpStandardIO)
THEN EXIT(dpStandardIO);
WITH PB DO
BEGIN
thePubCB := PubCBHandle(ioRefNum);
CASE selector OF
ioHasFormat:
BEGIN
dpStandardIO := dpStandardLookUpFormat(thePubCB, format, formatIndex, buffLen);
END;
ioReadFormat:
BEGIN
dpStandardIO := dpStandardReadFormat(thePubCB, buffPtr, buffLen, format, formatIndex, offset);
END;
ioNewFormat:
BEGIN
dpStandardIO := dpStandardCreateNewFormat(thePubCB, format, formatIndex);
END;
ioWriteFormat:
BEGIN
dpStandardIO := dpStandardWriteFormat(thePubCB, buffPtr, buffLen, format, formatIndex, offset);
END;
END; {case}
END; {with}
Success(fi);
END; { dpStandardIO }
{=============================== public routines ==================================}
{------------- dp_EditionHasFormat -------------}
FUNCTION dp_EditionHasFormat(sectCB: SIOCBHandle; whichFormat: FormatType;
VAR length: Size): OSErr;
VAR
SIOCBIndex: INTEGER;
SIOCBPtr: FormatPositionInfoPtr;
fi: FailInfo;
BEGIN
{ set up failure handling }
IF IsFailure(fi, dp_EditionHasFormat)
THEN EXIT(dp_EditionHasFormat);
{ get format position in SectCB array }
FailOSErr(dpGetFormat(sectCB, whichFormat, {canCreate}FALSE, SIOCBIndex, SIOCBPtr));
{ return length of the format }
length := SIOCBPtr^.length;
{ remove failure handling }
Success(fi);
END; { dp_EditionHasFormat }
{------------- dp_GetEditionFormatMark -------------}
FUNCTION dp_GetEditionFormatMark(sectCB: SIOCBHandle; whichFormat: FormatType;
VAR mark: LONGINT): OSErr;
VAR
SIOCBIndex: INTEGER;
SIOCBPtr: FormatPositionInfoPtr;
fi: FailInfo;
BEGIN
{ set up failure handling }
IF IsFailure(fi, dp_GetEditionFormatMark)
THEN EXIT(dp_GetEditionFormatMark);
{ get format position in SectCB array }
FailOSErr(dpGetFormat(sectCB, whichFormat, {canCreate}FALSE, SIOCBIndex, SIOCBPtr));
{ yes, I do. So return mark I know }
mark := SIOCBPtr^.mark;
{ remove failure handling }
Success(fi);
END; { dp_GetEditionFormatMark }
{------------- dp_SetEditionFormatMark -------------}
FUNCTION dp_SetEditionFormatMark(sectCB: SIOCBHandle; whichFormat: FormatType;
mark: LONGINT): OSErr;
VAR
SIOCBIndex: INTEGER;
SIOCBPtr: FormatPositionInfoPtr;
sectionH: SectionHandle;
canCreateFormat:BOOLEAN;
fi: FailInfo;
BEGIN
{ set up failure handling }
IF IsFailure(fi, dp_SetEditionFormatMark)
THEN EXIT(dp_SetEditionFormatMark);
{ figure out if this could cause the creation of a new format }
sectionH := sectCB^^.section;
canCreateFormat := (sectionH <> NIL) & bTST(sectionH^^.kind, kCanWriteEditionsBit);
{ get format position in SectCB array }
FailOSErr(dpGetFormat(sectCB, whichFormat, canCreateFormat, SIOCBIndex, SIOCBPtr));
{ set to new mark }
SIOCBPtr^.mark := mark;
{ remove failure handling }
Success(fi);
END; { dp_SetEditionFormatMark }
{------------- dp_ReadOrWriteEdition -------------}
FUNCTION dp_ReadOrWriteEdition(selector: FormatIOVerb; sectCB: SIOCBHandle; whichFormat: FormatType;
buffPtr: Ptr; VAR buffLen: Size): OSErr;
VAR
params: FormatIOParamBlock;
SIOCBIndex: INTEGER;
SIOCBPtr: FormatPositionInfoPtr;
fi: FailInfo;
BEGIN
{ set up failure handling }
IF IsFailure(fi, dp_ReadOrWriteEdition)
THEN EXIT(dp_ReadOrWriteEdition);
{ get format position in SectCB array }
FailOSErr(dpGetFormat(sectCB, whichFormat, {canCreate}selector=ioWriteFormat, SIOCBIndex, SIOCBPtr));
WITH SIOCBPtr^, sectCB^^ DO
BEGIN
{ set up call to io routine }
params.ioRefNum := {sectCB^^.}ioRefNum;
params.format := whichFormat;
params.formatIndex := {SIOCBPtr^.}index;
params.offset := {SIOCBPtr^.}mark;
params.buffPtr := buffPtr;
params.buffLen := buffLen;
FailOSErr(dp_CallFormatIOProc(selector, params, {sectCB^^.}ioProc));
END;
{ return amount read or written }
buffLen := params.buffLen;
{ advance marker, read may have moved memory so recalc pointer }
FailOSErr(dpGetDynamicArrayEntry(DyanmicArrayHandle(sectCB), SizeOf(SIOCBRecord), SIOCBIndex, SIOCBPtr));
WITH SIOCBPtr^ DO
mark := mark + params.buffLen;
Success(fi);
END; { dp_ReadOrWriteEdition }
{------------- dp_ReadEdition -------------}
FUNCTION dp_ReadEdition(sectCB: SIOCBHandle; whichFormat: FormatType;
buffPtr: Ptr; VAR buffLen: Size): OSErr;
BEGIN
dp_ReadEdition := dp_ReadOrWriteEdition(ioReadFormat, sectCB, whichFormat, buffPtr, buffLen);
END; { dp_ReadEdition }
{------------- dp_WriteEdition -------------}
FUNCTION dp_WriteEdition(sectCB: SIOCBHandle; whichFormat: FormatType;
buffPtr: Ptr; buffLen: Size): OSErr;
VAR
sectionH: SectionHandle;
BEGIN
{ if this is a subscriber trying to write, then return error }
sectionH := sectCB^^.section;
IF (sectionH <> NIL) & (NOT bTST(sectionH^^.kind, kCanWriteEditionsBit))
THEN dp_WriteEdition := wrPermErr
ELSE dp_WriteEdition := dp_ReadOrWriteEdition(ioWriteFormat, sectCB, whichFormat, buffPtr, buffLen);
END; { dp_WriteEdition }