Add audio attachment handling

presentation
Ulrich Huber 7 years ago
parent 02d496291b
commit 96b20d31f8
  1. 126
      src/control/xojfile/LoadHandler.cpp
  2. 6
      src/control/xojfile/LoadHandler.h
  3. 6
      src/gui/PageViewFindObjectHelper.h
  4. BIN
      test/files/packaged_xopp/audioAttachment/new.xopp
  5. BIN
      test/files/packaged_xopp/audioAttachment/old.xopp
  6. BIN
      test/files/packaged_xopp/audioAttachment/test.ogg

@ -81,6 +81,12 @@ void LoadHandler::initAttributes()
this->image = NULL;
this->teximage = NULL;
this->text = NULL;
if (this->audioFiles)
{
g_hash_table_unref(this->audioFiles);
}
this->audioFiles = g_hash_table_new(g_str_hash, g_str_equal);
}
string LoadHandler::getLastError()
@ -360,6 +366,10 @@ void LoadHandler::parseContents()
this->doc.addPage(this->page);
}
else if (strcmp(elementName, "audio") == 0)
{
this->parseAudio();
}
else if (strcmp(elementName, "title") == 0)
{
// Ignore this tag, it says nothing...
@ -678,11 +688,20 @@ void LoadHandler::parseStroke()
stroke->setColor(color);
/** read stroke timestamps (xopp fileformat) */
//TODO how to handle attached audio files?
const char* fn = LoadHandlerHelper::getAttrib("fn", true, this);
if (fn != NULL)
{
stroke->setAudioFilename(fn);
if (this->isGzFile)
{
stroke->setAudioFilename(fn);
} else
{
string tempFile = getTempFileForPath(fn);
if (!tempFile.empty())
{
stroke->setAudioFilename(tempFile);
}
}
}
@ -771,11 +790,20 @@ void LoadHandler::parseText()
LoadHandlerHelper::parseColor(sColor, color, this);
text->setColor(color);
//TODO how to handle attached audio files
const char* fn = LoadHandlerHelper::getAttrib("fn", true, this);
if (fn != NULL)
{
text->setAudioFilename(fn);
if (this->isGzFile)
{
text->setAudioFilename(fn);
} else
{
string tempFile = getTempFileForPath(fn);
if (!tempFile.empty())
{
text->setAudioFilename(tempFile);
}
}
}
size_t ts = 0;
@ -899,6 +927,81 @@ void LoadHandler::parseLayer()
}
}
/**
* Create a temporary file for the attached audio file.
* The OS should take care of removing the file.
*/
void LoadHandler::parseAudio()
{
XOJ_CHECK_TYPE(LoadHandler);
const char* filename = LoadHandlerHelper::getAttrib("fn", false, this);
GFileIOStream* fileStream;
GFile* tmpFile = g_file_new_tmp("xournal_audio_XXXXXX.tmp", &fileStream, nullptr);
if (!tmpFile)
{
g_warning("Unable to create temporary file for audio attachment.");
return;
}
GOutputStream* outputStream = g_io_stream_get_output_stream(G_IO_STREAM(fileStream));
zip_stat_t attachmentFileStat;
int statStatus = zip_stat(this->zipFp, filename, 0, &attachmentFileStat);
if (statStatus != 0)
{
error("%s", FC(_F("Could not open attachment: {1}. Error message: {2}") % filename % zip_error_strerror(zip_get_error(this->zipFp))));
return;
}
gsize length;
if (attachmentFileStat.valid & ZIP_STAT_SIZE)
{
length = attachmentFileStat.size;
} else
{
error("%s", FC(_F("Could not open attachment: {1}. Error message: No valid file size provided") % filename));
return;
}
zip_file_t* attachmentFile = zip_fopen(this->zipFp, filename, 0);
if (!attachmentFile)
{
error("%s", FC(_F("Could not open attachment: {1}. Error message: {2}") % filename % zip_error_strerror(zip_get_error(this->zipFp))));
return;
}
gpointer data = g_malloc(1024);
zip_uint64_t readBytes = 0;
while (readBytes < length)
{
zip_int64_t read = zip_fread(attachmentFile, data, 1024);
if (read == -1)
{
g_object_unref(tmpFile);
g_free(data);
error("%s", FC(_F("Could not open attachment: {1}. Error message: Could not read file") % filename));
return;
}
gboolean writeSuccessful = g_output_stream_write_all(outputStream, data, static_cast<gsize>(read), nullptr, nullptr, nullptr);
if (!writeSuccessful)
{
g_object_unref(tmpFile);
g_free(data);
error("%s", FC(_F("Could not open attachment: {1}. Error message: Could not write file") % filename));
return;
}
readBytes += read;
}
zip_fclose(attachmentFile);
g_hash_table_insert(this->audioFiles, g_strdup(filename), g_file_get_path(tmpFile));
}
void LoadHandler::parserStartElement(GMarkupParseContext* context, const gchar* elementName, const gchar** attributeNames,
const gchar** attributeValues, gpointer userdata, GError** error)
{
@ -1215,4 +1318,17 @@ bool LoadHandler::readZipAttachment(string filename, gpointer& data, gsize& leng
zip_fclose(attachmentFile);
return true;
}
}
string LoadHandler::getTempFileForPath(string filename)
{
gpointer tmpFilename = g_hash_table_lookup(this->audioFiles, filename.c_str());
if (tmpFilename)
{
return string((char*) tmpFilename);
} else
{
error("%s", FC(_F("Requested temporary file was not found for attachment {1}") % filename));
return "";
}
}

@ -59,6 +59,7 @@ private:
void parseContents();
void parsePage();
void parseLayer();
void parseAudio();
void parseStroke();
void parseText();
@ -94,10 +95,10 @@ private:
void readImage(const gchar* base64string, gsize base64stringLen);
void readTexImage(const gchar* base64string, gsize base64stringLen);
bool readZipAttachment(string filename, gpointer& data, gsize& length);
private:
string parseBase64(const gchar* base64, gsize lenght);
bool readZipAttachment(string filename, gpointer& data, gsize& length);
string getTempFileForPath(string filename);
private:
XOJ_TYPE_ATTRIB;
@ -133,6 +134,7 @@ private:
Text* text;
Image* image;
TexImage* teximage;
GHashTable* audioFiles = nullptr;
const char* endRootTag = "xournal";

@ -162,7 +162,11 @@ protected:
if (!fn.empty())
{
view->getXournal()->getControl()->getAudioController()->startPlayback(Path::fromUri(view->settings->getAudioFolder()).str() + "/" + fn, (unsigned int) ts);
if (fn.rfind('/', 0) != 0)
{
fn = Path::fromUri(view->settings->getAudioFolder()).str() + "/" + fn;
}
view->getXournal()->getControl()->getAudioController()->startPlayback(fn, (unsigned int) ts);
}
}
}

Loading…
Cancel
Save