1998-03-28 05:44:41 +03:00
|
|
|
/* -*- 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Editor save stuff. LWT 06/01/95
|
|
|
|
//
|
|
|
|
// Added all ITapeFileSystem stuff, hardts 10/96
|
|
|
|
|
|
|
|
#ifdef EDITOR
|
|
|
|
|
|
|
|
#include "editor.h"
|
|
|
|
#include "streams.h"
|
|
|
|
#include "shist.h"
|
|
|
|
#include "xpgetstr.h"
|
|
|
|
#include "net.h"
|
|
|
|
#include "mime.h"
|
|
|
|
#include "prefapi.h"
|
|
|
|
|
|
|
|
// Other error values are created from ALLXPSTR.RC during compiling
|
|
|
|
//extern "C" int MK_UNABLE_TO_LOCATE_FILE;
|
|
|
|
//extern "C" int MK_MALFORMED_URL_ERROR;
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// CEditImageLoader
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
CEditImageLoader::CEditImageLoader( CEditBuffer *pBuffer, EDT_ImageData *pImageData,
|
|
|
|
XP_Bool bReplaceImage ):
|
|
|
|
m_pBuffer( pBuffer ),
|
|
|
|
m_pImageData( edt_DupImageData( pImageData ) ),
|
|
|
|
m_bReplaceImage( bReplaceImage )
|
|
|
|
{
|
|
|
|
char *pStr;
|
|
|
|
if( !pBuffer->m_pContext->is_new_document ){
|
|
|
|
intn retVal = NET_MakeRelativeURL( LO_GetBaseURL( m_pBuffer->m_pContext ),
|
|
|
|
m_pImageData->pSrc,
|
|
|
|
&pStr );
|
|
|
|
|
|
|
|
if( retVal != NET_URL_FAIL ){
|
|
|
|
XP_FREE( m_pImageData->pSrc );
|
|
|
|
m_pImageData->pSrc = pStr;
|
|
|
|
}
|
|
|
|
|
|
|
|
retVal = NET_MakeRelativeURL( LO_GetBaseURL( m_pBuffer->m_pContext ),
|
|
|
|
m_pImageData->pLowSrc,
|
|
|
|
&pStr );
|
|
|
|
|
|
|
|
if( retVal != NET_URL_FAIL ){
|
|
|
|
XP_FREE( m_pImageData->pLowSrc );
|
|
|
|
m_pImageData->pLowSrc = pStr;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CEditImageLoader::~CEditImageLoader(){
|
|
|
|
m_pBuffer->m_pLoadingImage = 0;
|
|
|
|
FE_ImageLoadDialogDestroy( m_pBuffer->m_pContext );
|
|
|
|
FE_EnableClicking( m_pBuffer->m_pContext );
|
|
|
|
edt_FreeImageData( m_pImageData );
|
|
|
|
}
|
|
|
|
|
|
|
|
void CEditImageLoader::LoadImage(){
|
|
|
|
char *pStr;
|
|
|
|
XP_ObserverList image_obs_list; // List of image observers.
|
|
|
|
|
|
|
|
m_pLoImage = LO_NewImageElement( m_pBuffer->m_pContext );
|
|
|
|
|
|
|
|
// convert the URL to an absolute path
|
|
|
|
pStr = NET_MakeAbsoluteURL( LO_GetBaseURL( m_pBuffer->m_pContext ),
|
|
|
|
m_pImageData->pSrc );
|
|
|
|
m_pLoImage->image_url = PA_strdup( pStr );
|
|
|
|
XP_FREE( pStr );
|
|
|
|
|
|
|
|
// convert the URL to an absolute path
|
|
|
|
pStr = NET_MakeAbsoluteURL( LO_GetBaseURL( m_pBuffer->m_pContext ),
|
|
|
|
m_pImageData->pLowSrc );
|
|
|
|
m_pLoImage->lowres_image_url = PA_strdup( pStr );
|
|
|
|
XP_FREE( pStr );
|
|
|
|
|
|
|
|
// tell layout to pass the size info back to us.
|
|
|
|
m_pLoImage->ele_id = ED_IMAGE_LOAD_HACK_ID;
|
|
|
|
FE_ImageLoadDialog( m_pBuffer->m_pContext );
|
|
|
|
|
|
|
|
image_obs_list = lo_NewImageObserverList(m_pBuffer->m_pContext,
|
|
|
|
m_pLoImage);
|
|
|
|
if (!image_obs_list) {
|
|
|
|
XP_ASSERT(FALSE); // Out of memory.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
lo_GetImage(m_pBuffer->m_pContext, m_pBuffer->m_pContext->img_cx,
|
|
|
|
m_pLoImage, image_obs_list, NET_DONT_RELOAD);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// The image library is telling us the size of the image. Actually do the
|
|
|
|
// insert now.
|
1998-07-24 08:14:39 +04:00
|
|
|
void CEditImageLoader::SetImageInfo(int32 width, int32 height){
|
1998-03-28 05:44:41 +03:00
|
|
|
if( m_pImageData->iHeight == 0 || m_pImageData->iWidth == 0 ){
|
|
|
|
m_pImageData->iHeight = height;
|
|
|
|
m_pImageData->iWidth = width;
|
|
|
|
m_pImageData->iOriginalHeight = height;
|
|
|
|
m_pImageData->iOriginalWidth = width;
|
|
|
|
}
|
|
|
|
if( m_bReplaceImage ){
|
|
|
|
// whack this in here...
|
|
|
|
m_pBuffer->m_pCurrent->Image()->SetImageData( m_pImageData );
|
|
|
|
// we could be doing a better job here. We probably repaint too much...
|
|
|
|
CEditElement *pContainer = m_pBuffer->m_pCurrent->FindContainer();
|
|
|
|
m_pBuffer->Relayout( pContainer, 0, pContainer->GetLastMostChild(),
|
|
|
|
RELAYOUT_NOCARET );
|
|
|
|
m_pBuffer->SelectCurrentElement();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
m_pBuffer->InsertImage( m_pImageData );
|
|
|
|
}
|
|
|
|
delete this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// CEditSaveObject
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#if defined(XP_OS2)
|
|
|
|
extern "C"
|
|
|
|
#else
|
|
|
|
PRIVATE
|
|
|
|
#endif
|
1998-07-24 08:14:39 +04:00
|
|
|
unsigned int edt_file_save_stream_write_ready( NET_StreamClass * /* stream */ ){
|
1998-03-28 05:44:41 +03:00
|
|
|
return MAX_WRITE_READY;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(XP_OS2)
|
|
|
|
extern "C"
|
|
|
|
#else
|
|
|
|
PRIVATE
|
|
|
|
#endif
|
|
|
|
int edt_FileSaveStreamWrite (NET_StreamClass *stream, const char *block, int32 length) {
|
|
|
|
CFileSaveObject *pSaver = (CFileSaveObject*)stream->data_object;
|
|
|
|
return pSaver->NetStreamWrite( block, length );
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(XP_OS2)
|
|
|
|
extern "C"
|
|
|
|
#else
|
|
|
|
PRIVATE
|
|
|
|
#endif
|
1998-07-24 08:14:39 +04:00
|
|
|
void edt_file_save_stream_complete( NET_StreamClass * /* stream */ ){
|
1998-03-28 05:44:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(XP_OS2)
|
|
|
|
extern "C"
|
|
|
|
#else
|
|
|
|
PRIVATE
|
|
|
|
#endif
|
1998-07-24 08:14:39 +04:00
|
|
|
void edt_file_save_stream_abort (NET_StreamClass * /* stream */, int /* status */ ) {
|
1998-03-28 05:44:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#if defined(XP_OS2)
|
|
|
|
extern "C"
|
|
|
|
#else
|
|
|
|
PRIVATE
|
|
|
|
#endif
|
1998-07-24 08:14:39 +04:00
|
|
|
void edt_UrlExit( URL_Struct *pURL, int status, MWContext * /* context */ )
|
1998-03-28 05:44:41 +03:00
|
|
|
{
|
|
|
|
// hardts, changed from CEditSaveObject to CFileSaveObject
|
1998-07-24 08:14:39 +04:00
|
|
|
((CFileSaveObject*)(pURL->fe_data))->NetFetchDone(status);
|
1998-03-28 05:44:41 +03:00
|
|
|
|
|
|
|
NET_FreeURLStruct(pURL);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(XP_OS2)
|
|
|
|
extern "C"
|
|
|
|
#else
|
|
|
|
PRIVATE
|
|
|
|
#endif
|
1998-07-24 08:14:39 +04:00
|
|
|
NET_StreamClass * edt_MakeFileSaveStream (int /* format_out */, void * /* closure */,
|
1998-03-28 05:44:41 +03:00
|
|
|
URL_Struct *url, MWContext *context ) {
|
|
|
|
|
|
|
|
NET_StreamClass *stream;
|
|
|
|
CFileSaveObject *pSaver = (CFileSaveObject*)url->fe_data;
|
|
|
|
|
|
|
|
// OpenOutputFile will return 0 if OK
|
|
|
|
if( !pSaver || pSaver->OpenOutputFile() != 0 ){
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ### mwelch Relay the information stored in this URL. We do it here instead of
|
|
|
|
// in the url exit routine because edt_MakeFileSaveStream could
|
|
|
|
// have been invoked by an inferior URL which represents a parsed
|
|
|
|
// piece of a mail or news message. If this URL is what was originally
|
|
|
|
// invoked, the correct mime type should still be present here.
|
|
|
|
if (url)
|
|
|
|
pSaver->CopyURLInfo(url);
|
|
|
|
|
|
|
|
TRACEMSG(("Setting up attachment stream. Have URL: %s\n", url->address));
|
|
|
|
|
|
|
|
stream = XP_NEW (NET_StreamClass);
|
|
|
|
if (stream == NULL)
|
|
|
|
return (NULL);
|
|
|
|
|
|
|
|
XP_MEMSET (stream, 0, sizeof (NET_StreamClass));
|
|
|
|
|
|
|
|
stream->name = "editor file save";
|
|
|
|
stream->complete = edt_file_save_stream_complete;
|
|
|
|
stream->abort = edt_file_save_stream_abort;
|
|
|
|
stream->put_block = edt_FileSaveStreamWrite;
|
|
|
|
stream->is_write_ready = edt_file_save_stream_write_ready;
|
|
|
|
stream->data_object = url->fe_data;
|
|
|
|
stream->window_id = context;
|
|
|
|
|
|
|
|
return stream;
|
|
|
|
}
|
|
|
|
|
|
|
|
static XP_Bool bNetRegistered = FALSE;
|
|
|
|
|
|
|
|
#ifdef MOZ_MAIL_NEWS
|
|
|
|
extern "C"
|
|
|
|
{
|
|
|
|
NET_StreamClass *MIME_MessageConverter (int format_out, void *closure,
|
|
|
|
URL_Struct *url,
|
|
|
|
MWContext *context);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// CFileSaveObject
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
1998-07-24 08:14:39 +04:00
|
|
|
CFileSaveObject::CFileSaveObject( MWContext *pContext,
|
1998-03-28 05:44:41 +03:00
|
|
|
ITapeFileSystem *tapeFS, XP_Bool bAutoSave,
|
|
|
|
CEditSaveToTempData *pSaveToTempData) :
|
|
|
|
m_pContext( pContext ) ,
|
|
|
|
m_bOverwriteAll( FALSE ),
|
|
|
|
m_bDontOverwriteAll( FALSE ),
|
|
|
|
m_bDontOverwrite( FALSE ),
|
|
|
|
m_iCurFile(0),
|
|
|
|
m_pOutStream(0),
|
|
|
|
m_bOpenOutputHandledError(FALSE),
|
|
|
|
m_tapeFS(tapeFS),
|
|
|
|
m_status( ED_ERROR_NONE ),
|
|
|
|
m_bFromAutoSave(bAutoSave),
|
|
|
|
m_pSaveToTempData(pSaveToTempData)
|
|
|
|
{
|
|
|
|
if( !bNetRegistered ){
|
|
|
|
#ifdef MOZ_MAIL_NEWS
|
|
|
|
// ### mwelch Need to pass mail/news messages through
|
|
|
|
// MIME_MessageConverter since we're likely to be
|
|
|
|
// extracting a part of the message.
|
|
|
|
NET_RegisterContentTypeConverter( MESSAGE_RFC822, FO_EDT_SAVE_IMAGE,
|
|
|
|
NULL, MIME_MessageConverter);
|
|
|
|
NET_RegisterContentTypeConverter( MESSAGE_NEWS, FO_EDT_SAVE_IMAGE,
|
|
|
|
NULL, MIME_MessageConverter);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// For everything else, just write to the tapefs.
|
|
|
|
NET_RegisterContentTypeConverter( "*", FO_EDT_SAVE_IMAGE,
|
|
|
|
NULL, edt_MakeFileSaveStream );
|
|
|
|
//// Why is this duplicated? hardts
|
|
|
|
#if defined(XP_WIN) || defined(XP_OS2)
|
|
|
|
NET_RegisterContentTypeConverter( "*", FO_EDT_SAVE_IMAGE,
|
|
|
|
NULL, edt_MakeFileSaveStream );
|
|
|
|
#else
|
|
|
|
NET_RegisterContentTypeConverter( "*", FO_EDT_SAVE_IMAGE,
|
|
|
|
NULL, edt_MakeFileSaveStream );
|
|
|
|
#endif /* XP_WIN */
|
|
|
|
bNetRegistered = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// MUST DISABLE WINDOW INTERACTION HERE!
|
|
|
|
// (It will always be cleared in the GetURLExitRoutine)
|
|
|
|
// (This is normally set TRUE by front end before calling NET_GetURL)
|
|
|
|
m_pContext->waitingMode = TRUE;
|
|
|
|
|
|
|
|
// Set a flag so we know when we are saving a file
|
|
|
|
// (also set in CEditBuffer::SaveFile() - may not be needed here, but its safe to set again)
|
|
|
|
m_pContext->edit_saving_url = TRUE;
|
|
|
|
|
|
|
|
// set base URL for the tape file system.
|
|
|
|
char *pBaseURL = edt_GetDocRelativeBaseURL(m_pContext);
|
|
|
|
if (pBaseURL) {
|
|
|
|
m_tapeFS->SetSourceBaseURL(pBaseURL);
|
|
|
|
XP_FREE(pBaseURL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CFileSaveObject::~CFileSaveObject(){
|
|
|
|
// Success message for publishing. Moved from WinFE to back end.
|
|
|
|
if (m_tapeFS->GetType() == ITapeFileSystem::Publish &&
|
|
|
|
m_status == ED_ERROR_NONE) {
|
|
|
|
char *msg = NULL;
|
|
|
|
// Different message for 1 or multiple files.
|
|
|
|
if (m_tapeFS->GetNumFiles() > 1) {
|
|
|
|
char *tmplate = XP_GetString(XP_EDT_PUBLISH_REPORT_MSG);
|
|
|
|
if (tmplate) {
|
|
|
|
msg = PR_smprintf(tmplate,m_tapeFS->GetNumFiles());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
msg = XP_STRDUP(XP_GetString(XP_EDT_PUBLISH_REPORT_ONE_FILE));
|
|
|
|
}
|
|
|
|
if (msg) {
|
|
|
|
char * pBrowse = NULL, *pPub = NULL, *pLastPub = NULL;
|
|
|
|
PREF_CopyCharPref("editor.publish_browse_location",&pBrowse);
|
|
|
|
PREF_CopyCharPref("editor.publish_location",&pPub);
|
|
|
|
PREF_CopyCharPref("editor.publish_last_loc",&pLastPub);
|
|
|
|
|
|
|
|
#if defined(XP_WIN) || defined(XP_OS2)
|
|
|
|
/* FE_LoadUrl needs to be implemented in X */
|
|
|
|
|
|
|
|
if( EDT_IsSameURL(pPub, pLastPub,0,0) && pBrowse && *pBrowse ){
|
|
|
|
// We just saved to the default home location
|
|
|
|
StrAllocCat(msg, XP_GetString(XP_EDT_BROWSE_TO_DEFAULT));
|
|
|
|
if( FE_Confirm(m_pContext,msg) ){
|
|
|
|
// User said Yes - load location into a BROWSER window (FALSE param)
|
|
|
|
FE_LoadUrl(pBrowse, FALSE );
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
FE_Alert(m_pContext,msg);
|
|
|
|
}
|
|
|
|
XP_FREEIF(pBrowse);
|
|
|
|
XP_FREEIF(pPub);
|
|
|
|
#else
|
|
|
|
// mac and unix
|
|
|
|
FE_Message(m_pContext,msg);
|
|
|
|
#endif
|
|
|
|
XP_FREE(msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// LOU: What should I do here. There appear to be connections on the
|
|
|
|
// window that are still open....
|
|
|
|
if( NET_AreThereActiveConnectionsForWindow( m_pContext ) ){
|
|
|
|
//XP_ASSERT(FALSE);
|
|
|
|
//NET_SilentInterruptWindow( m_pContext );
|
|
|
|
XP_TRACE(("NET_AreThereActiveConnectionsForWindow is TRUE in ~CFileSaveObject"));
|
|
|
|
}
|
|
|
|
|
|
|
|
////XP_FREE( m_pDestPathURL );
|
|
|
|
|
|
|
|
// Allow front end interaction
|
|
|
|
m_pContext->waitingMode = FALSE;
|
|
|
|
// Clear flag (also done in CEditBuffer::FinishedLoad2)
|
|
|
|
m_pContext->edit_saving_url = FALSE;
|
|
|
|
|
|
|
|
#ifdef XP_WIN
|
|
|
|
// Tell front end we finished autosave
|
|
|
|
// so it can gray the Save toolbar button
|
|
|
|
if( m_bFromAutoSave )
|
|
|
|
FE_UpdateEnableStates(m_pContext);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Tape File system should not be deleted yet.
|
|
|
|
if (m_tapeFS &&
|
|
|
|
m_tapeFS->GetType() == ITapeFileSystem::Publish &&
|
|
|
|
m_status == ED_ERROR_NONE) {
|
|
|
|
// Call publishComplete event.
|
|
|
|
char *pDestURL = m_tapeFS->GetDestAbsURL();
|
|
|
|
EDT_PerformEvent(m_pContext,"publishComplete",pDestURL,TRUE,FALSE,0,0);
|
|
|
|
XP_FREEIF(pDestURL);
|
|
|
|
}
|
|
|
|
|
|
|
|
///// This code will have to change if we implement a "saveComplete" event for
|
|
|
|
///// composer plugins.
|
|
|
|
// Call callback for saving file to temporary location.
|
|
|
|
if (m_tapeFS &&
|
|
|
|
m_tapeFS->GetType() == ITapeFileSystem::File &&
|
|
|
|
m_pSaveToTempData && m_pSaveToTempData->doneFn) {
|
|
|
|
if (m_status == ED_ERROR_NONE) {
|
|
|
|
(*m_pSaveToTempData->doneFn)(m_pSaveToTempData->pFileURL,m_pSaveToTempData->hook);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Failed, pass in NULL as the temporary file name.
|
|
|
|
(*m_pSaveToTempData->doneFn)(NULL,m_pSaveToTempData->hook);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
delete m_pSaveToTempData;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Callback from tape file system.
|
|
|
|
//
|
|
|
|
//** Don't make this function static because it is a friend of CFileSaveObject
|
|
|
|
//** so it must be extern. (at least on MAC)
|
|
|
|
void edt_CFileSaveObjectDone(XP_Bool success,void *arg) {
|
|
|
|
CFileSaveObject *saveObject = (CFileSaveObject *)arg;
|
|
|
|
if (!saveObject) {
|
|
|
|
XP_ASSERT(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!success) {
|
|
|
|
saveObject->m_status = ED_ERROR_TAPEFS_COMPLETION;
|
|
|
|
}
|
|
|
|
// Tape File system should not be deleted yet.
|
|
|
|
delete saveObject;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CFileSaveObject::CopyURLInfo(const URL_Struct *pURL)
|
|
|
|
{
|
|
|
|
XP_ASSERT((m_tapeFS) && (m_iCurFile <= m_tapeFS->GetNumFiles()));
|
|
|
|
|
|
|
|
if ((m_tapeFS) && (m_iCurFile <= m_tapeFS->GetNumFiles()))
|
|
|
|
m_tapeFS->CopyURLInfo(m_iCurFile-1, pURL);
|
|
|
|
}
|
|
|
|
|
|
|
|
ED_FileError CFileSaveObject::FileFetchComplete() {
|
|
|
|
XP_ASSERT(m_tapeFS->GetNumFiles());
|
|
|
|
|
|
|
|
if( !m_bFromAutoSave && // Don't want dialogs from autosave, bug 43878
|
|
|
|
m_tapeFS->GetType() != ITapeFileSystem::MailSend ){ // Suppress dialog for mail send.
|
|
|
|
FE_SaveDialogDestroy( m_pContext, m_status, 0);
|
|
|
|
}
|
|
|
|
if (!m_tapeFS) {
|
|
|
|
XP_ASSERT(0);
|
|
|
|
return ED_ERROR_BLOCKED; // is this the right thing to return?
|
|
|
|
}
|
|
|
|
|
|
|
|
ED_FileError statusResult = m_status;
|
|
|
|
|
|
|
|
m_tapeFS->Complete( m_status == ED_ERROR_NONE,
|
|
|
|
edt_CFileSaveObjectDone, (void *)this );
|
|
|
|
|
|
|
|
// "this" may already be deleted at this point, so we can't just return m_status.
|
|
|
|
return statusResult;
|
|
|
|
}
|
|
|
|
|
|
|
|
ED_FileError CFileSaveObject::SaveFiles(){
|
|
|
|
XP_ASSERT(m_tapeFS && m_tapeFS->GetNumFiles());
|
|
|
|
|
|
|
|
// Next param indicates if we are downloading (FALSE)
|
|
|
|
// or uploading (TRUE), so this can be used for publishing
|
|
|
|
if( !m_bFromAutoSave && // Don't want dialogs from autosave, bug 43878
|
|
|
|
m_tapeFS->GetType() != ITapeFileSystem::MailSend ){ // Suppress dialog for mail send.
|
|
|
|
ED_SaveDialogType saveType;
|
|
|
|
switch (m_tapeFS->GetType()) {
|
|
|
|
case ITapeFileSystem::File:
|
|
|
|
saveType = ED_SAVE_DLG_SAVE_LOCAL;
|
|
|
|
break;
|
|
|
|
case ITapeFileSystem::Publish:
|
|
|
|
saveType = ED_SAVE_DLG_PREPARE_PUBLISH;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
XP_ASSERT(0);
|
|
|
|
}
|
|
|
|
FE_SaveDialogCreate( m_pContext, m_tapeFS->GetNumFiles(), saveType );
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SaveFirstFile()) {
|
|
|
|
// Child of CFileSaveObject took care of the first file.
|
|
|
|
m_iCurFile++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// loop through the tree getting all the image elements...
|
|
|
|
return FetchNextFile();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Just a wrapper around the Tape File System.
|
|
|
|
intn CFileSaveObject::AddFile( char *pSrcURL, char *pMIMEType, int16 iDocCharSetID){
|
|
|
|
XP_ASSERT(m_tapeFS);
|
|
|
|
return m_tapeFS->AddFile(pSrcURL,pMIMEType,iDocCharSetID);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// open the file and get the Netlib to fetch it from the cache.
|
|
|
|
//
|
|
|
|
ED_FileError CFileSaveObject::FetchNextFile(){
|
|
|
|
XP_ASSERT(m_tapeFS);
|
|
|
|
|
|
|
|
if( m_status != ED_ERROR_NONE || m_iCurFile >= m_tapeFS->GetNumFiles() ){
|
|
|
|
return FileFetchComplete();
|
|
|
|
}
|
|
|
|
// m_iCurFile is 1-based, so i is 0-based.
|
|
|
|
int i = m_iCurFile++;
|
|
|
|
|
|
|
|
char *srcURL = m_tapeFS->GetSourceURL(i);
|
|
|
|
if (!srcURL) {
|
|
|
|
XP_ASSERT(0);
|
|
|
|
return ED_ERROR_FILE_READ;
|
|
|
|
}
|
|
|
|
URL_Struct *pUrl;
|
|
|
|
pUrl= NET_CreateURLStruct( srcURL, NET_DONT_RELOAD );
|
|
|
|
if (!pUrl) {
|
|
|
|
XP_ASSERT(0);
|
|
|
|
XP_FREE(srcURL);
|
|
|
|
return ED_ERROR_FILE_READ;
|
|
|
|
}
|
|
|
|
XP_FREE(srcURL);
|
|
|
|
// Store file save object so we can access OpenOutputFile etc.
|
|
|
|
pUrl->fe_data = this;
|
1998-07-30 06:30:35 +04:00
|
|
|
|
1998-07-21 05:59:47 +04:00
|
|
|
//TODO: Should we be setting the referer field as well?
|
1998-03-28 05:44:41 +03:00
|
|
|
NET_GetURL( pUrl, FO_EDT_SAVE_IMAGE, m_pContext, edt_UrlExit );
|
|
|
|
return m_status;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CFileSaveObject::CheckFinishedSave(intn oneBased,ED_FileError iError) // one-based index.
|
|
|
|
{
|
|
|
|
if (m_tapeFS->IsLocalPersistentFile(oneBased - 1)) {
|
|
|
|
char *pAbsURL = GetDestAbsoluteURL(oneBased - 1);
|
|
|
|
if (pAbsURL) {
|
|
|
|
// Tell the front end that a new local file has been created.
|
|
|
|
// We use number to tell between Main image (1) and Low-Res image (2)
|
|
|
|
FE_FinishedSave( m_pContext, iError, pAbsURL, oneBased );
|
|
|
|
XP_FREE(pAbsURL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-07-24 08:14:39 +04:00
|
|
|
void CFileSaveObject::NetFetchDone( int status ){
|
1998-03-28 05:44:41 +03:00
|
|
|
// close the file in any case.
|
|
|
|
if( m_pOutStream ){
|
|
|
|
m_tapeFS->CloseStream(m_iCurFile-1);
|
|
|
|
m_pOutStream = 0;
|
|
|
|
}
|
|
|
|
// Default: No error, show destination name for most errors
|
|
|
|
ED_FileError iError = ED_ERROR_NONE;
|
|
|
|
|
|
|
|
// NOTE: This is the NETLIB error code: (see merrors.h)
|
|
|
|
// < 0 is an error
|
|
|
|
if( status < 0 ){
|
|
|
|
// As we become familiar with typical errors,
|
|
|
|
// add specialized error types here
|
|
|
|
// Use " extern MK_..." to access the error value
|
|
|
|
if( status == MK_UNABLE_TO_LOCATE_FILE ||
|
|
|
|
status == MK_MALFORMED_URL_ERROR ) {
|
|
|
|
// Couldn't find source -- use source filename
|
|
|
|
// for error report
|
|
|
|
iError = ED_ERROR_SRC_NOT_FOUND;
|
|
|
|
} else if( m_bDontOverwrite ) {
|
|
|
|
// We get status = MK_UNABLE_TO_CONVERT
|
|
|
|
// if user said NO to overwriting an existing file:
|
|
|
|
// edt_MakeFileSaveStream returns 0,
|
|
|
|
// making NET_GetURL think it failed,
|
|
|
|
// but its not really an error
|
|
|
|
iError = ED_ERROR_NONE;
|
|
|
|
} else if( m_status == ED_ERROR_CANCEL ) {
|
|
|
|
// User selected CANCEL at overwrite warning dialog,
|
|
|
|
// thus stream was not created and returns error status,
|
|
|
|
// but its not really an error
|
|
|
|
iError = ED_ERROR_CANCEL;
|
|
|
|
} else {
|
|
|
|
// "Unknown" error default
|
|
|
|
iError = ED_ERROR_FILE_READ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ED_ERROR_FILE_OPEN was already handled in CFileSaveObject::OpenOutputFile()
|
|
|
|
if (!m_bOpenOutputHandledError) {
|
|
|
|
// No longer uses FE_SaveErrorContinueDialog()
|
|
|
|
if (!SaveErrorContinueDialog(iError) ) {
|
|
|
|
Cancel();
|
|
|
|
}
|
|
|
|
CheckFinishedSave(m_iCurFile,iError);
|
|
|
|
}
|
|
|
|
|
|
|
|
FetchNextFile();
|
|
|
|
}
|
|
|
|
|
|
|
|
intn CFileSaveObject::OpenOutputFile(){
|
|
|
|
m_bOpenOutputHandledError = FALSE;
|
|
|
|
|
|
|
|
// Return if we already have an open stream
|
|
|
|
if( m_pOutStream != NULL){
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
// Current number incremented before comming here,
|
|
|
|
// or think of it as 1-based counting
|
|
|
|
int i = m_iCurFile-1;
|
|
|
|
|
|
|
|
XP_Bool bWriteThis = TRUE;
|
|
|
|
char *pHumanName = m_tapeFS->GetHumanName(i);
|
|
|
|
|
|
|
|
// Tell front end the filename even if we are not writing the file
|
|
|
|
//
|
|
|
|
if (!m_bDontOverwriteAll &&
|
|
|
|
!m_bFromAutoSave && // Don't want dialogs from autosave, bug 43878
|
|
|
|
m_tapeFS->GetType() != ITapeFileSystem::MailSend) { // Suppress dialog for mail send.
|
|
|
|
FE_SaveDialogSetFilename( m_pContext, pHumanName );
|
|
|
|
}
|
|
|
|
|
|
|
|
m_bDontOverwrite = m_bDontOverwriteAll;
|
|
|
|
|
|
|
|
if( !m_bOverwriteAll){
|
|
|
|
if( m_tapeFS->FileExists(i) ){
|
|
|
|
// file exists.
|
|
|
|
if( m_bDontOverwriteAll ){
|
|
|
|
bWriteThis = FALSE;
|
|
|
|
CheckFinishedSave(m_iCurFile,ED_ERROR_FILE_EXISTS);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ED_SaveOption e;
|
|
|
|
e = FE_SaveFileExistsDialog( m_pContext, pHumanName);
|
|
|
|
|
|
|
|
switch( e ){
|
|
|
|
case ED_SAVE_OVERWRITE_THIS:
|
|
|
|
break;
|
|
|
|
case ED_SAVE_OVERWRITE_ALL:
|
|
|
|
m_bOverwriteAll = TRUE;
|
|
|
|
break;
|
|
|
|
case ED_SAVE_DONT_OVERWRITE_ALL:
|
|
|
|
m_bDontOverwriteAll = TRUE;
|
|
|
|
// intentionally fall through
|
|
|
|
case ED_SAVE_DONT_OVERWRITE_THIS:
|
|
|
|
// This flag prevents us from reporting
|
|
|
|
// "failed" file stream creation as an error
|
|
|
|
m_bDontOverwrite = TRUE;
|
|
|
|
bWriteThis = FALSE;
|
|
|
|
|
|
|
|
CheckFinishedSave(m_iCurFile,ED_ERROR_FILE_EXISTS);
|
|
|
|
break;
|
|
|
|
case ED_SAVE_CANCEL:
|
|
|
|
Cancel();
|
|
|
|
bWriteThis = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( bWriteThis ){
|
|
|
|
m_pOutStream = m_tapeFS->OpenStream( i );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// We are returning, not doing the save, but not an error condition
|
|
|
|
XP_FREE(pHumanName);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
XP_TRACE(("Opening stream number %d gives %d.", i, (int)m_pOutStream));
|
|
|
|
|
|
|
|
if ( m_pOutStream == NULL ) {
|
|
|
|
// No longer uses FE_SaveErrorContinueDialog()
|
|
|
|
if(!SaveErrorContinueDialog( ED_ERROR_FILE_OPEN ) ){
|
|
|
|
Cancel();
|
|
|
|
}
|
|
|
|
XP_FREE(pHumanName);
|
|
|
|
|
|
|
|
CheckFinishedSave(m_iCurFile,ED_ERROR_FILE_OPEN);
|
|
|
|
|
|
|
|
// So we don't report error twice, once on opening file and once
|
|
|
|
// when netlib is unable to write to it.
|
|
|
|
m_bOpenOutputHandledError = TRUE;
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
XP_FREE(pHumanName);
|
|
|
|
return 0; // success
|
|
|
|
}
|
|
|
|
|
|
|
|
int CFileSaveObject::NetStreamWrite( const char *block, int32 length ){
|
|
|
|
XP_TRACE(("NetStreamWrite: length = %lu", length));
|
|
|
|
XP_ASSERT(m_pOutStream);
|
|
|
|
m_pOutStream->Write((char *)block,length);
|
|
|
|
return m_pOutStream->Status() == IStreamOut::EOS_NoError;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CFileSaveObject::Cancel(){
|
|
|
|
// tell net URL to stop...
|
|
|
|
m_status = ED_ERROR_CANCEL;
|
|
|
|
// Above alone does seem to work! Don't we need this?
|
|
|
|
// NET_InterruptWindow causes a "reentrant interrupt" error message now!
|
|
|
|
NET_SilentInterruptWindow( m_pContext );
|
|
|
|
}
|
|
|
|
|
|
|
|
char *CFileSaveObject::GetDestName( intn index ){
|
|
|
|
if (!m_tapeFS) {
|
|
|
|
XP_ASSERT(0);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return m_tapeFS->GetDestURL(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
char *CFileSaveObject::GetDestAbsoluteURL( intn index ){
|
|
|
|
if (!m_tapeFS) {
|
|
|
|
XP_ASSERT(0);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
char *pDestPathURL = m_tapeFS->GetDestPathURL();
|
|
|
|
char *pDestRelativeURL = m_tapeFS->GetDestURL(index);
|
|
|
|
if (!pDestRelativeURL) {
|
|
|
|
XP_ASSERT(0);
|
|
|
|
XP_FREEIF(pDestPathURL);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Maybe should use NET_MakeAbsolute() instead of concatenation.
|
|
|
|
char *pDestAbsURL = pDestPathURL ?
|
|
|
|
PR_smprintf( "%s%s", pDestPathURL, pDestRelativeURL ) :
|
|
|
|
XP_STRDUP(pDestRelativeURL);
|
|
|
|
XP_FREEIF(pDestPathURL);
|
|
|
|
XP_FREE(pDestRelativeURL);
|
|
|
|
|
|
|
|
return pDestAbsURL;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *CFileSaveObject::GetSrcName( intn index ){
|
|
|
|
if (!m_tapeFS) {
|
|
|
|
XP_ASSERT(0);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return m_tapeFS->GetSourceURL(index);
|
|
|
|
|
|
|
|
/*if( index >= m_srcImageURLs.Size() ){
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return XP_STRDUP( m_srcImageURLs[index] );
|
|
|
|
} */
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert file:// URLs into local file names for display to user.
|
|
|
|
PRIVATE void edt_url_make_human(char **pURL) {
|
|
|
|
if (NET_IsLocalFileURL(*pURL)) {
|
|
|
|
char *pTemp;
|
|
|
|
XP_ConvertUrlToLocalFile(*pURL,&pTemp);
|
|
|
|
XP_FREEIF(*pURL);
|
|
|
|
*pURL = pTemp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
XP_Bool CFileSaveObject::SaveErrorContinueDialog(ED_FileError iError) {
|
|
|
|
// No user interaction for these conditions.
|
|
|
|
if (iError == ED_ERROR_NONE ||
|
|
|
|
iError == ED_ERROR_CANCEL ||
|
|
|
|
iError == ED_ERROR_FILE_EXISTS) {
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *tmplate = NULL;
|
|
|
|
char *msg = NULL;
|
|
|
|
// m_iCurFile is 1-based.
|
|
|
|
char *pAbsDest = GetDestAbsoluteURL(m_iCurFile-1);
|
|
|
|
char *pRelDest = m_tapeFS->GetHumanName(m_iCurFile-1);
|
|
|
|
char *pAbsSrc = GetSrcName(m_iCurFile-1);
|
|
|
|
char *pRootAbsDest = GetDestAbsoluteURL(0);
|
|
|
|
|
|
|
|
edt_url_make_human(&pAbsDest);
|
|
|
|
edt_url_make_human(&pAbsSrc);
|
|
|
|
edt_url_make_human(&pRootAbsDest);
|
|
|
|
|
|
|
|
// Two level switch, first on different types of file systems,
|
|
|
|
// second on different classes of errors.
|
|
|
|
switch (m_tapeFS->GetType()) {
|
|
|
|
case ITapeFileSystem::File:
|
|
|
|
switch (iError) {
|
|
|
|
case ED_ERROR_FILE_OPEN:
|
|
|
|
case ED_ERROR_FILE_WRITE:
|
|
|
|
tmplate = XP_STRDUP(XP_GetString(XP_EDT_ERR_SAVE_FILE_WRITE));
|
|
|
|
StrAllocCat(tmplate,XP_GetString(XP_EDT_ERR_SAVE_CONTINUE));
|
|
|
|
msg = PR_smprintf(tmplate,pRelDest,pRootAbsDest,pRelDest);
|
|
|
|
break;
|
|
|
|
case ED_ERROR_SRC_NOT_FOUND:
|
|
|
|
tmplate = XP_STRDUP(XP_GetString(XP_EDT_ERR_SAVE_SRC_NOT_FOUND));
|
|
|
|
StrAllocCat(tmplate,XP_GetString(XP_EDT_ERR_SAVE_CONTINUE));
|
|
|
|
msg = PR_smprintf(tmplate,pAbsSrc,pAbsSrc);
|
|
|
|
break;
|
|
|
|
case ED_ERROR_FILE_READ:
|
|
|
|
tmplate = XP_STRDUP(XP_GetString(XP_EDT_ERR_SAVE_FILE_READ));
|
|
|
|
StrAllocCat(tmplate,XP_GetString(XP_EDT_ERR_SAVE_CONTINUE));
|
|
|
|
msg = PR_smprintf(tmplate,pRelDest,pRelDest);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ITapeFileSystem::Publish:
|
|
|
|
switch (iError) {
|
|
|
|
case ED_ERROR_FILE_OPEN:
|
|
|
|
case ED_ERROR_FILE_WRITE:
|
|
|
|
tmplate = XP_STRDUP(XP_GetString(XP_EDT_ERR_PUBLISH_FILE_WRITE));
|
|
|
|
StrAllocCat(tmplate,XP_GetString(XP_EDT_ERR_PUBLISH_CONTINUE));
|
|
|
|
msg = PR_smprintf(tmplate,pRelDest,pRelDest);
|
|
|
|
break;
|
|
|
|
case ED_ERROR_SRC_NOT_FOUND:
|
|
|
|
tmplate = XP_STRDUP(XP_GetString(XP_EDT_ERR_PUBLISH_SRC_NOT_FOUND));
|
|
|
|
StrAllocCat(tmplate,XP_GetString(XP_EDT_ERR_PUBLISH_CONTINUE));
|
|
|
|
msg = PR_smprintf(tmplate,pAbsSrc,pAbsSrc);
|
|
|
|
break;
|
|
|
|
case ED_ERROR_FILE_READ:
|
|
|
|
tmplate = XP_STRDUP(XP_GetString(XP_EDT_ERR_PUBLISH_FILE_READ));
|
|
|
|
StrAllocCat(tmplate,XP_GetString(XP_EDT_ERR_PUBLISH_CONTINUE));
|
|
|
|
msg = PR_smprintf(tmplate,pRelDest,pRelDest);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ITapeFileSystem::MailSend:
|
|
|
|
switch (iError) {
|
|
|
|
case ED_ERROR_FILE_OPEN:
|
|
|
|
case ED_ERROR_FILE_WRITE:
|
|
|
|
tmplate = XP_STRDUP(XP_GetString(XP_EDT_ERR_MAIL_FILE_WRITE));
|
|
|
|
StrAllocCat(tmplate,XP_GetString(XP_EDT_ERR_MAIL_CONTINUE));
|
|
|
|
msg = PR_smprintf(tmplate,pRelDest,pRelDest);
|
|
|
|
break;
|
|
|
|
case ED_ERROR_SRC_NOT_FOUND:
|
|
|
|
tmplate = XP_STRDUP(XP_GetString(XP_EDT_ERR_MAIL_SRC_NOT_FOUND));
|
|
|
|
StrAllocCat(tmplate,XP_GetString(XP_EDT_ERR_MAIL_CONTINUE));
|
|
|
|
msg = PR_smprintf(tmplate,pAbsSrc,pAbsSrc);
|
|
|
|
break;
|
|
|
|
case ED_ERROR_FILE_READ:
|
|
|
|
tmplate = XP_STRDUP(XP_GetString(XP_EDT_ERR_MAIL_FILE_READ));
|
|
|
|
StrAllocCat(tmplate,XP_GetString(XP_EDT_ERR_MAIL_CONTINUE));
|
|
|
|
msg = PR_smprintf(tmplate,pRelDest,pRelDest);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
XP_Bool retVal = FALSE;
|
|
|
|
if (msg) {
|
|
|
|
retVal = FE_Confirm(m_pContext,msg);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
XP_ASSERT(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
XP_FREEIF(tmplate);
|
|
|
|
XP_FREEIF(msg);
|
|
|
|
XP_FREEIF(pAbsDest);
|
|
|
|
XP_FREEIF(pRelDest);
|
|
|
|
XP_FREEIF(pAbsSrc);
|
|
|
|
XP_FREEIF(pRootAbsDest);
|
|
|
|
|
|
|
|
return retVal;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char * CEditSaveObject::m_pFailedPublishUrl = NULL;
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// CEditSaveObject
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
CEditSaveObject::CEditSaveObject( CEditBuffer *pBuffer,
|
|
|
|
ED_SaveFinishedOption finishedOpt,
|
|
|
|
char *pSrcURL,
|
|
|
|
ITapeFileSystem *tapeFS,
|
|
|
|
XP_Bool, // bSaveAs is ignored.
|
|
|
|
XP_Bool bKeepImagesWithDoc,
|
|
|
|
XP_Bool bAutoAdjustLinks,
|
|
|
|
XP_Bool bAutoSave,
|
|
|
|
CEditSaveToTempData *pSaveToTempData ) :
|
1998-07-24 08:14:39 +04:00
|
|
|
CFileSaveObject( pBuffer->m_pContext,tapeFS,bAutoSave, pSaveToTempData ),
|
1998-03-28 05:44:41 +03:00
|
|
|
m_pBuffer( pBuffer ),
|
|
|
|
m_pDocStateSave( 0 ),
|
|
|
|
m_pSrcURL( XP_STRDUP( pSrcURL ) ),
|
|
|
|
m_finishedOpt( finishedOpt ),
|
|
|
|
m_bKeepImagesWithDoc( bKeepImagesWithDoc ),
|
|
|
|
m_bAutoAdjustLinks( bAutoAdjustLinks ),
|
1998-06-21 23:03:10 +04:00
|
|
|
m_backgroundIndex(IgnoreImage) {
|
1998-03-28 05:44:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
CEditSaveObject::~CEditSaveObject(){
|
|
|
|
XP_Bool bRevertBuffer = FALSE;
|
|
|
|
XP_Bool bRelayout = FALSE;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* possible values for m_finishedOpt:
|
|
|
|
* ED_FINISHED_GOTO_NEW, Point the editor to the location of the
|
|
|
|
* newly saved document if successful, otherwise revert buffer.
|
|
|
|
* ED_FINISHED_REVERT_BUFFER, Revert the buffer to the state before
|
|
|
|
* the save operation began, regardless.
|
|
|
|
* ED_FINISHED_SAVE_DRAFT Like ED_FINISHED_REVERT_BUFFER, except clears the dirty flag
|
|
|
|
* on success.
|
|
|
|
* ED_FINISHED_MAIL_SEND If we succeed we're going to throw the buffer
|
|
|
|
* away, so don't revert it, but don't bother gotoNew.
|
|
|
|
* If failure, revert the buffer.
|
|
|
|
* Used for mail compose, we don't
|
|
|
|
* want the editor to start any operation that
|
|
|
|
* causes problems when libmsg destroys the editor
|
|
|
|
* context.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
if ( m_finishedOpt == ED_FINISHED_GOTO_NEW && m_status == ED_ERROR_NONE )
|
|
|
|
{
|
|
|
|
//// Go to new location.
|
|
|
|
|
|
|
|
m_pBuffer->m_pContext->is_new_document = FALSE;
|
|
|
|
|
|
|
|
// Set the document title and history entry to the new location.
|
|
|
|
|
|
|
|
char *pDestFileURL = GetDestAbsoluteURL(0);
|
|
|
|
if ( !pDestFileURL )
|
|
|
|
{
|
|
|
|
XP_ASSERT( 0 );
|
|
|
|
m_status = ED_ERROR_FILE_WRITE; // Not really the right thing to set.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// We used to do the ftp://username@path here, but it's moved to earlier in
|
|
|
|
// the save process, in EDT_PublishFile.
|
|
|
|
|
|
|
|
// Set this first - FE_SetDocTitle will get URL from it
|
|
|
|
LO_SetBaseURL( m_pBuffer->m_pContext, pDestFileURL );
|
|
|
|
History_entry * hist_ent =
|
|
|
|
SHIST_GetCurrent(&(m_pBuffer->m_pContext->hist));
|
|
|
|
char * pTitle = NULL;
|
|
|
|
if(hist_ent)
|
|
|
|
{
|
|
|
|
if ( hist_ent->title && XP_STRLEN(hist_ent->title) > 0 ){
|
|
|
|
// Note: hist_ent->title should always = m_pContext->title?
|
|
|
|
// Change "file:///Untitled" into URL
|
|
|
|
// Use the new address if old title == old address
|
|
|
|
if( 0 != XP_STRCMP(hist_ent->title, XP_GetString(XP_EDIT_NEW_DOC_NAME) ) &&
|
|
|
|
0 != XP_STRCMP(hist_ent->title, hist_ent->address) )
|
|
|
|
{
|
|
|
|
pTitle = XP_STRDUP(hist_ent->title);
|
|
|
|
} else {
|
|
|
|
pTitle = XP_STRDUP(pDestFileURL);
|
|
|
|
XP_FREE(hist_ent->title);
|
|
|
|
hist_ent->title = XP_STRDUP(pDestFileURL);
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// Use the URL if no Document title
|
|
|
|
pTitle = XP_STRDUP(pDestFileURL);
|
|
|
|
XP_FREEIF(hist_ent->title);
|
|
|
|
hist_ent->title = XP_STRDUP(pDestFileURL);
|
|
|
|
}
|
|
|
|
// Test if new URL is same as current before we replace the latter
|
|
|
|
XP_Bool bSameURL = EDT_IsSameURL( hist_ent->address, pDestFileURL, NULL, NULL);
|
|
|
|
|
|
|
|
// Set history entry address to new URL
|
|
|
|
XP_FREEIF(hist_ent->address);
|
|
|
|
hist_ent->address = XP_STRDUP(pDestFileURL);
|
|
|
|
|
|
|
|
// We may inherit this URL (used for faster reloading in browser)
|
|
|
|
// when saving a remote URL to local disk,
|
|
|
|
// so always clear it since Editor never uses it.
|
|
|
|
XP_FREEIF(hist_ent->wysiwyg_url);
|
|
|
|
|
|
|
|
// This changes doc title, window caption, history title,
|
|
|
|
/// but not history address
|
|
|
|
if (pTitle)
|
|
|
|
{
|
|
|
|
FE_SetDocTitle(m_pBuffer->m_pContext, pTitle);
|
|
|
|
XP_FREE(pTitle);
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !bSameURL )
|
|
|
|
{
|
|
|
|
// Make the new URL (now in current history entry)
|
|
|
|
// as the most-recently-used URL in prefs. list
|
|
|
|
// (Note: We should never be here in mail message composer)
|
|
|
|
EDT_SyncEditHistory(m_pBuffer->m_pContext);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // if (hist_ent)
|
|
|
|
XP_FREE(pDestFileURL);
|
|
|
|
|
|
|
|
// Saved successfully.
|
|
|
|
m_pBuffer->DocumentStored();
|
|
|
|
|
|
|
|
// This flag must be cleared before GetFileWriteTime,
|
|
|
|
// else the write time will not be recorded
|
|
|
|
m_pContext->edit_saving_url = FALSE;
|
|
|
|
// Get the current file time
|
|
|
|
m_pBuffer->GetFileWriteTime();
|
|
|
|
// Some of the links may have changed, so relayout
|
|
|
|
bRelayout = TRUE;
|
|
|
|
}
|
|
|
|
else if ( m_finishedOpt == ED_FINISHED_MAIL_SEND && m_status == ED_ERROR_NONE )
|
|
|
|
{
|
|
|
|
//// Do nothing.
|
|
|
|
// Don't relayout, we're throwing the buffer away.
|
|
|
|
}
|
|
|
|
else if (m_pDocStateSave) {
|
|
|
|
//// Don't go to the new document, revert to m_pDocStateSave.
|
|
|
|
bRevertBuffer = TRUE;
|
|
|
|
// Don't relayout, reverting the buffer will take care of it.
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( m_finishedOpt == ED_FINISHED_SAVE_DRAFT && m_status == ED_ERROR_NONE )
|
|
|
|
{
|
|
|
|
// Note that we are still reverting the buffer.
|
|
|
|
|
|
|
|
// Saved successfully.
|
|
|
|
m_pBuffer->DocumentStored();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Originally, this was only called if m_status == ED_ERROR_NONE.
|
|
|
|
m_pBuffer->FileFetchComplete(m_status);
|
|
|
|
if (bRelayout)
|
|
|
|
{
|
|
|
|
// Don't always relayout because we may have "cid:" links which cause an error.
|
|
|
|
// reverting the buffer will take care of it.
|
|
|
|
m_pBuffer->RefreshLayout();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Already cleared above if ED_FINISHED_GOTO_NEW and success,
|
|
|
|
// but it must be cleared eventually in all cases.
|
|
|
|
m_pContext->edit_saving_url = FALSE;
|
|
|
|
|
|
|
|
m_pBuffer->m_pSaveObject = 0;
|
|
|
|
|
|
|
|
if (bRevertBuffer) {
|
|
|
|
// Must be after CEditBuffer::FileFetchComplete(), because it deletes CEditBuffer.
|
|
|
|
m_pBuffer->RestoreState(m_pDocStateSave);
|
|
|
|
}
|
|
|
|
|
|
|
|
if( m_tapeFS->GetType() == ITapeFileSystem::Publish ){
|
|
|
|
XP_FREEIF(m_pFailedPublishUrl);
|
|
|
|
|
|
|
|
if( m_status == ED_ERROR_NONE ){
|
|
|
|
// Save the last-used location into the history list
|
|
|
|
EDT_SyncPublishingHistory();
|
|
|
|
} else {
|
|
|
|
// Save this URL so we can supply the "bad" location
|
|
|
|
// to user if they try to publish that URL again
|
|
|
|
m_pFailedPublishUrl = XP_STRDUP(m_pSrcURL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
XP_FREE( m_pSrcURL );
|
|
|
|
|
|
|
|
delete m_pDocStateSave;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add all images in document that are also in ppIncludedFiles.
|
|
|
|
//
|
|
|
|
// If ppIncludedFiles is NULL, this should add exactly those files that would be returned by
|
|
|
|
// CEditBuffer::GetAllDocumentFiles() with the selected flag set TRUE.
|
|
|
|
// i.e. Regular Saving should save exactly those files that are published by default in remote publishing.
|
|
|
|
XP_Bool CEditSaveObject::AddAllFiles(char **ppIncludedFiles){
|
|
|
|
//////// WARNING: if you change this function, fix CEditBuffer::GetAllDocumentFiles and CEditSaveObject::FixupLinks() also.
|
|
|
|
EDT_ImageData *pData;
|
|
|
|
EDT_PageData *pPageData;
|
|
|
|
|
|
|
|
// Make sure all URLs in ppIncludedFiles are absolute
|
|
|
|
if (ppIncludedFiles) {
|
|
|
|
char **ppFile = ppIncludedFiles;
|
|
|
|
while (*ppFile) {
|
|
|
|
char *pAbs = NET_MakeAbsoluteURL(m_pSrcURL,*ppFile);
|
|
|
|
if (pAbs) {
|
|
|
|
// If making *ppFile absolute changed it, replace it with absolute URL.
|
|
|
|
if (XP_STRCMP(pAbs,*ppFile)) {
|
|
|
|
XP_FREE(*ppFile);
|
|
|
|
*ppFile = pAbs;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
XP_FREE(pAbs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ppFile++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add actual HTML document.
|
|
|
|
intn firstIndex = AddFile(m_pSrcURL,TEXT_HTML,m_pBuffer->GetDocCharSetID());
|
|
|
|
if (firstIndex != 0) {
|
|
|
|
m_status = ED_ERROR_BAD_URL;
|
|
|
|
FreeList(ppIncludedFiles);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CEditElement *pImage = m_pBuffer->m_pRoot->FindNextElement(
|
|
|
|
&CEditElement::FindImage, 0 );
|
|
|
|
|
|
|
|
// If there is a background Image, make it the first image.
|
|
|
|
pPageData = m_pBuffer->GetPageData();
|
|
|
|
if( pPageData ) {
|
|
|
|
if ( pPageData->pBackgroundImage && *pPageData->pBackgroundImage){
|
|
|
|
m_backgroundIndex = CheckAddFile( pPageData->pBackgroundImage, NULL, ppIncludedFiles,
|
|
|
|
m_bKeepImagesWithDoc && !pPageData->bBackgroundNoSave );
|
|
|
|
}
|
1998-06-21 23:03:10 +04:00
|
|
|
// We now support > 1 FontDefURL per page
|
|
|
|
int iFontDefCount = m_pBuffer->m_FontDefURL.Size();
|
|
|
|
for( int i = 0; i < iFontDefCount; i++ )
|
|
|
|
{
|
|
|
|
intn iIndex = CheckAddFile( m_pBuffer->m_FontDefURL[i], NULL, ppIncludedFiles,
|
|
|
|
m_bKeepImagesWithDoc && !m_pBuffer->m_FontDefNoSave[i] );
|
|
|
|
m_FontDefIndex.Add(iIndex);
|
|
|
|
}
|
|
|
|
#if 0
|
1998-03-28 05:44:41 +03:00
|
|
|
if ( pPageData->pFontDefURL && *pPageData->pFontDefURL ){
|
|
|
|
m_fontDefIndex = CheckAddFile( pPageData->pFontDefURL, NULL, ppIncludedFiles,
|
|
|
|
m_bKeepImagesWithDoc && !pPageData->bFontDefNoSave );
|
|
|
|
}
|
1998-06-21 23:03:10 +04:00
|
|
|
#endif
|
1998-03-28 05:44:41 +03:00
|
|
|
}
|
|
|
|
m_pBuffer->FreePageData( pPageData );
|
|
|
|
|
1998-07-02 05:20:39 +04:00
|
|
|
while( pImage )
|
|
|
|
{
|
1998-03-28 05:44:41 +03:00
|
|
|
// If this assert fails, it is probably because FinishedLoad
|
|
|
|
// didn't get called on the image. And that's probably because
|
|
|
|
// of some bug in the recursive FinishedLoad code.
|
|
|
|
// If the size isn't known, the relayout after the save will block,
|
|
|
|
// and the fourth .. nth images in the document will get zero size.
|
|
|
|
// XP_ASSERT(pImage->Image()->SizeIsKnown());
|
|
|
|
pImage->Image()->m_iSaveIndex = IgnoreImage;
|
|
|
|
pImage->Image()->m_iSaveLowIndex = IgnoreImage;
|
|
|
|
pData = pImage->Image()->GetImageData();
|
1998-07-02 05:20:39 +04:00
|
|
|
if( pData )
|
|
|
|
{
|
|
|
|
// Only consider images that are not server-generated
|
|
|
|
if( EDT_IsImageURL(pData->pSrc) )
|
|
|
|
{
|
|
|
|
pImage->Image()->m_iSaveIndex = CheckAddFile( pData->pSrc, NULL, ppIncludedFiles,
|
|
|
|
m_bKeepImagesWithDoc && !pData->bNoSave );
|
|
|
|
}
|
|
|
|
if( EDT_IsImageURL(pData->pLowSrc) )
|
|
|
|
{
|
|
|
|
pImage->Image()->m_iSaveLowIndex = CheckAddFile( pData->pLowSrc, NULL,ppIncludedFiles,
|
|
|
|
m_bKeepImagesWithDoc && !pData->bNoSave );
|
|
|
|
}
|
|
|
|
edt_FreeImageData( pData );
|
1998-03-28 05:44:41 +03:00
|
|
|
}
|
|
|
|
pImage = pImage->FindNextElement( &CEditElement::FindImage, 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//// Sure would be nice to abstract all the different types of table
|
|
|
|
//// backgrounds.
|
|
|
|
// table backgrounds <table>
|
|
|
|
CEditElement *pNext = m_pBuffer->m_pRoot;
|
|
|
|
while(NULL != (pNext = pNext->FindNextElement( &CEditElement::FindTable, 0 )) ){
|
|
|
|
EDT_TableData *pData = ((CEditTableElement *)pNext)->GetData();
|
|
|
|
if (pData) {
|
|
|
|
if ( pData->pBackgroundImage && *pData->pBackgroundImage) {
|
|
|
|
((CEditTableElement *)pNext)->m_iBackgroundSaveIndex = CheckAddFile( pData->pBackgroundImage, NULL, ppIncludedFiles,
|
|
|
|
m_bKeepImagesWithDoc && !pData->bBackgroundNoSave);
|
|
|
|
}
|
|
|
|
CEditTableElement::FreeData(pData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// table row backgrounds <tr>
|
|
|
|
pNext = m_pBuffer->m_pRoot;
|
|
|
|
while(NULL != (pNext = pNext->FindNextElement( &CEditElement::FindTableRow, 0 )) ){
|
|
|
|
EDT_TableRowData *pData = ((CEditTableRowElement *)pNext)->GetData();
|
|
|
|
if (pData) {
|
|
|
|
if ( pData->pBackgroundImage && *pData->pBackgroundImage) {
|
|
|
|
((CEditTableRowElement *)pNext)->m_iBackgroundSaveIndex = CheckAddFile( pData->pBackgroundImage, NULL, ppIncludedFiles,
|
|
|
|
m_bKeepImagesWithDoc && !pData->bBackgroundNoSave);
|
|
|
|
}
|
|
|
|
CEditTableRowElement::FreeData(pData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// table cell backgrounds <td> <th>
|
|
|
|
pNext = m_pBuffer->m_pRoot;
|
|
|
|
while(NULL != (pNext = pNext->FindNextElement( &CEditElement::FindTableCell, 0 )) ){
|
|
|
|
EDT_TableCellData *pData = ((CEditTableCellElement *)pNext)->GetData(0);
|
|
|
|
if (pData) {
|
|
|
|
if ( pData->pBackgroundImage && *pData->pBackgroundImage) {
|
|
|
|
((CEditTableCellElement *)pNext)->m_iBackgroundSaveIndex = CheckAddFile( pData->pBackgroundImage, NULL, ppIncludedFiles,
|
|
|
|
m_bKeepImagesWithDoc && !pData->bBackgroundNoSave);
|
|
|
|
}
|
|
|
|
CEditTableCellElement::FreeData(pData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// UnknownHTML tags with LOCALDATA attribute.
|
|
|
|
pNext = m_pBuffer->m_pRoot;
|
|
|
|
if ( pNext ) {
|
|
|
|
while(NULL != (pNext = pNext->FindNextElement( &CEditElement::FindUnknownHTML, 0 )) ){
|
|
|
|
CEditIconElement *pIcon = CEditIconElement::Cast(pNext);
|
|
|
|
if (pIcon) {
|
|
|
|
char **pMimeTypes;
|
|
|
|
char **pURLs;
|
|
|
|
int count = pIcon->ParseLocalData(&pMimeTypes,&pURLs);
|
|
|
|
|
|
|
|
// Remember indices into save object.
|
|
|
|
if (count) {
|
|
|
|
XP_FREEIF(pIcon->m_piSaveIndices);
|
|
|
|
// allocate memory.
|
|
|
|
pIcon->m_piSaveIndices = new intn[count];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Maybe should make a check that pURLs[n] is a relative URL
|
|
|
|
// in current directory.
|
|
|
|
for (int n = 0; n < count; n++) {
|
|
|
|
pIcon->m_piSaveIndices[n] = CheckAddFile(pURLs[n],pMimeTypes[n],ppIncludedFiles,TRUE);
|
|
|
|
}
|
|
|
|
CEditIconElement::FreeLocalDataLists(pMimeTypes,pURLs,count);
|
|
|
|
}
|
|
|
|
} // while
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Go through ppIncludedFiles once more to add anything we missed.
|
|
|
|
//
|
|
|
|
// This is for the "add all files in directory" button in publishing,
|
|
|
|
// here ppIncludedFiles may contain files that CEditSaveObject knows
|
|
|
|
// nothing about.
|
|
|
|
//
|
|
|
|
// Doesn't hurt to add files twice to tape file system, it'll just
|
|
|
|
// return the previous index.
|
|
|
|
if (ppIncludedFiles) {
|
|
|
|
char **pFile = ppIncludedFiles;
|
|
|
|
while (*pFile) {
|
|
|
|
// Ignore returned index, we're not going to update any links here.
|
|
|
|
AddFile(*pFile,NULL,m_pBuffer->GetDocCharSetID());
|
|
|
|
pFile++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FreeList(ppIncludedFiles);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the URL that should be used as the base for relative URLs in
|
|
|
|
// the document. Similar to just calling LO_GetBaseURL(), except returns
|
|
|
|
// the document temp directory for untitled documents.
|
|
|
|
// Must free returned memory.
|
|
|
|
char *edt_GetDocRelativeBaseURL(MWContext *pContext) {
|
|
|
|
char *pDocURL = NULL;
|
|
|
|
|
|
|
|
// Interpret URLs relative to temp directory if a new document.
|
|
|
|
if (EDT_IS_NEW_DOCUMENT(pContext)) {
|
|
|
|
char *pxpURL = EDT_GetDocTempDir(pContext);
|
|
|
|
if (!pxpURL) {
|
|
|
|
return pDocURL;
|
|
|
|
}
|
|
|
|
// prepend "file://" to make a URL.
|
|
|
|
StrAllocCat(pDocURL,"file://");
|
|
|
|
StrAllocCat(pDocURL,pxpURL);
|
|
|
|
XP_FREE(pxpURL);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
pDocURL = edt_StrDup(LO_GetBaseURL(pContext));
|
|
|
|
}
|
|
|
|
return pDocURL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Mostly a wrapper for CFileSaveObject::AddFile, except deals with adjusting links.
|
|
|
|
//
|
|
|
|
// Analogous to AddToBufferUnique() in edtbuf.cpp
|
|
|
|
intn CEditSaveObject::CheckAddFile( char *pSrc, char *pMIMEType,
|
|
|
|
char **ppIncludedFiles, XP_Bool bSaveDefault ){
|
|
|
|
intn retVal = IgnoreImage;
|
|
|
|
if( EDT_IS_LIVEWIRE_MACRO( pSrc ) ){
|
|
|
|
return IgnoreImage;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *pDocURL = edt_GetDocRelativeBaseURL(m_pContext);
|
|
|
|
if (!pDocURL) {
|
|
|
|
return IgnoreImage;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *pAbsoluteSrc = NET_MakeAbsoluteURL(pDocURL,pSrc);
|
|
|
|
XP_FREE(pDocURL);
|
|
|
|
if (!pAbsoluteSrc) {
|
|
|
|
return IgnoreImage;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If ppIncludedFiles is passed in, use it to decide whether to add file.
|
|
|
|
// Otherwise, use bSaveDefault to decide.
|
|
|
|
XP_Bool saveMe;
|
|
|
|
if (ppIncludedFiles) {
|
|
|
|
saveMe = URLInList(ppIncludedFiles,pAbsoluteSrc);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
saveMe = bSaveDefault;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (saveMe) {
|
|
|
|
retVal = AddFile(pSrc,pMIMEType,m_pBuffer->GetDocCharSetID());
|
|
|
|
if (retVal == ITapeFileSystem::Error || retVal == ITapeFileSystem::SourceDestSame) {
|
|
|
|
// couldn't make a good local name, so try to fix it.
|
|
|
|
retVal = AttemptAdjust;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( m_bAutoAdjustLinks ) {
|
|
|
|
retVal = AttemptAdjust;
|
|
|
|
}
|
|
|
|
|
|
|
|
XP_FREE(pAbsoluteSrc);
|
|
|
|
return retVal;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CEditSaveObject::FreeList(char **ppList) {
|
|
|
|
if (!ppList)
|
|
|
|
return;
|
|
|
|
|
|
|
|
int n = 0;
|
|
|
|
while (ppList[n]) {
|
|
|
|
XP_FREE(ppList[n]);
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
|
|
|
|
XP_FREE(ppList);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ppList and pURL must be absolute URLs.
|
|
|
|
XP_Bool CEditSaveObject::URLInList(char **ppList, char *pURL ) {
|
|
|
|
for (int n = 0; ppList[n]; n++) {
|
|
|
|
if (EDT_IsSameURL(ppList[n],pURL,NULL,NULL))
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Should be called no matter what, even if error or cancel occurs.
|
|
|
|
ED_FileError CEditSaveObject::FileFetchComplete(){
|
|
|
|
XP_ASSERT(XP_IsContextInList(m_pBuffer->m_pContext));
|
|
|
|
|
|
|
|
return CFileSaveObject::FileFetchComplete();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Always return TRUE.
|
|
|
|
XP_Bool CEditSaveObject::SaveFirstFile() {
|
|
|
|
if ( m_status != ED_ERROR_NONE ) {
|
|
|
|
XP_ASSERT(0);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
XP_ASSERT(!m_pDocStateSave);
|
|
|
|
m_pDocStateSave = m_pBuffer->RecordState();
|
|
|
|
|
|
|
|
char *pBadLinks = FixupLinks();
|
|
|
|
PRBool needEncrypt = EDT_EncryptState( m_pContext );
|
|
|
|
|
|
|
|
// Tell user some links may be broken by this operation, give choice
|
|
|
|
// of continuing or not.
|
|
|
|
if (pBadLinks) {
|
|
|
|
XP_Bool bCancel = FALSE;
|
|
|
|
char *tmplate = XP_GetString(XP_EDT_BREAKING_LINKS);
|
|
|
|
char *msg = NULL;
|
|
|
|
if (tmplate) {
|
|
|
|
msg = PR_smprintf(tmplate,pBadLinks);
|
|
|
|
bCancel = !FE_Confirm(m_pContext,msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
XP_FREEIF(msg);
|
|
|
|
XP_FREEIF(pBadLinks);
|
|
|
|
if (bCancel) {
|
|
|
|
Cancel();
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write root HTML document
|
|
|
|
char *pHumanName = m_tapeFS->GetHumanName(0);
|
|
|
|
if (pHumanName == NULL) {
|
|
|
|
XP_ASSERT(0);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tell front end the filename.
|
|
|
|
if( !m_bFromAutoSave && // Don't want dialogs from autosave, bug 43878
|
|
|
|
m_tapeFS->GetType() != ITapeFileSystem::MailSend ){// Suppress dialog for mail send.
|
|
|
|
FE_SaveDialogSetFilename( m_pContext, pHumanName );
|
|
|
|
}
|
|
|
|
|
|
|
|
IStreamOut *out = NULL;
|
|
|
|
URL_Struct *URL_s = NULL;
|
|
|
|
|
|
|
|
if (needEncrypt) {
|
|
|
|
// by the time the file gets to the tapeFS, it will be binary.
|
|
|
|
m_tapeFS->SetFirstBinary();
|
|
|
|
out = new CNetStreamToTapeFS(m_pContext,m_tapeFS);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
out = m_tapeFS->OpenStream(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (out == NULL) {
|
|
|
|
m_status = ED_ERROR_FILE_OPEN;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
m_pBuffer->WriteToStream( out );
|
|
|
|
if ( out->Status() != IStreamOut::EOS_NoError ) {
|
|
|
|
m_status = ED_ERROR_FILE_WRITE;
|
|
|
|
}
|
|
|
|
if (!needEncrypt) {
|
|
|
|
m_tapeFS->CloseStream(0);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
delete out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( m_status != ED_ERROR_NONE ){
|
|
|
|
char *tmplate = NULL;
|
|
|
|
char *msg = NULL;
|
|
|
|
char *pAbsDest = GetDestAbsoluteURL(0);
|
|
|
|
char *pAbsSrc = GetSrcName(0);
|
|
|
|
edt_url_make_human(&pAbsDest);
|
|
|
|
edt_url_make_human(&pAbsSrc);
|
|
|
|
|
|
|
|
switch (m_tapeFS->GetType()) {
|
|
|
|
case ITapeFileSystem::File:
|
|
|
|
tmplate = XP_GetString(XP_EDT_ERR_SAVE_WRITING_ROOT);
|
|
|
|
if (tmplate) {
|
|
|
|
char *pRelDest = m_tapeFS->GetHumanName(0);
|
|
|
|
msg = PR_smprintf(tmplate,pRelDest,pAbsDest);
|
|
|
|
XP_FREEIF(pRelDest);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ITapeFileSystem::Publish:
|
|
|
|
tmplate = XP_GetString(XP_EDT_ERR_PUBLISH_PREPARING_ROOT);
|
|
|
|
if (tmplate) {
|
|
|
|
msg = PR_smprintf(tmplate,pAbsSrc);
|
|
|
|
StrAllocCat(msg,XP_GetString(XP_EDT_ERR_CHECK_DISK));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ITapeFileSystem::MailSend:
|
|
|
|
msg = XP_STRDUP(XP_GetString(XP_EDT_ERR_MAIL_PREPARING_ROOT));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (msg) {
|
|
|
|
FE_Alert(m_pContext,msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
XP_FREEIF(msg);
|
|
|
|
XP_FREEIF(pAbsDest);
|
|
|
|
XP_FREEIF(pAbsSrc);
|
|
|
|
}
|
|
|
|
|
|
|
|
// We know this is file number 1, CFileSaveObject::m_iCurFile is 1-based.
|
|
|
|
CheckFinishedSave(1,m_status);
|
|
|
|
|
|
|
|
XP_FREE(pHumanName);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CEditSaveObject::FixupLink(intn iIndex, // index to tape file system
|
|
|
|
char **ppImageURL, // Value to fixup.
|
|
|
|
char *pDestPathURL,
|
|
|
|
ED_HREFList *badLinks) {
|
|
|
|
if( iIndex == IgnoreImage ){
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( iIndex == AttemptAdjust ){
|
|
|
|
CEditLinkManager::AdjustLink(ppImageURL,m_pSrcURL,pDestPathURL,badLinks);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Look it up from tape file system.
|
|
|
|
char *pNewURL = GetDestName(iIndex);
|
|
|
|
if (pNewURL) {
|
|
|
|
XP_FREEIF(*ppImageURL);
|
|
|
|
*ppImageURL = pNewURL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
char *CEditSaveObject::FixupLinks(){
|
|
|
|
//////// WARNING: if you change this function, fix CEditSaveObject::AddAllFiles() and CEditBuffer::GetAllDocumentFiles() also.
|
|
|
|
ED_HREFList badLinks;
|
|
|
|
|
|
|
|
EDT_ImageData *pData;
|
|
|
|
|
|
|
|
char *pDestPathURL = m_tapeFS->GetDestPathURL();
|
|
|
|
// Note: pDestPathURL may legally be NULL.
|
|
|
|
|
|
|
|
// If there is a background Image, make it the first one.
|
|
|
|
FixupLink(m_backgroundIndex,&m_pBuffer->m_pBackgroundImage,pDestPathURL,&badLinks);
|
|
|
|
|
1998-06-21 23:03:10 +04:00
|
|
|
// We now support > 1 FontDefURLs
|
|
|
|
int iFontDefCount = m_pBuffer->m_FontDefURL.Size();
|
1998-07-07 20:49:37 +04:00
|
|
|
for( int i=0; i < iFontDefCount; i++ )
|
1998-06-21 23:03:10 +04:00
|
|
|
FixupLink(m_FontDefIndex[i], &m_pBuffer->m_FontDefURL[i], pDestPathURL, &badLinks);
|
1998-03-28 05:44:41 +03:00
|
|
|
|
|
|
|
// regular images.
|
1998-06-21 23:03:10 +04:00
|
|
|
CEditElement *pImage = m_pBuffer->m_pRoot->FindNextElement( &CEditElement::FindImage, 0 );
|
1998-07-02 05:20:39 +04:00
|
|
|
while( pImage )
|
|
|
|
{
|
1998-03-28 05:44:41 +03:00
|
|
|
pData = pImage->Image()->GetImageData();
|
1998-07-02 05:20:39 +04:00
|
|
|
if( pData )
|
|
|
|
{
|
|
|
|
// Only consider images that are not server-generated
|
|
|
|
if( EDT_IsImageURL(pData->pSrc) )
|
|
|
|
{
|
|
|
|
// do the normal image
|
|
|
|
FixupLink(pImage->Image()->m_iSaveIndex,&pData->pSrc,pDestPathURL,&badLinks);
|
|
|
|
}
|
|
|
|
if( EDT_IsImageURL(pData->pLowSrc) )
|
|
|
|
{
|
|
|
|
// do the lowres image
|
|
|
|
FixupLink(pImage->Image()->m_iSaveLowIndex,&pData->pLowSrc,pDestPathURL,&badLinks);
|
|
|
|
}
|
|
|
|
pImage->Image()->SetImageData( pData );
|
|
|
|
edt_FreeImageData( pData );
|
|
|
|
}
|
1998-03-28 05:44:41 +03:00
|
|
|
pImage = pImage->FindNextElement( &CEditElement::FindImage, 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//// Sure would be nice to abstract all the different types of table
|
|
|
|
//// backgrounds.
|
|
|
|
// table backgrounds <table>
|
|
|
|
CEditElement *pNext = m_pBuffer->m_pRoot;
|
|
|
|
while(NULL != (pNext = pNext->FindNextElement( &CEditElement::FindTable, 0 )) ){
|
|
|
|
CEditTableElement *pTable = (CEditTableElement *)pNext;
|
|
|
|
EDT_TableData *pData = pTable->GetData();
|
|
|
|
if (pData) {
|
|
|
|
if ( pData->pBackgroundImage && *pData->pBackgroundImage) {
|
|
|
|
FixupLink(pTable->m_iBackgroundSaveIndex,&pData->pBackgroundImage,pDestPathURL,&badLinks);
|
|
|
|
pTable->SetData(pData);
|
|
|
|
}
|
|
|
|
CEditTableElement::FreeData(pData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// table row backgrounds <tr>
|
|
|
|
pNext = m_pBuffer->m_pRoot;
|
|
|
|
while(NULL != (pNext = pNext->FindNextElement( &CEditElement::FindTableRow, 0 )) ){
|
|
|
|
CEditTableRowElement *pTable = (CEditTableRowElement *)pNext;
|
|
|
|
EDT_TableRowData *pData = pTable->GetData();
|
|
|
|
if (pData) {
|
|
|
|
if ( pData->pBackgroundImage && *pData->pBackgroundImage) {
|
|
|
|
FixupLink(pTable->m_iBackgroundSaveIndex,&pData->pBackgroundImage,pDestPathURL,&badLinks);
|
|
|
|
pTable->SetData(pData);
|
|
|
|
}
|
|
|
|
CEditTableRowElement::FreeData(pData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// table cell backgrounds <td> <th>
|
|
|
|
pNext = m_pBuffer->m_pRoot;
|
|
|
|
while(NULL != (pNext = pNext->FindNextElement( &CEditElement::FindTableCell, 0 )) ){
|
|
|
|
CEditTableCellElement *pTable = (CEditTableCellElement *)pNext;
|
|
|
|
EDT_TableCellData *pData = pTable->GetData(0);
|
|
|
|
if (pData) {
|
|
|
|
if ( pData->pBackgroundImage && *pData->pBackgroundImage) {
|
|
|
|
FixupLink(pTable->m_iBackgroundSaveIndex,&pData->pBackgroundImage,pDestPathURL,&badLinks);
|
|
|
|
pTable->SetData(pData);
|
|
|
|
}
|
|
|
|
CEditTableCellElement::FreeData(pData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnknownHTML tags with LOCALDATA attribute.
|
|
|
|
pNext = m_pBuffer->m_pRoot;
|
|
|
|
while(NULL != (pNext = pNext->FindNextElement( &CEditElement::FindUnknownHTML, 0 )) ){
|
|
|
|
CEditIconElement *pIcon = CEditIconElement::Cast(pNext);
|
|
|
|
if (pIcon) {
|
|
|
|
char **pMimeTypes;
|
|
|
|
char **pURLs;
|
|
|
|
int count = pIcon->ParseLocalData(&pMimeTypes,&pURLs);
|
|
|
|
|
|
|
|
if (count) {
|
|
|
|
if (pIcon->m_piSaveIndices) {
|
|
|
|
// Change all occurances of pURLs[n] in the unknown tag to
|
|
|
|
// take account of the new location.
|
|
|
|
for (int n = 0; n < count; n++) {
|
|
|
|
char *pPrev = XP_STRDUP(pURLs[n]); // Remember, so we can se if pURLs[n] changes.
|
|
|
|
FixupLink(pIcon->m_piSaveIndices[n],&pURLs[n],pDestPathURL,&badLinks);
|
|
|
|
// Note: ReplaceParamValue checks if the two are the same.
|
|
|
|
// Also note: the LOCALDATA parameter itself will be updated.
|
|
|
|
pIcon->ReplaceParamValues(pPrev,pURLs[n]);
|
|
|
|
XP_FREEIF(pPrev);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
XP_ASSERT(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// kill and zero memory for saved indices.
|
|
|
|
XP_FREEIF(pIcon->m_piSaveIndices);
|
|
|
|
CEditIconElement::FreeLocalDataLists(pMimeTypes,pURLs,count);
|
|
|
|
}
|
|
|
|
} // while
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Adjust the HREFs.
|
|
|
|
if( m_bAutoAdjustLinks && pDestPathURL ){
|
|
|
|
// No longer use CEditLinkManager::AdjustAllLinks because its ref counting is
|
|
|
|
// messed up and has more links than are currently in document. It adds too
|
|
|
|
// many lines to badLinks (which is actually displayed to the user.)
|
|
|
|
// m_pBuffer->linkManager.AdjustAllLinks( m_pSrcURL, pDestPathURL, &badLinks );
|
|
|
|
|
|
|
|
// Walk the tree and find all HREFs.
|
|
|
|
CEditElement *pLeaf = m_pBuffer->m_pRoot->FindNextElement(
|
|
|
|
&CEditElement::FindLeafAll,0 );
|
|
|
|
// First sweep, mark all HREFs as not adjusted.
|
|
|
|
while (pLeaf) {
|
|
|
|
m_pBuffer->linkManager.SetAdjusted(pLeaf->Leaf()->GetHREF(),FALSE);
|
|
|
|
pLeaf = pLeaf->FindNextElement(&CEditElement::FindLeafAll,0 );
|
|
|
|
}
|
|
|
|
// Second sweep, actually adjust the HREFs.
|
|
|
|
pLeaf = m_pBuffer->m_pRoot->FindNextElement(
|
|
|
|
&CEditElement::FindLeafAll,0 );
|
|
|
|
while (pLeaf) {
|
|
|
|
ED_LinkId linkId = pLeaf->Leaf()->GetHREF();
|
|
|
|
if (linkId && !m_pBuffer->linkManager.GetAdjusted(linkId)) {
|
|
|
|
// linkManager can deal with NULL HREF.
|
|
|
|
m_pBuffer->linkManager.AdjustLink(linkId,m_pSrcURL, pDestPathURL, &badLinks );
|
|
|
|
m_pBuffer->linkManager.SetAdjusted(linkId,TRUE);
|
|
|
|
}
|
|
|
|
pLeaf = pLeaf->FindNextElement(&CEditElement::FindLeafAll,0 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
XP_FREEIF(pDestPathURL);
|
|
|
|
|
|
|
|
// Package up a string of all the bad links found.
|
|
|
|
char *pRet = NULL;
|
|
|
|
if (badLinks.Size() > 0) {
|
|
|
|
int n;
|
|
|
|
for (n = 0; n < badLinks.Size(); n++) {
|
|
|
|
StrAllocCat(pRet,badLinks[n]);
|
|
|
|
StrAllocCat(pRet,"\n");
|
|
|
|
XP_FREEIF(badLinks[n]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return pRet;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#if 0 //// Now obsolete
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// CEditImageSaveObject
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
CEditImageSaveObject::CEditImageSaveObject( CEditBuffer *pBuffer,
|
|
|
|
EDT_ImageData *pData, XP_Bool bReplaceImage )
|
|
|
|
:
|
|
|
|
CFileSaveObject( pBuffer->m_pContext ),
|
|
|
|
m_pBuffer( pBuffer ),
|
|
|
|
m_pData( edt_DupImageData( pData ) ),
|
|
|
|
m_srcIndex(-1),
|
|
|
|
m_lowSrcIndex(-1),
|
|
|
|
m_bReplaceImage( bReplaceImage )
|
|
|
|
{
|
|
|
|
// we are going to write the image files into
|
|
|
|
SetDestPathURL( LO_GetBaseURL( pBuffer->m_pContext ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
CEditImageSaveObject::~CEditImageSaveObject(){
|
|
|
|
edt_FreeImageData( m_pData );
|
|
|
|
m_pBuffer->m_pSaveObject = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ED_FileError CEditImageSaveObject::FileFetchComplete(){
|
|
|
|
|
|
|
|
if( m_status == ED_ERROR_NONE ){
|
|
|
|
char *pName = 0;
|
|
|
|
if( m_srcIndex != -1 && (pName = GetDestName(m_srcIndex)) != 0 ){
|
|
|
|
if( m_pData->pSrc) XP_FREE( m_pData->pSrc );
|
|
|
|
m_pData->pSrc = pName;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( m_lowSrcIndex != -1 && (pName = GetDestName(m_lowSrcIndex)) != 0 ){
|
|
|
|
XP_FREE( m_pData->pLowSrc );
|
|
|
|
m_pData->pLowSrc = pName;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_pBuffer->m_pLoadingImage = new CEditImageLoader( m_pBuffer,
|
|
|
|
m_pData, m_bReplaceImage );
|
|
|
|
m_pBuffer->m_pLoadingImage->LoadImage();
|
|
|
|
}
|
|
|
|
return CFileSaveObject::FileFetchComplete();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if 0 // now obsolete
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// CEditBackgroundImageSaveObject
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
CEditBackgroundImageSaveObject::CEditBackgroundImageSaveObject( CEditBuffer *pBuffer)
|
|
|
|
:
|
|
|
|
CFileSaveObject( pBuffer->m_pContext ),
|
|
|
|
m_pBuffer( pBuffer )
|
|
|
|
{
|
|
|
|
// we are going to write the image files into
|
|
|
|
SetDestPathURL( LO_GetBaseURL( pBuffer->m_pContext ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
CEditBackgroundImageSaveObject::~CEditBackgroundImageSaveObject(){
|
|
|
|
m_pBuffer->m_pSaveObject = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ED_FileError CEditBackgroundImageSaveObject::FileFetchComplete(){
|
|
|
|
// Note: If user canceled in overwrite dialog, then we don't change the background
|
|
|
|
if( m_status == ED_ERROR_NONE ){
|
|
|
|
if( m_pBuffer->m_pBackgroundImage ) XP_FREE(m_pBuffer->m_pBackgroundImage);
|
|
|
|
|
|
|
|
// Get the one and only image file (without local or URL path)
|
|
|
|
m_pBuffer->m_pBackgroundImage = GetDestName(0);
|
|
|
|
|
|
|
|
// This will set background image
|
|
|
|
m_pBuffer->RefreshLayout();
|
|
|
|
// LO_SetBackgroundImage( m_pBuffer->m_pContext, m_pBuffer->m_pBackgroundImage );
|
|
|
|
}
|
|
|
|
return CFileSaveObject::FileFetchComplete();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//
|
|
|
|
// Sigh, why did the editor invent a new streaming type? This function
|
|
|
|
// allows the preencrypted file standard streamer to point back to the
|
|
|
|
// Editor's stream without turning the C++ virus loose on the security
|
|
|
|
// library.
|
|
|
|
//
|
|
|
|
|
|
|
|
typedef struct edtPrivStructStr {
|
|
|
|
ITapeFileSystem *tapeFS;
|
|
|
|
IStreamOut *out;
|
|
|
|
} edtPrivStruct;
|
|
|
|
|
|
|
|
static unsigned int
|
1998-07-24 08:14:39 +04:00
|
|
|
edt_TapeIsReady(NET_StreamClass * /* stream */ ) {
|
1998-03-28 05:44:41 +03:00
|
|
|
return MAX_WRITE_READY;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
edt_TapeComplete(NET_StreamClass *stream) {
|
|
|
|
edtPrivStruct *obj = (edtPrivStruct *)stream->data_object;
|
|
|
|
obj->tapeFS->CloseStream(0);
|
|
|
|
XP_FREE(obj);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
1998-07-24 08:14:39 +04:00
|
|
|
edt_TapeAbort(NET_StreamClass *stream, int /* status */) {
|
1998-03-28 05:44:41 +03:00
|
|
|
edt_TapeComplete(stream);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
edt_TapeWrite(NET_StreamClass *stream, char *str, int32 len) {
|
|
|
|
edtPrivStruct *obj= (edtPrivStruct *)stream->data_object;
|
|
|
|
obj->out->Write(str,len);
|
|
|
|
if ( obj->out->Status() != IStreamOut::EOS_NoError ) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" NET_StreamClass *EDT_NetToTape(void *data) {
|
|
|
|
NET_StreamClass *stream;
|
|
|
|
edtPrivStruct *obj;
|
|
|
|
|
|
|
|
stream = (NET_StreamClass *) XP_ALLOC(sizeof(NET_StreamClass));
|
|
|
|
if (stream == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
obj = (edtPrivStruct *)XP_ALLOC(sizeof(edtPrivStruct));
|
|
|
|
|
|
|
|
if (obj == NULL) {
|
|
|
|
XP_FREE(stream);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
stream->name = "Editor Tape FS stream";
|
|
|
|
stream->complete = edt_TapeComplete;
|
|
|
|
stream->abort = edt_TapeAbort;
|
|
|
|
stream->is_write_ready = edt_TapeIsReady;
|
|
|
|
stream->data_object = obj;
|
|
|
|
stream->window_id = NULL; // if this were a real stream we would need a
|
|
|
|
// url and a window context.
|
|
|
|
stream->put_block = (MKStreamWriteFunc)edt_TapeWrite;
|
|
|
|
|
|
|
|
obj->tapeFS = (ITapeFileSystem *)data;
|
|
|
|
obj->out = obj->tapeFS->OpenStream(0);
|
|
|
|
|
|
|
|
if (obj->out == NULL) {
|
|
|
|
XP_FREE(obj);
|
|
|
|
XP_FREE(stream);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return stream;
|
|
|
|
}
|
|
|
|
#endif
|