***************************************************************************************************** ; PL I/O Routines ; ; This file contains the routines used by PL to open and save documents. ; ***************************************************************************************************** load 'macros.dump' include 'driver.equ' include 'pl.equ' IMPORT D_BeachBall IMPORT D_Deref IMPORT D_DestroyByRef IMPORT D_FastMult IMPORT D_NeedHand IMPORT D_Read2 IMPORT D_ReadHandle2 IMPORT D_SetCursor IMPORT D_UnLock IMPORT D_Write2 IMPORT D_WriteHandle2 IMPORT P_CheckHand IMPORT P_CurrentWin IMPORT P_ErrorAlert IMPORT P_Header IMPORT P_HeaderSize IMPORT P_HorizGCount IMPORT P_HorizGuides IMPORT P_InitDoc IMPORT P_KillPage IMPORT P_LastObj IMPORT P_LoadPage IMPORT P_LoadWindowStuff IMPORT P_MergeGuides IMPORT P_NotActive IMPORT P_OBJSIZES IMPORT P_ObjList IMPORT P_PInfoSize IMPORT P_Page IMPORT P_PageArray IMPORT P_PageCount IMPORT P_SavePage IMPORT P_SaveWindowStuff IMPORT P_ShowDoc IMPORT P_UseTemplate IMPORT P_Version IMPORT P_VertGCount IMPORT P_VertGuides IMPORT T_ReThread IMPORT X_ReadWPScrap IMPORT X_WriteWPScrap IMPORT X_DisposeThread ***************************************************************************************************** ; P_Thread2Pair ( ThreadHdl:long ): PageNo:word, ObjNo:word ; ; This routine is called to determine the page and object number for a given text thread. The page ; and object numbers will be used when saving to disk to replace the handles. These values can be ; used on an Open to correctly relink the new handles in the same way. P_Thread2Pair PROC EXPORT ;Using P_Data ;Using P_ObjData input ThreadHdl:l output PageNo:w,ObjNo:w local Hdl:l,Ptr:l,ThreadPtr:l,ObjHdl:l,ObjPtr:l,Offset:l begin ; If thread handle is NIL then blow it off. cpzl ThreadHdl beq NoThread ; Get page number from the thread. movelong [ThreadHdl],ThreadPtr moveword [ThreadPtr]:#P_PageNo,PageNo ; Get pointer to page entry in the page array. tool _Multiply,in=(PageNo:w,#P_PInfoSize:w),out=(Offset:l) movelong P_PageArray,Hdl movelong [Hdl],Ptr addlong Ptr,Offset,Ptr ; Scan page object list to see if we can find the thread we are looking for. Get its object number. movelong [Ptr],ObjHdl stz ObjNo loop cmpl ObjHdl,ThreadHdl beq exit movelong [ObjHdl],ObjPtr movelong [ObjPtr],ObjHdl inc ObjNo bra loop ; The thread was NIL so return page number and object number of -1. NoThread moveword #-1,PageNo sta ObjNo exit return ENDP ***************************************************************************************************** ; P_Pair2Thread ( PageNo:word, ObjNo:word ): ThreadHdl:long ; ; This routine is called to determine the text thread corresponding to the given text object for ; the given page. P_Pair2Thread PROC EXPORT ;Using P_Data ;Using P_ObjData input PageNo:w,ObjNo:w output ObjHdl:l local Hdl:l,Ptr:l,ObjPtr:l,Offset:l begin ; If page number is -1 then no thread exists for this page object; return NIL. cmpw PageNo,#-1 beq NoThread ; Get pointer to page entry in the page array. tool _Multiply,in=(PageNo:w,#P_PInfoSize:w),out=(Offset:l) movelong P_PageArray,Hdl movelong [Hdl],Ptr addlong Ptr,Offset,Ptr ; Scan object array for the given page to find the object handle for the given object number. movelong [Ptr],ObjHdl ldx #0 loop cpx ObjNo beq exit movelong [ObjHdl],ObjPtr movelong [ObjPtr],ObjHdl inx bra loop ; No thread exists for this page/object return NIL. NoThread stzl ObjHdl exit return ENDP ***************************************************************************************************** ; P_SetParag ( ObjectPtr:long ) ; ; This routine is called to put the given objects paragraph handle into all the text threads in ; its linked list. P_SetParag PROC EXPORT ;Using P_ObjData input objptr:l local objhdl:l,paraghdl:l begin movelong [objptr]:#P_ParagHdl,paraghdl objloop cpzl [objptr]:#P_NThread beq exit movelong [objptr]:#P_NThread,objhdl movelong [objhdl],objptr movelong paraghdl,[objptr]:#P_ParagHdl bra objloop exit return ENDP ***************************************************************************************************** ; P_OpenDoc ( FileId:word, WindowPtr:long ) ; ; This routine will handle reading in a page layout document with the given file reference. The ; file has already been opened by the driver and the file mark moved to the start of the document ; data. Memory or file I/O errors are returned to the driver which will handle closing the file and ; alerting the user. P_OpenDoc PROC EXPORT ;Using P_Data ;Using P_ObjData ;Using D_IOData ;Using P_RulerData input fileid:w,window:l local page:w,pagecount:w,oldpage:w,tmp:l,tmphdl:l local oldwin:l,tmpobj:l,objptr:l,xhdl:l,xtype:w local xobj:l,xobjhdl:l,table:l,refcon:l,lastpage:w ; these 4 variables are clustered. Do not rearrange or seperate. local templ:w,hguide:w,vguide:w,count:w error err begin +b ; Clear local variables and put up the watch cursor. stzl tmp stzl tmphdl stzl xobj stzl xobjhdl stzl table stzl refcon stzl oldwin stzl tmpobj stzl objptr stz pagecount call D_SetCursor,in=(#WatchCursor:w) ; Page out current window information. Set table to point to table of object sizes. movelong P_CurrentWin,oldwin call P_SaveWindowStuff,in=(oldwin:l) movelong #P_OBJSIZES,table ; If we can't get 32k then probably shouldn't be trying to open a document. Return driver a memory ; error. call P_CheckHand,in=(#$8000:l),err=(err) jcs exit ; Read header information for the file. If read error then return with error to driver. call D_Read2,in=(fileid:w,#P_Header:l,#P_HeaderSize:l),out=(ax:l),err=(err) jcs exit ; Check if PL id present in file if not then this file must be damaged or not a real PL file. Since ; we are handling the error return -1 to the driver. jsr chkversion jcs exit ; Traverse the document page by page, object by object... ; File looks OK so far; clear error status and get temp object for use in loading file. If we can't ; get it return to the driver with a mem error, else lock down the temp object and clear the temp ; object handle variable. stz err call D_NeedHand,in=(#P_TextObjSize:l),out=(xobjhdl:l),err=(err) jcs exit rcall D_Deref,in=(xobjhdl:ax),out=(xobj:ax) movelong #0,xhdl ; Initialize the document structure. Get refcon in case we need to dispose it on error. call P_InitDoc,in=(window:l),out=(refcon:l),err=err jcs killxobj ; Initialize pagecount (including master pages) and current/last page. addword P_PageCount,#2,pagecount moveword #-1,page sta lastpage ; Try to allocate a page array large enough to hold all the pages in the document. If we can't then ; dispose of the temp object and the refcon we allocated. spacelong tool _Multiply,in=(#P_PInfoSize:w,pagecount:w),out=(:l) call D_NeedHand,err=(err) pulllong P_PageArray jcs killrefcon ; Remember what the old page used to be. Clear loop variables and bump to next page and last page. moveword P_Page,oldpage pageloop stzl P_HorizGuides stzl P_VertGuides stzl P_ObjList stzl P_LastObj inc page inc lastpage ; Read count, vguide, hguide and templ in one call. If error reading then dispose of all pages read ; so far, refcon, and xobj before returning mem error to the driver. Set global based on values read. call D_Read2,in=(fileid:w,!count:l,#8:l),out=(ax:l),err=(err) jcs killpages moveword vguide,P_VertGCount moveword hguide,P_HorizGCount moveword templ,P_UseTemplate ; Read in objects from file. objloop jsl D_BeachBall dec count jmi doneobj ; Get object information. If error then dispose of all memory allocated so far. stzl xhdl call D_Read2,in=(fileid:w,xobj:l,#P_TextObjSize:l),out=(ax:l),err=(err) jcs killpages ; Check if object type is text object. If so check if text object has a thread associated with it. ; If not then ready to add object to page layout, else read in text thread for the object. cmpw [xobj]:#P_Type,#P_ALPHA bne CkPict cmpw [xobj]:#P_PThread,#-1 jne DidObj call X_ReadWPScrap,in=(FileId:w,#1:w),out=(tmp:l),err=err jcs killpages ; Put text thread into the temp object. Unlock the text thread since read WP returns it locked. movelong tmp,xhdl moveword #P_Alpha,xtype movelong xhdl,[xobj]:#P_ParagHdl rcall D_UnLock,in=(xhdl:ax) bra DidObj ; Check if object type is PICT. If so read in PICT handle. CkPict cmp #P_PICTURE bne DidObj call D_ReadHandle2,in=(fileid:w),out=(tmp:l),err=(err) jcs killpages ; Put picture handle in temp object. Unlock the pict handle since read handle returns it locked. movelong tmp,xhdl moveword #P_Picture,xtype movelong xhdl,[xobj]:#P_PictHandle rcall D_UnLock,in=(xhdl:ax) ; Xobj now has entire object including picture or text thread handles. Check if valid object type ; if not the file must be corrupt; warn user and dispose of all memory so far allocated. DidObj cmpw [xobj]:#P_Type,#P_Picture+1 blt oktype moveword #-1,err call P_ErrorAlert,in=(#2:w) brl killpages ; Make copy of temp object to put in the data structure. If memory error then dispose of all memory ; so far allocated and return with mem error. { use table to determine true size needed for object } oktype dec a asl a asl a tay movelong [table]:y,tmp call D_NeedHand,in=(tmp:l),out=(tmphdl:l),err=(err) jcs killpages tool _BlockMove,in=(xobj:l,[tmphdl]:l,tmp:l) stzl xhdl ; Get pointer to new object. Add object to linked list. movelong [tmphdl],tmp IsNil P_ObjList bne NotFirst movelong tmphdl,P_ObjList movelong tmphdl,P_LastObj movelong #0,[tmp] movelong #0,[tmp]:#P_Prev bra DidInsert NotFirst movelong P_LastObj,[tmp]:#P_Prev movelong #0,[tmp] movelong tmphdl,P_LastObj movelong [tmp]:#P_Prev,tmphdl movelong [tmphdl],tmp movelong P_LastObj,[tmp] DidInsert brl objloop ; Object successfully added to page data structure. If horz. guides exists then read its handle. doneobj lda hguide beq CkVguide call D_ReadHandle2,in=(fileid:w),out=(P_HorizGuides:l),err=(err) bcc GotH stzl P_HorizGuides brl killpages GotH rcall D_UnLock,in=(P_HorizGuides:ax) ; If vert. guides exist then read its handle. CkVguide lda vguide beq DidGuides call D_ReadHandle2,in=(fileid:w),out=(P_VertGuides:l),err=(err) bcc GotV stzl P_VertGuides brl killguides GotV rcall D_UnLock,in=(P_VertGuides:ax) ; Save page information. And go back for any remaining pages to be loaded. DidGuides call P_SavePage,in=(page:w) dec pagecount jne pageloop ; Verify that file is still valid by checking version numbers. call D_Read2,in=(fileid:w,#P_Header:l,#2:l),out=(ax:l),err=(err) jcs gokillgs jsr chkversion gokillgs jcs killguides stz err ; File completely read in. Now repair threads so they use real handles instead of page number and ; object number offsets. ; Repair threads, part I. Loop through all objects on all pages updating their next & previous thread ; handles if they are text objects. addword P_PageCount,#2,pagecount moveword #-1,page pageloop2 inc page call P_LoadPage,in=(page:w) stz count movelong P_ObjList,tmpobj objloop2 jsl D_BeachBall IsNil tmpobj jeq doneobj2 rcall D_Deref,in=(tmpobj:ax),out=(objptr:ax) cmpw [objptr]:#P_Type,#P_ALPHA bne DidText call P_Pair2Thread,in=([objptr]:#P_PThread:l),out=([objptr]:#P_PThread:l) call P_Pair2Thread,in=([objptr]:#P_NThread:l),out=([objptr]:#P_NThread:l) DidText rcall D_UnLock,in=(tmpobj:ax) movelong [objptr],tmpobj brl objloop2 doneobj2 call P_SavePage,in=(page:w) dec pagecount jne pageloop2 ; Repair threads, part II. Loop through all objects on all pages and if object is a text object then ; set the paragraph blocks for all objects in the list then rethread the object. addword P_PageCount,#2,pagecount moveword #-1,page pageloop3 inc page call P_LoadPage,in=(page:w) stz count movelong P_ObjList,tmpobj objloop3 jsl D_BeachBall IsNil tmpobj jeq doneobj3 rcall D_Deref,in=(tmpobj:ax),out=(objptr:ax) cmpw [objptr]:#P_Type,#P_ALPHA jne DidText3 cpzl [objptr]:#P_PThread bne DidText3 call P_SetParag,in=(objptr:l) call T_ReThread,in=(tmpobj:l) DidText3 rcall D_UnLock,in=(tmpobj:ax) movelong [objptr],tmpobj brl objloop3 doneobj3 call P_SavePage,in=(page:w) dec pagecount jne pageloop3 ; Successfully loaded file get ready to show document. Load the original page that document was saved ; on and merge guides. Then dispose of xobj. call P_ShowDoc,in=(window:l),err=(err) bcs killpages call P_LoadPage,in=(oldpage:w) call P_MergeGuides brl killxobj ; Error loading file so dispose of memory we have allocated. killguides lda hguide beq killvguide cpzl P_HorizGuides beq killvguide tool _DisposeHandle,in=(P_HorizGuides:l) killvguide lda vguide beq killpages cpzl P_VertGuides beq killpages tool _DisposeHandle,in=(P_VertGuides:l) killpages call P_SavePage,in=(page:w) riploop jsl D_BeachBall call P_KillPage,in=(lastpage:w,#1:w) dec lastpage bpl riploop killparray tool _DisposeHandle,in=(P_PageArray:l) ; Error loading file so dispose of memory we have allocated. killrefcon tool _DisposeHandle,in=(RefCon:l) killxobj tool _DisposeHandle,in=(xobjhdl:l) ; If paragraph handle exists in the temp object make sure to dispose of it too. cpzl xhdl beq exit cmpw xtype,#P_Picture beq killpict call X_DisposeThread,in=(xhdl:l,#1:w) bra exit killpict tool _KillPicture,in=(xhdl:l) ; Restore old window before returning. exit call P_LoadWindowStuff,in=(oldwin:l) return ;...................................................................................................; ; Check if PL id present in file if not then this file must be damaged or not a real PL file. Since ; we are handling the error return -1 to the driver. chkversion moveword #-1,err lda P_Version xba and #$FF cmp #P_ID beq CkVers1 ldx #2 bra doalert ; Warn user that this version of file cannot be loaded. CkVers1 lda P_Version and #$FF cmp #P_VNum beq chkvok ldx #3 doalert call P_ErrorAlert,in=(x:w) sec rts chkvok clc rts ;...................................................................................................; ENDP ;--------------------------------------------------------------------------- ; ; P_SaveDoc (Fileid:w,Winptr:l,BogusType:w) ; P_SaveDoc PROC EXPORT ;Using P_Data ;Using P_ObjData ;Using D_IOData ;Using D_GlobalData input fileid:w,winptr:l,bogusType:w local oldwin:l,oldpage:w local xobjhdl:l,xobj:l,pagecount:w,page:w local tmpobj:l,objptr:l ; these 4 variables are clustered. Do not rearrange or seperate. local templ:w,hguide:w,vguide:w,count:w ; error err begin +b call D_SetCursor,in=(#WatchCursor:w) cmpl WinPtr,P_CurrentWin beq Active inc P_NotActive Active movelong P_CurrentWin,oldwin call P_LoadWindowStuff,in=(winptr:l) moveword P_Page,oldpage call P_SavePage,in=(P_Page:w) moveword #P_VersNum,P_Version call D_Write2,in=(fileid:w,#P_Header:l,#P_HeaderSize:l),out=(ax:l),err=(err) jcs Whoops ;** ; ;************************************ ; Traverse the document, page by page ; object by object call D_NeedHand,in=(#P_TextObjSize:l),out=(xobjhdl:l),err=(err) jcs Whoops ;** rcall D_Deref,in=(xobjhdl:ax),out=(xobj:ax) addword P_PageCount,#2,pagecount moveword #-1,page pageloop inc page call P_LoadPage,in=(page:w) stz count movelong P_ObjList,tmpobj countloop IsNil tmpobj beq gotcount inc count movelong [tmpobj],objptr movelong [objptr],tmpobj bra countloop gotcount moveword P_VertGCount,vguide moveword P_HorizGCount,hguide moveword P_UseTemplate,templ call D_Write2,in=(fileid:w,!count:l,#8:l),out=(ax:l),err=(err) jcs Whoops ;** movelong P_ObjList,tmpobj objloop IsNil tmpobj jeq doneobj rcall D_Deref,in=(tmpobj:ax),out=(objptr:ax) cmpw [objptr]:#P_Type,#P_ALPHA jne CkPict tool _BlockMove,in=(objptr:l,xobj:l,#P_TextObjSize:l) in [xobj]:#P_PThread:l out [xobj]:#P_PThread:l xcall P_Thread2Pair in [xobj]:#P_NThread:l out [xobj]:#P_NThread:l xcall P_Thread2Pair call D_Write2,in=(fileid:w,xobj:l,#P_TextObjSize:l),out=(ax:l),err=(err) jcs Whoops ;** moveword [objptr]:#P_PThread,a iny iny ora [objptr],y jne DidObj call X_WriteWPScrap,in=(fileid:w,[xobj]:#P_ParagHdl:l,#1:w),err=(err) jcs whoops ;** brl DidObj CkPict cmp #P_PICTURE bne NormObj call D_Write2,in=(fileid:w,objptr:l,#P_TextObjSize:l),out=(ax:l),err=(err) jcs Whoops ;** call D_WriteHandle2,in=(fileid:w,[objptr]:#P_PictHandle:l),err=(err) jcs Whoops ;** pushlong [objptr]:#P_PictHandle _HUnlock bra DidObj NormObj call D_Write2,in=(fileid:w,objptr:l,#P_TextObjSize:l),out=(ax:l),err=(err) jcs Whoops ;** DidObj rcall D_UnLock,in=(tmpobj:ax) movelong [objptr],tmpobj brl objloop doneobj lda hguide beq CkVguide call D_WriteHandle2,in=(fileid:w,P_HorizGuides:l),err=(err) jcs Whoops ;** rcall D_UnLock,in=(P_HorizGuides:ax) CkVguide lda vguide beq DidGuides call D_WriteHandle2,in=(fileid:w,P_VertGuides:l),err=(err) jcs Whoops ;** rcall D_UnLock,in=(P_VertGuides:ax) DidGuides dec pagecount jne pageloop call D_Write2,in=(fileid:w,#P_Header:l,#2:l),out=(ax:l),err=(err) ; bcs Whoops ;** ; ; bra exit whoops ; The driver now does all file cleanup! exit tool _DisposeHandle,in=(xobjhdl:l) call P_LoadPage,in=(oldpage:w) call P_LoadWindowStuff,in=(oldwin:l) stz P_NotActive return ENDP END