mirror of
https://review.haiku-os.org/haiku
synced 2025-02-15 10:08:36 +01:00
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5904 a95241bf-73f2-0310-859d-f6bbb57e9c96
1015 lines
32 KiB
C++
1015 lines
32 KiB
C++
/*****************************************************************************/
|
|
// File: TranslationUtils.h
|
|
// Class: BTranslationUtils
|
|
// Reimplemented by: Michael Wilber, Translation Kit Team
|
|
// Reimplementation: 2002-04
|
|
//
|
|
// Description: Utility functions for the Translation Kit
|
|
//
|
|
//
|
|
// Copyright (c) 2002 OpenBeOS Project
|
|
//
|
|
// 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 <Roster.h>
|
|
#include <Bitmap.h>
|
|
#include <BitmapStream.h>
|
|
#include <File.h>
|
|
#include <MenuItem.h>
|
|
#include <Resources.h>
|
|
#include <stdlib.h>
|
|
#include <TextView.h>
|
|
#include <TranslatorFormats.h>
|
|
#include <TranslatorRoster.h>
|
|
#include <TranslationUtils.h>
|
|
#include <Entry.h>
|
|
#include <Path.h>
|
|
|
|
// ---------------------------------------------------------------
|
|
// Constructor
|
|
//
|
|
// Does nothing! :) This class has no data members.
|
|
//
|
|
// Preconditions:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Postconditions:
|
|
//
|
|
// Returns:
|
|
// ---------------------------------------------------------------
|
|
BTranslationUtils::BTranslationUtils()
|
|
{
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// Desstructor
|
|
//
|
|
// Does nothing! :) This class has no data members.
|
|
//
|
|
// Preconditions:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Postconditions:
|
|
//
|
|
// Returns:
|
|
// ---------------------------------------------------------------
|
|
BTranslationUtils::~BTranslationUtils()
|
|
{
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// Constructor
|
|
//
|
|
// Does nothing! :) This class has no data members.
|
|
//
|
|
// Preconditions:
|
|
//
|
|
// Parameters: kUtils, not used
|
|
//
|
|
// Postconditions:
|
|
//
|
|
// Returns:
|
|
// ---------------------------------------------------------------
|
|
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::operator=(const BTranslationUtils &kUtils)
|
|
{
|
|
return *this;
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// GetBitmap
|
|
//
|
|
// Returns a BBitmap object for the bitmap file or resource
|
|
// kName. The user has to delete this object. It first tries
|
|
// to open kName as a file, then as a resource.
|
|
//
|
|
// Preconditions:
|
|
//
|
|
// Parameters: kName, the name of the bitmap file or resource to
|
|
// be returned
|
|
// roster, BTranslatorRoster used to do the translation
|
|
//
|
|
// Postconditions:
|
|
//
|
|
// Returns: NULL, if the file could not be opened and the
|
|
// resource couldn't be found or couldn't be
|
|
// translated to a BBitmap
|
|
// BBitmap * to the bitmap reference by kName
|
|
// ---------------------------------------------------------------
|
|
BBitmap *
|
|
BTranslationUtils::GetBitmap(const char *kName, BTranslatorRoster *roster)
|
|
{
|
|
BBitmap *pBitmap = GetBitmapFile(kName, roster);
|
|
// Try loading a bitmap from the file named name
|
|
|
|
// Try loading the bitmap as an application resource
|
|
if (pBitmap == NULL)
|
|
pBitmap = GetBitmap(B_TRANSLATOR_BITMAP, kName, roster);
|
|
|
|
return pBitmap;
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// GetBitmap
|
|
//
|
|
// Returns a BBitmap object for the bitmap resource identified by
|
|
// the type type with the resource id, id.
|
|
// The user has to delete this object.
|
|
//
|
|
// Preconditions:
|
|
//
|
|
// Parameters: type, the type of resource to be loaded
|
|
// id, the id for the resource to be loaded
|
|
// roster, BTranslatorRoster used to do the translation
|
|
//
|
|
// Postconditions:
|
|
//
|
|
// Returns: NULL, if the resource couldn't be loaded or couldn't
|
|
// be translated to a BBitmap
|
|
// BBitmap * to the bitmap identified by type and id
|
|
// ---------------------------------------------------------------
|
|
BBitmap *
|
|
BTranslationUtils::GetBitmap(uint32 type, int32 id, BTranslatorRoster *roster)
|
|
{
|
|
BResources *pResources = BApplication::AppResources();
|
|
// Remember: pResources must not be freed because
|
|
// it belongs to the application
|
|
if (pResources == NULL || pResources->HasResource(type, id) == false)
|
|
return NULL;
|
|
|
|
// Load the bitmap resource from the application file
|
|
// pRawData should be NULL if the resource is an
|
|
// unknown type or not available
|
|
size_t bitmapSize = 0;
|
|
const void *kpRawData = pResources->LoadResource(type, id, &bitmapSize);
|
|
if (kpRawData == NULL || bitmapSize == 0)
|
|
return NULL;
|
|
|
|
BMemoryIO memio(kpRawData, bitmapSize);
|
|
// Put the pointer to the raw image data into a BMemoryIO object
|
|
// so that it can be used with BTranslatorRoster->Translate() in
|
|
// the GetBitmap(BPositionIO *, BTranslatorRoster *) function
|
|
|
|
return GetBitmap(&memio, roster);
|
|
// Translate the data in memio using the BTranslatorRoster roster
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// GetBitmap
|
|
//
|
|
// Returns a BBitmap object for the bitmap resource identified by
|
|
// the type type with the resource name, kName.
|
|
// The user has to delete this object. Note that a resource type
|
|
// and name does not uniquely identify a resource in a file.
|
|
//
|
|
// Preconditions:
|
|
//
|
|
// Parameters: type, the type of resource to be loaded
|
|
// kName, the name of the resource to be loaded
|
|
// roster, BTranslatorRoster used to do the translation
|
|
//
|
|
// Postconditions:
|
|
//
|
|
// Returns: NULL, if the resource couldn't be loaded or couldn't
|
|
// be translated to a BBitmap
|
|
// BBitmap * to the bitmap identified by type and kName
|
|
// ---------------------------------------------------------------
|
|
BBitmap *
|
|
BTranslationUtils::GetBitmap(uint32 type, const char *kName,
|
|
BTranslatorRoster *roster)
|
|
{
|
|
BResources *pResources = BApplication::AppResources();
|
|
// Remember: pResources must not be freed because
|
|
// it belongs to the application
|
|
if (pResources == NULL || pResources->HasResource(type, kName) == false)
|
|
return NULL;
|
|
|
|
// Load the bitmap resource from the application file
|
|
size_t bitmapSize = 0;
|
|
const void *kpRawData = pResources->LoadResource(type, kName, &bitmapSize);
|
|
if (kpRawData == NULL || bitmapSize == 0)
|
|
return NULL;
|
|
|
|
BMemoryIO memio(kpRawData, bitmapSize);
|
|
// Put the pointer to the raw image data into a BMemoryIO object so
|
|
// that it can be used with BTranslatorRoster->Translate()
|
|
|
|
return GetBitmap(&memio, roster);
|
|
// Translate the data in memio using the BTranslatorRoster roster
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// GetBitmapFile
|
|
//
|
|
// Returns a BBitmap object for the bitmap file named kName.
|
|
// The user has to delete this object.
|
|
//
|
|
// Preconditions:
|
|
//
|
|
// Parameters: kName, the name of the bitmap file
|
|
// roster, BTranslatorRoster used to do the translation
|
|
//
|
|
// Postconditions:
|
|
//
|
|
// Returns: NULL, if the file couldn't be opened or couldn't
|
|
// be translated to a BBitmap
|
|
// BBitmap * to the bitmap file named kName
|
|
// ---------------------------------------------------------------
|
|
BBitmap *
|
|
BTranslationUtils::GetBitmapFile(const char *kName, BTranslatorRoster *roster)
|
|
{
|
|
if (!be_app || !kName || kName[0] == '\0')
|
|
return NULL;
|
|
|
|
BPath path;
|
|
if (kName[0] != '/') {
|
|
// If kName is a relative path, use the path of the application's
|
|
// executable as the base for the relative path
|
|
app_info info;
|
|
if (be_app->GetAppInfo(&info) != B_OK)
|
|
return NULL;
|
|
BEntry appRef(&info.ref);
|
|
if (path.SetTo(&appRef) != B_OK)
|
|
return NULL;
|
|
if (path.GetParent(&path) != B_OK)
|
|
return NULL;
|
|
if (path.Append(kName) != B_OK)
|
|
return NULL;
|
|
|
|
} else if (path.SetTo(kName) != B_OK)
|
|
return NULL;
|
|
|
|
BFile bitmapFile(path.Path(), B_READ_ONLY);
|
|
if (bitmapFile.InitCheck() != B_OK)
|
|
return NULL;
|
|
|
|
return GetBitmap(&bitmapFile, roster);
|
|
// Translate the data in memio using the BTranslatorRoster roster
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// GetBitmap
|
|
//
|
|
// Returns a BBitmap object for the bitmap file with the entry_ref
|
|
// kRef. The user has to delete this object.
|
|
//
|
|
// Preconditions:
|
|
//
|
|
// Parameters: kRef, the entry_ref for the bitmap file
|
|
// roster, BTranslatorRoster used to do the translation
|
|
//
|
|
// Postconditions:
|
|
//
|
|
// Returns: NULL, if the file couldn't be opened or couldn't
|
|
// be translated to a BBitmap
|
|
// BBitmap * to the bitmap file referenced by kRef
|
|
// ---------------------------------------------------------------
|
|
BBitmap *
|
|
BTranslationUtils::GetBitmap(const entry_ref *kRef, BTranslatorRoster *roster)
|
|
{
|
|
BFile bitmapFile(kRef, B_READ_ONLY);
|
|
if (bitmapFile.InitCheck() != B_OK)
|
|
return NULL;
|
|
|
|
return GetBitmap(&bitmapFile, roster);
|
|
// Translate the data in bitmapFile using the BTranslatorRoster roster
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// GetBitmap
|
|
//
|
|
// Returns a BBitmap object from the BPositionIO *stream. The
|
|
// user must delete the returned object. This GetBitmap function
|
|
// is used by the other GetBitmap functions to do all of the
|
|
// "real" work.
|
|
//
|
|
// Preconditions:
|
|
//
|
|
// Parameters: stream, the stream with bitmap data in it
|
|
// roster, BTranslatorRoster used to do the translation
|
|
//
|
|
// Postconditions:
|
|
//
|
|
// Returns: NULL, if the stream couldn't be translated to a BBitmap
|
|
// BBitmap * for the bitmap data from pio if successful
|
|
// ---------------------------------------------------------------
|
|
BBitmap *
|
|
BTranslationUtils::GetBitmap(BPositionIO *stream, BTranslatorRoster *roster)
|
|
{
|
|
if (stream == NULL)
|
|
return NULL;
|
|
|
|
// Use default Translator if none is specified
|
|
if (roster == NULL) {
|
|
roster = BTranslatorRoster::Default();
|
|
if (roster == NULL)
|
|
return NULL;
|
|
}
|
|
|
|
// Translate the file from whatever format it is in the file
|
|
// to the type format so that it can be stored in a BBitmap
|
|
BBitmapStream bitmapStream;
|
|
if (roster->Translate(stream, NULL, NULL, &bitmapStream,
|
|
B_TRANSLATOR_BITMAP) < B_OK)
|
|
return NULL;
|
|
|
|
// Detach the BBitmap from the BBitmapStream so the user
|
|
// of this function can do what they please with it.
|
|
BBitmap *pBitmap = NULL;
|
|
if (bitmapStream.DetachBitmap(&pBitmap) == B_NO_ERROR)
|
|
return pBitmap;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// GetStyledText
|
|
//
|
|
// This function translates the styled text in fromStream and
|
|
// inserts it at the end of the text in intoView, using the
|
|
// BTranslatorRoster *roster to do the translation. The structs
|
|
// that make it possible to work with the translated data are
|
|
// defined in
|
|
// /boot/develop/headers/be/translation/TranslatorFormats.h
|
|
//
|
|
// Preconditions:
|
|
//
|
|
// Parameters: fromStream, the stream with the styled text
|
|
// intoView, the view where the test will be inserted
|
|
// roster, BTranslatorRoster used to do the translation
|
|
//
|
|
// 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
|
|
BTranslationUtils::GetStyledText(BPositionIO *fromStream, BTextView *intoView,
|
|
BTranslatorRoster *roster)
|
|
{
|
|
if (fromStream == NULL || intoView == NULL)
|
|
return B_BAD_VALUE;
|
|
|
|
// Use default Translator if none is specified
|
|
if (roster == NULL) {
|
|
roster = BTranslatorRoster::Default();
|
|
if (roster == NULL)
|
|
return B_ERROR;
|
|
}
|
|
|
|
// Translate the file from whatever format it is in the file
|
|
// to the B_STYLED_TEXT_FORMAT, placing the translated data into mallio
|
|
BMallocIO mallio;
|
|
if (roster->Translate(fromStream, NULL, NULL, &mallio,
|
|
B_STYLED_TEXT_FORMAT) < B_OK)
|
|
return B_ERROR;
|
|
|
|
// make sure there is enough data to fill the stream header
|
|
const size_t kStreamHeaderSize = sizeof(TranslatorStyledTextStreamHeader);
|
|
if (mallio.BufferLength() < kStreamHeaderSize)
|
|
return B_ERROR;
|
|
|
|
// copy the stream header from the mallio buffer
|
|
TranslatorStyledTextStreamHeader stm_header =
|
|
*(reinterpret_cast<const TranslatorStyledTextStreamHeader *> (mallio.Buffer()));
|
|
|
|
// convert the stm_header.header struct to the host format
|
|
const size_t kRecordHeaderSize = sizeof(TranslatorStyledTextRecordHeader);
|
|
if (swap_data(B_UINT32_TYPE, &stm_header.header, kRecordHeaderSize,
|
|
B_SWAP_BENDIAN_TO_HOST) != B_OK)
|
|
return B_ERROR;
|
|
if (swap_data(B_INT32_TYPE, &stm_header.version, sizeof(int32),
|
|
B_SWAP_BENDIAN_TO_HOST) != B_OK)
|
|
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 +
|
|
stm_header.header.data_size;
|
|
const size_t kTextHeaderSize = sizeof(TranslatorStyledTextTextHeader);
|
|
if (mallio.BufferLength() < offset + kTextHeaderSize)
|
|
return B_ERROR;
|
|
|
|
TranslatorStyledTextTextHeader txt_header =
|
|
*(reinterpret_cast<const TranslatorStyledTextTextHeader *>
|
|
(reinterpret_cast<const char *> (mallio.Buffer()) + offset));
|
|
|
|
// convert the stm_header.header struct to the host format
|
|
if (swap_data(B_UINT32_TYPE, &txt_header.header, kRecordHeaderSize,
|
|
B_SWAP_BENDIAN_TO_HOST) != B_OK)
|
|
return B_ERROR;
|
|
if (swap_data(B_INT32_TYPE, &txt_header.charset, sizeof(int32),
|
|
B_SWAP_BENDIAN_TO_HOST) != B_OK)
|
|
return B_ERROR;
|
|
if (txt_header.header.magic != 'TEXT')
|
|
return B_ERROR;
|
|
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
|
|
|
|
if (mallio.BufferLength() > offset + txt_header.header.data_size) {
|
|
// If the stream contains information beyond the text data
|
|
// (which means that this data is probably styled text data)
|
|
|
|
offset += txt_header.header.data_size;
|
|
const size_t kStyleHeaderSize =
|
|
sizeof(TranslatorStyledTextStyleHeader);
|
|
if (mallio.BufferLength() < offset + kStyleHeaderSize)
|
|
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;
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// PutStyledText
|
|
//
|
|
// This function takes styled text data from fromView and writes it to
|
|
// intoStream. The plain text data and styled text data are combined
|
|
// when they are written to intoStream. This is different than how
|
|
// a save operation in StyledEdit works. With StyledEdit, it writes
|
|
// plain text data to the file, but puts the styled text data in
|
|
// the "styles" attribute. In other words, this function writes
|
|
// styled text data to files in a manner that isn't human readable.
|
|
//
|
|
// So, if you want to write styled text
|
|
// data to a file, and you want it to behave the way StyledEdit does,
|
|
// you want to use the BTranslationUtils::WriteStyledEditFile() function.
|
|
//
|
|
// Preconditions:
|
|
//
|
|
// Parameters: fromView, the view with the styled text in it
|
|
// intoStream, the stream where the styled text is put
|
|
// roster, not used
|
|
//
|
|
// 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
|
|
BTranslationUtils::PutStyledText(BTextView *fromView, BPositionIO *intoStream,
|
|
BTranslatorRoster *roster)
|
|
{
|
|
if (fromView == NULL || intoStream == NULL)
|
|
return B_BAD_VALUE;
|
|
|
|
int32 textLength = fromView->TextLength();
|
|
if (textLength < 0)
|
|
return B_ERROR;
|
|
|
|
const char *pTextData = fromView->Text();
|
|
// its OK if the result of fromView->Text() is NULL
|
|
|
|
int32 runArrayLength = 0;
|
|
text_run_array *pRunArray = fromView->RunArray(0, textLength,
|
|
&runArrayLength);
|
|
if (pRunArray == NULL)
|
|
return B_ERROR;
|
|
|
|
int32 flatRunArrayLength = 0;
|
|
void *pflatRunArray =
|
|
BTextView::FlattenRunArray(pRunArray, &flatRunArrayLength);
|
|
if (pflatRunArray == NULL) {
|
|
free(pRunArray);
|
|
pRunArray = NULL;
|
|
|
|
return B_ERROR;
|
|
}
|
|
|
|
// 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
|
|
// if there is an error. If there is no error, loop is set
|
|
// 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 writting of the
|
|
// data to the stream. I've gathered all of the data that I
|
|
// need at this point.
|
|
bool loop = true;
|
|
while (loop) {
|
|
const size_t kStreamHeaderSize =
|
|
sizeof(TranslatorStyledTextStreamHeader);
|
|
TranslatorStyledTextStreamHeader stm_header;
|
|
stm_header.header.magic = 'STXT';
|
|
stm_header.header.header_size = kStreamHeaderSize;
|
|
stm_header.header.data_size = 0;
|
|
stm_header.version = 100;
|
|
|
|
// convert the stm_header.header struct to the host format
|
|
const size_t kRecordHeaderSize =
|
|
sizeof(TranslatorStyledTextRecordHeader);
|
|
if (swap_data(B_UINT32_TYPE, &stm_header.header, kRecordHeaderSize,
|
|
B_SWAP_HOST_TO_BENDIAN) != B_OK)
|
|
break;
|
|
if (swap_data(B_INT32_TYPE, &stm_header.version, sizeof(int32),
|
|
B_SWAP_HOST_TO_BENDIAN) != B_OK)
|
|
break;
|
|
|
|
const size_t kTextHeaderSize = sizeof(TranslatorStyledTextTextHeader);
|
|
TranslatorStyledTextTextHeader txt_header;
|
|
txt_header.header.magic = 'TEXT';
|
|
txt_header.header.header_size = kTextHeaderSize;
|
|
txt_header.header.data_size = textLength;
|
|
txt_header.charset = B_UNICODE_UTF8;
|
|
|
|
// convert the stm_header.header struct to the host format
|
|
if (swap_data(B_UINT32_TYPE, &txt_header.header, kRecordHeaderSize,
|
|
B_SWAP_HOST_TO_BENDIAN) != B_OK)
|
|
break;
|
|
if (swap_data(B_INT32_TYPE, &txt_header.charset, sizeof(int32),
|
|
B_SWAP_HOST_TO_BENDIAN) != B_OK)
|
|
break;
|
|
|
|
const size_t kStyleHeaderSize =
|
|
sizeof(TranslatorStyledTextStyleHeader);
|
|
TranslatorStyledTextStyleHeader stl_header;
|
|
stl_header.header.magic = 'STYL';
|
|
stl_header.header.header_size = kStyleHeaderSize;
|
|
stl_header.header.data_size = flatRunArrayLength;
|
|
stl_header.apply_offset = 0;
|
|
stl_header.apply_length = textLength;
|
|
|
|
// convert the stl_header.header struct to the host format
|
|
if (swap_data(B_UINT32_TYPE, &stl_header.header, kRecordHeaderSize,
|
|
B_SWAP_HOST_TO_BENDIAN) != B_OK)
|
|
break;
|
|
if (swap_data(B_UINT32_TYPE, &stl_header.apply_offset, sizeof(uint32),
|
|
B_SWAP_HOST_TO_BENDIAN) != B_OK)
|
|
break;
|
|
if (swap_data(B_UINT32_TYPE, &stl_header.apply_length, sizeof(uint32),
|
|
B_SWAP_HOST_TO_BENDIAN) != B_OK)
|
|
break;
|
|
|
|
// Here, you can see the structure of the styled text data by
|
|
// observing the order that the various structs and data are
|
|
// written to the stream
|
|
ssize_t amountWritten = 0;
|
|
amountWritten = intoStream->Write(&stm_header, kStreamHeaderSize);
|
|
if ((size_t) amountWritten != kStreamHeaderSize)
|
|
break;
|
|
amountWritten = intoStream->Write(&txt_header, kTextHeaderSize);
|
|
if ((size_t) amountWritten != kTextHeaderSize)
|
|
break;
|
|
amountWritten = intoStream->Write(pTextData, textLength);
|
|
if (amountWritten != textLength)
|
|
break;
|
|
amountWritten = intoStream->Write(&stl_header, kStyleHeaderSize);
|
|
if ((size_t) amountWritten != kStyleHeaderSize)
|
|
break;
|
|
amountWritten = intoStream->Write(pflatRunArray, flatRunArrayLength);
|
|
if (amountWritten != flatRunArrayLength)
|
|
break;
|
|
|
|
loop = false;
|
|
// gracefully break out of the loop
|
|
} // end of while(loop)
|
|
|
|
free(pflatRunArray);
|
|
pflatRunArray = NULL;
|
|
free(pRunArray);
|
|
pRunArray = NULL;
|
|
|
|
if (loop)
|
|
return B_ERROR;
|
|
else
|
|
return B_NO_ERROR;
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// WriteStyledEditFile
|
|
//
|
|
// 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
|
|
// 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
|
|
// human readable.
|
|
//
|
|
// It is important to note that this function doesn't
|
|
// write files in exactly the same manner that you get
|
|
// when you do a File->Save operation in StyledEdit.
|
|
// This function doesn't write all of the attributes
|
|
// 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
|
|
BTranslationUtils::WriteStyledEditFile(BTextView *fromView, BFile *intoFile)
|
|
{
|
|
if (fromView == NULL || intoFile == NULL)
|
|
return B_BAD_VALUE;
|
|
|
|
int32 textLength = fromView->TextLength();
|
|
if (textLength < 0)
|
|
return B_ERROR;
|
|
|
|
const char *kpTextData = fromView->Text();
|
|
if (kpTextData == NULL && textLength != 0)
|
|
return B_ERROR;
|
|
|
|
// move to the start of the file if not already there
|
|
status_t result = B_OK;
|
|
result = intoFile->Seek(0,SEEK_SET);
|
|
if (result != B_OK)
|
|
return result;
|
|
|
|
// Write plain text data to file
|
|
ssize_t amtWritten = intoFile->Write(kpTextData, textLength);
|
|
if (amtWritten != textLength)
|
|
return B_ERROR;
|
|
|
|
// truncate any extra text
|
|
result = intoFile->SetSize(textLength);
|
|
if (result != B_OK)
|
|
return result;
|
|
|
|
// get the BVolume that this file is on and
|
|
// check the volume for the attribute support
|
|
node_ref nref;
|
|
result = intoFile->GetNodeRef(&nref);
|
|
if (result != B_OK)
|
|
return result;
|
|
BVolume volume(nref.device);
|
|
result = volume.InitCheck();
|
|
if (result != B_OK)
|
|
return result;
|
|
if (!volume.KnowsAttr())
|
|
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
|
|
int32 nwrap = ((fromView->DoesWordWrap()) ? 1 : 0);
|
|
amtWritten = intoFile->WriteAttr("wrap", B_INT32_TYPE, 0,
|
|
&nwrap, sizeof(int32));
|
|
if (amtWritten != 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;
|
|
else
|
|
return B_ERROR;
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// GetDefaultSettings
|
|
//
|
|
// Each translator can have default settings, set by the
|
|
// "translations" control panel. You can read these settings to
|
|
// pass on to a translator using one of these functions.
|
|
//
|
|
// Preconditions:
|
|
//
|
|
// Parameters: forTranslator, the translator the settings are for
|
|
// roster, the roster used to get the settings
|
|
//
|
|
// Postconditions:
|
|
//
|
|
// Returns: NULL, if anything went wrong
|
|
// BMessage * of configuration data for forTranslator
|
|
// ---------------------------------------------------------------
|
|
BMessage *
|
|
BTranslationUtils::GetDefaultSettings(translator_id forTranslator,
|
|
BTranslatorRoster *roster)
|
|
{
|
|
// Use default Translator if none is specified
|
|
if (roster == NULL) {
|
|
roster = BTranslatorRoster::Default();
|
|
if (roster == NULL)
|
|
return NULL;
|
|
}
|
|
|
|
BMessage *pMessage = new BMessage();
|
|
if (pMessage == NULL)
|
|
return NULL;
|
|
|
|
status_t result = roster->GetConfigurationMessage(forTranslator, pMessage);
|
|
switch (result) {
|
|
case B_OK:
|
|
break;
|
|
|
|
case B_NO_TRANSLATOR:
|
|
// 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;
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// GetDefaultSettings
|
|
//
|
|
// Attempts to find the translator settings for
|
|
// the translator named kTranslatorName with a version of
|
|
// translatorVersion.
|
|
//
|
|
// Preconditions:
|
|
//
|
|
// Parameters: kTranslatorName, the name of the translator
|
|
// the settings are for
|
|
// translatorVersion, the version of the translator
|
|
// to retrieve
|
|
//
|
|
// Postconditions:
|
|
//
|
|
// Returns: NULL, if anything went wrong
|
|
// BMessage * of configuration data for kTranslatorName
|
|
// ---------------------------------------------------------------
|
|
BMessage *
|
|
BTranslationUtils::GetDefaultSettings(const char *kTranslatorName,
|
|
int32 translatorVersion)
|
|
{
|
|
BTranslatorRoster *roster = BTranslatorRoster::Default();
|
|
translator_id *translators = NULL;
|
|
int32 numTranslators = 0;
|
|
if (roster == NULL
|
|
|| roster->GetAllTranslators(&translators, &numTranslators) != B_OK)
|
|
return NULL;
|
|
|
|
// Cycle through all of the default translators
|
|
// looking for a translator that matches the name and version
|
|
// that I was given
|
|
BMessage *pMessage = NULL;
|
|
const char *currentTranName = NULL, *currentTranInfo = NULL;
|
|
int32 currentTranVersion = 0;
|
|
for (int i = 0; i < numTranslators; i++) {
|
|
|
|
if (roster->GetTranslatorInfo(translators[i], ¤tTranName,
|
|
¤tTranInfo, ¤tTranVersion) == B_OK) {
|
|
|
|
if (currentTranVersion == translatorVersion
|
|
&& strcmp(currentTranName, kTranslatorName) == 0) {
|
|
pMessage = GetDefaultSettings(translators[i], roster);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
delete[] translators;
|
|
return pMessage;
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// AddTranslationItems
|
|
//
|
|
// Envious of that "Save As" menu in ShowImage? Well, you can have your own!
|
|
// AddTranslationItems will add menu items for all translations from the
|
|
// basic format you specify (B_TRANSLATOR_BITMAP, B_TRANSLATOR_TEXT etc).
|
|
// The translator ID and format constant chosen will be added to the message
|
|
// that is sent to you when the menu item is selected.
|
|
//
|
|
// The following code is a modified version of code
|
|
// written by Jon Watte from
|
|
// http://www.b500.com/bepage/TranslationKit2.html
|
|
//
|
|
// Preconditions:
|
|
//
|
|
// Parameters: intoMenu, the menu where the entries are created
|
|
// fromType, the type of translators to put on
|
|
// intoMenu
|
|
// kModel, the BMessage model for creating the menu
|
|
// if NULL, B_TRANSLATION_MENU is used
|
|
// kTranslationIdName, the name used for
|
|
// translator_id in the menuitem,
|
|
// if NULL, be:translator is used
|
|
// kTranslatorTypeName, the name used for
|
|
// output format id in the menuitem
|
|
// roster, BTranslatorRoster used to find translators
|
|
// if NULL, the default translators are used
|
|
//
|
|
//
|
|
// Postconditions:
|
|
//
|
|
// Returns: B_BAD_VALUE, if intoMenu is NULL
|
|
// B_OK, if successful
|
|
// error value if not successful
|
|
// ---------------------------------------------------------------
|
|
status_t
|
|
BTranslationUtils::AddTranslationItems(BMenu *intoMenu, uint32 fromType,
|
|
const BMessage *kModel, const char *kTranslatorIdName,
|
|
const char *kTranslatorTypeName, BTranslatorRoster *roster)
|
|
{
|
|
if (!intoMenu)
|
|
return B_BAD_VALUE;
|
|
|
|
if (!roster)
|
|
roster = BTranslatorRoster::Default();
|
|
|
|
if (!kTranslatorIdName)
|
|
kTranslatorIdName = "be:translator";
|
|
|
|
if (!kTranslatorTypeName)
|
|
kTranslatorTypeName = "be:type";
|
|
|
|
translator_id * ids = NULL;
|
|
int32 count = 0;
|
|
status_t err = roster->GetAllTranslators(&ids, &count);
|
|
if (err < B_OK)
|
|
return err;
|
|
|
|
for (int tix = 0; tix < count; tix++) {
|
|
const translation_format *formats = NULL;
|
|
int32 numFormats = 0;
|
|
bool ok = false;
|
|
err = roster->GetInputFormats(ids[tix], &formats, &numFormats);
|
|
if (err == B_OK) {
|
|
for (int iix = 0; iix < numFormats; iix++) {
|
|
if (formats[iix].type == fromType) {
|
|
ok = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!ok)
|
|
continue;
|
|
|
|
err = roster->GetOutputFormats(ids[tix], &formats, &numFormats);
|
|
if (err == B_OK) {
|
|
for (int oix = 0; oix < numFormats; oix++) {
|
|
if (formats[oix].type != fromType) {
|
|
BMessage *itemmsg;
|
|
if (kModel)
|
|
itemmsg = new BMessage(*kModel);
|
|
else
|
|
itemmsg = new BMessage(B_TRANSLATION_MENU);
|
|
itemmsg->AddInt32(kTranslatorIdName, ids[tix]);
|
|
itemmsg->AddInt32(kTranslatorTypeName, formats[oix].type);
|
|
intoMenu->AddItem(
|
|
new BMenuItem(formats[oix].name, itemmsg));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
delete[] ids;
|
|
return B_OK;
|
|
}
|