* Made GetStyledText() and WriteStyledEditFile() more robust against errors.

* Cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16700 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2006-03-11 12:50:47 +00:00
parent 5b14ba1a07
commit 9acf186f65

View File

@ -1,114 +1,48 @@
/*****************************************************************************/ /*
// File: TranslationUtils.h * Copyright 2002-2006, Haiku Inc.
// Class: BTranslationUtils * Distributed under the terms of the MIT License.
// Reimplemented by: Michael Wilber, Translation Kit Team *
// Reimplementation: 2002-04 * Authors:
// * Michael Wilber
// Description: Utility functions for the Translation Kit * Axel Dörfler, axeld@pinc-software.de
// */
//
// Copyright (c) 2002 OpenBeOS Project /*! Utility functions for the Translation Kit */
//
// Original Version: Copyright 1998, Be Incorporated, All Rights Reserved.
// Copyright 1995-1997, Jon Watte
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
/*****************************************************************************/
#include <Application.h> #include <Application.h>
#include <Roster.h>
#include <Bitmap.h> #include <Bitmap.h>
#include <BitmapStream.h> #include <BitmapStream.h>
#include <Entry.h>
#include <File.h> #include <File.h>
#include <MenuItem.h> #include <MenuItem.h>
#include <NodeInfo.h>
#include <Path.h>
#include <Resources.h> #include <Resources.h>
#include <stdlib.h> #include <Roster.h>
#include <TextView.h> #include <TextView.h>
#include <TranslationUtils.h>
#include <TranslatorFormats.h> #include <TranslatorFormats.h>
#include <TranslatorRoster.h> #include <TranslatorRoster.h>
#include <TranslationUtils.h>
#include <Entry.h>
#include <Path.h>
// --------------------------------------------------------------- #include <stdlib.h>
// Constructor
//
// Does nothing! :) This class has no data members.
//
// Preconditions:
//
// Parameters:
//
// Postconditions:
//
// Returns:
// ---------------------------------------------------------------
BTranslationUtils::BTranslationUtils() BTranslationUtils::BTranslationUtils()
{ {
} }
// ---------------------------------------------------------------
// Desstructor
//
// Does nothing! :) This class has no data members.
//
// Preconditions:
//
// Parameters:
//
// Postconditions:
//
// Returns:
// ---------------------------------------------------------------
BTranslationUtils::~BTranslationUtils() BTranslationUtils::~BTranslationUtils()
{ {
} }
// ---------------------------------------------------------------
// Constructor
//
// Does nothing! :) This class has no data members.
//
// Preconditions:
//
// Parameters: kUtils, not used
//
// Postconditions:
//
// Returns:
// ---------------------------------------------------------------
BTranslationUtils::BTranslationUtils(const BTranslationUtils &kUtils) BTranslationUtils::BTranslationUtils(const BTranslationUtils &kUtils)
{ {
} }
// ---------------------------------------------------------------
// operator=
//
// Does nothing! :) This class has no data members.
//
// Preconditions:
//
// Parameters: kUtils, not used
//
// Postconditions:
//
// Returns: reference to the object
// ---------------------------------------------------------------
BTranslationUtils & BTranslationUtils &
BTranslationUtils::operator=(const BTranslationUtils &kUtils) BTranslationUtils::operator=(const BTranslationUtils &kUtils)
{ {
@ -361,35 +295,30 @@ BTranslationUtils::GetBitmap(BPositionIO *stream, BTranslatorRoster *roster)
return NULL; return NULL;
} }
// ---------------------------------------------------------------
// GetStyledText /*!
// This function translates the styled text in fromStream and
// This function translates the styled text in fromStream and inserts it at the end of the text in intoView, using the
// inserts it at the end of the text in intoView, using the BTranslatorRoster *roster to do the translation. The structs
// BTranslatorRoster *roster to do the translation. The structs that make it possible to work with the translated data are
// that make it possible to work with the translated data are defined in
// defined in /boot/develop/headers/be/translation/TranslatorFormats.h
// /boot/develop/headers/be/translation/TranslatorFormats.h
// \param fromStream the stream with the styled text
// Preconditions: \param intoView the view where the test will be inserted
// roster, BTranslatorRoster used to do the translation
// Parameters: fromStream, the stream with the styled text
// intoView, the view where the test will be inserted \return B_BAD_VALUE, if fromStream or intoView is NULL
// roster, BTranslatorRoster used to do the translation \return B_ERROR, if any other error occurred
// \return B_OK, if successful
// Postconditions: */
//
// Returns: B_BAD_VALUE, if fromStream or intoView is NULL
// B_ERROR, if any other error occurred
// B_NO_ERROR, if successful
// ---------------------------------------------------------------
status_t status_t
BTranslationUtils::GetStyledText(BPositionIO *fromStream, BTextView *intoView, BTranslationUtils::GetStyledText(BPositionIO *fromStream, BTextView *intoView,
BTranslatorRoster *roster) BTranslatorRoster *roster)
{ {
if (fromStream == NULL || intoView == NULL) if (fromStream == NULL || intoView == NULL)
return B_BAD_VALUE; return B_BAD_VALUE;
// Use default Translator if none is specified // Use default Translator if none is specified
if (roster == NULL) { if (roster == NULL) {
roster = BTranslatorRoster::Default(); roster = BTranslatorRoster::Default();
@ -397,139 +326,127 @@ BTranslationUtils::GetStyledText(BPositionIO *fromStream, BTextView *intoView,
return B_ERROR; return B_ERROR;
} }
// Translate the file from whatever format it is in the file // Translate the file from whatever format it is to B_STYLED_TEXT_FORMAT
// to the B_STYLED_TEXT_FORMAT, placing the translated data into mallio // we understand
BMallocIO mallio; BMallocIO mallocIO;
if (roster->Translate(fromStream, NULL, NULL, &mallio, if (roster->Translate(fromStream, NULL, NULL, &mallocIO,
B_STYLED_TEXT_FORMAT) < B_OK) B_STYLED_TEXT_FORMAT) < B_OK)
return B_ERROR; return B_BAD_TYPE;
const uint8* buffer = (const uint8*)mallocIO.Buffer();
// make sure there is enough data to fill the stream header // make sure there is enough data to fill the stream header
const size_t kStreamHeaderSize = sizeof(TranslatorStyledTextStreamHeader); const size_t kStreamHeaderSize = sizeof(TranslatorStyledTextStreamHeader);
if (mallio.BufferLength() < kStreamHeaderSize) if (mallocIO.BufferLength() < kStreamHeaderSize)
return B_ERROR; return B_ERROR;
// copy the stream header from the mallio buffer // copy the stream header from the mallio buffer
TranslatorStyledTextStreamHeader stm_header = TranslatorStyledTextStreamHeader stm_header =
*(reinterpret_cast<const TranslatorStyledTextStreamHeader *> (mallio.Buffer())); *(reinterpret_cast<const TranslatorStyledTextStreamHeader *>(buffer));
// convert the stm_header.header struct to the host format // convert the stm_header.header struct to the host format
const size_t kRecordHeaderSize = sizeof(TranslatorStyledTextRecordHeader); const size_t kRecordHeaderSize = sizeof(TranslatorStyledTextRecordHeader);
if (swap_data(B_UINT32_TYPE, &stm_header.header, kRecordHeaderSize, if (swap_data(B_UINT32_TYPE, &stm_header.header, kRecordHeaderSize,
B_SWAP_BENDIAN_TO_HOST) != B_OK) B_SWAP_BENDIAN_TO_HOST) != B_OK
|| swap_data(B_INT32_TYPE, &stm_header.version, sizeof(int32),
B_SWAP_BENDIAN_TO_HOST) != B_OK
|| stm_header.header.magic != 'STXT')
return B_ERROR; return B_ERROR;
if (swap_data(B_INT32_TYPE, &stm_header.version, sizeof(int32),
B_SWAP_BENDIAN_TO_HOST) != B_OK) // copy the text header from the mallocIO buffer
return B_ERROR;
if (stm_header.header.magic != 'STXT')
return B_ERROR;
// copy the text header from the mallio buffer
uint32 offset = stm_header.header.header_size + uint32 offset = stm_header.header.header_size +
stm_header.header.data_size; stm_header.header.data_size;
const size_t kTextHeaderSize = sizeof(TranslatorStyledTextTextHeader); const size_t kTextHeaderSize = sizeof(TranslatorStyledTextTextHeader);
if (mallio.BufferLength() < offset + kTextHeaderSize) if (mallocIO.BufferLength() < offset + kTextHeaderSize)
return B_ERROR; return B_ERROR;
TranslatorStyledTextTextHeader txt_header = TranslatorStyledTextTextHeader textHeader =
*(reinterpret_cast<const TranslatorStyledTextTextHeader *> *(const TranslatorStyledTextTextHeader *)(buffer + offset);
(reinterpret_cast<const char *> (mallio.Buffer()) + offset));
// convert the stm_header.header struct to the host format // convert the stm_header.header struct to the host format
if (swap_data(B_UINT32_TYPE, &txt_header.header, kRecordHeaderSize, if (swap_data(B_UINT32_TYPE, &textHeader.header, kRecordHeaderSize,
B_SWAP_BENDIAN_TO_HOST) != B_OK) B_SWAP_BENDIAN_TO_HOST) != B_OK
|| swap_data(B_INT32_TYPE, &textHeader.charset, sizeof(int32),
B_SWAP_BENDIAN_TO_HOST) != B_OK
|| textHeader.header.magic != 'TEXT'
|| textHeader.charset != B_UNICODE_UTF8)
return B_ERROR; return B_ERROR;
if (swap_data(B_INT32_TYPE, &txt_header.charset, sizeof(int32),
B_SWAP_BENDIAN_TO_HOST) != B_OK) offset += textHeader.header.header_size;
if (mallocIO.BufferLength() < offset + textHeader.header.data_size)
return B_ERROR; return B_ERROR;
if (txt_header.header.magic != 'TEXT')
return B_ERROR; const char* text = (const char*)buffer + offset;
if (txt_header.charset != B_UNICODE_UTF8)
return B_ERROR;
offset += txt_header.header.header_size;
if (mallio.BufferLength() < offset + txt_header.header.data_size)
return B_ERROR;
const char *pTextData =
(reinterpret_cast<const char *> (mallio.Buffer())) + offset;
// point text pointer at the actual character data // point text pointer at the actual character data
if (mallio.BufferLength() > offset + txt_header.header.data_size) { if (mallocIO.BufferLength() > offset + textHeader.header.data_size) {
// If the stream contains information beyond the text data // If the stream contains information beyond the text data
// (which means that this data is probably styled text data) // (which means that this data is probably styled text data)
offset += txt_header.header.data_size; offset += textHeader.header.data_size;
const size_t kStyleHeaderSize = const size_t kStyleHeaderSize =
sizeof(TranslatorStyledTextStyleHeader); sizeof(TranslatorStyledTextStyleHeader);
if (mallio.BufferLength() < offset + kStyleHeaderSize) if (mallocIO.BufferLength() < offset + kStyleHeaderSize)
return B_ERROR; return B_ERROR;
TranslatorStyledTextStyleHeader stl_header =
*(reinterpret_cast<const TranslatorStyledTextStyleHeader *>
(reinterpret_cast<const char *> (mallio.Buffer()) + offset));
if (swap_data(B_UINT32_TYPE, &stl_header.header, kRecordHeaderSize,
B_SWAP_BENDIAN_TO_HOST) != B_OK)
return B_ERROR;
if (swap_data(B_UINT32_TYPE, &stl_header.apply_offset, sizeof(uint32),
B_SWAP_BENDIAN_TO_HOST) != B_OK)
return B_ERROR;
if (swap_data(B_UINT32_TYPE, &stl_header.apply_length, sizeof(uint32),
B_SWAP_BENDIAN_TO_HOST) != B_OK)
return B_ERROR;
if (stl_header.header.magic != 'STYL')
return B_ERROR;
offset += stl_header.header.header_size;
if (mallio.BufferLength() < offset + stl_header.header.data_size)
return B_ERROR;
// set pRawData to the flattened run array data
const void *kpRawData = reinterpret_cast<const void *>
(reinterpret_cast<const char *> (mallio.Buffer()) + offset);
text_run_array *pRunArray = BTextView::UnflattenRunArray(kpRawData);
if (pRunArray) {
intoView->Insert(intoView->TextLength(), pTextData,
txt_header.header.data_size, pRunArray);
free(pRunArray);
pRunArray = NULL;
} else
return B_ERROR;
} else
intoView->Insert(intoView->TextLength(), pTextData,
txt_header.header.data_size);
return B_NO_ERROR; TranslatorStyledTextStyleHeader styleHeader =
*(reinterpret_cast<const TranslatorStyledTextStyleHeader *>(buffer + offset));
if (swap_data(B_UINT32_TYPE, &styleHeader.header, kRecordHeaderSize,
B_SWAP_BENDIAN_TO_HOST) != B_OK
|| swap_data(B_UINT32_TYPE, &styleHeader.apply_offset, sizeof(uint32),
B_SWAP_BENDIAN_TO_HOST) != B_OK
|| swap_data(B_UINT32_TYPE, &styleHeader.apply_length, sizeof(uint32),
B_SWAP_BENDIAN_TO_HOST) != B_OK
|| styleHeader.header.magic != 'STYL')
return B_ERROR;
offset += styleHeader.header.header_size;
if (mallocIO.BufferLength() < offset + styleHeader.header.data_size)
return B_ERROR;
// get the text run array
text_run_array *runArray = BTextView::UnflattenRunArray(buffer + offset);
if (runArray) {
intoView->Insert(intoView->TextLength(), text,
textHeader.header.data_size, runArray);
BTextView::FreeRunArray(runArray);
} else {
// run array seems to be garbled; the text alone must be enough
intoView->Insert(intoView->TextLength(), text,
textHeader.header.data_size);
}
} else {
intoView->Insert(intoView->TextLength(), text,
textHeader.header.data_size);
}
return B_OK;
} }
// ---------------------------------------------------------------
// PutStyledText /*!
// This function takes styled text data from fromView and writes it to
// This function takes styled text data from fromView and writes it to intoStream. The plain text data and styled text data are combined
// intoStream. The plain text data and styled text data are combined when they are written to intoStream. This is different than how
// when they are written to intoStream. This is different than how a save operation in StyledEdit works. With StyledEdit, it writes
// a save operation in StyledEdit works. With StyledEdit, it writes plain text data to the file, but puts the styled text data in
// plain text data to the file, but puts the styled text data in the "styles" attribute. In other words, this function writes
// the "styles" attribute. In other words, this function writes styled text data to files in a manner that isn't human readable.
// styled text data to files in a manner that isn't human readable.
// So, if you want to write styled text
// So, if you want to write styled text data to a file, and you want it to behave the way StyledEdit does,
// data to a file, and you want it to behave the way StyledEdit does, you want to use the BTranslationUtils::WriteStyledEditFile() function.
// you want to use the BTranslationUtils::WriteStyledEditFile() function.
// \param fromView, the view with the styled text in it
// Preconditions: \param intoStream, the stream where the styled text is put
// roster, not used
// Parameters: fromView, the view with the styled text in it
// intoStream, the stream where the styled text is put \return B_BAD_VALUE, if fromView or intoStream is NULL
// roster, not used \return B_ERROR, if anything else went wrong
// \return B_NO_ERROR, if successful
// Postconditions: */
//
// Returns: B_BAD_VALUE, if fromView or intoStream is NULL
// B_ERROR, if anything else went wrong
// B_NO_ERROR, if successful
// ---------------------------------------------------------------
status_t status_t
BTranslationUtils::PutStyledText(BTextView *fromView, BPositionIO *intoStream, BTranslationUtils::PutStyledText(BTextView *fromView, BPositionIO *intoStream,
BTranslatorRoster *roster) BTranslatorRoster *roster)
@ -545,32 +462,28 @@ BTranslationUtils::PutStyledText(BTextView *fromView, BPositionIO *intoStream,
// its OK if the result of fromView->Text() is NULL // its OK if the result of fromView->Text() is NULL
int32 runArrayLength = 0; int32 runArrayLength = 0;
text_run_array *pRunArray = fromView->RunArray(0, textLength, text_run_array *runArray = fromView->RunArray(0, textLength,
&runArrayLength); &runArrayLength);
if (pRunArray == NULL) if (runArray == NULL)
return B_ERROR; return B_ERROR;
int32 flatRunArrayLength = 0; int32 flatRunArrayLength = 0;
void *pflatRunArray = void *pflatRunArray =
BTextView::FlattenRunArray(pRunArray, &flatRunArrayLength); BTextView::FlattenRunArray(runArray, &flatRunArrayLength);
if (pflatRunArray == NULL) { if (pflatRunArray == NULL) {
free(pRunArray); BTextView::FreeRunArray(runArray);
pRunArray = NULL;
return B_ERROR; return B_ERROR;
} }
// Rather than use a goto, I put a whole bunch of code that // Rather than use a goto, I put a whole bunch of code that
// could error out inside of a loop, and break out of the loop // could error out inside of a loop, and break out of the loop
// if there is an error. If there is no error, loop is set // if there is an error.
// to false. This is so that I don't have to put free()
// calls everywhere there could be an error. // This block of code is where I do all of the writing of the
// This block of code is where I do all of the writting of the
// data to the stream. I've gathered all of the data that I // data to the stream. I've gathered all of the data that I
// need at this point. // need at this point.
bool loop = true; bool ok = false;
while (loop) { while (ok) {
const size_t kStreamHeaderSize = const size_t kStreamHeaderSize =
sizeof(TranslatorStyledTextStreamHeader); sizeof(TranslatorStyledTextStreamHeader);
TranslatorStyledTextStreamHeader stm_header; TranslatorStyledTextStreamHeader stm_header;
@ -588,14 +501,14 @@ BTranslationUtils::PutStyledText(BTextView *fromView, BPositionIO *intoStream,
if (swap_data(B_INT32_TYPE, &stm_header.version, sizeof(int32), if (swap_data(B_INT32_TYPE, &stm_header.version, sizeof(int32),
B_SWAP_HOST_TO_BENDIAN) != B_OK) B_SWAP_HOST_TO_BENDIAN) != B_OK)
break; break;
const size_t kTextHeaderSize = sizeof(TranslatorStyledTextTextHeader); const size_t kTextHeaderSize = sizeof(TranslatorStyledTextTextHeader);
TranslatorStyledTextTextHeader txt_header; TranslatorStyledTextTextHeader txt_header;
txt_header.header.magic = 'TEXT'; txt_header.header.magic = 'TEXT';
txt_header.header.header_size = kTextHeaderSize; txt_header.header.header_size = kTextHeaderSize;
txt_header.header.data_size = textLength; txt_header.header.data_size = textLength;
txt_header.charset = B_UNICODE_UTF8; txt_header.charset = B_UNICODE_UTF8;
// convert the stm_header.header struct to the host format // convert the stm_header.header struct to the host format
if (swap_data(B_UINT32_TYPE, &txt_header.header, kRecordHeaderSize, if (swap_data(B_UINT32_TYPE, &txt_header.header, kRecordHeaderSize,
B_SWAP_HOST_TO_BENDIAN) != B_OK) B_SWAP_HOST_TO_BENDIAN) != B_OK)
@ -603,7 +516,7 @@ BTranslationUtils::PutStyledText(BTextView *fromView, BPositionIO *intoStream,
if (swap_data(B_INT32_TYPE, &txt_header.charset, sizeof(int32), if (swap_data(B_INT32_TYPE, &txt_header.charset, sizeof(int32),
B_SWAP_HOST_TO_BENDIAN) != B_OK) B_SWAP_HOST_TO_BENDIAN) != B_OK)
break; break;
const size_t kStyleHeaderSize = const size_t kStyleHeaderSize =
sizeof(TranslatorStyledTextStyleHeader); sizeof(TranslatorStyledTextStyleHeader);
TranslatorStyledTextStyleHeader stl_header; TranslatorStyledTextStyleHeader stl_header;
@ -612,7 +525,7 @@ BTranslationUtils::PutStyledText(BTextView *fromView, BPositionIO *intoStream,
stl_header.header.data_size = flatRunArrayLength; stl_header.header.data_size = flatRunArrayLength;
stl_header.apply_offset = 0; stl_header.apply_offset = 0;
stl_header.apply_length = textLength; stl_header.apply_length = textLength;
// convert the stl_header.header struct to the host format // convert the stl_header.header struct to the host format
if (swap_data(B_UINT32_TYPE, &stl_header.header, kRecordHeaderSize, if (swap_data(B_UINT32_TYPE, &stl_header.header, kRecordHeaderSize,
B_SWAP_HOST_TO_BENDIAN) != B_OK) B_SWAP_HOST_TO_BENDIAN) != B_OK)
@ -623,7 +536,7 @@ BTranslationUtils::PutStyledText(BTextView *fromView, BPositionIO *intoStream,
if (swap_data(B_UINT32_TYPE, &stl_header.apply_length, sizeof(uint32), if (swap_data(B_UINT32_TYPE, &stl_header.apply_length, sizeof(uint32),
B_SWAP_HOST_TO_BENDIAN) != B_OK) B_SWAP_HOST_TO_BENDIAN) != B_OK)
break; break;
// Here, you can see the structure of the styled text data by // Here, you can see the structure of the styled text data by
// observing the order that the various structs and data are // observing the order that the various structs and data are
// written to the stream // written to the stream
@ -643,185 +556,134 @@ BTranslationUtils::PutStyledText(BTextView *fromView, BPositionIO *intoStream,
amountWritten = intoStream->Write(pflatRunArray, flatRunArrayLength); amountWritten = intoStream->Write(pflatRunArray, flatRunArrayLength);
if (amountWritten != flatRunArrayLength) if (amountWritten != flatRunArrayLength)
break; break;
loop = false; ok = true;
// gracefully break out of the loop // gracefully break out of the loop
} // end of while(loop) }
free(pflatRunArray); free(pflatRunArray);
pflatRunArray = NULL; BTextView::FreeRunArray(runArray);
free(pRunArray);
pRunArray = NULL; return ok ? B_OK : B_ERROR;
if (loop)
return B_ERROR;
else
return B_NO_ERROR;
} }
// ---------------------------------------------------------------
// WriteStyledEditFile /*!
// \brief Writes the styled text data from \a view to the specified \a file.
// This function writes the styled text data from fromView
// and stores it in the file intoFile. This function is similar to PutStyledText() except that it
// only writes styled text data to files and it puts the
// This function is similar to PutStyledText() except that it plain text data in the file and stores the styled data as
// only writes styled text data to files and it puts the the attribute "styles".
// plain text data in the file and stores the styled data as
// the attribute "styles". You can use PutStyledText() to write styled text data
// to files, but it writes the data in a format that isn't
// You can use PutStyledText() to write styled text data human readable.
// to files, but it writes the data in a format that isn't
// human readable. \param view the view with the styled text
// \param file the file where the styled text is written to
// It is important to note that this function doesn't
// write files in exactly the same manner that you get \return B_BAD_VALUE, if either parameter is NULL
// when you do a File->Save operation in StyledEdit. B_OK, if successful, and any possible file error
// This function doesn't write all of the attributes if writing failed.
// that StyledEdit does, even though it easily could. */
//
// Preconditions:
//
// Parameters: fromView, the view with the styled text
// intoFile, the file where the styled text
// is written to
//
// Postconditions:
//
// Returns: B_BAD_VALUE, if either parameter is NULL
// B_ERROR, if anything else went wrong
// B_OK, if successful
// ---------------------------------------------------------------
status_t status_t
BTranslationUtils::WriteStyledEditFile(BTextView *fromView, BFile *intoFile) BTranslationUtils::WriteStyledEditFile(BTextView* view, BFile* file)
{ {
if (fromView == NULL || intoFile == NULL) if (view == NULL || file == NULL)
return B_BAD_VALUE; return B_BAD_VALUE;
int32 textLength = fromView->TextLength(); int32 textLength = view->TextLength();
if (textLength < 0) if (textLength < 0)
return B_ERROR; return B_ERROR;
const char *kpTextData = fromView->Text(); const char *text = view->Text();
if (kpTextData == NULL && textLength != 0) if (text == NULL && textLength != 0)
return B_ERROR; return B_ERROR;
// move to the start of the file if not already there // move to the start of the file if not already there
status_t result = B_OK; status_t result = file->Seek(0, SEEK_SET);
result = intoFile->Seek(0,SEEK_SET);
if (result != B_OK) if (result != B_OK)
return result; return result;
// Write plain text data to file // Write plain text data to file
ssize_t amtWritten = intoFile->Write(kpTextData, textLength); ssize_t bytesWritten = file->Write(text, textLength);
if (amtWritten != textLength) if (bytesWritten != textLength)
return B_ERROR; return B_ERROR;
// truncate any extra text // truncate any extra text
result = intoFile->SetSize(textLength); result = file->SetSize(textLength);
if (result != B_OK) if (result != B_OK)
return result; return result;
// get the BVolume that this file is on and // Write attributes. We don't report an error anymore after this point,
// check the volume for the attribute support // as attributes aren't that crucial - not all volumes support attributes.
node_ref nref; // However, if writing one attribute fails, no further attributes are
result = intoFile->GetNodeRef(&nref); // tried to be written.
if (result != B_OK)
return result; BNodeInfo info(file);
BVolume volume(nref.device); char type[B_MIME_TYPE_LENGTH];
result = volume.InitCheck(); if (info.GetType(type) != B_OK) {
if (result != B_OK) // This file doesn't have a file type yet, so let's set it
return result; result = info.SetType("text/plain");
if (!volume.KnowsAttr()) if (result < B_OK)
return B_OK; return B_OK;
}
// Write attributes
// BEOS:TYPE
// (this is so that the BeOS will recognize this file as a text file)
amtWritten = intoFile->WriteAttr("BEOS:TYPE", 'MIMS', 0, "text/plain", 11);
if ((size_t) amtWritten != 11)
return B_ERROR;
// wrap
// word wrap setting, turned on by default // word wrap setting, turned on by default
int32 nwrap = ((fromView->DoesWordWrap()) ? 1 : 0); int32 wordWrap = view->DoesWordWrap() ? 1 : 0;
amtWritten = intoFile->WriteAttr("wrap", B_INT32_TYPE, 0, bytesWritten = file->WriteAttr("wrap", B_INT32_TYPE, 0,
&nwrap, sizeof(int32)); &wordWrap, sizeof(int32));
if (amtWritten != sizeof(int32)) if (bytesWritten != sizeof(int32))
return B_ERROR;
// alignment
// alignment, either B_ALIGN_LEFT, B_ALIGN_RIGHT or B_ALIGN_CENTER,
// default is B_ALIGN_LEFT
int32 nalignment = fromView->Alignment();
amtWritten = intoFile->WriteAttr("alignment", B_INT32_TYPE, 0,
&nalignment, sizeof(int32));
if (amtWritten != sizeof(int32))
return B_ERROR;
// be:encoding
// how the text is encoded, StyledEdit's list of encoding options
// is listed under the Encoding menu in the Save As dialog box
// default is Unicode UTF8 (65535)
// note that the B_UNICODE_UTF8 constant is 0 and not appropriate
// for use here
int32 nencoding = 65535;
amtWritten = intoFile->WriteAttr("be:encoding", B_INT32_TYPE, 0,
&nencoding, sizeof(int32));
if (amtWritten != sizeof(int32))
return B_ERROR;
text_run_array *pRunArray = fromView->RunArray(0, fromView->TextLength());
if (pRunArray == NULL)
return B_ERROR;
int32 runArraySize = 0;
void *pflatRunArray = BTextView::FlattenRunArray(pRunArray, &runArraySize);
if (pflatRunArray == NULL) {
free(pRunArray);
pRunArray = NULL;
return B_ERROR;
}
if (runArraySize < 0) {
free(pflatRunArray);
pflatRunArray = NULL;
free(pRunArray);
pRunArray = NULL;
return B_ERROR;
}
// This is how the styled text data is stored in the file
// (the trick is that it isn't actually stored in the file, its stored
// as an attribute in the file's node)
amtWritten = intoFile->WriteAttr("styles", B_RAW_TYPE, 0, pflatRunArray,
runArraySize);
free(pflatRunArray);
pflatRunArray = NULL;
free(pRunArray);
pRunArray = NULL;
if (amtWritten == runArraySize)
return B_OK; return B_OK;
else
return B_ERROR; // alignment, default is B_ALIGN_LEFT
int32 alignment = view->Alignment();
bytesWritten = file->WriteAttr("alignment", B_INT32_TYPE, 0,
&alignment, sizeof(int32));
if (bytesWritten != sizeof(int32))
return B_OK;
// be:encoding, defaults to UTF-8 (65535)
// Note that the B_UNICODE_UTF8 constant is 0 and for some reason
// not appropriate for use here.
int32 encoding = 65535;
bytesWritten = file->WriteAttr("be:encoding", B_INT32_TYPE, 0,
&encoding, sizeof(int32));
if (bytesWritten != sizeof(int32))
return B_OK;
// Write text_run_array, ie. the styles of the text
text_run_array *runArray = view->RunArray(0, view->TextLength());
if (runArray != NULL) {
int32 runArraySize = 0;
void *flattenedRunArray = BTextView::FlattenRunArray(runArray, &runArraySize);
if (flattenedRunArray != NULL) {
file->WriteAttr("styles", B_RAW_TYPE, 0, flattenedRunArray,
runArraySize);
}
free(flattenedRunArray);
BTextView::FreeRunArray(runArray);
}
return B_OK;
} }
// ---------------------------------------------------------------
// GetDefaultSettings /*!
// Each translator can have default settings, set by the
// Each translator can have default settings, set by the "translations" control panel. You can read these settings to
// "translations" control panel. You can read these settings to pass on to a translator using one of these functions.
// pass on to a translator using one of these functions.
// \param forTranslator, the translator the settings are for
// Preconditions: roster, the roster used to get the settings
//
// Parameters: forTranslator, the translator the settings are for \return BMessage of configuration data for forTranslator - you own
// roster, the roster used to get the settings this message and have to free it when you're done with it.
// \return NULL, if anything went wrong
// Postconditions: */
//
// Returns: NULL, if anything went wrong
// BMessage * of configuration data for forTranslator
// ---------------------------------------------------------------
BMessage * BMessage *
BTranslationUtils::GetDefaultSettings(translator_id forTranslator, BTranslationUtils::GetDefaultSettings(translator_id forTranslator,
BTranslatorRoster *roster) BTranslatorRoster *roster)
@ -833,37 +695,22 @@ BTranslationUtils::GetDefaultSettings(translator_id forTranslator,
return NULL; return NULL;
} }
BMessage *pMessage = new BMessage(); BMessage *message = new BMessage();
if (pMessage == NULL) if (message == NULL)
return NULL; return NULL;
status_t result = roster->GetConfigurationMessage(forTranslator, pMessage); status_t result = roster->GetConfigurationMessage(forTranslator, message);
switch (result) { if (result != B_OK && result != B_NO_TRANSLATOR) {
case B_OK: // Be's version seems to just pass an empty BMessage
break; // in case of B_NO_TRANSLATOR, well, in some cases anyway
delete message;
case B_NO_TRANSLATOR: return NULL;
// Be's version seems to just pass an empty
// BMessage for this case, well, in some cases anyway
break;
case B_NOT_INITIALIZED:
delete pMessage;
pMessage = NULL;
break;
case B_BAD_VALUE:
delete pMessage;
pMessage = NULL;
break;
default:
break;
} }
return pMessage; return message;
} }
// --------------------------------------------------------------- // ---------------------------------------------------------------
// GetDefaultSettings // GetDefaultSettings
// //