forked from mia/Aegisub
aee6b0a540
Originally committed to SVN as r4805.
322 lines
6.5 KiB
C++
322 lines
6.5 KiB
C++
// Copyright (c) 2006, Rodrigo Braz Monteiro
|
|
// All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are met:
|
|
//
|
|
// * Redistributions of source code must retain the above copyright notice,
|
|
// this list of conditions and the following disclaimer.
|
|
// * Redistributions in binary form must reproduce the above copyright notice,
|
|
// this list of conditions and the following disclaimer in the documentation
|
|
// and/or other materials provided with the distribution.
|
|
// * Neither the name of the Aegisub Group nor the names of its contributors
|
|
// may be used to endorse or promote products derived from this software
|
|
// without specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
// POSSIBILITY OF SUCH DAMAGE.
|
|
//
|
|
// Aegisub Project http://www.aegisub.org/
|
|
//
|
|
// $Id$
|
|
|
|
/// @file ass_attachment.cpp
|
|
/// @brief Manage files embedded in subtitles
|
|
/// @ingroup subs_storage
|
|
///
|
|
|
|
|
|
////////////
|
|
// Includes
|
|
#include "config.h"
|
|
|
|
#ifndef AGI_PRE
|
|
#include <wx/filename.h>
|
|
#include <wx/wfstream.h>
|
|
#endif
|
|
|
|
#include "ass_attachment.h"
|
|
|
|
|
|
|
|
/// @brief Constructor
|
|
/// @param _name
|
|
///
|
|
AssAttachment::AssAttachment(wxString _name) {
|
|
// Parse name
|
|
filename = _name;
|
|
wxFileName fname(GetFileName());
|
|
wxString ext = fname.GetExt().Lower();
|
|
wxString name;
|
|
if (ext == _T("ttf")) {
|
|
name = fname.GetName() + _T("_0.") + ext;
|
|
}
|
|
else name = _name;
|
|
|
|
// Set data
|
|
filename = name;
|
|
data = std::tr1::shared_ptr<AttachData> (new AttachData);
|
|
}
|
|
|
|
|
|
|
|
/// @brief Destructor
|
|
///
|
|
AssAttachment::~AssAttachment() {
|
|
}
|
|
|
|
|
|
|
|
/// @brief Clone
|
|
/// @return
|
|
///
|
|
AssEntry *AssAttachment::Clone() const {
|
|
// New object
|
|
AssAttachment *clone = new AssAttachment(filename);
|
|
|
|
// Copy fields
|
|
clone->data = data;
|
|
clone->group = group;
|
|
|
|
// Return
|
|
return clone;
|
|
}
|
|
|
|
|
|
|
|
/// @brief Get data
|
|
/// @return
|
|
///
|
|
const DataVec &AssAttachment::GetData() {
|
|
return data->GetData();
|
|
}
|
|
|
|
|
|
|
|
/// @brief Add more data
|
|
/// @param _data
|
|
///
|
|
void AssAttachment::AddData(wxString _data) {
|
|
data->AddData(_data);
|
|
}
|
|
|
|
|
|
|
|
/// @brief Finish adding data
|
|
///
|
|
void AssAttachment::Finish() {
|
|
data->Finish();
|
|
}
|
|
|
|
|
|
|
|
/// @brief Get encoded data to write on file
|
|
/// @return
|
|
///
|
|
const wxString AssAttachment::GetEntryData() const {
|
|
// Get data
|
|
const DataVec &dat = data->GetData();
|
|
int pos = 0;
|
|
int size = dat.size();
|
|
int written = 0;
|
|
unsigned char src[3];
|
|
unsigned char dst[4];
|
|
|
|
// Write header
|
|
wxString entryData;
|
|
if (group == _T("[Fonts]")) entryData = _T("fontname: ");
|
|
else entryData = _T("filename: ");
|
|
entryData += filename + _T("\r\n");
|
|
|
|
// Read three bytes
|
|
while (pos < size) {
|
|
// Number to read
|
|
int read = size - pos;
|
|
if (read > 3) read = 3;
|
|
|
|
// Read source
|
|
src[0] = dat[pos];
|
|
if (read >= 2) src[1] = dat[pos+1];
|
|
else src[1] = 0;
|
|
if (read == 3) src[2] = dat[pos+2];
|
|
else src[2] = 0;
|
|
pos += read;
|
|
|
|
// Codify
|
|
dst[0] = src[0] >> 2;
|
|
dst[1] = ((src[0] & 0x3) << 4) | ((src[1] & 0xF0) >> 4);
|
|
dst[2] = ((src[1] & 0xF) << 2) | ((src[2] & 0xC0) >> 6);
|
|
dst[3] = src[2] & 0x3F;
|
|
|
|
// Number to write
|
|
int toWrite = read+1;
|
|
|
|
// Convert to text
|
|
for (int i=0;i<toWrite;i++) {
|
|
entryData += wxChar(dst[i]+33);
|
|
written++;
|
|
|
|
// Line break
|
|
if (written == 80 && pos < size) {
|
|
written = 0;
|
|
entryData += _T("\r\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
// Return
|
|
return entryData;
|
|
}
|
|
|
|
|
|
|
|
/// @brief Extract as a file
|
|
/// @param filename
|
|
/// @return
|
|
///
|
|
void AssAttachment::Extract(wxString filename) {
|
|
// Open file
|
|
wxFileOutputStream fp(filename);
|
|
if (!fp.Ok()) return;
|
|
fp.Write(&data->GetData()[0],data->GetData().size());
|
|
}
|
|
|
|
|
|
|
|
/// @brief Read a file as attachment
|
|
/// @param filename
|
|
///
|
|
void AssAttachment::Import(wxString filename) {
|
|
// Data
|
|
DataVec &datavec = data->GetData();
|
|
|
|
// Open file and get size
|
|
wxFileInputStream fp(filename);
|
|
if (!fp.Ok()) throw _T("Failed opening file");
|
|
int size = fp.SeekI(0,wxFromEnd);
|
|
fp.SeekI(0,wxFromStart);
|
|
|
|
// Set size and read
|
|
datavec.resize(size);
|
|
fp.Read(&datavec[0],size);
|
|
}
|
|
|
|
|
|
|
|
/// @brief Get filename
|
|
/// @param raw
|
|
/// @return
|
|
///
|
|
wxString AssAttachment::GetFileName(bool raw) {
|
|
// Raw
|
|
if (raw || filename.Right(4).Lower() != _T(".ttf")) return filename;
|
|
|
|
// Remove stuff after last underscore if it's a font
|
|
int lastUnder = -1;
|
|
for (size_t i=0;i<filename.Length();i++) {
|
|
if (filename[i] == _T('_')) lastUnder = i;
|
|
}
|
|
|
|
// Underline found
|
|
wxString final = filename;
|
|
if (lastUnder != -1) {
|
|
final = filename.Left(lastUnder) + _T(".ttf");
|
|
}
|
|
return final;
|
|
}
|
|
|
|
|
|
|
|
|
|
/// @brief Constructor Attachment //////////////////
|
|
///
|
|
AttachData::AttachData() {
|
|
}
|
|
|
|
|
|
|
|
/// @brief Destructor
|
|
///
|
|
AttachData::~AttachData() {
|
|
}
|
|
|
|
|
|
|
|
/// @brief Get data
|
|
/// @return
|
|
///
|
|
DataVec &AttachData::GetData() {
|
|
return data;
|
|
}
|
|
|
|
|
|
|
|
/// @brief Add data
|
|
/// @param data
|
|
///
|
|
void AttachData::AddData(wxString data) {
|
|
buffer += data;
|
|
}
|
|
|
|
|
|
|
|
/// @brief Finish
|
|
///
|
|
void AttachData::Finish() {
|
|
// Source and dest buffers
|
|
unsigned char src[4];
|
|
unsigned char dst[3];
|
|
int bufPos = 0;
|
|
bool ok = true;
|
|
|
|
// Read buffer
|
|
while (ok) {
|
|
// Find characters left
|
|
int read = buffer.Length() - bufPos;
|
|
if (read > 4) read = 4;
|
|
int nbytes;
|
|
|
|
// At least four, proceed normally
|
|
if (read >= 2) {
|
|
// Move 4 bytes from buffer to src
|
|
for (int i=0;i<read;i++) {
|
|
src[i] = (unsigned char) buffer[bufPos] - 33;
|
|
bufPos++;
|
|
}
|
|
for (int i=read;i<4;i++) src[i] = 0;
|
|
ok = true;
|
|
nbytes = read-1;
|
|
}
|
|
|
|
// Zero, end
|
|
else {
|
|
ok = false;
|
|
break;
|
|
}
|
|
|
|
// Convert the 4 bytes from source to 3 in dst
|
|
dst[0] = (src[0] << 2) | (src[1] >> 4);
|
|
dst[1] = ((src[1] & 0xF) << 4) | (src[2] >> 2);
|
|
dst[2] = ((src[2] & 0x3) << 6) | (src[3]);
|
|
|
|
// Push into vector
|
|
size_t size = data.size();
|
|
data.resize(size+nbytes);
|
|
for (int i=0;i<nbytes;i++) data[size+i] = dst[i];
|
|
}
|
|
|
|
// Clear buffer
|
|
buffer.Clear();
|
|
buffer.Shrink();
|
|
}
|
|
|
|
|