Update libaaf to v1.0-1-gdef35bf

This commit is contained in:
agfline 2024-03-10 21:55:40 +01:00 committed by Robin Gareus
parent 2b1349ffc2
commit bd937366fd
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
38 changed files with 9153 additions and 7831 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2017-2023 Adrien Gesta-Fline
* Copyright (C) 2017-2024 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
@ -38,31 +38,31 @@
#include "aaf/AAFDefs/AAFPropertyIDs.h"
#include "aaf/AAFDefs/AAFTypeDefUIDs.h"
#include "aaf/debug.h"
#include "aaf/log.h"
#include "aaf/AAFClass.h"
#define debug(...) \
_dbg (aafd->dbg, aafd, DEBUG_SRC_ID_AAF_CORE, VERB_DEBUG, __VA_ARGS__)
AAF_LOG (aafd->log, aafd, DEBUG_SRC_ID_AAF_CORE, VERB_DEBUG, __VA_ARGS__)
#define warning(...) \
_dbg (aafd->dbg, aafd, DEBUG_SRC_ID_AAF_CORE, VERB_WARNING, __VA_ARGS__)
AAF_LOG (aafd->log, aafd, DEBUG_SRC_ID_AAF_CORE, VERB_WARNING, __VA_ARGS__)
#define error(...) \
_dbg (aafd->dbg, aafd, DEBUG_SRC_ID_AAF_CORE, VERB_ERROR, __VA_ARGS__)
AAF_LOG (aafd->log, aafd, DEBUG_SRC_ID_AAF_CORE, VERB_ERROR, __VA_ARGS__)
#define attachNewProperty(aafd, Class, Prop, Pid, IsReq) \
Prop = calloc (sizeof (aafPropertyDef), sizeof (unsigned char)); \
if (Prop == NULL) { \
error ("%s.", strerror (errno)); \
return -1; \
} \
Prop->pid = Pid; \
Prop->name = NULL; \
Prop->isReq = IsReq; \
Prop->meta = 0; \
Prop->next = Class->Properties; \
memset (&Prop->type, 0x00, sizeof (aafUID_t)); \
#define attachNewProperty(aafd, Class, Prop, Pid, IsReq) \
Prop = calloc (1, sizeof (aafPropertyDef)); \
if (!Prop) { \
error ("Out of memory"); \
return -1; \
} \
Prop->pid = Pid; \
Prop->name = NULL; \
Prop->isReq = IsReq; \
Prop->meta = 0; \
Prop->next = Class->Properties; \
memset (&Prop->type, 0x00, sizeof (aafUID_t)); \
Class->Properties = Prop;
int
@ -72,7 +72,7 @@ aafclass_classExists (AAF_Data* aafd, aafUID_t* ClassID)
foreachClass (Class, aafd->Classes) if (aafUIDCmp (Class->ID, ClassID)) break;
if (Class == NULL)
if (!Class)
return 0;
return 1;
@ -95,8 +95,8 @@ aafclass_defineNewClass (AAF_Data* aafd, const aafUID_t* id, uint8_t isConcrete,
{
aafClass* Class = malloc (sizeof (aafClass));
if (Class == NULL) {
error ("%s.", strerror (errno));
if (!Class) {
error ("Out of memory");
return NULL;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2017-2023 Adrien Gesta-Fline
* Copyright (C) 2017-2024 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
@ -21,68 +21,134 @@
#include <stdio.h>
#include <string.h>
#include "aaf/AAFDefs/AAFClassDefUIDs.h"
#include "aaf/AAFDefs/AAFPropertyIDs.h"
#include "aaf/AAFDefs/AAFTypeDefUIDs.h"
#include "aaf/AAFDump.h"
#include "aaf/AAFToText.h"
#include "aaf/AAFTypes.h"
#include "aaf/AAFClass.h"
#include "aaf/utils.h"
#include "aaf/AAFClass.h"
void
aaf_dump_Header (AAF_Data* aafd)
aaf_dump_Header (AAF_Data* aafd, const char* padding)
{
struct dbg* dbg = aafd->dbg;
struct aafLog* log = aafd->log;
DBG_BUFFER_WRITE (dbg, " ByteOrder : %ls (0x%04x)\n", aaft_ByteOrderToText (aafd->Header.ByteOrder), aafd->Header.ByteOrder);
DBG_BUFFER_WRITE (dbg, " LastModified : %ls\n", aaft_TimestampToText (aafd->Header.LastModified));
DBG_BUFFER_WRITE (dbg, " AAF ObjSpec Version : %ls\n", aaft_VersionToText (aafd->Header.Version));
DBG_BUFFER_WRITE (dbg, " ObjectModel Version : %u\n", aafd->Header.ObjectModelVersion);
DBG_BUFFER_WRITE (dbg, " Operational Pattern : %ls\n", aaft_OPDefToText (aafd->Header.OperationalPattern));
LOG_BUFFER_WRITE (log, "%sByteOrder : %s%s (0x%04x)%s\n", padding, ANSI_COLOR_DARKGREY (log), aaft_ByteOrderToText (aafd->Header.ByteOrder), aafd->Header.ByteOrder, ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%sLastModified : %s%s%s\n", padding, ANSI_COLOR_DARKGREY (log), aaft_TimestampToText (aafd->Header.LastModified), ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%sAAF ObjSpec Version : %s%s%s\n", padding, ANSI_COLOR_DARKGREY (log), aaft_VersionToText (aafd->Header.Version), ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%sObjectModel Version : %s%u%s\n", padding, ANSI_COLOR_DARKGREY (log), aafd->Header.ObjectModelVersion, ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%sOperational Pattern : %s%s%s\n", padding, ANSI_COLOR_DARKGREY (log), aaft_OPDefToText (aafd->Header.OperationalPattern), ANSI_COLOR_RESET (log));
DBG_BUFFER_WRITE (dbg, "\n\n");
LOG_BUFFER_WRITE (log, "\n\n");
dbg->debug_callback (dbg, (void*)aafd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, dbg->_dbg_msg, dbg->user);
log->debug_callback (log, (void*)aafd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, log->_msg, log->user);
}
void
aaf_dump_Identification (AAF_Data* aafd)
aaf_dump_Identification (AAF_Data* aafd, const char* padding)
{
struct dbg* dbg = aafd->dbg;
struct aafLog* log = aafd->log;
DBG_BUFFER_WRITE (dbg, " CompanyName : %ls\n", (aafd->Identification.CompanyName) ? aafd->Identification.CompanyName : L"n/a");
DBG_BUFFER_WRITE (dbg, " ProductName : %ls\n", (aafd->Identification.ProductName) ? aafd->Identification.ProductName : L"n/a");
DBG_BUFFER_WRITE (dbg, " ProductVersion : %ls\n", aaft_ProductVersionToText (aafd->Identification.ProductVersion));
DBG_BUFFER_WRITE (dbg, " ProductVersionString : %ls\n", (aafd->Identification.ProductVersionString) ? aafd->Identification.ProductVersionString : L"n/a");
DBG_BUFFER_WRITE (dbg, " ProductID : %ls\n", AUIDToText (aafd->Identification.ProductID));
DBG_BUFFER_WRITE (dbg, " Date : %ls\n", aaft_TimestampToText (aafd->Identification.Date));
DBG_BUFFER_WRITE (dbg, " ToolkitVersion : %ls\n", aaft_ProductVersionToText (aafd->Identification.ToolkitVersion));
DBG_BUFFER_WRITE (dbg, " Platform : %ls\n", (aafd->Identification.Platform) ? aafd->Identification.Platform : L"n/a");
DBG_BUFFER_WRITE (dbg, " GenerationAUID : %ls\n", AUIDToText (aafd->Identification.GenerationAUID));
LOG_BUFFER_WRITE (log, "%sCompanyName : %s%s%s\n", padding, ANSI_COLOR_DARKGREY (log), (aafd->Identification.CompanyName) ? aafd->Identification.CompanyName : "n/a", ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%sProductName : %s%s%s\n", padding, ANSI_COLOR_DARKGREY (log), (aafd->Identification.ProductName) ? aafd->Identification.ProductName : "n/a", ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%sProductVersion : %s%s%s\n", padding, ANSI_COLOR_DARKGREY (log), aaft_ProductVersionToText (aafd->Identification.ProductVersion), ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%sProductVersionString : %s%s%s\n", padding, ANSI_COLOR_DARKGREY (log), (aafd->Identification.ProductVersionString) ? aafd->Identification.ProductVersionString : "n/a", ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%sProductID : %s%s%s\n", padding, ANSI_COLOR_DARKGREY (log), AUIDToText (aafd->Identification.ProductID), ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%sDate : %s%s%s\n", padding, ANSI_COLOR_DARKGREY (log), aaft_TimestampToText (aafd->Identification.Date), ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%sToolkitVersion : %s%s%s\n", padding, ANSI_COLOR_DARKGREY (log), aaft_ProductVersionToText (aafd->Identification.ToolkitVersion), ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%sPlatform : %s%s%s\n", padding, ANSI_COLOR_DARKGREY (log), (aafd->Identification.Platform) ? aafd->Identification.Platform : "n/a", ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%sGenerationAUID : %s%s%s\n", padding, ANSI_COLOR_DARKGREY (log), AUIDToText (aafd->Identification.GenerationAUID), ANSI_COLOR_RESET (log));
DBG_BUFFER_WRITE (dbg, "\n\n");
LOG_BUFFER_WRITE (log, "\n\n");
dbg->debug_callback (dbg, (void*)aafd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, dbg->_dbg_msg, dbg->user);
log->debug_callback (log, (void*)aafd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, log->_msg, log->user);
}
void
aaf_dump_ObjectProperty (AAF_Data* aafd, aafProperty* Prop)
aaf_dump_ObjectProperty (AAF_Data* aafd, aafProperty* Prop, const char* padding)
{
struct dbg* dbg = aafd->dbg;
struct aafLog* log = aafd->log;
if (Prop->def->meta) {
DBG_BUFFER_WRITE (dbg, " :.: %s(0x%04x) %ls%s (%ls)\n", ANSI_COLOR_YELLOW (dbg), Prop->pid, aaft_PIDToText (aafd, Prop->pid), ANSI_COLOR_RESET (dbg), aaft_StoredFormToText (Prop->sf) /*AUIDToText( &Prop->def->type ),*/ /*aaft_TypeIDToText( &(Prop->def->type) )*/);
LOG_BUFFER_WRITE (log, "%s%s[%s0x%04x%s] %s (%s)\n",
padding,
ANSI_COLOR_RESET (log),
ANSI_COLOR_MAGENTA (log),
Prop->pid,
ANSI_COLOR_RESET (log),
aaft_PIDToText (aafd, Prop->pid),
aaft_StoredFormToText (Prop->sf));
} else {
DBG_BUFFER_WRITE (dbg, " :.: (0x%04x) %ls (%ls)\n", Prop->pid, aaft_PIDToText (aafd, Prop->pid), aaft_StoredFormToText (Prop->sf) /*AUIDToText( &Prop->def->type ),*/ /*aaft_TypeIDToText( &(Prop->def->type) )*/);
LOG_BUFFER_WRITE (log, "%s%s[%s0x%04x%s] %s (%s)\n",
padding,
ANSI_COLOR_RESET (log),
ANSI_COLOR_DARKGREY (log),
Prop->pid,
ANSI_COLOR_RESET (log),
aaft_PIDToText (aafd, Prop->pid),
aaft_StoredFormToText (Prop->sf));
}
// WARNING : Wont print strong references (set/vector) corectly.
aafd->dbg->_dbg_msg_pos += laaf_util_dump_hex (Prop->val, Prop->len, &aafd->dbg->_dbg_msg, &aafd->dbg->_dbg_msg_size, aafd->dbg->_dbg_msg_pos);
int rc = laaf_util_dump_hex (Prop->val, Prop->len, &aafd->log->_msg, &aafd->log->_msg_size, aafd->log->_msg_pos, padding);
dbg->debug_callback (dbg, (void*)aafd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, dbg->_dbg_msg, dbg->user);
if (rc > 0) {
aafd->log->_msg_pos += (size_t)rc;
}
log->debug_callback (log, (void*)aafd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, log->_msg, log->user);
}
void
aaf_dump_ObjectProperties (AAF_Data* aafd, aafObject* Obj)
aaf_dump_TaggedValueSet (AAF_Data* aafd, aafObject* ObjCollection, const char* padding)
{
struct aafLog* log = aafd->log;
aafObject* Obj = NULL;
int i = 0;
AAF_foreach_ObjectInSet (&Obj, ObjCollection, NULL)
{
i++;
if (!aafUIDCmp (Obj->Class->ID, &AAFClassID_TaggedValue)) {
LOG_BUFFER_WRITE (log, "%s%sObject > %s\n",
padding,
ANSI_COLOR_RESET (log),
aaft_ClassIDToText (aafd, Obj->Class->ID));
continue;
}
char* name = aaf_get_propertyValue (Obj, PID_TaggedValue_Name, &AAFTypeID_String);
aafIndirect_t* indirect = aaf_get_propertyValue (Obj, PID_TaggedValue_Value, &AAFTypeID_Indirect);
LOG_BUFFER_WRITE (log, "%s%sTagged > Name: %s%s%s%*s Value: %s(%s)%s %s%s%s%s%s\n",
padding,
ANSI_COLOR_RESET (log),
ANSI_COLOR_DARKGREY (log),
(name) ? name : "<unknown>",
ANSI_COLOR_RESET (log),
(name) ? (size_t) (34 - (int)strlen (name)) : (size_t) (34 - strlen ("<unknown>")), " ",
ANSI_COLOR_DARKGREY (log),
aaft_TypeIDToText (&indirect->TypeDef),
ANSI_COLOR_RESET (log),
ANSI_COLOR_DARKGREY (log),
(aafUIDCmp (&indirect->TypeDef, &AAFTypeID_String)) ? "\"" : "",
aaft_IndirectValueToText (aafd, indirect),
(aafUIDCmp (&indirect->TypeDef, &AAFTypeID_String)) ? "\"" : "",
ANSI_COLOR_RESET (log));
log->debug_callback (log, (void*)aafd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, log->_msg, log->user);
free (name);
}
}
void
aaf_dump_ObjectProperties (AAF_Data* aafd, aafObject* Obj, const char* padding)
{
/*
* List the properties once they have been parsed and interpreted by AAFCore.
@ -91,20 +157,23 @@ aaf_dump_ObjectProperties (AAF_Data* aafd, aafObject* Obj)
aafProperty* Prop = NULL;
for (Prop = Obj->Properties; Prop != NULL; Prop = Prop->next) {
aaf_dump_ObjectProperty (aafd, Prop);
aaf_dump_ObjectProperty (aafd, Prop, padding);
}
}
void
aaf_dump_rawProperties (AAF_Data* aafd, aafByte_t* propStream)
aaf_dump_rawProperties (AAF_Data* aafd, aafByte_t* propStream, const char* padding)
{
struct dbg* dbg = aafd->dbg;
struct aafLog* log = aafd->log;
if (propStream == NULL) {
DBG_BUFFER_WRITE (dbg,
" ## Property_Header____________________________________________________\n\n"
" aafPropertyIndexHeader_t is NULL\n"
" ======================================================================\n\n");
LOG_BUFFER_WRITE (log,
"%s## Property_Header____________________________________________________\n\n"
"%saafPropertyIndexHeader_t is NULL\n"
"%s======================================================================\n\n",
padding,
padding,
padding);
return;
}
@ -115,53 +184,52 @@ aaf_dump_rawProperties (AAF_Data* aafd, aafByte_t* propStream)
memcpy (&Header, propStream, sizeof (aafPropertyIndexHeader_t));
uint32_t i = 0;
uint32_t valueOffset = 0;
size_t valueOffset = 0;
DBG_BUFFER_WRITE (dbg,
" ## Property_Header____________________________________________________\n\n"
" _byteOrder : 0x%02x\n"
" _formatVersion : 0x%02x\n"
" _entryCount : %u\n\n"
" ======================================================================\n\n",
Header._byteOrder,
Header._formatVersion,
Header._entryCount);
LOG_BUFFER_WRITE (log,
"%s## Property_Header____________________________________________________\n\n"
"%s_byteOrder : %s0x%02x%s\n"
"%s_formatVersion : %s0x%02x%s\n"
"%s_entryCount : %s%u%s\n\n"
"%s======================================================================\n\n",
padding,
padding, ANSI_COLOR_DARKGREY (log), Header._byteOrder, ANSI_COLOR_RESET (log),
padding, ANSI_COLOR_DARKGREY (log), Header._formatVersion, ANSI_COLOR_RESET (log),
padding, ANSI_COLOR_DARKGREY (log), Header._entryCount, ANSI_COLOR_RESET (log),
padding);
DBG_BUFFER_WRITE (dbg, "\n\n");
LOG_BUFFER_WRITE (log, "\n\n");
/*
* Since the following for-loop macro is not intended to be user
* accessible, it has been defined as a local macro in AAFCore.c.
*/
foreachPropertyEntry (propStream, Header, Prop, value, valueOffset, i)
{
LOG_BUFFER_WRITE (log,
"%s#%u Property_Entry_____________________________________________________\n"
"%s_pid : %s0x%04x (%s)%s\n"
"%s_storedForm : %s%s%s\n"
"%s_length : %s%u bytes%s\n",
padding, i,
padding, ANSI_COLOR_DARKGREY (log), Prop._pid, aaft_PIDToText (aafd, Prop._pid), ANSI_COLOR_RESET (log),
padding, ANSI_COLOR_DARKGREY (log), aaft_StoredFormToText (Prop._storedForm), ANSI_COLOR_RESET (log),
padding, ANSI_COLOR_DARKGREY (log), Prop._length, ANSI_COLOR_RESET (log));
// foreachPropertyEntry( Header, Prop, value, i )
for (valueOffset = sizeof (aafPropertyIndexHeader_t) + (Header._entryCount * sizeof (aafPropertyIndexEntry_t)),
i = 0;
i < Header._entryCount &&
memcpy (&Prop, (propStream + ((sizeof (aafPropertyIndexHeader_t)) + (sizeof (aafPropertyIndexEntry_t) * i))), sizeof (aafPropertyIndexEntry_t)) &&
(value = propStream + valueOffset);
valueOffset += Prop._length,
i++) {
DBG_BUFFER_WRITE (dbg,
" #%u Property_Entry_____________________________________________________\n"
" _pid : 0x%04x (%ls)\n"
" _storedForm : %ls\n"
" _length : %u bytes\n",
i,
Prop._pid, aaft_PIDToText (aafd, Prop._pid),
aaft_StoredFormToText (Prop._storedForm),
Prop._length);
int rc = laaf_util_dump_hex (value, Prop._length, &aafd->log->_msg, &aafd->log->_msg_size, aafd->log->_msg_pos, padding);
aafd->dbg->_dbg_msg_pos += laaf_util_dump_hex (value, Prop._length, &aafd->dbg->_dbg_msg, &aafd->dbg->_dbg_msg_size, aafd->dbg->_dbg_msg_pos);
if (rc > 0) {
aafd->log->_msg_pos += (size_t)rc;
}
DBG_BUFFER_WRITE (dbg, "\n");
LOG_BUFFER_WRITE (log, "\n");
}
dbg->debug_callback (dbg, (void*)aafd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, dbg->_dbg_msg, dbg->user);
log->debug_callback (log, (void*)aafd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, log->_msg, log->user);
}
void
aaf_dump_nodeStreamProperties (AAF_Data* aafd, cfbNode* node)
aaf_dump_nodeStreamProperties (AAF_Data* aafd, cfbNode* node, const char* padding)
{
/*
* List the raw properties directly from a CFB Node's stream.
@ -171,13 +239,13 @@ aaf_dump_nodeStreamProperties (AAF_Data* aafd, cfbNode* node)
cfb_getStream (aafd->cfbd, node, &propStream, NULL);
aaf_dump_rawProperties (aafd, propStream);
aaf_dump_rawProperties (aafd, propStream, padding);
free (propStream);
}
void
aaf_dump_MetaDictionary (AAF_Data* aafd)
aaf_dump_MetaDictionary (AAF_Data* aafd, const char* padding)
{
/*
* NOTE Only dumps the "custom" classes/properties, since those are the only
@ -185,7 +253,7 @@ aaf_dump_MetaDictionary (AAF_Data* aafd)
* wont be printed out.
*/
struct dbg* dbg = aafd->dbg;
struct aafLog* log = aafd->log;
aafClass* Class = NULL;
@ -198,42 +266,42 @@ aaf_dump_MetaDictionary (AAF_Data* aafd)
foreachPropertyDefinition (PDef, Class->Properties)
{
if (Class->meta) {
DBG_BUFFER_WRITE (dbg, "%s%ls::%ls (0x%04x)%s\n",
ANSI_COLOR_YELLOW (dbg),
LOG_BUFFER_WRITE (log, "%s%s%s::%s (0x%04x)%s\n",
padding,
ANSI_COLOR_MAGENTA (log),
Class->name,
PDef->name,
PDef->pid,
ANSI_COLOR_RESET (dbg));
ANSI_COLOR_RESET (log));
print++;
} else if (PDef->meta) {
DBG_BUFFER_WRITE (dbg, "%ls::%s%ls (0x%04x)%s\n",
LOG_BUFFER_WRITE (log, "%s%s::%s%s (0x%04x)%s\n",
padding,
aaft_ClassIDToText (aafd, Class->ID),
ANSI_COLOR_YELLOW (dbg),
ANSI_COLOR_MAGENTA (log),
PDef->name,
PDef->pid,
ANSI_COLOR_RESET (dbg));
ANSI_COLOR_RESET (log));
print++;
}
}
if (print) {
DBG_BUFFER_WRITE (dbg, "\n");
LOG_BUFFER_WRITE (log, "\n");
}
print = 1;
}
DBG_BUFFER_WRITE (dbg, "\n\n");
LOG_BUFFER_WRITE (log, "\n\n");
dbg->debug_callback (dbg, (void*)aafd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, dbg->_dbg_msg, dbg->user);
log->debug_callback (log, (void*)aafd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, log->_msg, log->user);
}
void
aaf_dump_Classes (AAF_Data* aafd)
aaf_dump_Classes (AAF_Data* aafd, const char* padding)
{
struct dbg* dbg = aafd->dbg;
struct aafLog* log = aafd->log;
aafClass* ConcreteClass = NULL;
aafClass* Class = NULL;
@ -242,19 +310,21 @@ aaf_dump_Classes (AAF_Data* aafd)
{
foreachClassInheritance (Class, ConcreteClass)
{
DBG_BUFFER_WRITE (dbg, "%s%ls%s",
(Class->meta) ? ANSI_COLOR_YELLOW (dbg) : "",
LOG_BUFFER_WRITE (log, "%s%s%s%s",
padding,
(Class->meta) ? ANSI_COLOR_MAGENTA (log) : "",
aaft_ClassIDToText (aafd, Class->ID),
(Class->meta) ? ANSI_COLOR_RESET (dbg) : "");
(Class->meta) ? ANSI_COLOR_RESET (log) : "");
if (Class->Parent != NULL)
DBG_BUFFER_WRITE (dbg, " > ");
if (Class->Parent != NULL) {
LOG_BUFFER_WRITE (log, " > ");
}
}
DBG_BUFFER_WRITE (dbg, "\n");
LOG_BUFFER_WRITE (log, "\n");
}
DBG_BUFFER_WRITE (dbg, "\n\n");
LOG_BUFFER_WRITE (log, "\n\n");
dbg->debug_callback (dbg, (void*)aafd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, dbg->_dbg_msg, dbg->user);
log->debug_callback (log, (void*)aafd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, log->_msg, log->user);
}

View File

@ -1,647 +0,0 @@
/*
* Copyright (C) 2017-2023 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <ctype.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <wchar.h>
#include "aaf/AAFIAudioFiles.h"
#include "aaf/AAFIface.h"
#include "aaf/debug.h"
#include "aaf/RIFFParser.h"
#include "aaf/URIParser.h"
#include "aaf/utils.h"
#if defined(__linux__)
#include <linux/limits.h>
#include <arpa/inet.h>
#include <mntent.h>
#include <unistd.h> /* access() */
#elif defined(__APPLE__)
#include <sys/syslimits.h>
#include <unistd.h> /* access() */
#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
#include <limits.h>
#define R_OK 4 /* Test for read permission. */
#define W_OK 2 /* Test for write permission. */
#define F_OK 0 /* Test for existence. */
#ifndef _MSC_VER
#include <unistd.h> // access()
#endif
#endif
#define WAV_FILE_EXT "wav"
#define AIFF_FILE_EXT "aif"
#define debug(...) \
_dbg (aafi->dbg, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_DEBUG, __VA_ARGS__)
#define warning(...) \
_dbg (aafi->dbg, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_WARNING, __VA_ARGS__)
#define error(...) \
_dbg (aafi->dbg, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_ERROR, __VA_ARGS__)
static size_t
embeddedAudioDataReaderCallback (unsigned char* buf, size_t offset, size_t reqLen, void* user1, void* user2, void* user3);
static size_t
externalAudioDataReaderCallback (unsigned char* buf, size_t offset, size_t reqLen, void* user1, void* user2, void* user3);
wchar_t*
aafi_locate_external_essence_file (AAF_Iface* aafi, const wchar_t* original_uri_filepath, const char* search_location)
{
/*
* Absolute Uniform Resource Locator (URL) complying with RFC 1738 or relative
* Uniform Resource Identifier (URI) complying with RFC 2396 for file containing
* the essence. If it is a relative URI, the base URI is determined from the URI
* of the AAF file itself.
*
* Informative note: A valid URL or URI uses a constrained character set and
* uses the / character as the path separator.
*/
char* uri_filepath = NULL;
char* local_filepath = NULL;
char* aaf_path = NULL;
char* foundpath = NULL;
wchar_t* retpath = NULL;
struct uri* uri = NULL;
if (original_uri_filepath == NULL) {
error ("Cant locate a NULL filepath");
goto err;
}
uri_filepath = laaf_util_wstr2str (original_uri_filepath);
if (uri_filepath == NULL) {
error ("Could not convert original_uri_filepath from wstr to str : %ls", original_uri_filepath);
goto err;
}
// debug( "Original URI : %s", uri_filepath );
uri = uriParse (uri_filepath, URI_OPT_DECODE_ALL, aafi->dbg);
if (uri == NULL) {
error ("Could not parse URI");
goto err;
}
if (uri->path == NULL) {
error ("Could not retrieve <path> out of URI");
goto err;
}
// debug( "Decoded URI's path : %s", uri->path );
/* extract relative path to essence file : "<firstparent>/<essence.file>" */
char* relativeEssencePath = NULL;
char* p = uri->path + strlen (uri->path);
int sepcount = 0;
while (p > uri->path) {
if (*p == '/') { /* parsing URI, so will always be '/' as separator character */
sepcount++;
if (sepcount == 2) {
relativeEssencePath = (p + 1);
break;
}
}
p--;
}
const char* essenceFileName = laaf_util_fop_get_file (uri->path);
// debug( "Essence filename : %s", essenceFileName );
if (search_location) {
/*
* "<search_location>/<essence.file>"
*/
local_filepath = laaf_util_build_path (DIR_SEP_STR, search_location, essenceFileName, NULL);
if (local_filepath == NULL) {
error ("Could not build search filepath");
goto err;
}
// debug( "Search filepath : %s", local_filepath );
if (access (local_filepath, F_OK) != -1) {
// debug( "FOUND: %s", local_filepath );
foundpath = local_filepath;
goto found;
}
free (local_filepath);
local_filepath = NULL;
/*
* "<search_location>/<firstparentInOriginalEssencePath>/<essence.file>"
*/
local_filepath = laaf_util_build_path (DIR_SEP_STR, search_location, relativeEssencePath, NULL);
if (local_filepath == NULL) {
error ("Could not build search filepath");
goto err;
}
// debug( "Search filepath : %s", local_filepath );
if (access (local_filepath, F_OK) != -1) {
// debug( "FOUND: %s", local_filepath );
foundpath = local_filepath;
goto found;
}
free (local_filepath);
local_filepath = NULL;
}
/* Try AAF essence's URI */
if (access (uri_filepath, F_OK) != -1) {
// debug( "FOUND: %s", uri_filepath );
foundpath = uri_filepath;
goto found;
}
/* Try <path> part of URI */
if (access (uri->path, F_OK) != -1) {
// debug( "FOUND: %s", uri->path );
foundpath = uri->path;
goto found;
}
if (uri->flags & URI_T_LOCALHOST) {
// debug( "URI targets localhost : %s", uri_filepath );
} else {
if (uri->flags & URI_T_HOST_IPV4) {
// debug( "URI targets IPV4 : %s", uri_filepath );
} else if (uri->flags & URI_T_HOST_IPV6) {
// debug( "URI targets IPV6 : %s", uri_filepath );
} else if (uri->flags & URI_T_HOST_REGNAME) {
// debug( "URI targets hostname : %s", uri_filepath );
}
}
/*
* Try to locate essence file from the AAF file location.
*
* e.g.
* - AAF filepath : /home/user/AAFFile.aaf
* - Essence URI : file://localhost/C:/Users/user/Desktop/AudioFiles/essence.wav
* = /home/user/AudioFiles/essence.file
*/
/* extract path to AAF file */
aaf_path = laaf_util_c99strdup (aafi->aafd->cfbd->file);
if (aaf_path == NULL) {
error ("Could not duplicate AAF filepath");
goto err;
}
p = aaf_path + strlen (aaf_path);
while (p > aaf_path) {
if (IS_DIR_SEP (*p)) {
*p = 0x00;
break;
}
p--;
}
/*
* "<localPathToAAFfile>/<essence.file>"
*/
local_filepath = laaf_util_build_path (DIR_SEP_STR, aaf_path, essenceFileName, NULL);
if (local_filepath == NULL) {
error ("Could not build filepath");
goto err;
}
// debug( "AAF relative filepath : %s", local_filepath );
if (access (local_filepath, F_OK) != -1) {
// debug( "FOUND: %s", filepath );
foundpath = local_filepath;
goto found;
}
free (local_filepath);
local_filepath = NULL;
/*
* "<localPathToAAFfile>/<firstparentInOriginalEssencePath>/<essence.file>"
*/
local_filepath = laaf_util_build_path (DIR_SEP_STR, aaf_path, relativeEssencePath, NULL);
if (local_filepath == NULL) {
error ("Could not build filepath");
goto err;
}
// debug( "AAF relative filepath : %s", local_filepath );
if (access (local_filepath, F_OK) != -1) {
// debug( "FOUND: %s", filepath );
foundpath = local_filepath;
goto found;
}
free (local_filepath);
local_filepath = NULL;
// debug("File not found");
found:
if (foundpath) {
retpath = laaf_util_str2wstr (foundpath);
if (retpath == NULL) {
error ("Could not convert foundpath from str to wstr : %s", foundpath);
goto err;
}
}
goto end;
err:
retpath = NULL;
end:
if (uri)
uriFree (uri);
if (uri_filepath)
free (uri_filepath);
if (local_filepath)
free (local_filepath);
if (aaf_path)
free (aaf_path);
return retpath;
/*
* AAFInfo --aaf-clips ../libaaf_testfiles/fonk_2.AAF
file://localhost/Users/horlaprod/Music/Logic/fonk_2/Audio Files_1/fonk_2_3#04.wav
* AAFInfo --aaf-clips ../libaaf_testfiles/ADP/ADP3_51-ST-MONO-NOBREAKOUT.aaf
file:///C:/Users/Loviniou/Downloads/ChID-BLITS-EBU-Narration441-16b.wav
* AAFInfo --aaf-clips ../libaaf_testfiles/ADP/ADP2_SEQ-FULL.aaf
file://?/E:/Adrien/ADPAAF/Sequence A Rendu.mxf
* AAFInfo --aaf-clips ../libaaf_testfiles/TEST-AVID_COMP2977052\ \ -\ \ OFF\ PODIUM\ ETAPE\ 2.aaf
file:////C:/Users/mix_limo/Desktop/TEST2977052 - OFF PODIUM ETAPE 2.aaf
* AAFInfo --aaf-clips ../ardio/watchfolder/3572607_RUGBY_F_1_1.aaf
file://10.87.230.71/mixage/DR2/Avid MediaFiles/MXF/1/3572607_RUGBY_F2_S65CFA3D0V.mxf
* AAFInfo --aaf-clips ../libaaf_testfiles/ProTools/pt2MCC.aaf
file:///_system/Users/horlaprod/pt2MCCzmhsFRHQgdgsTMQX.mxf
*/
}
int
aafi_extract_audio_essence (AAF_Iface* aafi, aafiAudioEssence* audioEssence, const char* outfilepath, const wchar_t* forcedFileName)
{
int rc = 0;
int reqlen = 0;
FILE* fp = NULL;
char* filename = NULL;
char* filepath = NULL;
unsigned char* data = NULL;
uint64_t datasz = 0;
if (audioEssence->is_embedded == 0) {
warning ("Audio essence is not embedded : nothing to extract");
return -1;
}
/* Retrieve stream from CFB */
cfb_getStream (aafi->aafd->cfbd, audioEssence->node, &data, &datasz);
if (data == NULL) {
error ("Could not retrieve audio essence stream from CFB");
goto err;
}
/* Build file path */
reqlen = snprintf (NULL, 0, "%ls.%s", (forcedFileName != NULL) ? forcedFileName : audioEssence->unique_file_name, (audioEssence->type == AAFI_ESSENCE_TYPE_AIFC) ? AIFF_FILE_EXT : WAV_FILE_EXT);
if (reqlen < 0) {
error ("Failed to build filename");
goto err;
}
int filenamelen = reqlen + 1;
filename = malloc (filenamelen);
if (filename == NULL) {
error ("Could not allocate memory : %s", strerror (errno));
goto err;
}
rc = snprintf (filename, filenamelen, "%ls.%s", (forcedFileName != NULL) ? forcedFileName : audioEssence->unique_file_name, (audioEssence->type == AAFI_ESSENCE_TYPE_AIFC) ? AIFF_FILE_EXT : WAV_FILE_EXT);
if (rc < 0 || (unsigned)rc >= (unsigned)filenamelen) {
error ("Failed to build filename");
goto err;
}
filepath = laaf_util_build_path (DIR_SEP_STR, outfilepath, laaf_util_clean_filename (filename), NULL);
if (filepath == NULL) {
error ("Could not build filepath");
goto err;
}
fp = fopen (filepath, "wb");
if (fp == NULL) {
error ("Could not open '%s' for writing : %s", filepath, strerror (errno));
goto err;
}
if (audioEssence->type == AAFI_ESSENCE_TYPE_PCM) {
struct wavFmtChunk wavFmt;
wavFmt.channels = audioEssence->channels;
wavFmt.samples_per_sec = audioEssence->samplerate;
wavFmt.bits_per_sample = audioEssence->samplesize;
struct wavBextChunk wavBext;
memset (&wavBext, 0x00, sizeof (wavBext));
memcpy (wavBext.umid, audioEssence->sourceMobID, sizeof (aafMobID_t));
if (audioEssence->mobSlotEditRate) {
wavBext.time_reference = laaf_util_converUnit (audioEssence->timeReference, audioEssence->mobSlotEditRate, audioEssence->samplerateRational);
}
if (datasz >= (uint32_t)-1) {
// TODO RF64 support ?
error ("Audio essence is bigger than maximum wav file size (2^32 bytes) : %" PRIu64 " bytes", datasz);
goto err;
}
if (riff_writeWavFileHeader (fp, &wavFmt, &wavBext, (uint32_t)datasz, aafi->dbg) < 0) {
error ("Could not write wav audio header : %s", filepath);
goto err;
}
}
uint64_t writtenBytes = fwrite (data, sizeof (unsigned char), datasz, fp);
if (writtenBytes < datasz) {
error ("Could not write audio file (%" PRIu64 " bytes written out of %" PRIu64 " bytes) : %s", writtenBytes, datasz, filepath);
goto err;
}
audioEssence->usable_file_path = malloc ((strlen (filepath) + 1) * sizeof (wchar_t));
if (audioEssence->usable_file_path == NULL) {
error ("Could not allocate memory : %s", strerror (errno));
goto err;
}
audioEssence->usable_file_path = laaf_util_str2wstr (filepath);
if (audioEssence->usable_file_path == NULL) {
error ("Could not convert usable_file_path from str to wstr : %s", filepath);
goto err;
}
rc = 0;
goto end;
err:
rc = -1;
end:
if (filename)
free (filename);
if (filepath)
free (filepath);
if (data)
free (data);
if (fp)
fclose (fp);
return rc;
}
int
aafi_parse_audio_essence (AAF_Iface* aafi, aafiAudioEssence* audioEssence)
{
// aafi->dbg->_dbg_msg_pos += laaf_util_dump_hex( audioEssence->summary->val, audioEssence->summary->len, &aafi->dbg->_dbg_msg, &aafi->dbg->_dbg_msg_size, aafi->dbg->_dbg_msg_pos );
int rc = 0;
char* externalFilePath = NULL;
FILE* fp = NULL;
struct RIFFAudioFile RIFFAudioFile;
/* try audioEssence->summary first, for both embedded and external */
if (audioEssence->summary) {
rc = riff_parseAudioFile (&RIFFAudioFile, RIFF_PARSE_AAF_SUMMARY, &embeddedAudioDataReaderCallback, audioEssence->summary->val, &audioEssence->summary->len, aafi, aafi->dbg);
if (rc < 0) {
warning ("Could not parse essence summary of %ls", audioEssence->file_name);
if (audioEssence->is_embedded) {
return -1;
}
} else {
audioEssence->channels = RIFFAudioFile.channels;
audioEssence->samplerate = RIFFAudioFile.sampleRate;
audioEssence->samplesize = RIFFAudioFile.sampleSize;
audioEssence->length = RIFFAudioFile.sampleCount;
audioEssence->samplerateRational->numerator = audioEssence->samplerate;
audioEssence->samplerateRational->denominator = 1;
return 0;
}
} else if (audioEssence->is_embedded) {
if (audioEssence->type != AAFI_ESSENCE_TYPE_PCM) {
warning ("TODO: Embedded audio essence has no summary. Should we try essence data stream ?");
}
return -1;
} else if (!audioEssence->usable_file_path) {
// warning( "Can't parse a missing external essence file" );
return -1;
}
if (laaf_util_fop_is_wstr_fileext (audioEssence->usable_file_path, L"wav") ||
laaf_util_fop_is_wstr_fileext (audioEssence->usable_file_path, L"wave") ||
laaf_util_fop_is_wstr_fileext (audioEssence->usable_file_path, L"aif") ||
laaf_util_fop_is_wstr_fileext (audioEssence->usable_file_path, L"aiff") ||
laaf_util_fop_is_wstr_fileext (audioEssence->usable_file_path, L"aifc")) {
externalFilePath = laaf_util_wstr2str (audioEssence->usable_file_path);
if (externalFilePath == NULL) {
error ("Could not convert usable_file_path from wstr to str : %ls", audioEssence->usable_file_path);
goto err;
}
fp = fopen (externalFilePath, "rb");
if (fp == NULL) {
error ("Could not open external audio essence file for reading : %s", externalFilePath);
goto err;
}
rc = riff_parseAudioFile (&RIFFAudioFile, 0, &externalAudioDataReaderCallback, fp, externalFilePath, aafi, aafi->dbg);
if (rc < 0) {
error ("Failed parsing external audio essence file : %s", externalFilePath);
goto err;
}
if (audioEssence->channels > 0 && audioEssence->channels != RIFFAudioFile.channels) {
warning ("%ls : summary channel count (%i) mismatch located file (%i)", audioEssence->usable_file_path, audioEssence->channels, RIFFAudioFile.channels);
}
if (audioEssence->samplerate > 0 && audioEssence->samplerate != RIFFAudioFile.sampleRate) {
warning ("%ls : summary samplerate (%i) mismatch located file (%i)", audioEssence->usable_file_path, audioEssence->samplerate, RIFFAudioFile.sampleRate);
}
if (audioEssence->samplesize > 0 && audioEssence->samplesize != RIFFAudioFile.sampleSize) {
warning ("%ls : summary samplesize (%i) mismatch located file (%i)", audioEssence->usable_file_path, audioEssence->samplesize, RIFFAudioFile.sampleSize);
}
if (audioEssence->length > 0 && audioEssence->length != RIFFAudioFile.sampleCount) {
warning ("%ls : summary samplecount (%" PRIi64 ") mismatch located file (%" PRIi64 ")", audioEssence->usable_file_path, audioEssence->length, RIFFAudioFile.sampleCount);
}
audioEssence->channels = RIFFAudioFile.channels;
audioEssence->samplerate = RIFFAudioFile.sampleRate;
audioEssence->samplesize = RIFFAudioFile.sampleSize;
audioEssence->length = RIFFAudioFile.sampleCount;
audioEssence->samplerateRational->numerator = audioEssence->samplerate;
audioEssence->samplerateRational->denominator = 1;
} else {
/*
* should be considered as a non-pcm audio format
*
04317 AAFClassID_TimelineMobSlot [slot:6 track:4] (DataDef : AAFDataDef_Sound) : Audio 4 - Layered Audio Editing
01943 AAFClassID_Sequence
02894 AAFClassID_SourceClip
02899 AAFClassID_MasterMob (UsageCode: n/a) : speech-sample
04405 AAFClassID_TimelineMobSlot [slot:1 track:1] (DataDef : AAFDataDef_Sound)
03104 AAFClassID_SourceClip
04140 AAFClassID_SourceMob (UsageCode: n/a) : speech-sample
01287 AAFClassID_PCMDescriptor
01477 AAFClassID_NetworkLocator : file:///C:/Users/user/Desktop/libAAF/test/res/speech-sample.mp3
*
*/
audioEssence->type = AAFI_ESSENCE_TYPE_UNK;
// /* clears any wrong data previously retrieved out of AAFClassID_PCMDescriptor */
// audioEssence->samplerate = 0;
// audioEssence->samplesize = 0;
}
rc = 0;
goto end;
err:
rc = -1;
end:
if (fp)
fclose (fp);
if (externalFilePath)
free (externalFilePath);
return rc;
}
static size_t
embeddedAudioDataReaderCallback (unsigned char* buf, size_t offset, size_t reqLen, void* user1, void* user2, void* user3)
{
unsigned char* data = user1;
size_t datasz = *(size_t*)user2;
AAF_Iface* aafi = (AAF_Iface*)user3;
if (offset > datasz) {
error ("Requested data starts beyond data length");
return -1;
}
if (offset + reqLen > datasz) {
reqLen = datasz - (offset + reqLen);
}
memcpy (buf, data + offset, reqLen);
return reqLen;
}
static size_t
externalAudioDataReaderCallback (unsigned char* buf, size_t offset, size_t reqLen, void* user1, void* user2, void* user3)
{
FILE* fp = (FILE*)user1;
const char* filename = (const char*)user2;
AAF_Iface* aafi = (AAF_Iface*)user3;
if (fseek (fp, offset, SEEK_SET) < 0) {
error ("Could not seek to %zu in file '%s' : %s", offset, filename, strerror (errno));
return -1;
}
size_t read = fread (buf, sizeof (unsigned char), reqLen, fp);
if (read < reqLen) {
error ("File read failed at %zu (expected %zu, read %zu) in file '%s' : %s", offset, reqLen, read, filename, strerror (errno));
return -1;
}
return read;
}

941
libs/aaf/AAFIEssenceFile.c Normal file
View File

@ -0,0 +1,941 @@
/*
* Copyright (C) 2017-2024 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <assert.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "aaf/AAFIEssenceFile.h"
#include "aaf/AAFIface.h"
#include "aaf/log.h"
#include "aaf/version.h"
#include "aaf/MediaComposer.h"
#include "aaf/utils.h"
#include "aaf/RIFFParser.h"
#include "aaf/URIParser.h"
#define debug(...) \
AAF_LOG (aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_DEBUG, __VA_ARGS__)
#define success(...) \
AAF_LOG (aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_SUCCESS, __VA_ARGS__)
#define warning(...) \
AAF_LOG (aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_WARNING, __VA_ARGS__)
#define error(...) \
AAF_LOG (aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_ERROR, __VA_ARGS__)
static int
set_audioEssenceWithRIFF (AAF_Iface* aafi, const char* filename, aafiAudioEssenceFile* audioEssenceFile, struct RIFFAudioFile* RIFFAudioFile, int isExternalFile);
static size_t
embeddedAudioDataReaderCallback (unsigned char* buf, size_t offset, size_t reqLen, void* user1, void* user2, void* user3);
static size_t
externalAudioDataReaderCallback (unsigned char* buf, size_t offset, size_t reqLen, void* user1, void* user2, void* user3);
int
aafi_build_unique_audio_essence_name (AAF_Iface* aafi, aafiAudioEssenceFile* audioEssenceFile)
{
if (audioEssenceFile->unique_name) {
debug ("Unique name was already set");
return -1;
}
if (aafi->ctx.options.mobid_essence_filename) {
aafUID_t* uuid = &(audioEssenceFile->sourceMobID->material);
int rc = laaf_util_snprintf_realloc (&audioEssenceFile->unique_name, 0, 0, "%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x",
uuid->Data1,
uuid->Data2,
uuid->Data3,
uuid->Data4[0],
uuid->Data4[1],
uuid->Data4[2],
uuid->Data4[3],
uuid->Data4[4],
uuid->Data4[5],
uuid->Data4[6],
uuid->Data4[7]);
if (rc < 0) {
error ("Failed to set unique filename with SourceMobID UID");
free (audioEssenceFile->unique_name);
return -1;
}
return 0;
} else {
audioEssenceFile->unique_name = laaf_util_c99strdup ((audioEssenceFile->name) ? audioEssenceFile->name : "unknown");
if (!audioEssenceFile->unique_name) {
error ("Could not duplicate essence name : %s", (audioEssenceFile->name) ? audioEssenceFile->name : "unknown");
return -1;
}
}
size_t unique_size = strlen (audioEssenceFile->unique_name) + 1;
int index = 0;
aafiAudioEssenceFile* ae = NULL;
AAFI_foreachAudioEssenceFile (aafi, ae)
{
if (ae != audioEssenceFile && ae->unique_name != NULL && strcmp (ae->unique_name, audioEssenceFile->unique_name) == 0) {
if (laaf_util_snprintf_realloc (&audioEssenceFile->unique_name, &unique_size, 0, "%s_%i", (audioEssenceFile->name) ? audioEssenceFile->name : "unknown", ++index) < 0) {
error ("Failed to increment unique filename");
return -1;
}
/* recheck entire essence list */
ae = aafi->Audio->essenceFiles;
}
}
return 0;
}
char*
aafi_locate_external_essence_file (AAF_Iface* aafi, const char* original_uri_filepath, const char* search_location)
{
/*
* Absolute Uniform Resource Locator (URL) complying with RFC 1738 or relative
* Uniform Resource Identifier (URI) complying with RFC 2396 for file containing
* the essence. If it is a relative URI, the base URI is determined from the URI
* of the AAF file itself.
*
* Informative note: A valid URL or URI uses a constrained character set and
* uses the / character as the path separator.
*/
char* local_filepath = NULL;
char* aaf_path = NULL;
const char* foundpath = NULL;
char* retpath = NULL;
struct uri* uri = NULL;
if (original_uri_filepath == NULL) {
error ("Cant locate a NULL filepath");
goto err;
}
debug ("Original URI : %s", original_uri_filepath);
uri = laaf_uri_parse (original_uri_filepath, URI_OPT_DECODE_ALL, aafi->log);
if (uri == NULL) {
error ("Could not parse URI");
goto err;
}
if (uri->path == NULL) {
error ("Could not retrieve <path> out of URI");
goto err;
}
debug ("Decoded URI's path : %s", uri->path);
/* extract relative path to essence file : "<firstparent>/<essence.file>" */
const char* relativeEssencePath = NULL;
const char* essenceFileName = NULL;
int sepcount = 0;
char* p = uri->path + strlen (uri->path);
while (p > uri->path) {
if (*p == '/') { /* parsing URI, so will always be '/' as separator character */
sepcount++;
if (sepcount == 1) {
essenceFileName = (p + 1);
} else if (sepcount == 2) {
relativeEssencePath = (p + 1);
break;
}
}
p--;
}
if (!relativeEssencePath) {
error ("Could not retrieve relative file path out of URI : %s", uri->path);
goto err;
}
if (!essenceFileName) {
error ("Could not retrieve file name out of URI : %s", uri->path);
goto err;
}
debug ("Essence filename : %s", essenceFileName);
if (search_location) {
/*
* "<search_location>/<essence.file>"
*/
local_filepath = laaf_util_build_path ("/", search_location, essenceFileName, NULL);
if (!local_filepath) {
error ("Could not build search filepath");
goto err;
}
debug ("Search filepath : %s", local_filepath);
if (laaf_util_file_exists (local_filepath) == 1) {
foundpath = local_filepath;
goto found;
}
free (local_filepath);
local_filepath = NULL;
/*
* "<search_location>/<firstparentInOriginalEssencePath>/<essence.file>"
*/
local_filepath = laaf_util_build_path ("/", search_location, relativeEssencePath, NULL);
if (!local_filepath) {
error ("Could not build search filepath");
goto err;
}
debug ("Search filepath : %s", local_filepath);
if (laaf_util_file_exists (local_filepath) == 1) {
foundpath = local_filepath;
goto found;
}
free (local_filepath);
local_filepath = NULL;
}
/* Try AAF essence's URI */
if (laaf_util_file_exists (original_uri_filepath) == 1) {
foundpath = original_uri_filepath;
goto found;
}
/* Try <path> part of URI */
if (laaf_util_file_exists (uri->path) == 1) {
foundpath = uri->path;
goto found;
}
if (uri->flags & URI_T_LOCALHOST) {
// debug( "URI targets localhost : %s", uri_filepath );
} else {
if (uri->flags & URI_T_HOST_IPV4) {
// debug( "URI targets IPV4 : %s", uri_filepath );
} else if (uri->flags & URI_T_HOST_IPV6) {
// debug( "URI targets IPV6 : %s", uri_filepath );
} else if (uri->flags & URI_T_HOST_REGNAME) {
// debug( "URI targets hostname : %s", uri_filepath );
}
}
/*
* Try to locate essence file from the AAF file location.
*
* e.g.
* - AAF filepath : /home/user/AAFFile.aaf
* - Essence URI : file://localhost/C:/Users/user/Desktop/AudioFiles/essence.wav
* = /home/user/AudioFiles/essence.file
*/
/* extract path to AAF file */
aaf_path = laaf_util_c99strdup (aafi->aafd->cfbd->file);
if (!aaf_path) {
error ("Could not duplicate AAF filepath : %s", aafi->aafd->cfbd->file);
goto err;
}
p = aaf_path + strlen (aaf_path);
while (p > aaf_path) {
if (IS_DIR_SEP (*p)) {
*p = 0x00;
break;
}
p--;
}
/*
* "<localPathToAAFfile>/<essence.file>"
*/
local_filepath = laaf_util_build_path (DIR_SEP_STR, aaf_path, essenceFileName, NULL);
if (!local_filepath) {
error ("Could not build filepath");
goto err;
}
debug ("AAF relative filepath : %s", local_filepath);
if (laaf_util_file_exists (local_filepath) == 1) {
foundpath = local_filepath;
goto found;
}
free (local_filepath);
local_filepath = NULL;
/*
* "<localPathToAAFfile>/<firstparentInOriginalEssencePath>/<essence.file>"
*/
local_filepath = laaf_util_build_path (DIR_SEP_STR, aaf_path, relativeEssencePath, NULL);
if (!local_filepath) {
error ("Could not build filepath");
goto err;
}
debug ("AAF relative sub filepath : %s", local_filepath);
if (laaf_util_file_exists (local_filepath) == 1) {
foundpath = local_filepath;
goto found;
}
free (local_filepath);
local_filepath = NULL;
debug ("File not found");
found:
if (foundpath) {
/*
* When runing through wine, computing absolute path adds a Z:/ drive letter.
* This causes issue when trying to make relative essence path from the AAF
* file path, since it also went through laaf_util_absolute_path().
* So even if foundpath is already absolute, we need that drive letter at it
* start.
*/
// retpath = laaf_util_c99strdup(foundpath);
retpath = laaf_util_absolute_path (foundpath);
if (!retpath) {
error ("Could not make absolute path to located file : %s", foundpath);
goto err;
}
debug ("File found at : %s", foundpath);
}
goto end;
err:
retpath = NULL;
end:
laaf_uri_free (uri);
free (local_filepath);
free (aaf_path);
return retpath;
/*
* AAFInfo --aaf-clips ../libaaf_testfiles/fonk_2.AAF
file://localhost/Users/horlaprod/Music/Logic/fonk_2/Audio Files_1/fonk_2_3#04.wav
* AAFInfo --aaf-clips ../libaaf_testfiles/ADP/ADP3_51-ST-MONO-NOBREAKOUT.aaf
file:///C:/Users/Loviniou/Downloads/ChID-BLITS-EBU-Narration441-16b.wav
* AAFInfo --aaf-clips ../libaaf_testfiles/ADP/ADP2_SEQ-FULL.aaf
file://?/E:/Adrien/ADPAAF/Sequence A Rendu.mxf
* AAFInfo --aaf-clips ../libaaf_testfiles/TEST-AVID_COMP2977052\ \ -\ \ OFF\ PODIUM\ ETAPE\ 2.aaf
file:////C:/Users/mix_limo/Desktop/TEST2977052 - OFF PODIUM ETAPE 2.aaf
* AAFInfo --aaf-clips ../ardio/watchfolder/3572607_RUGBY_F_1_1.aaf
file://10.87.230.71/mixage/DR2/Avid MediaFiles/MXF/1/3572607_RUGBY_F2_S65CFA3D0V.mxf
* AAFInfo --aaf-clips ../libaaf_testfiles/ProTools/pt2MCC.aaf
file:///_system/Users/horlaprod/pt2MCCzmhsFRHQgdgsTMQX.mxf
*/
}
int
aafi_extractAudioEssenceFile (AAF_Iface* aafi, aafiAudioEssenceFile* audioEssenceFile, enum aafiExtractFormat extractFormat, const char* outpath, uint64_t sampleOffset, uint64_t sampleLength, const char* forcedFileName, char** usable_file_path)
{
int rc = 0;
int tmp = 0;
FILE* fp = NULL;
char* filename = NULL;
char* filepath = NULL;
int write_header = 0;
int extracting_clip = 0;
unsigned char* data = NULL;
uint64_t datasz = 0;
if (audioEssenceFile->is_embedded == 0) {
error ("Audio essence is not embedded : nothing to extract");
goto err;
}
if (!outpath) {
error ("Missing output path");
goto err;
}
if (audioEssenceFile->usable_file_path) {
debug ("usable_file_path was already set");
free (audioEssenceFile->usable_file_path);
audioEssenceFile->usable_file_path = NULL;
}
uint64_t pcmByteOffset = sampleOffset * audioEssenceFile->channels * (audioEssenceFile->samplesize / 8);
uint64_t pcmByteLength = sampleLength * audioEssenceFile->channels * (audioEssenceFile->samplesize / 8);
/* Retrieve stream from CFB */
cfb_getStream (aafi->aafd->cfbd, audioEssenceFile->node, &data, &datasz);
if (data == NULL) {
error ("Could not retrieve audio essence stream from CFB");
goto err;
}
/* Calculate offset and length */
debug ("Requesting extract of essence \"%s\"", audioEssenceFile->name);
debug (" - ReqSampleOffset: %" PRIu64 " samples (%" PRIu64 " bytes)", sampleOffset, pcmByteOffset);
debug (" - ReqSampleLength: %" PRIu64 " samples (%" PRIu64 " bytes)", sampleLength, pcmByteLength);
debug (" - FileHeaderOffset: %" PRIu64 " bytes (0x%04" PRIx64 ")",
audioEssenceFile->pcm_audio_start_offset,
audioEssenceFile->pcm_audio_start_offset);
debug (" - EssenceTotalLength: %" PRIu64 " bytes", datasz);
uint64_t sourceFileOffset = 0;
if (pcmByteOffset ||
pcmByteLength ||
extractFormat != AAFI_EXTRACT_DEFAULT) {
if (audioEssenceFile->type != AAFI_ESSENCE_TYPE_PCM) {
sourceFileOffset += audioEssenceFile->pcm_audio_start_offset;
}
write_header = 1;
}
if (pcmByteOffset || pcmByteLength) {
extracting_clip = 1;
}
sourceFileOffset += pcmByteOffset;
if ((datasz - audioEssenceFile->pcm_audio_start_offset) < (pcmByteLength + sourceFileOffset)) {
error ("Requested audio range (%" PRIi64 " bytes) is bigger than source audio size (%" PRIu64 " bytes)",
(pcmByteLength + sourceFileOffset),
datasz - audioEssenceFile->pcm_audio_start_offset);
goto err;
}
datasz = (pcmByteLength) ? pcmByteLength : (datasz - sourceFileOffset);
if (datasz >= (uint32_t)-1) {
error ("Audio essence is bigger than maximum wav file size (2^32 bytes) : %" PRIu64 " bytes", datasz);
goto err;
}
debug (" - Calculated Offset: %" PRIu64 " bytes", sourceFileOffset);
debug (" - Calculated Length: %" PRIu64 " bytes", datasz);
if (audioEssenceFile->type != AAFI_ESSENCE_TYPE_PCM) {
if (!write_header) {
debug ("Writting exact copy of embedded file.");
} else {
debug ("Rewriting file header.");
}
}
/* Build file path */
const char* name = NULL;
if (forcedFileName) {
name = forcedFileName;
} else {
name = audioEssenceFile->unique_name;
}
const char* fileext = NULL;
if (write_header ||
audioEssenceFile->type == AAFI_ESSENCE_TYPE_WAVE ||
audioEssenceFile->type == AAFI_ESSENCE_TYPE_PCM) {
if (!laaf_util_is_fileext (name, "wav") &&
!laaf_util_is_fileext (name, "wave")) {
fileext = "wav";
}
} else if (!write_header &&
audioEssenceFile->type == AAFI_ESSENCE_TYPE_AIFC) {
if (!laaf_util_is_fileext (name, "aif") &&
!laaf_util_is_fileext (name, "aiff") &&
!laaf_util_is_fileext (name, "aifc")) {
fileext = "aif";
}
}
if (fileext) {
if (laaf_util_snprintf_realloc (&filename, NULL, 0, "%s.%s", name, fileext) < 0) {
error ("Could not concat filename + fileext");
goto err;
}
} else {
filename = laaf_util_c99strdup (name);
if (!filename) {
error ("Could not duplicate filename : %s", name);
goto err;
}
}
filepath = laaf_util_build_path (DIR_SEP_STR, outpath, laaf_util_clean_filename (filename), NULL);
if (!filepath) {
error ("Could not build filepath.");
goto err;
}
fp = fopen (filepath, "wb");
if (!fp) {
error ("Could not open '%s' for writing : %s", filepath, strerror (errno));
goto err;
}
if (write_header ||
audioEssenceFile->type == AAFI_ESSENCE_TYPE_PCM) {
struct wavFmtChunk wavFmt;
wavFmt.channels = audioEssenceFile->channels;
wavFmt.samples_per_sec = audioEssenceFile->samplerate;
wavFmt.bits_per_sample = audioEssenceFile->samplesize;
struct wavBextChunk wavBext;
memset (&wavBext, 0x00, sizeof (wavBext));
memcpy (wavBext.umid, audioEssenceFile->sourceMobID, sizeof (aafMobID_t));
tmp = snprintf (wavBext.originator, sizeof (((struct wavBextChunk*)0)->originator), "%s %s", aafi->aafd->Identification.ProductName, (mediaComposer_AAF (aafi)) ? "" : aafi->aafd->Identification.ProductVersionString);
assert (tmp > 0 && (size_t)tmp < sizeof (((struct wavBextChunk*)0)->originator));
// if ( tmp < 0 || (size_t)tmp >= sizeof(((struct wavBextChunk *)0)->originator) ) {
// fprintf( stderr, "snprintf() error" );
// goto err;
// }
tmp = snprintf (wavBext.originator_reference, sizeof (((struct wavBextChunk*)0)->originator_reference), "libAAF %s", LIBAAF_VERSION);
assert (tmp > 0 && (size_t)tmp < sizeof (((struct wavBextChunk*)0)->originator_reference));
// if ( tmp < 0 || (size_t)tmp >= sizeof(((struct wavBextChunk *)0)->originator_reference) ) {
// fprintf( stderr, "snprintf() error" );
// goto err;
// }
tmp = snprintf (wavBext.description, sizeof (((struct wavBextChunk*)0)->description), "%s\n%s.aaf", audioEssenceFile->name, aafi->compositionName);
assert (tmp > 0 && (size_t)tmp < sizeof (((struct wavBextChunk*)0)->description));
// if ( tmp < 0 || (size_t)tmp >= sizeof(((struct wavBextChunk *)0)->description) ) {
// fprintf( stderr, "snprintf() error" );
// goto err;
// }
memcpy (wavBext.origination_date, audioEssenceFile->originationDate, sizeof (((struct wavBextChunk*)0)->origination_date));
memcpy (wavBext.origination_time, audioEssenceFile->originationTime, sizeof (((struct wavBextChunk*)0)->origination_time));
wavBext.time_reference = aafi_convertUnitUint64 (audioEssenceFile->sourceMobSlotOrigin, audioEssenceFile->sourceMobSlotEditRate, audioEssenceFile->samplerateRational);
if (laaf_riff_writeWavFileHeader (fp, &wavFmt, (extractFormat != AAFI_EXTRACT_WAV) ? &wavBext : NULL, (uint32_t)datasz, aafi->log) < 0) {
error ("Could not write wav audio header : %s", filepath);
goto err;
}
}
uint64_t writtenBytes = 0;
if (write_header && audioEssenceFile->type == AAFI_ESSENCE_TYPE_AIFC && audioEssenceFile->samplesize > 8) {
unsigned char sample[4];
uint16_t samplesize = (audioEssenceFile->samplesize >> 3);
for (uint64_t i = 0; i < datasz; i += samplesize) {
if (samplesize == 2) {
sample[0] = *(unsigned char*)(data + pcmByteOffset + i + 1);
sample[1] = *(unsigned char*)(data + pcmByteOffset + i);
} else if (samplesize == 3) {
sample[0] = *(unsigned char*)(data + pcmByteOffset + i + 2);
sample[1] = *(unsigned char*)(data + pcmByteOffset + i + 1);
sample[2] = *(unsigned char*)(data + pcmByteOffset + i);
} else if (samplesize == 4) {
sample[0] = *(unsigned char*)(data + pcmByteOffset + i + 3);
sample[1] = *(unsigned char*)(data + pcmByteOffset + i + 2);
sample[2] = *(unsigned char*)(data + pcmByteOffset + i + 1);
sample[3] = *(unsigned char*)(data + pcmByteOffset + i);
}
writtenBytes += fwrite (sample, samplesize, 1, fp);
}
writtenBytes *= samplesize;
} else {
writtenBytes = fwrite (data + sourceFileOffset, sizeof (unsigned char), datasz, fp);
}
if (writtenBytes < datasz) {
error ("Could not write audio file (%" PRIu64 " bytes written out of %" PRIu64 " bytes) : %s", writtenBytes, datasz, filepath);
goto err;
}
if (!extracting_clip) {
/*
* Set audioEssenceFile->usable_file_path only if we axtract essence, not if we
* extract clip (subset of an essence), as a single essence can have multiple
* clips using it. Otherwise, we would reset audioEssenceFile->usable_file_path
* as many times as there are clips using the same essence.
*/
audioEssenceFile->usable_file_path = laaf_util_c99strdup (filepath);
if (!audioEssenceFile->usable_file_path) {
error ("Could not duplicate usable filepath : %s", filepath);
goto err;
}
}
if (usable_file_path) {
*usable_file_path = laaf_util_c99strdup (filepath);
if (!(*usable_file_path)) {
error ("Could not duplicate usable filepath : %s", filepath);
goto err;
}
}
rc = 0;
goto end;
err:
rc = -1;
end:
free (filename);
free (filepath);
free (data);
if (fp)
fclose (fp);
return rc;
}
int
aafi_extractAudioClip (AAF_Iface* aafi, aafiAudioClip* audioClip, enum aafiExtractFormat extractFormat, const char* outpath)
{
int rc = 0;
for (aafiAudioEssencePointer* audioEssencePtr = audioClip->essencePointerList; audioEssencePtr; audioEssencePtr = audioEssencePtr->next) {
aafiAudioEssenceFile* audioEssenceFile = audioClip->essencePointerList->essenceFile;
uint64_t sampleOffset = aafi_convertUnitUint64 (audioClip->essence_offset, audioClip->track->edit_rate, audioEssenceFile->samplerateRational);
uint64_t sampleLength = aafi_convertUnitUint64 (audioClip->len, audioClip->track->edit_rate, audioEssenceFile->samplerateRational);
char* name = NULL;
char* usable_file_path = NULL;
laaf_util_snprintf_realloc (&name, NULL, 0, "%i_%i_%s", audioClip->track->number, aafi_get_clipIndex (audioClip), audioClip->essencePointerList->essenceFile->unique_name);
if ((rc += aafi_extractAudioEssenceFile (aafi, audioEssenceFile, extractFormat, outpath, sampleOffset, sampleLength, name, &usable_file_path)) == 0) {
success ("Audio clip file extracted to %s\"%s\"%s",
ANSI_COLOR_DARKGREY (aafi->log),
usable_file_path,
ANSI_COLOR_RESET (aafi->log));
} else {
error ("Audio clip file extraction failed : %s\"%s\"%s", ANSI_COLOR_DARKGREY (aafi->log), name, ANSI_COLOR_RESET (aafi->log));
}
free (usable_file_path);
free (name);
usable_file_path = NULL;
name = NULL;
}
return rc;
}
static int
set_audioEssenceWithRIFF (AAF_Iface* aafi, const char* filename, aafiAudioEssenceFile* audioEssenceFile, struct RIFFAudioFile* RIFFAudioFile, int isExternalFile)
{
if (RIFFAudioFile->sampleCount >= INT64_MAX) {
error ("%s : summary sample count is bigger than INT64_MAX (%" PRIu64 ")", audioEssenceFile->usable_file_path, RIFFAudioFile->sampleCount);
return -1;
}
if (RIFFAudioFile->sampleRate >= INT_MAX) {
error ("%s : summary sample rate is bigger than INT_MAX (%li)", audioEssenceFile->usable_file_path, RIFFAudioFile->sampleRate);
return -1;
}
if (audioEssenceFile->channels > 0 && audioEssenceFile->channels != RIFFAudioFile->channels) {
warning ("%s : summary channel count (%i) mismatch %s (%i)", filename, audioEssenceFile->channels, ((isExternalFile) ? "located file" : "previously retrieved data"), RIFFAudioFile->channels);
}
// else {
// /* In Davinci Resolve embedded multichannel WAV, summary channel is always 1 */
// audioEssenceFile->channels = RIFFAudioFile->channels;
// }
if (audioEssenceFile->samplerate > 0 && audioEssenceFile->samplerate != RIFFAudioFile->sampleRate) {
warning ("%s : summary samplerate (%i) mismatch %s (%i)", filename, audioEssenceFile->samplerate, ((isExternalFile) ? "located file" : "previously retrieved data"), RIFFAudioFile->sampleRate);
}
if (audioEssenceFile->samplesize > 0 && audioEssenceFile->samplesize != RIFFAudioFile->sampleSize) {
warning ("%s : summary samplesize (%i) mismatch %s (%i)", filename, audioEssenceFile->samplesize, ((isExternalFile) ? "located file" : "previously retrieved data"), RIFFAudioFile->sampleSize);
}
if (audioEssenceFile->length > 0 && (uint64_t)audioEssenceFile->length != RIFFAudioFile->sampleCount) {
warning ("%s : summary samplecount (%" PRIi64 ") mismatch %s (%" PRIi64 ")", filename, audioEssenceFile->length, ((isExternalFile) ? "located file" : "previously retrieved data"), RIFFAudioFile->sampleCount);
}
audioEssenceFile->channels = RIFFAudioFile->channels;
audioEssenceFile->samplerate = RIFFAudioFile->sampleRate;
audioEssenceFile->samplesize = RIFFAudioFile->sampleSize;
audioEssenceFile->length = (aafPosition_t)RIFFAudioFile->sampleCount;
audioEssenceFile->pcm_audio_start_offset = (uint64_t)RIFFAudioFile->pcm_audio_start_offset;
audioEssenceFile->samplerateRational->numerator = (int32_t)audioEssenceFile->samplerate;
audioEssenceFile->samplerateRational->denominator = 1;
return 0;
}
int
aafi_parse_audio_essence (AAF_Iface* aafi, aafiAudioEssenceFile* audioEssenceFile)
{
int rc = 0;
uint64_t dataStreamSize = 0;
unsigned char* dataStream = NULL;
FILE* fp = NULL;
struct RIFFAudioFile RIFFAudioFile;
/* try audioEssenceFile->summary first, for both embedded and external */
if (audioEssenceFile->summary) {
rc = laaf_riff_parseAudioFile (&RIFFAudioFile, RIFF_PARSE_AAF_SUMMARY, &embeddedAudioDataReaderCallback, audioEssenceFile->summary->val, &audioEssenceFile->summary->len, aafi, aafi->log);
if (rc < 0) {
if (!audioEssenceFile->is_embedded && !audioEssenceFile->usable_file_path) {
warning ("Could not parse essence summary of \"%s\".", audioEssenceFile->name);
goto err;
}
warning ("Could not parse essence summary of \"%s\". %s",
audioEssenceFile->name,
(audioEssenceFile->is_embedded) ? "Trying essence data stream." : (audioEssenceFile->usable_file_path) ? "Trying external essence file."
: " WTF ???");
} else {
if (set_audioEssenceWithRIFF (aafi, "AAF Summary", audioEssenceFile, &RIFFAudioFile, 0) < 0) {
goto err;
}
if (!RIFFAudioFile.channels ||
!RIFFAudioFile.sampleRate ||
!RIFFAudioFile.sampleSize ||
!RIFFAudioFile.sampleCount) {
/*
* Adobe Premiere Pro AIFC/WAVE Summaries of external files are missing
* SSND chunk/DATA chunk size (RIFFAudioFile.sampleCount)
*/
if (!audioEssenceFile->is_embedded && !audioEssenceFile->usable_file_path) {
warning ("Summary of \"%s\" is missing some data.", audioEssenceFile->name);
goto err;
}
warning ("Summary of \"%s\" is missing some data. %s",
audioEssenceFile->name,
(audioEssenceFile->is_embedded) ? "Trying essence data stream." : (audioEssenceFile->usable_file_path) ? "Trying external essence file."
: " WTF ???");
} else {
goto end;
}
}
} else if (audioEssenceFile->is_embedded) {
warning ("Embedded audio essence \"%s\" has no summary. Trying essence data stream.", audioEssenceFile->name);
} else if (audioEssenceFile->usable_file_path) {
warning ("External audio essence \"%s\" has no summary. Trying external file.", audioEssenceFile->name);
}
if (audioEssenceFile->is_embedded) {
cfb_getStream (aafi->aafd->cfbd, audioEssenceFile->node, &dataStream, &dataStreamSize);
if (dataStream == NULL) {
error ("Could not retrieve audio essence stream from CFB");
goto err;
}
rc = laaf_riff_parseAudioFile (&RIFFAudioFile, RIFF_PARSE_AAF_SUMMARY, &embeddedAudioDataReaderCallback, dataStream, &dataStreamSize, aafi, aafi->log);
if (rc < 0) {
warning ("Could not parse embedded essence stream of \"%s\".", audioEssenceFile->name);
goto err;
}
if (set_audioEssenceWithRIFF (aafi, "AAF Embedded stream", audioEssenceFile, &RIFFAudioFile, 0) < 0) {
goto err;
}
goto end;
}
if (laaf_util_is_fileext (audioEssenceFile->usable_file_path, "wav") ||
laaf_util_is_fileext (audioEssenceFile->usable_file_path, "wave") ||
laaf_util_is_fileext (audioEssenceFile->usable_file_path, "aif") ||
laaf_util_is_fileext (audioEssenceFile->usable_file_path, "aiff") ||
laaf_util_is_fileext (audioEssenceFile->usable_file_path, "aifc")) {
fp = fopen (audioEssenceFile->usable_file_path, "rb");
if (fp == NULL) {
error ("Could not open external audio essence file for reading : %s", audioEssenceFile->usable_file_path);
goto err;
}
rc = laaf_riff_parseAudioFile (&RIFFAudioFile, 0, &externalAudioDataReaderCallback, fp, audioEssenceFile->usable_file_path, aafi, aafi->log);
if (rc < 0) {
error ("Failed parsing external audio essence file : %s", audioEssenceFile->usable_file_path);
goto err;
}
if (set_audioEssenceWithRIFF (aafi, audioEssenceFile->usable_file_path, audioEssenceFile, &RIFFAudioFile, 1) < 0) {
goto err;
}
} else {
/*
* should be considered as a non-pcm audio format
*
04317 AAFClassID_TimelineMobSlot [slot:6 track:4] (DataDef : AAFDataDef_Sound) : Audio 4 - Layered Audio Editing
01943 AAFClassID_Sequence
02894 AAFClassID_SourceClip
02899 AAFClassID_MasterMob (UsageCode: n/a) : speech-sample
04405 AAFClassID_TimelineMobSlot [slot:1 track:1] (DataDef : AAFDataDef_Sound)
03104 AAFClassID_SourceClip
04140 AAFClassID_SourceMob (UsageCode: n/a) : speech-sample
01287 AAFClassID_PCMDescriptor
01477 AAFClassID_NetworkLocator : file:///C:/Users/user/Desktop/libAAF/test/res/speech-sample.mp3
*
*/
audioEssenceFile->type = AAFI_ESSENCE_TYPE_UNK;
}
rc = 0;
goto end;
err:
rc = -1;
end:
free (dataStream);
if (fp)
fclose (fp);
return rc;
}
static size_t
embeddedAudioDataReaderCallback (unsigned char* buf, size_t offset, size_t reqlen, void* user1, void* user2, void* user3)
{
unsigned char* data = user1;
size_t datasz = *(size_t*)user2;
AAF_Iface* aafi = (AAF_Iface*)user3;
if (offset > datasz) {
error ("Requested data starts beyond data length");
return RIFF_READER_ERROR;
}
if (offset + reqlen > datasz) {
reqlen = datasz - (offset + reqlen);
}
memcpy (buf, data + offset, reqlen);
return reqlen;
}
static size_t
externalAudioDataReaderCallback (unsigned char* buf, size_t offset, size_t reqlen, void* user1, void* user2, void* user3)
{
FILE* fp = (FILE*)user1;
const char* filename = (const char*)user2;
AAF_Iface* aafi = (AAF_Iface*)user3;
#ifdef _WIN32
assert (offset < _I64_MAX);
if (_fseeki64 (fp, (__int64)offset, SEEK_SET) < 0) {
error ("Could not seek to %" PRIu64 " in file '%s' : %s", offset, filename, strerror (errno));
return RIFF_READER_ERROR;
}
#else
assert (offset < LONG_MAX);
if (fseek (fp, (long)offset, SEEK_SET) < 0) {
error ("Could not seek to %" PRIu64 " in file '%s' : %s", offset, filename, strerror (errno));
return RIFF_READER_ERROR;
}
#endif
size_t byteRead = fread (buf, sizeof (unsigned char), reqlen, fp);
if (feof (fp)) {
if (byteRead < reqlen) {
error ("Incomplete fread() of '%s' due to EOF : %" PRIu64 " bytes read out of %" PRIu64 " requested", filename, byteRead, reqlen);
return RIFF_READER_ERROR;
}
debug ("fread() : EOF reached in file '%s'", filename);
} else if (ferror (fp)) {
if (byteRead < reqlen) {
error ("Incomplete fread() of '%s' due to error : %" PRIu64 " bytes read out of %" PRIu64 " requested", filename, byteRead, reqlen);
} else {
error ("fread() error of '%s' : %" PRIu64 " bytes read out of %" PRIu64 " requested", filename, byteRead, reqlen);
}
return RIFF_READER_ERROR;
}
return byteRead;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2017-2023 Adrien Gesta-Fline
* Copyright (C) 2017-2024 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
@ -18,11 +18,9 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "aaf/CFBDump.h"
#include "aaf/LibCFB.h"
@ -30,16 +28,16 @@
#include "aaf/utils.h"
#define debug(...) \
_dbg (cfbd->dbg, cfbd, DEBUG_SRC_ID_LIB_CFB, VERB_DEBUG, __VA_ARGS__)
AAF_LOG (cfbd->log, cfbd, DEBUG_SRC_ID_LIB_CFB, VERB_DEBUG, __VA_ARGS__)
#define warning(...) \
_dbg (cfbd->dbg, cfbd, DEBUG_SRC_ID_LIB_CFB, VERB_WARNING, __VA_ARGS__)
AAF_LOG (cfbd->log, cfbd, DEBUG_SRC_ID_LIB_CFB, VERB_WARNING, __VA_ARGS__)
#define error(...) \
_dbg (cfbd->dbg, cfbd, DEBUG_SRC_ID_LIB_CFB, VERB_ERROR, __VA_ARGS__)
AAF_LOG (cfbd->log, cfbd, DEBUG_SRC_ID_LIB_CFB, VERB_ERROR, __VA_ARGS__)
void
cfb_dump_node (CFB_Data* cfbd, cfbNode* node, int print_stream)
cfb_dump_node (CFB_Data* cfbd, cfbNode* node, int print_stream, const char* padding)
{
if (node == NULL)
return;
@ -47,77 +45,86 @@ cfb_dump_node (CFB_Data* cfbd, cfbNode* node, int print_stream)
if (node->_mse == STGTY_INVALID)
return;
wchar_t nodeName[CFB_NODE_NAME_SZ];
char* nodeName = cfb_w16toUTF8 (node->_ab, node->_cb);
cfb_w16towchar (nodeName, node->_ab, node->_cb);
struct aafLog* log = cfbd->log;
struct dbg* dbg = cfbd->dbg;
DBG_BUFFER_WRITE (dbg, "\n");
DBG_BUFFER_WRITE (dbg, " _ab : %ls\n", nodeName);
DBG_BUFFER_WRITE (dbg, " _cb : %u\n", node->_cb);
DBG_BUFFER_WRITE (dbg, " _mse : %s\n",
LOG_BUFFER_WRITE (log, "\n");
LOG_BUFFER_WRITE (log, "%s_ab : %s%s%s\n", padding, ANSI_COLOR_DARKGREY (log), nodeName, ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%s_cb : %s%u%s\n", padding, ANSI_COLOR_DARKGREY (log), node->_cb, ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%s_mse : %s%s%s\n",
padding,
ANSI_COLOR_DARKGREY (log),
node->_mse == 0 ? "STGTY_INVALID" : node->_mse == 1 ? "STGTY_STORAGE"
: node->_mse == 2 ? "STGTY_STREAM"
: node->_mse == 3 ? "STGTY_LOCKBYTES"
: node->_mse == 4 ? "STGTY_PROPERTY"
: node->_mse == 5 ? "STGTY_ROOT"
: "");
: "",
ANSI_COLOR_RESET (log));
DBG_BUFFER_WRITE (dbg, " _bflags : %s\n", node->_bflags == 1 ? "BLACK" : "RED");
DBG_BUFFER_WRITE (dbg, " _sidLeftSib : 0x%08x\n", node->_sidLeftSib);
DBG_BUFFER_WRITE (dbg, " _sidRightSib : 0x%08x\n", node->_sidRightSib);
LOG_BUFFER_WRITE (log, "%s_bflags : %s%s%s\n", padding, ANSI_COLOR_DARKGREY (log), node->_bflags == 1 ? "BLACK" : "RED", ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%s_sidLeftSib : %s0x%08x%s\n", padding, ANSI_COLOR_DARKGREY (log), node->_sidLeftSib, ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%s_sidRightSib : %s0x%08x%s\n", padding, ANSI_COLOR_DARKGREY (log), node->_sidRightSib, ANSI_COLOR_RESET (log));
if (node->_mse == STGTY_STORAGE ||
node->_mse == STGTY_ROOT) {
DBG_BUFFER_WRITE (dbg, " _sidChild : 0x%08x\n", node->_sidChild);
DBG_BUFFER_WRITE (dbg, " _clsid : %ls\n", cfb_CLSIDToText (&(node->_clsId)));
DBG_BUFFER_WRITE (dbg, " _dwUserFlags : 0x%08x (%d)\n", node->_dwUserFlags, node->_dwUserFlags);
LOG_BUFFER_WRITE (log, "%s_sidChild : %s0x%08x%s\n", padding, ANSI_COLOR_DARKGREY (log), node->_sidChild, ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%s_clsid : %s%s%s\n", padding, ANSI_COLOR_DARKGREY (log), cfb_CLSIDToText (&(node->_clsId)), ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%s_dwUserFlags : %s0x%08x (%d)%s\n", padding, ANSI_COLOR_DARKGREY (log), node->_dwUserFlags, node->_dwUserFlags, ANSI_COLOR_RESET (log));
}
if (node->_mse == STGTY_INVALID) {
DBG_BUFFER_WRITE (dbg, " _time (cre) : 0x%08x%08x\n",
LOG_BUFFER_WRITE (log, "%s_time (cre) : %s0x%08x%08x%s\n",
padding,
ANSI_COLOR_DARKGREY (log),
node->_time[0].dwHighDateTime,
node->_time[0].dwLowDateTime);
node->_time[0].dwLowDateTime,
ANSI_COLOR_RESET (log));
DBG_BUFFER_WRITE (dbg, " _ (mod) : 0x%08x%08x\n",
LOG_BUFFER_WRITE (log, "%s_ (mod) : %s0x%08x%08x%s\n",
padding,
ANSI_COLOR_DARKGREY (log),
node->_time[1].dwHighDateTime,
node->_time[1].dwLowDateTime);
node->_time[1].dwLowDateTime,
ANSI_COLOR_RESET (log));
}
if (node->_mse == STGTY_STREAM ||
node->_mse == STGTY_ROOT) {
DBG_BUFFER_WRITE (dbg, " _sectStart : 0x%08x (%d)\n", node->_sectStart, node->_sectStart);
DBG_BUFFER_WRITE (dbg, " _ulSizeLow : 0x%08x (%d)\n", node->_ulSizeLow, node->_ulSizeLow);
DBG_BUFFER_WRITE (dbg, " _ulSizeHigh : 0x%08x (%d)\n", node->_ulSizeHigh, node->_ulSizeHigh);
LOG_BUFFER_WRITE (log, "%s_sectStart : %s0x%08x (%d)%s\n", padding, ANSI_COLOR_DARKGREY (log), node->_sectStart, node->_sectStart, ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%s_ulSizeLow : %s0x%08x (%d)%s\n", padding, ANSI_COLOR_DARKGREY (log), node->_ulSizeLow, node->_ulSizeLow, ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%s_ulSizeHigh : %s0x%08x (%d)%s\n", padding, ANSI_COLOR_DARKGREY (log), node->_ulSizeHigh, node->_ulSizeHigh, ANSI_COLOR_RESET (log));
}
DBG_BUFFER_WRITE (dbg, "\n\n");
LOG_BUFFER_WRITE (log, "\n\n");
dbg->debug_callback (dbg, (void*)cfbd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, dbg->_dbg_msg, dbg->user);
log->debug_callback (log, (void*)cfbd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, log->_msg, log->user);
if (print_stream == 1) {
cfb_dump_nodeStream (cfbd, node);
cfb_dump_nodeStream (cfbd, node, "");
}
free (nodeName);
}
void
cfb_dump_nodePath (CFB_Data* cfbd, const wchar_t* path, int print_stream)
cfb_dump_nodePath (CFB_Data* cfbd, const char* path, int print_stream, const char* padding)
{
cfbNode* node = cfb_getNodeByPath (cfbd, path, 0);
if (node == NULL) {
error ("cfb_dump_nodePath() : Could not find node at \"%ls\"\n", path);
error ("cfb_dump_nodePath() : Could not find node at \"%s\"\n", path);
return;
}
cfb_dump_node (cfbd, node, print_stream);
cfb_dump_node (cfbd, node, print_stream, padding);
}
void
cfb_dump_nodeStream (CFB_Data* cfbd, cfbNode* node)
cfb_dump_nodeStream (CFB_Data* cfbd, cfbNode* node, const char* padding)
{
struct dbg* dbg = cfbd->dbg;
struct aafLog* log = cfbd->log;
unsigned char* stream = NULL;
uint64_t stream_sz = 0;
@ -128,22 +135,22 @@ cfb_dump_nodeStream (CFB_Data* cfbd, cfbNode* node)
return;
}
laaf_util_dump_hex (stream, stream_sz, &dbg->_dbg_msg, &dbg->_dbg_msg_size, dbg->_dbg_msg_pos);
laaf_util_dump_hex (stream, stream_sz, &log->_msg, &log->_msg_size, log->_msg_pos, padding);
dbg->debug_callback (dbg, (void*)cfbd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, dbg->_dbg_msg, dbg->user);
log->debug_callback (log, (void*)cfbd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, log->_msg, log->user);
free (stream);
}
void
cfb_dump_nodePathStream (CFB_Data* cfbd, const wchar_t* path)
cfb_dump_nodePathStream (CFB_Data* cfbd, const char* path, const char* padding)
{
struct dbg* dbg = cfbd->dbg;
struct aafLog* log = cfbd->log;
cfbNode* node = cfb_getNodeByPath (cfbd, path, 0);
if (node == NULL) {
error ("cfb_dump_nodePathStream() : Could not find node at \"%ls\"\n", path);
error ("Could not find node at \"%s\"\n", path);
return;
}
@ -152,204 +159,266 @@ cfb_dump_nodePathStream (CFB_Data* cfbd, const wchar_t* path)
cfb_getStream (cfbd, node, &stream, &stream_sz);
laaf_util_dump_hex (stream, stream_sz, &dbg->_dbg_msg, &dbg->_dbg_msg_size, dbg->_dbg_msg_pos);
laaf_util_dump_hex (stream, stream_sz, &log->_msg, &log->_msg_size, log->_msg_pos, padding);
dbg->debug_callback (dbg, (void*)cfbd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, dbg->_dbg_msg, dbg->user);
log->debug_callback (log, (void*)cfbd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, log->_msg, log->user);
free (stream);
}
void
cfb_dump_nodePaths (CFB_Data* cfbd, uint32_t prevPath, char* strArray[], uint32_t* str_i, cfbNode* node)
cfb_dump_nodePaths (CFB_Data* cfbd, uint32_t prevPath, char* strArray[], uint32_t* str_i, cfbNode* node, const char* padding, int firstIteration)
{
struct dbg* dbg = cfbd->dbg;
struct aafLog* log = cfbd->log;
// if ( !node ) {
if (firstIteration) {
/* initial function call */
node = &cfbd->nodes[0];
if (!node) {
return;
}
if (node == NULL) {
/* the begining of the first function call. */
node = &cfbd->nodes[0];
strArray = calloc (cfbd->nodes_cnt, sizeof (char*));
if (!strArray) {
error ("Out of memory");
return;
}
}
uint32_t thisPath = (*str_i);
wchar_t nodeName[CFB_NODE_NAME_SZ];
cfb_w16towchar (nodeName, node->_ab, node->_cb);
/* TODO snprintf_realloc() ? */
char* nodeName = cfb_w16toUTF8 (node->_ab, node->_cb);
int pathlen = snprintf (NULL, 0, "%s/%ls", strArray[prevPath], nodeName);
laaf_util_snprintf_realloc (&strArray[thisPath], 0, 0, "%s/%s", strArray[prevPath], nodeName);
if (pathlen < 0) {
// TODO error
return;
}
pathlen++;
strArray[thisPath] = malloc (pathlen);
snprintf (strArray[thisPath], pathlen, "%s/%ls", strArray[prevPath], nodeName);
free (nodeName);
(*str_i)++;
if ((int32_t)node->_sidChild > 0)
cfb_dump_nodePaths (cfbd, thisPath, strArray, str_i, &cfbd->nodes[node->_sidChild]);
cfb_dump_nodePaths (cfbd, thisPath, strArray, str_i, &cfbd->nodes[node->_sidChild], padding, 0);
if ((int32_t)node->_sidLeftSib > 0)
cfb_dump_nodePaths (cfbd, prevPath, strArray, str_i, &cfbd->nodes[node->_sidLeftSib]);
cfb_dump_nodePaths (cfbd, prevPath, strArray, str_i, &cfbd->nodes[node->_sidLeftSib], padding, 0);
if ((int32_t)node->_sidRightSib > 0)
cfb_dump_nodePaths (cfbd, prevPath, strArray, str_i, &cfbd->nodes[node->_sidRightSib]);
cfb_dump_nodePaths (cfbd, prevPath, strArray, str_i, &cfbd->nodes[node->_sidRightSib], padding, 0);
/* the end of the first function call, recursion is over. */
if (node == &cfbd->nodes[0]) {
/* commented out because output is proper this way... why did we call qsort() in the first place ?! */
// if ( node == &cfbd->nodes[0] ) {
if (firstIteration) {
/* commented out because output seems proper this way... why did we call qsort() in the first place ?! */
// qsort( strArray, *str_i, sizeof(char*), compareStrings );
for (uint32_t i = 0; i < cfbd->nodes_cnt && strArray[i] != NULL; i++) {
DBG_BUFFER_WRITE (dbg, "%05i : %s\n", i, strArray[i]);
LOG_BUFFER_WRITE (log, "%s%0*i : %s%s%s\n",
padding,
(cfbd->nodes_cnt > 1000000) ? 7 : (cfbd->nodes_cnt > 100000) ? 6
: (cfbd->nodes_cnt > 10000) ? 5
: (cfbd->nodes_cnt > 1000) ? 4
: (cfbd->nodes_cnt > 100) ? 3
: (cfbd->nodes_cnt > 10) ? 2
: 1,
i,
ANSI_COLOR_DARKGREY (log),
strArray[i],
ANSI_COLOR_RESET (log));
free (strArray[i]);
}
free (strArray);
DBG_BUFFER_WRITE (dbg, "\n\n");
LOG_BUFFER_WRITE (log, "\n\n");
dbg->debug_callback (dbg, (void*)cfbd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, dbg->_dbg_msg, dbg->user);
log->debug_callback (log, (void*)cfbd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, log->_msg, log->user);
}
}
void
cfb_dump_header (CFB_Data* cfbd)
cfb_dump_header (CFB_Data* cfbd, const char* padding)
{
struct dbg* dbg = cfbd->dbg;
struct aafLog* log = cfbd->log;
cfbHeader* cfbh = cfbd->hdr;
DBG_BUFFER_WRITE (dbg, "_abSig : 0x%08" PRIx64 "\n", cfbh->_abSig);
DBG_BUFFER_WRITE (dbg, "_clsId : %ls\n", cfb_CLSIDToText (&(cfbh->_clsid)));
DBG_BUFFER_WRITE (dbg, " version : %u.%u ( 0x%04x 0x%04x )\n",
LOG_BUFFER_WRITE (log, "%s_abSig : %s0x%08" PRIx64 "%s\n", padding, ANSI_COLOR_DARKGREY (log), cfbh->_abSig, ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%s_clsId : %s%s%s\n", padding, ANSI_COLOR_DARKGREY (log), cfb_CLSIDToText (&(cfbh->_clsid)), ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%s_version : %s%u.%u ( 0x%04x 0x%04x )%s\n",
padding,
ANSI_COLOR_DARKGREY (log),
cfbh->_uMinorVersion, cfbh->_uDllVersion,
cfbh->_uMinorVersion, cfbh->_uDllVersion);
DBG_BUFFER_WRITE (dbg, "_uByteOrder : %s ( 0x%04x )\n",
cfbh->_uMinorVersion, cfbh->_uDllVersion,
ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%s_uByteOrder : %s%s ( 0x%04x )%s\n",
padding,
ANSI_COLOR_DARKGREY (log),
cfbh->_uByteOrder == 0xFFFE ? "little-endian" : cfbh->_uByteOrder == 0xFEFF ? "big-endian"
: "?",
cfbh->_uByteOrder);
DBG_BUFFER_WRITE (dbg, "_uSectorShift : %u (%u bytes sectors)\n",
cfbh->_uByteOrder,
ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%s_uSectorShift : %s%u (%u bytes sectors)%s\n",
padding,
ANSI_COLOR_DARKGREY (log),
cfbh->_uSectorShift,
1 << cfbh->_uSectorShift);
DBG_BUFFER_WRITE (dbg, "_uMiniSectorShift : %u (%u bytes mini-sectors)\n",
1 << cfbh->_uSectorShift,
ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%s_uMiniSectorShift : %s%u (%u bytes mini-sectors)%s\n",
padding,
ANSI_COLOR_DARKGREY (log),
cfbh->_uMiniSectorShift,
1 << cfbh->_uMiniSectorShift);
DBG_BUFFER_WRITE (dbg, "_usReserved0 : 0x%02x\n", cfbh->_usReserved);
DBG_BUFFER_WRITE (dbg, "_ulReserved1 : 0x%04x\n", cfbh->_ulReserved1);
DBG_BUFFER_WRITE (dbg, "_csectDir : %u\n", cfbh->_csectDir);
DBG_BUFFER_WRITE (dbg, "_csectFat : %u\n", cfbh->_csectFat);
DBG_BUFFER_WRITE (dbg, "_sectDirStart : %u\n", cfbh->_sectDirStart);
DBG_BUFFER_WRITE (dbg, "_signature : %u\n", cfbh->_signature);
DBG_BUFFER_WRITE (dbg, "_ulMiniSectorCutoff : %u\n", cfbh->_ulMiniSectorCutoff);
DBG_BUFFER_WRITE (dbg, "_sectMiniFatStart : %u\n", cfbh->_sectMiniFatStart);
DBG_BUFFER_WRITE (dbg, "_csectMiniFat : %u\n", cfbh->_csectMiniFat);
DBG_BUFFER_WRITE (dbg, "_sectDifStart : %u\n", cfbh->_sectDifStart);
DBG_BUFFER_WRITE (dbg, "_csectDif : %u\n", cfbh->_csectDif);
1 << cfbh->_uMiniSectorShift,
ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%s_usReserved0 : %s0x%02x%s\n", padding, ANSI_COLOR_DARKGREY (log), cfbh->_usReserved, ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%s_ulReserved1 : %s0x%04x%s\n", padding, ANSI_COLOR_DARKGREY (log), cfbh->_ulReserved1, ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%s_csectDir : %s%u%s\n", padding, ANSI_COLOR_DARKGREY (log), cfbh->_csectDir, ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%s_csectFat : %s%u%s\n", padding, ANSI_COLOR_DARKGREY (log), cfbh->_csectFat, ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%s_sectDirStart : %s%u%s\n", padding, ANSI_COLOR_DARKGREY (log), cfbh->_sectDirStart, ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%s_signature : %s%u%s\n", padding, ANSI_COLOR_DARKGREY (log), cfbh->_signature, ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%s_ulMiniSectorCutoff : %s%u%s\n", padding, ANSI_COLOR_DARKGREY (log), cfbh->_ulMiniSectorCutoff, ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%s_sectMiniFatStart : %s%u%s\n", padding, ANSI_COLOR_DARKGREY (log), cfbh->_sectMiniFatStart, ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%s_csectMiniFat : %s%u%s\n", padding, ANSI_COLOR_DARKGREY (log), cfbh->_csectMiniFat, ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%s_sectDifStart : %s%u%s\n", padding, ANSI_COLOR_DARKGREY (log), cfbh->_sectDifStart, ANSI_COLOR_RESET (log));
LOG_BUFFER_WRITE (log, "%s_csectDif : %s%u%s\n", padding, ANSI_COLOR_DARKGREY (log), cfbh->_csectDif, ANSI_COLOR_RESET (log));
DBG_BUFFER_WRITE (dbg, "\n");
LOG_BUFFER_WRITE (log, "\n");
dbg->debug_callback (dbg, (void*)cfbd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, dbg->_dbg_msg, dbg->user);
log->debug_callback (log, (void*)cfbd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, log->_msg, log->user);
}
void
cfb_dump_FAT (CFB_Data* cfbd)
cfb_dump_FAT (CFB_Data* cfbd, const char* padding)
{
struct dbg* dbg = cfbd->dbg;
struct aafLog* log = cfbd->log;
DBG_BUFFER_WRITE (dbg, "_CFB_FAT_______________________________________________________________________________________\n\n");
LOG_BUFFER_WRITE (log, "_CFB_FAT_______________________________________________________________________________________\n\n");
uint32_t i = 0;
for (i = 0; i < cfbd->fat_sz; i++) {
DBG_BUFFER_WRITE (dbg, " SECT[%u] : 0x%08x %s\n",
LOG_BUFFER_WRITE (log, "%sSECT[%s%0*u%s] : %s0x%08x %s%s\n",
padding,
ANSI_COLOR_DARKGREY (log),
(cfbd->fat_sz > 1000000) ? 7 : (cfbd->fat_sz > 100000) ? 6
: (cfbd->fat_sz > 10000) ? 5
: (cfbd->fat_sz > 1000) ? 4
: (cfbd->fat_sz > 100) ? 3
: (cfbd->fat_sz > 10) ? 2
: 1,
i,
ANSI_COLOR_RESET (log),
ANSI_COLOR_DARKGREY (log),
cfbd->fat[i],
(cfbd->fat[i] == CFB_MAX_REG_SECT) ? "(CFB_MAX_REG_SECT)" : (cfbd->fat[i] == CFB_DIFAT_SECT) ? "(CFB_DIFAT_SECT)"
: (cfbd->fat[i] == CFB_FAT_SECT) ? "(CFB_FAT_SECT)"
: (cfbd->fat[i] == CFB_END_OF_CHAIN) ? "(CFB_END_OF_CHAIN)"
: (cfbd->fat[i] == CFB_FREE_SECT) ? "(CFB_FREE_SECT)"
: "");
: "",
ANSI_COLOR_RESET (log));
}
DBG_BUFFER_WRITE (dbg, "\n");
LOG_BUFFER_WRITE (log, "\n");
DBG_BUFFER_WRITE (dbg, " End of FAT.\n\n");
LOG_BUFFER_WRITE (log, "%sEnd of FAT.\n\n", padding);
DBG_BUFFER_WRITE (dbg, " Total FAT entries : %u\n", cfbd->fat_sz);
DBG_BUFFER_WRITE (dbg, " Count of FAT sector : %u\n", cfbd->hdr->_csectFat);
LOG_BUFFER_WRITE (log, "%sTotal FAT entries : %u\n", padding, cfbd->fat_sz);
LOG_BUFFER_WRITE (log, "%sCount of FAT sector : %u\n", padding, cfbd->hdr->_csectFat);
DBG_BUFFER_WRITE (dbg, "\n\n");
LOG_BUFFER_WRITE (log, "\n\n");
dbg->debug_callback (dbg, (void*)cfbd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, dbg->_dbg_msg, dbg->user);
log->debug_callback (log, (void*)cfbd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, log->_msg, log->user);
}
void
cfb_dump_MiniFAT (CFB_Data* cfbd)
cfb_dump_MiniFAT (CFB_Data* cfbd, const char* padding)
{
struct dbg* dbg = cfbd->dbg;
struct aafLog* log = cfbd->log;
DBG_BUFFER_WRITE (dbg, "_CFB_MiniFAT___________________________________________________________________________________\n\n");
LOG_BUFFER_WRITE (log, "_CFB_MiniFAT___________________________________________________________________________________\n\n");
uint32_t i = 0;
for (i = 0; i < cfbd->miniFat_sz; i++) {
DBG_BUFFER_WRITE (dbg, " SECT[%u] : 0x%08x %s\n",
LOG_BUFFER_WRITE (log, "%sSECT[%s%0*u%s] : %s0x%08x %s%s\n",
padding,
ANSI_COLOR_DARKGREY (log),
(cfbd->miniFat_sz > 1000000) ? 7 : (cfbd->miniFat_sz > 100000) ? 6
: (cfbd->miniFat_sz > 10000) ? 5
: (cfbd->miniFat_sz > 1000) ? 4
: (cfbd->miniFat_sz > 100) ? 3
: (cfbd->miniFat_sz > 10) ? 2
: 1,
i,
ANSI_COLOR_RESET (log),
ANSI_COLOR_DARKGREY (log),
cfbd->miniFat[i],
(cfbd->miniFat[i] == CFB_MAX_REG_SECT) ? "(CFB_MAX_REG_SECT)" : (cfbd->miniFat[i] == CFB_DIFAT_SECT) ? "(CFB_DIFAT_SECT)"
: (cfbd->miniFat[i] == CFB_FAT_SECT) ? "(CFB_FAT_SECT)"
: (cfbd->miniFat[i] == CFB_END_OF_CHAIN) ? "(CFB_END_OF_CHAIN)"
: (cfbd->miniFat[i] == CFB_FREE_SECT) ? "(CFB_FREE_SECT)"
: "");
: "",
ANSI_COLOR_RESET (log));
}
DBG_BUFFER_WRITE (dbg, "\n");
LOG_BUFFER_WRITE (log, "\n");
DBG_BUFFER_WRITE (dbg, " End of MiniFAT.\n\n");
LOG_BUFFER_WRITE (log, "%sEnd of MiniFAT.\n\n", padding);
DBG_BUFFER_WRITE (dbg, " Total MiniFAT entries : %u\n", cfbd->miniFat_sz);
DBG_BUFFER_WRITE (dbg, " First MiniFAT sector ID : %u\n", cfbd->hdr->_sectMiniFatStart);
DBG_BUFFER_WRITE (dbg, " Count of MiniFAT sector : %u\n", cfbd->hdr->_csectMiniFat);
LOG_BUFFER_WRITE (log, "%sTotal MiniFAT entries : %u\n", padding, cfbd->miniFat_sz);
LOG_BUFFER_WRITE (log, "%sFirst MiniFAT sector ID : %u\n", padding, cfbd->hdr->_sectMiniFatStart);
LOG_BUFFER_WRITE (log, "%sCount of MiniFAT sector : %u\n", padding, cfbd->hdr->_csectMiniFat);
DBG_BUFFER_WRITE (dbg, "\n\n");
LOG_BUFFER_WRITE (log, "\n\n");
dbg->debug_callback (dbg, (void*)cfbd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, dbg->_dbg_msg, dbg->user);
log->debug_callback (log, (void*)cfbd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, log->_msg, log->user);
}
void
cfb_dump_DiFAT (CFB_Data* cfbd)
cfb_dump_DiFAT (CFB_Data* cfbd, const char* padding)
{
struct dbg* dbg = cfbd->dbg;
struct aafLog* log = cfbd->log;
DBG_BUFFER_WRITE (dbg, "_CFB_DiFAT_____________________________________________________________________________________\n\n");
LOG_BUFFER_WRITE (log, "_CFB_DiFAT_____________________________________________________________________________________\n\n");
uint32_t i = 0;
for (i = 0; i < cfbd->DiFAT_sz; i++) {
DBG_BUFFER_WRITE (dbg, " SECT[%u] : 0x%08x %s\n",
LOG_BUFFER_WRITE (log, "%sSECT[%s%0*u%s] : %s0x%08x %s%s\n",
padding,
ANSI_COLOR_DARKGREY (log),
(cfbd->miniFat_sz > 1000000) ? 7 : (cfbd->miniFat_sz > 100000) ? 6
: (cfbd->miniFat_sz > 10000) ? 5
: (cfbd->miniFat_sz > 1000) ? 4
: (cfbd->miniFat_sz > 100) ? 3
: (cfbd->miniFat_sz > 10) ? 2
: 1,
i,
ANSI_COLOR_RESET (log),
ANSI_COLOR_DARKGREY (log),
cfbd->DiFAT[i],
(cfbd->DiFAT[i] == CFB_MAX_REG_SECT) ? "(CFB_MAX_REG_SECT)" : (cfbd->DiFAT[i] == CFB_DIFAT_SECT) ? "(CFB_DIFAT_SECT)"
: (cfbd->DiFAT[i] == CFB_FAT_SECT) ? "(CFB_FAT_SECT)"
: (cfbd->DiFAT[i] == CFB_END_OF_CHAIN) ? "(CFB_END_OF_CHAIN)"
: (cfbd->DiFAT[i] == CFB_FREE_SECT) ? "(CFB_FREE_SECT)"
: "");
: "",
ANSI_COLOR_RESET (log));
}
DBG_BUFFER_WRITE (dbg, "\n");
LOG_BUFFER_WRITE (log, "\n");
DBG_BUFFER_WRITE (dbg, " End of DiFAT.\n\n");
LOG_BUFFER_WRITE (log, "%sEnd of DiFAT.\n\n", padding);
DBG_BUFFER_WRITE (dbg, " Total DiFAT entries : %u\n", cfbd->DiFAT_sz);
DBG_BUFFER_WRITE (dbg, " First DiFAT sector ID : %u\n", cfbd->hdr->_sectDifStart);
DBG_BUFFER_WRITE (dbg, " Count of DiFAT sector : Header + %u\n", cfbd->hdr->_csectDif);
LOG_BUFFER_WRITE (log, "%sTotal DiFAT entries : %u\n", padding, cfbd->DiFAT_sz);
LOG_BUFFER_WRITE (log, "%sFirst DiFAT sector ID : %u\n", padding, cfbd->hdr->_sectDifStart);
LOG_BUFFER_WRITE (log, "%sCount of DiFAT sector : Header + %u\n", padding, cfbd->hdr->_csectDif);
DBG_BUFFER_WRITE (dbg, "\n\n");
LOG_BUFFER_WRITE (log, "\n\n");
dbg->debug_callback (dbg, (void*)cfbd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, dbg->_dbg_msg, dbg->user);
log->debug_callback (log, (void*)cfbd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, log->_msg, log->user);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2017-2023 Adrien Gesta-Fline
* Copyright (C) 2017-2024 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
@ -53,7 +53,7 @@
*
* Once the file is loaded, you can access the nodes with the functions
* cfb_getNodeByPath() and cfb_getChildNode(), and access a node's stream with the
* functions cfb_getStream() or cfb_foreachSectorInStream(). The former is prefered
* functions cfb_getStream() or CFB_foreachSectorInStream(). The former is prefered
* for small-size streams, since it allocates the entire stream to memory, while the
* later loops through each sector that composes a stream, better for the big ones.
*
@ -77,7 +77,7 @@
* // Loop through each sector that composes the "properties" stream
* cfbSectorID_t sectorID = 0;
*
* cfb_foreachSectorInStream( cfbd, properties, &stream, &stream_sz, &sectorID )
* CFB_foreachSectorInStream( cfbd, properties, &stream, &stream_sz, &sectorID )
* {
* // do stuff..
* }
@ -93,26 +93,26 @@
*/
#include <errno.h>
#include <inttypes.h>
#include <math.h> // ceil()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "aaf/CFBDump.h"
#include "aaf/LibCFB.h"
#include "aaf/debug.h"
#include "aaf/log.h"
#include "aaf/utils.h"
#define debug(...) \
_dbg (cfbd->dbg, cfbd, DEBUG_SRC_ID_LIB_CFB, VERB_DEBUG, __VA_ARGS__)
AAF_LOG (cfbd->log, cfbd, DEBUG_SRC_ID_LIB_CFB, VERB_DEBUG, __VA_ARGS__)
#define warning(...) \
_dbg (cfbd->dbg, cfbd, DEBUG_SRC_ID_LIB_CFB, VERB_WARNING, __VA_ARGS__)
AAF_LOG (cfbd->log, cfbd, DEBUG_SRC_ID_LIB_CFB, VERB_WARNING, __VA_ARGS__)
#define error(...) \
_dbg (cfbd->dbg, cfbd, DEBUG_SRC_ID_LIB_CFB, VERB_ERROR, __VA_ARGS__)
AAF_LOG (cfbd->log, cfbd, DEBUG_SRC_ID_LIB_CFB, VERB_ERROR, __VA_ARGS__)
static int
cfb_getFileSize (CFB_Data* cfbd);
@ -121,7 +121,7 @@ static int
cfb_openFile (CFB_Data* cfbd);
static uint64_t
cfb_readFile (CFB_Data* cfbd, unsigned char* buf, uint64_t offset, uint64_t len);
cfb_readFile (CFB_Data* cfbd, unsigned char* buf, size_t offset, size_t len);
static void
cfb_closeFile (CFB_Data* cfbd);
@ -150,10 +150,10 @@ getNodeCount (CFB_Data* cfbd);
static cfbSID_t
cfb_getIDByNode (CFB_Data* cfbd, cfbNode* node);
const wchar_t*
const char*
cfb_CLSIDToText (const cfbCLSID_t* clsid)
{
static wchar_t str[96];
static char str[96];
if (clsid == NULL) {
str[0] = 'n';
@ -161,18 +161,23 @@ cfb_CLSIDToText (const cfbCLSID_t* clsid)
str[2] = 'a';
str[3] = '\0';
} else {
swprintf (str, sizeof (str), L"{ 0x%08x 0x%04x 0x%04x { 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x } }",
clsid->Data1,
clsid->Data2,
clsid->Data3,
clsid->Data4[0],
clsid->Data4[1],
clsid->Data4[2],
clsid->Data4[3],
clsid->Data4[4],
clsid->Data4[5],
clsid->Data4[6],
clsid->Data4[7]);
int rc = snprintf (str, sizeof (str), "{ 0x%08x 0x%04x 0x%04x { 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x } }",
clsid->Data1,
clsid->Data2,
clsid->Data3,
clsid->Data4[0],
clsid->Data4[1],
clsid->Data4[2],
clsid->Data4[3],
clsid->Data4[4],
clsid->Data4[5],
clsid->Data4[6],
clsid->Data4[7]);
if (rc < 0 || (size_t)rc >= sizeof (str)) {
// TODO error
return NULL;
}
}
return str;
@ -185,16 +190,15 @@ cfb_CLSIDToText (const cfbCLSID_t* clsid)
*/
CFB_Data*
cfb_alloc (struct dbg* dbg)
cfb_alloc (struct aafLog* log)
{
CFB_Data* cfbd = calloc (sizeof (CFB_Data), sizeof (unsigned char));
CFB_Data* cfbd = calloc (1, sizeof (CFB_Data));
if (cfbd == NULL) {
error ("%s.", strerror (errno));
if (!cfbd) {
return NULL;
}
cfbd->dbg = dbg;
cfbd->log = log;
return cfbd;
}
@ -214,30 +218,23 @@ cfb_release (CFB_Data** cfbd)
cfb_closeFile (*cfbd);
if ((*cfbd)->DiFAT != NULL) {
free ((*cfbd)->DiFAT);
(*cfbd)->DiFAT = NULL;
}
free ((*cfbd)->file);
(*cfbd)->file = NULL;
if ((*cfbd)->fat != NULL) {
free ((*cfbd)->fat);
(*cfbd)->fat = NULL;
}
free ((*cfbd)->DiFAT);
(*cfbd)->DiFAT = NULL;
if ((*cfbd)->miniFat != NULL) {
free ((*cfbd)->miniFat);
(*cfbd)->miniFat = NULL;
}
free ((*cfbd)->fat);
(*cfbd)->fat = NULL;
if ((*cfbd)->nodes != NULL) {
free ((*cfbd)->nodes);
(*cfbd)->nodes = NULL;
}
free ((*cfbd)->miniFat);
(*cfbd)->miniFat = NULL;
if ((*cfbd)->hdr != NULL) {
free ((*cfbd)->hdr);
(*cfbd)->hdr = NULL;
}
free ((*cfbd)->nodes);
(*cfbd)->nodes = NULL;
free ((*cfbd)->hdr);
(*cfbd)->hdr = NULL;
free (*cfbd);
*cfbd = NULL;
@ -260,7 +257,9 @@ int
cfb_load_file (CFB_Data** cfbd_p, const char* file)
{
CFB_Data* cfbd = *cfbd_p;
snprintf (cfbd->file, sizeof (((CFB_Data){ 0 }).file), "%s", file);
// laaf_util_snprintf_realloc( &cfbd->file, NULL, 0, "%s", file );
cfbd->file = laaf_util_absolute_path (file);
if (cfb_openFile (cfbd) < 0) {
cfb_release (cfbd_p);
@ -307,6 +306,11 @@ cfb_load_file (CFB_Data** cfbd_p, const char* file)
return -1;
}
// debug( "FAT size: %u", cfbd->fat_sz );
// debug( "DiFAT size: %u", cfbd->DiFAT_sz );
// debug( "MiniFAT size: %u", cfbd->miniFat_sz );
// debug( "MiniFAT sector (%u) per FAT setor (%u): %u", (1 << cfbd->hdr->_uMiniSectorShift), (1 << cfbd->hdr->_uSectorShift), (1 << cfbd->hdr->_uSectorShift) / (1 << cfbd->hdr->_uMiniSectorShift) );
return 0;
}
@ -323,11 +327,13 @@ cfb_new_file (CFB_Data* cfbd, const char* file, int sectSize)
cfbHeader* hdr = malloc (sizeof (cfbHeader));
if (cfbd->hdr == NULL) {
error ("%s.", strerror (errno));
if (!hdr) {
error ("Out of memory");
return -1;
}
cfbd->hdr = hdr;
hdr->_abSig = 0xe11ab1a1e011cfd0;
/*
@ -404,23 +410,36 @@ cfb_is_valid (CFB_Data* cfbd)
static int
cfb_getFileSize (CFB_Data* cfbd)
{
#ifdef _WIN32
if (_fseeki64 (cfbd->fp, 0L, SEEK_END) < 0) {
error ("fseek() failed : %s.", strerror (errno));
return -1;
}
__int64 filesz = _ftelli64 (cfbd->fp);
#else
if (fseek (cfbd->fp, 0L, SEEK_END) < 0) {
error ("fseek() failed : %s.", strerror (errno));
return -1;
}
cfbd->file_sz = ftell (cfbd->fp);
long filesz = ftell (cfbd->fp);
if ((long)cfbd->file_sz < 0) {
#endif
if (filesz < 0) {
error ("ftell() failed : %s.", strerror (errno));
return -1;
}
if (cfbd->file_sz == 0) {
if (filesz == 0) {
error ("File is empty (0 byte).");
return -1;
}
cfbd->file_sz = (size_t)filesz;
return 0;
}
@ -434,9 +453,28 @@ cfb_getFileSize (CFB_Data* cfbd)
static int
cfb_openFile (CFB_Data* cfbd)
{
cfbd->fp = fopen (cfbd->file, "rb");
if (!cfbd->file) {
return -1;
}
if (cfbd->fp == NULL) {
#ifdef _WIN32
wchar_t* wfile = laaf_util_windows_utf8toutf16 (cfbd->file);
if (!wfile) {
error ("Unable to convert filepath to wide string : %s", cfbd->file);
return -1;
}
cfbd->fp = _wfopen (wfile, L"rb");
free (wfile);
#else
cfbd->fp = fopen (cfbd->file, "rb");
#endif
if (!cfbd->fp) {
error ("%s.", strerror (errno));
return -1;
}
@ -456,26 +494,42 @@ cfb_openFile (CFB_Data* cfbd)
*/
static uint64_t
cfb_readFile (CFB_Data* cfbd, unsigned char* buf, uint64_t offset, uint64_t len)
cfb_readFile (CFB_Data* cfbd, unsigned char* buf, size_t offset, size_t reqlen)
{
FILE* fp = cfbd->fp;
if (len + offset > cfbd->file_sz) {
error ("Requested data goes %" PRIu64 " bytes beyond the EOF : offset %" PRIu64 " | length %" PRIu64 "", (len + offset) - cfbd->file_sz, offset, len);
// debug( "Requesting file read @ offset %"PRIu64" of length %"PRIu64, offset, reqlen );
if (offset >= LONG_MAX) {
error ("Requested data offset is bigger than LONG_MAX");
return 0;
}
int rc = fseek (fp, offset, SEEK_SET);
if (reqlen + offset > cfbd->file_sz) {
error ("Requested data goes %" PRIu64 " bytes beyond the EOF : offset %" PRIu64 " | length %" PRIu64 "", (reqlen + offset) - cfbd->file_sz, offset, reqlen);
return 0;
}
int rc = fseek (fp, (long)offset, SEEK_SET);
if (rc < 0) {
error ("%s.", strerror (errno));
return 0;
}
uint64_t byteRead = fread (buf, sizeof (unsigned char), len, fp);
size_t byteRead = fread (buf, sizeof (unsigned char), reqlen, fp);
if (byteRead < len) {
warning ("Could only retrieve %" PRIu64 " bytes out of %" PRIu64 " requested.", byteRead, len);
if (feof (fp)) {
if (byteRead < reqlen) {
error ("Incomplete fread() of CFB due to EOF : %" PRIu64 " bytes read out of %" PRIu64 " requested", byteRead, reqlen);
}
debug ("fread() : EOF reached in CFB file");
} else if (ferror (fp)) {
if (byteRead < reqlen) {
error ("Incomplete fread() of CFB due to error : %" PRIu64 " bytes read out of %" PRIu64 " requested", byteRead, reqlen);
} else {
error ("fread() error of CFB : %" PRIu64 " bytes read out of %" PRIu64 " requested", byteRead, reqlen);
}
}
return byteRead;
@ -528,10 +582,10 @@ cfb_getSector (CFB_Data* cfbd, cfbSectorID_t id)
uint64_t sectorSize = (1 << cfbd->hdr->_uSectorShift);
uint64_t fileOffset = (id + 1) << cfbd->hdr->_uSectorShift;
unsigned char* buf = calloc (sectorSize, sizeof (unsigned char));
unsigned char* buf = calloc (1, sectorSize);
if (buf == NULL) {
error ("%s.", strerror (errno));
if (!buf) {
error ("Out of memory");
return NULL;
}
@ -540,6 +594,8 @@ cfb_getSector (CFB_Data* cfbd, cfbSectorID_t id)
return NULL;
}
// laaf_util_dump_hex( buf, (1<<cfbd->hdr->_uSectorShift), &cfbd->log->_msg, &cfbd->log->_msg_size, cfbd->log->_msg_pos, "" );
return buf;
}
@ -568,13 +624,13 @@ cfb_getMiniSector (CFB_Data* cfbd, cfbSectorID_t id)
return NULL;
}
int MiniSectorSize = 1 << cfbd->hdr->_uMiniSectorShift;
int SectorSize = 1 << cfbd->hdr->_uSectorShift;
uint32_t SectorSize = 1 << cfbd->hdr->_uSectorShift;
uint32_t MiniSectorSize = 1 << cfbd->hdr->_uMiniSectorShift;
unsigned char* buf = calloc (MiniSectorSize, sizeof (unsigned char));
unsigned char* buf = calloc (1, MiniSectorSize);
if (buf == NULL) {
error ("%s.", strerror (errno));
if (!buf) {
error ("Out of memory");
return NULL;
}
@ -583,11 +639,30 @@ cfb_getMiniSector (CFB_Data* cfbd, cfbSectorID_t id)
uint64_t offset = 0;
uint32_t i = 0;
/* Fat Divisor: allow to guess the number of mini-stream sectors per standard sector */
// debug( "Requesting fatID: %u (%u)", fatId, id );
/* Fat Divisor: allow to guess the number of mini-stream sectors per standard FAT sector */
unsigned int fatDiv = SectorSize / MiniSectorSize;
/* move forward in the FAT's mini-stream chain to retrieve the sector we want. */
for (i = 0; i < id / fatDiv; i++) {
if (cfbd->fat[fatId] == 0) {
error ("Next FAT index (%i/%i) is null.", i, (id / fatDiv));
goto err;
}
if (cfbd->fat[fatId] >= CFB_MAX_REG_SID) {
error ("Next FAT index (%i/%i) is invalid: %u (%08x)", i, (id / fatDiv), cfbd->fat[fatId], cfbd->fat[fatId]);
goto err;
}
if (cfbd->fat[fatId] >= cfbd->fat_sz) {
error ("Next FAT index (%i/%i) is bigger than FAT size (%u): %u (%08x)", i, (id / fatDiv), cfbd->fat_sz, cfbd->fat[fatId], cfbd->fat[fatId]);
goto err;
}
// debug( "sectorCount: %i / %u fatId: %u", i, id/fatDiv, cfbd->fat[fatId] );
fatId = cfbd->fat[fatId];
}
@ -595,10 +670,16 @@ cfb_getMiniSector (CFB_Data* cfbd, cfbSectorID_t id)
offset += ((id % fatDiv) << cfbd->hdr->_uMiniSectorShift);
if (cfb_readFile (cfbd, buf, offset, MiniSectorSize) == 0) {
free (buf);
return NULL;
goto err;
}
goto end;
err:
free (buf);
buf = NULL;
end:
return buf;
}
@ -615,23 +696,20 @@ cfb_getMiniSector (CFB_Data* cfbd, cfbSectorID_t id)
uint64_t
cfb_getStream (CFB_Data* cfbd, cfbNode* node, unsigned char** stream, uint64_t* stream_sz)
{
// if ( node == NULL || node->_mse == STGTY_ROOT )
// return;
if (node == NULL) {
return 0;
}
// Should not happen.. or could it ?
// if ( node->_ulSizeLow < 1 )
// return;
uint64_t stream_len = cfb_getNodeStreamLen (cfbd, node); //node->_ulSizeLow;
uint64_t stream_len = CFB_getNodeStreamLen (cfbd, node);
if (stream_len == 0) {
return 0;
}
*stream = calloc (stream_len, sizeof (unsigned char));
*stream = calloc (1, stream_len);
if (*stream == NULL) {
error ("%s.", strerror (errno));
if (!(*stream)) {
error ("Out of memory");
return 0;
}
@ -642,7 +720,7 @@ cfb_getStream (CFB_Data* cfbd, cfbNode* node, unsigned char** stream, uint64_t*
if (stream_len < cfbd->hdr->_ulMiniSectorCutoff) { /* mini-stream */
cfb_foreachMiniSectorInChain (cfbd, buf, id)
CFB_foreachMiniSectorInChain (cfbd, buf, id)
{
if (!buf) {
free (*stream);
@ -659,7 +737,7 @@ cfb_getStream (CFB_Data* cfbd, cfbNode* node, unsigned char** stream, uint64_t*
offset += (1 << cfbd->hdr->_uMiniSectorShift);
}
} else {
cfb_foreachSectorInChain (cfbd, buf, id)
CFB_foreachSectorInChain (cfbd, buf, id)
{
cpy_sz = ((stream_len - offset) < (uint64_t) (1 << cfbd->hdr->_uSectorShift)) ? (stream_len - offset) : (uint64_t) (1 << cfbd->hdr->_uSectorShift);
@ -681,7 +759,7 @@ cfb_getStream (CFB_Data* cfbd, cfbNode* node, unsigned char** stream, uint64_t*
* Loops through all the sectors that compose a stream
* and retrieve their content.
*
* This function should be called through the macro cfb_foreachSectorInStream().
* This function should be called through the macro CFB_foreachSectorInStream().
*
* @param cfbd Pointer to the CFB_Data structure.
* @param node Pointer to the Node that hold the stream.
@ -704,20 +782,14 @@ cfb__foreachSectorInStream (CFB_Data* cfbd, cfbNode* node, unsigned char** buf,
if (*sectID >= CFB_MAX_REG_SID)
return 0;
/* is this possible ? */
// if ( node->_ulSizeLow < 1 )
// return 0;
/* free the previously allocated buf, if any */
if (*buf != NULL) {
free (*buf);
*buf = NULL;
}
free (*buf);
*buf = NULL;
/* if *nodeID == 0, then it is the first function call */
*sectID = (*sectID == 0) ? node->_sectStart : *sectID;
size_t stream_sz = cfb_getNodeStreamLen (cfbd, node);
size_t stream_sz = CFB_getNodeStreamLen (cfbd, node);
if (stream_sz < cfbd->hdr->_ulMiniSectorCutoff) {
/* Mini-Stream */
@ -731,12 +803,6 @@ cfb__foreachSectorInStream (CFB_Data* cfbd, cfbNode* node, unsigned char** buf,
*sectID = cfbd->fat[*sectID];
}
// trim data length to match the EXACT stream size
// if ( *sectID >= CFB_MAX_REG_SECT )
// *bytesRead = ( stream_sz % *bytesRead );
// *bytesRead = ( stream_sz % *bytesRead );
return 1;
}
@ -753,26 +819,36 @@ cfb__foreachSectorInStream (CFB_Data* cfbd, cfbNode* node, unsigned char** buf,
static int
cfb_retrieveFileHeader (CFB_Data* cfbd)
{
cfbd->hdr = calloc (sizeof (cfbHeader), sizeof (unsigned char));
cfbd->hdr = calloc (1, sizeof (cfbHeader));
if (cfbd->hdr == NULL) {
error ("%s.", strerror (errno));
if (!cfbd->hdr) {
error ("Out of memory");
return -1;
}
if (cfb_readFile (cfbd, (unsigned char*)cfbd->hdr, 0, sizeof (cfbHeader)) == 0) {
free (cfbd->hdr);
cfbd->hdr = NULL;
return -1;
goto err;
}
if (cfbd->hdr->_uSectorShift != 9 &&
cfbd->hdr->_uSectorShift != 12) {
goto err;
}
return 0;
err:
free (cfbd->hdr);
cfbd->hdr = NULL;
return -1;
}
static int
cfb_retrieveDiFAT (CFB_Data* cfbd)
{
cfbSectorID_t* DiFAT = NULL;
unsigned char* buf = NULL;
/*
* Check DiFAT properties in header.
@ -782,13 +858,18 @@ cfb_retrieveDiFAT (CFB_Data* cfbd)
cfbSectorID_t csectDif = 0;
if (cfbd->hdr->_csectFat > 109) {
csectDif = ceil ((float)((cfbd->hdr->_csectFat - 109) * 4) / (1 << cfbd->hdr->_uSectorShift));
double csectDifdouble = ceil ((float)((cfbd->hdr->_csectFat - 109) * 4) / (1 << cfbd->hdr->_uSectorShift));
if (csectDifdouble >= UINT_MAX || csectDifdouble < 0) {
warning ("Calculated csectDif is negative or bigger than UINT_MAX");
// return -1;
}
csectDif = (cfbSectorID_t)csectDifdouble;
}
if (csectDif != cfbd->hdr->_csectDif) {
warning ("cfbd->hdr->_csectDif value seems wrong (%u)", cfbd->hdr->_csectDif);
// warning( "cfbd->hdr->_csectDif value seems wrong (%u). Correcting from cfbd->hdr->_csectFat.", cfbd->hdr->_csectDif );
// cfbd->hdr->_csectDif = csectDif;
warning ("cfbd->hdr->_csectDif value (%u) does not match calculated csectDif (%u)", cfbd->hdr->_csectDif, csectDif);
}
if (csectDif == 0 && cfbd->hdr->_sectDifStart != CFB_END_OF_CHAIN) {
@ -798,14 +879,20 @@ cfb_retrieveDiFAT (CFB_Data* cfbd)
/*
* DiFAT size is the number of FAT sector entries in the DiFAT chain.
* _uSectorShift is guaranted to be 9 or 12, so DiFAT_sz will never override UINT_MAX
*/
uint32_t DiFAT_sz = (cfbd->hdr->_csectDif) * (((1 << cfbd->hdr->_uSectorShift) / sizeof (cfbSectorID_t)) - 1) + 109;
size_t DiFAT_sz = cfbd->hdr->_csectDif * (((1 << cfbd->hdr->_uSectorShift) / sizeof (cfbSectorID_t)) - 1) + 109;
if (DiFAT_sz >= UINT_MAX) {
error ("DiFAT size is bigger than UINT_MAX : %lu", DiFAT_sz);
return -1;
}
DiFAT = calloc (DiFAT_sz, sizeof (cfbSectorID_t));
if (DiFAT == NULL) {
error ("%s.", strerror (errno));
if (!DiFAT) {
error ("Out of memory");
return -1;
}
@ -816,22 +903,24 @@ cfb_retrieveDiFAT (CFB_Data* cfbd)
memcpy (DiFAT, cfbd->hdr->_sectFat, 109 * sizeof (cfbSectorID_t));
unsigned char* buf = NULL;
cfbSectorID_t id = 0; //cfbd->hdr->_sectDifStart;
uint64_t offset = 109 * sizeof (cfbSectorID_t);
cfbSectorID_t id = 0;
uint64_t offset = 109 * sizeof (cfbSectorID_t);
uint64_t cnt = 0;
cfb_foreachSectorInDiFATChain (cfbd, buf, id)
/* _uSectorShift is guaranted to be 9 or 12, so sectorSize will never be negative */
uint32_t sectorSize = (1U << cfbd->hdr->_uSectorShift) - 4U;
CFB_foreachSectorInDiFATChain (cfbd, buf, id)
{
if (buf == NULL) {
error ("Error retrieving sector %u (0x%08x) out of the DiFAT chain.", id, id);
return -1;
goto err;
}
memcpy ((unsigned char*)DiFAT + offset, buf, (1 << cfbd->hdr->_uSectorShift) - 4);
memcpy ((unsigned char*)DiFAT + offset, buf, sectorSize);
offset += (1 << cfbd->hdr->_uSectorShift) - 4;
offset += sectorSize;
cnt++;
/*
@ -845,6 +934,7 @@ cfb_retrieveDiFAT (CFB_Data* cfbd)
}
free (buf);
buf = NULL;
/*
* Standard says DIFAT should end with a CFB_END_OF_CHAIN index,
@ -855,9 +945,15 @@ cfb_retrieveDiFAT (CFB_Data* cfbd)
warning ("Incorrect end of DiFAT Chain 0x%08x (%d)", id, id);
cfbd->DiFAT = DiFAT;
cfbd->DiFAT_sz = DiFAT_sz;
cfbd->DiFAT_sz = (uint32_t)DiFAT_sz;
return 0;
err:
free (DiFAT);
free (buf);
return -1;
}
/**
@ -872,12 +968,12 @@ static int
cfb_retrieveFAT (CFB_Data* cfbd)
{
cfbSectorID_t* FAT = NULL;
uint64_t FAT_sz = (((cfbd->hdr->_csectFat) * (1 << cfbd->hdr->_uSectorShift))) / sizeof (cfbSectorID_t);
uint32_t FAT_sz = (((cfbd->hdr->_csectFat) * (1 << cfbd->hdr->_uSectorShift))) / sizeof (cfbSectorID_t);
FAT = calloc (FAT_sz, sizeof (cfbSectorID_t));
if (FAT == NULL) {
error ("%s.", strerror (errno));
if (!FAT) {
error ("Out of memory");
return -1;
}
@ -888,11 +984,13 @@ cfb_retrieveFAT (CFB_Data* cfbd)
cfbSectorID_t id = 0;
uint64_t offset = 0;
cfb_foreachFATSectorIDInDiFAT (cfbd, id)
CFB_foreachFATSectorIDInDiFAT (cfbd, id)
{
if (cfbd->DiFAT[id] == CFB_FREE_SECT)
continue;
// debug( "cfbd->DiFAT[id]: %u", cfbd->DiFAT[id] );
/* observed in fairlight's AAFs.. */
if (cfbd->DiFAT[id] == 0x00000000 && id > 0) {
warning ("Got a NULL FAT index in the DiFAT @ %u, should be CFB_FREE_SECT.", id);
@ -901,6 +999,8 @@ cfb_retrieveFAT (CFB_Data* cfbd)
buf = cfb_getSector (cfbd, cfbd->DiFAT[id]);
// laaf_util_dump_hex( buf, (1<<cfbd->hdr->_uSectorShift), &cfbd->log->_msg, &cfbd->log->_msg_size, cfbd->log->_msg_pos, "" );
if (buf == NULL) {
error ("Error retrieving FAT sector %u (0x%08x).", id, id);
return -1;
@ -926,12 +1026,12 @@ cfb_retrieveFAT (CFB_Data* cfbd)
static int
cfb_retrieveMiniFAT (CFB_Data* cfbd)
{
uint64_t miniFat_sz = cfbd->hdr->_csectMiniFat * (1 << cfbd->hdr->_uSectorShift) / sizeof (cfbSectorID_t);
uint32_t miniFat_sz = cfbd->hdr->_csectMiniFat * (1 << cfbd->hdr->_uSectorShift) / sizeof (cfbSectorID_t);
cfbSectorID_t* miniFat = calloc (miniFat_sz, sizeof (cfbSectorID_t));
if (miniFat == NULL) {
error ("%s.", strerror (errno));
if (!miniFat) {
error ("Out of memory");
return -1;
}
@ -939,7 +1039,7 @@ cfb_retrieveMiniFAT (CFB_Data* cfbd)
cfbSectorID_t id = cfbd->hdr->_sectMiniFatStart;
uint64_t offset = 0;
cfb_foreachSectorInChain (cfbd, buf, id)
CFB_foreachSectorInChain (cfbd, buf, id)
{
if (buf == NULL) {
error ("Error retrieving MiniFAT sector %u (0x%08x).", id, id);
@ -986,8 +1086,8 @@ cfb_retrieveNodes (CFB_Data* cfbd)
cfbNode* node = calloc (cfbd->nodes_cnt, sizeof (cfbNode));
if (node == NULL) {
error ("%s.", strerror (errno));
if (!node) {
error ("Out of memory");
return -1;
}
@ -997,7 +1097,7 @@ cfb_retrieveNodes (CFB_Data* cfbd)
if (cfbd->hdr->_uSectorShift == 9) { /* 512 bytes sectors */
cfb_foreachSectorInChain (cfbd, buf, id)
CFB_foreachSectorInChain (cfbd, buf, id)
{
if (buf == NULL) {
error ("Error retrieving Directory sector %u (0x%08x).", id, id);
@ -1013,7 +1113,7 @@ cfb_retrieveNodes (CFB_Data* cfbd)
}
} else if (cfbd->hdr->_uSectorShift == 12) { /* 4096 bytes sectors */
cfb_foreachSectorInChain (cfbd, buf, id)
CFB_foreachSectorInChain (cfbd, buf, id)
{
if (buf == NULL) {
error ("Error retrieving Directory sector %u (0x%08x).", id, id);
@ -1059,10 +1159,12 @@ cfb_retrieveNodes (CFB_Data* cfbd)
/* handle non-standard sector size, that is different than 512B or 4kB */
/* TODO has not been tested yet, should not even exist anyway */
warning ("Parsing non-standard sector size !!! (%u bytes)", (1 << cfbd->hdr->_uSectorShift))
uint32_t nodesPerSect = (1 << cfbd->hdr->_uMiniSectorShift) / sizeof (cfbNode);
warning ("Parsing non-standard sector size !!! (%u bytes)", (1 << cfbd->hdr->_uSectorShift));
cfb_foreachSectorInChain (cfbd, buf, id)
/* _uSectorShift is guaranted to be 9 or 12, so nodesPerSect will never override UINT_MAX */
uint32_t nodesPerSect = (1U << cfbd->hdr->_uMiniSectorShift) / sizeof (cfbNode);
CFB_foreachSectorInChain (cfbd, buf, id)
{
if (buf == NULL) {
error ("Error retrieving Directory sector %u (0x%08x).", id, id);
@ -1083,42 +1185,25 @@ cfb_retrieveNodes (CFB_Data* cfbd)
}
/**
* Converts 16-bits MS/CFB wchar_t to system wchar_t.
* Converts UTF-16 to UTF-8.
*
* @param buf Pointer to wchar_t output buffer. If NULL, then function will allocate a new buffer.
* @param w16buf Pointer to a 16-bits MS/CFB "wchar_t" array.
* @param w16blen Size of the w16buf array in bytes, including the NULL. If it is set to
* CFB_W16TOWCHAR_STRLEN, then function will parse w16buf up to NULL to retrieve w16buf byte size
* @param w16buf Pointer to a NULL terminated uint16_t UTF-16 array.
* @param w16blen Size of the w16buf array in bytes
*
* @return Pointer to buf,\n
* @return New allocated buffer with UTF-8 string\n
* NULL on failure.
*/
wchar_t*
cfb_w16towchar (wchar_t* buf, uint16_t* w16buf, size_t w16blen)
char*
cfb_w16toUTF8 (const uint16_t* w16buf, size_t w16blen)
{
if (w16buf == NULL)
(void)w16blen;
if (!w16buf) {
return NULL;
if (w16blen == CFB_W16TOWCHAR_STRLEN) {
w16blen = 0;
while (w16buf[w16blen >> 1] != 0x0000) {
w16blen += sizeof (uint16_t);
}
w16blen += sizeof (uint16_t); /* NULL termination */
}
if (buf == NULL) {
buf = malloc (w16blen * sizeof (wchar_t));
if (buf == NULL)
return NULL;
}
for (size_t i = 0; i < w16blen >> 1; i++) {
buf[i] = ((uint16_t*)w16buf)[i];
}
return buf;
return laaf_util_utf16Toutf8 (w16buf);
}
/**
@ -1134,7 +1219,7 @@ cfb_w16towchar (wchar_t* buf, uint16_t* w16buf, size_t w16blen)
*/
cfbNode*
cfb_getNodeByPath (CFB_Data* cfbd, const wchar_t* path, cfbSID_t id)
cfb_getNodeByPath (CFB_Data* cfbd, const char* path, cfbSID_t id)
{
/*
* begining of the first function call.
@ -1149,20 +1234,27 @@ cfb_getNodeByPath (CFB_Data* cfbd, const wchar_t* path, cfbSID_t id)
* work either with or without "/Root Entry"
*/
if (wcsncmp (path, L"/Root Entry", 11) != 0) {
if (strncmp (path, "/Root Entry", 11) != 0) {
id = cfbd->nodes[0]._sidChild;
}
}
uint32_t l = 0;
/*
* retrieves the first node's name from path
*/
for (l = 0; l < wcslen (path); l++)
if (l > 0 && path[l] == '/')
uint32_t nameLen = 0;
for (nameLen = 0; nameLen < strlen (path); nameLen++) {
if (nameLen == UINT_MAX) {
error ("Name length is bigger than UINT_MAX");
return NULL;
}
if (nameLen > 0 && path[nameLen] == '/') {
break;
}
}
/*
* removes any leading '/'
@ -1170,10 +1262,17 @@ cfb_getNodeByPath (CFB_Data* cfbd, const wchar_t* path, cfbSID_t id)
if (path[0] == '/') {
path++;
l--;
nameLen--;
}
wchar_t ab[CFB_NODE_NAME_SZ];
size_t nameUTF16Len = (nameLen + 1) << 1;
if (nameUTF16Len >= INT_MAX) {
error ("Name length is bigger than INT_MAX");
return NULL;
}
char* ab = NULL;
while (1) {
if (id >= cfbd->nodes_cnt) {
@ -1181,16 +1280,17 @@ cfb_getNodeByPath (CFB_Data* cfbd, const wchar_t* path, cfbSID_t id)
return NULL;
}
// laaf_util_dump_hex( cfbd->nodes[id]->_ab, cfbd->nodes[id]->_cb );
ab = cfb_w16toUTF8 (cfbd->nodes[id]._ab, cfbd->nodes[id]._cb);
cfb_w16towchar (ab, cfbd->nodes[id]._ab, cfbd->nodes[id]._cb);
int rc = 0;
int32_t rc = 0;
if (strlen (ab) == nameLen)
rc = strncmp (path, ab, nameLen);
else {
rc = (int)nameUTF16Len - cfbd->nodes[id]._cb;
}
if (wcslen (ab) == l)
rc = wcsncmp (path, ab, l);
else
rc = l - wcslen (ab);
free (ab);
/*
* Some node in the path was found.
@ -1201,7 +1301,7 @@ cfb_getNodeByPath (CFB_Data* cfbd, const wchar_t* path, cfbSID_t id)
* get full path length minus any terminating '/'
*/
uint32_t pathLen = wcslen (path);
size_t pathLen = strlen (path);
if (path[pathLen - 1] == '/')
pathLen--;
@ -1212,10 +1312,10 @@ cfb_getNodeByPath (CFB_Data* cfbd, const wchar_t* path, cfbSID_t id)
* to next node in the path.
*/
if (pathLen == l)
if (pathLen == nameLen)
return &cfbd->nodes[id];
else
return cfb_getNodeByPath (cfbd, path + l, cfbd->nodes[id]._sidChild);
return cfb_getNodeByPath (cfbd, path + nameLen, cfbd->nodes[id]._sidChild);
} else if (rc > 0)
id = cfbd->nodes[id]._sidRightSib;
else if (rc < 0)
@ -1239,16 +1339,23 @@ cfb_getNodeByPath (CFB_Data* cfbd, const wchar_t* path, cfbSID_t id)
*/
cfbNode*
cfb_getChildNode (CFB_Data* cfbd, const wchar_t* name, cfbNode* startNode)
cfb_getChildNode (CFB_Data* cfbd, const char* name, cfbNode* startNode)
{
int32_t rc = 0;
int rc = 0;
/** @TODO : cfb_getIDByNode should be quiker (macro ?) */
cfbSID_t id = cfb_getIDByNode (cfbd, &cfbd->nodes[startNode->_sidChild]);
uint32_t nameUTF16Len = ((wcslen (name) + 1) << 1);
if (id == UINT_MAX) {
error ("Could not retrieve id by node");
return NULL;
}
wchar_t nodename[CFB_NODE_NAME_SZ];
size_t nameUTF16Len = ((strlen (name) + 1) << 1);
if (nameUTF16Len >= INT_MAX) {
error ("Name length is bigger than INT_MAX");
return NULL;
}
while (1) {
if (id >= cfbd->nodes_cnt) {
@ -1256,13 +1363,15 @@ cfb_getChildNode (CFB_Data* cfbd, const wchar_t* name, cfbNode* startNode)
return NULL;
}
cfb_w16towchar (nodename, cfbd->nodes[id]._ab, cfbd->nodes[id]._cb);
char* nodename = cfb_w16toUTF8 (cfbd->nodes[id]._ab, cfbd->nodes[id]._cb);
if (cfbd->nodes[id]._cb == nameUTF16Len)
rc = wcscmp (name, nodename);
else
rc = nameUTF16Len - cfbd->nodes[id]._cb;
rc = strcmp (name, nodename);
else {
rc = (int)nameUTF16Len - cfbd->nodes[id]._cb;
}
free (nodename);
/*
* Node found
*/
@ -1310,7 +1419,7 @@ cfb_getIDByNode (CFB_Data* cfbd, cfbNode* node)
}
}
return -1;
return UINT_MAX;
}
/**
@ -1324,7 +1433,7 @@ cfb_getIDByNode (CFB_Data* cfbd, cfbNode* node)
static cfbSID_t
getNodeCount (CFB_Data* cfbd)
{
uint64_t cnt = (1 << cfbd->hdr->_uSectorShift);
uint32_t cnt = (1 << cfbd->hdr->_uSectorShift);
cfbSectorID_t id = cfbd->hdr->_sectDirStart;
while (id < CFB_MAX_REG_SID) {

59
libs/aaf/MediaComposer.c Normal file
View File

@ -0,0 +1,59 @@
/*
* Copyright (C) 2024 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <stdint.h>
#include <stdio.h>
#include "aaf/AAFDefs/AAFPropertyIDs.h"
#include "aaf/AAFDefs/AAFTypeDefUIDs.h"
#include "aaf/AAFIParser.h"
#include "aaf/AAFToText.h"
#include "aaf/libaaf.h"
#include "aaf/log.h"
#define debug(...) \
AAF_LOG (aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_DEBUG, __VA_ARGS__)
#define warning(...) \
AAF_LOG (aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_WARNING, __VA_ARGS__)
#define error(...) \
AAF_LOG (aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_ERROR, __VA_ARGS__)
int
mediaComposer_AAF (struct AAF_Iface* aafi)
{
int probe = 0;
if (aafi->aafd->Identification.CompanyName && strncmp (aafi->aafd->Identification.CompanyName, "Avid Technology, Inc.", strlen ("Avid Technology, Inc.")) == 0) {
probe++;
}
if (aafi->aafd->Identification.ProductName && strncmp (aafi->aafd->Identification.ProductName, "Avid Media Composer", strlen ("Avid Media Composer")) == 0) {
probe++;
}
if (probe == 2) {
return 1;
}
return 0;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2017-2023 Adrien Gesta-Fline
* Copyright (C) 2017-2024 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
@ -23,81 +23,70 @@
#include "aaf/AAFIface.h"
#include "aaf/ProTools.h"
#define PROTOOLS_CLIP_NAME_FADE_EN_LEN 5 // +1
#define PROTOOLS_CLIP_NAME_FADE_DE_LEN 5 // +1
#define PROTOOLS_CLIP_NAME_FADE_JA_LEN 5 // +1
#define PROTOOLS_CLIP_NAME_FADE_FR_LEN 6 // +1
#define PROTOOLS_CLIP_NAME_FADE_ES_LEN 8 // +1
#define PROTOOLS_CLIP_NAME_FADE_ZH_CN_LEN 3 // +1
#define PROTOOLS_CLIP_NAME_FADE_ZH_TW_LEN 3 // +1
#define PROTOOLS_CLIP_NAME_FADE_KO_LEN 3 // +1
#define PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_EN_LEN 20 // +1
#define PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_DE_LEN 24 // +1
#define PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ES_LEN 32 // +1
#define PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_FR_LEN 33 // +1
#define PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_JA_LEN 8 // +1
#define PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ZH_CN_LEN 6 // +1
#define PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ZH_TW_LEN 6 // +1
#define PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_KO_LEN 11 // +1
/* English : "Fade " (Same as JA and DE) */
static const wchar_t PROTOOLS_CLIP_NAME_FADE_EN[] = L"\x0046\x0061\x0064\x0065\x0020\x0000";
/* German : "Fade " (Same as JA and EN) */
// static const wchar_t PROTOOLS_CLIP_NAME_FADE_DE[] = L"\x0046\x0061\x0064\x0065\x0020\x0000";
/* Japanese : "Fade " (Same as EN and DE) */
// static const wchar_t PROTOOLS_CLIP_NAME_FADE_JA[] = L"\x0046\x0061\x0064\x0065\x0020\x0000";
static const char PROTOOLS_CLIP_NAME_FADE_EN[] = "\x46\x61\x64\x65\x20";
/* French : "Fondu " */
static const wchar_t PROTOOLS_CLIP_NAME_FADE_FR[] = L"\x0046\x006f\x006e\x0064\x0075\x0020\x0000";
static const char PROTOOLS_CLIP_NAME_FADE_FR[] = "\x46\x6f\x6e\x64\x75\x20";
/* Spanish : "Fundido" */
static const wchar_t PROTOOLS_CLIP_NAME_FADE_ES[] = L"\x0046\x0075\x006e\x0064\x0069\x0064\x006f\x0020\x0000";
/* Chinese (S) : "淡变 " */
static const wchar_t PROTOOLS_CLIP_NAME_FADE_ZH_CN[] = L"\x6de1\x53d8\x0020\x0000";
/* Chinese (T) : "淡變 " */
static const wchar_t PROTOOLS_CLIP_NAME_FADE_ZH_TW[] = L"\x6de1\x8b8a\x0020\x0000";
static const char PROTOOLS_CLIP_NAME_FADE_ES[] = "\x46\x75\x6e\x64\x69\x64\x6f\x20";
/* Korean : "페이드" */
static const wchar_t PROTOOLS_CLIP_NAME_FADE_KO[] = L"\xd398\xc774\xb4dc\x0000";
static const char PROTOOLS_CLIP_NAME_FADE_KO[] = "\xed\x8e\x98\xec\x9d\xb4\xeb\x93\x9c";
/* Chinese (S) : "淡变 " */
static const char PROTOOLS_CLIP_NAME_FADE_ZH_CN[] = "\xe6\xb7\xa1\xe5\x8f\x98\x20";
/* Chinese (T) : "淡變 " */
static const char PROTOOLS_CLIP_NAME_FADE_ZH_TW[] = "\xe6\xb7\xa1\xe8\xae\x8a\x20";
/* English : "Sample accurate edit" */
static const wchar_t PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_EN[] = L"\x0053\x0061\x006d\x0070\x006c\x0065\x0020\x0061\x0063\x0063\x0075\x0072\x0061\x0074\x0065\x0020\x0065\x0064\x0069\x0074\x0000";
static const char PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_EN[] = "\x53\x61\x6d\x70\x6c\x65\x20\x61\x63\x63\x75\x72\x61\x74\x65\x20\x65\x64\x69\x74";
/* German : "Samplegenaue Bearbeitung" */
static const wchar_t PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_DE[] = L"\x0053\x0061\x006d\x0070\x006c\x0065\x0067\x0065\x006e\x0061\x0075\x0065\x0020\x0042\x0065\x0061\x0072\x0062\x0065\x0069\x0074\x0075\x006e\x0067\x0000";
static const char PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_DE[] = "\x53\x61\x6d\x70\x6c\x65\x67\x65\x6e\x61\x75\x65\x20\x42\x65\x61\x72\x62\x65\x69\x74\x75\x6e\x67";
/* Spanish : "Edición con precisión de muestra" */
static const wchar_t PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ES[] = L"\x0045\x0064\x0069\x0063\x0069\x00f3\x006e\x0020\x0063\x006f\x006e\x0020\x0070\x0072\x0065\x0063\x0069\x0073\x0069\x00f3\x006e\x0020\x0064\x0065\x0020\x006d\x0075\x0065\x0073\x0074\x0072\x0061\x0000";
static const char PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ES[] = "\x45\x64\x69\x63\x69\xc3\xb3\x6e\x20\x63\x6f\x6e\x20\x70\x72\x65\x63\x69\x73\x69\xc3\xb3\x6e\x20\x64\x65\x20\x6d\x75\x65\x73\x74\x72\x61";
/* French : "Modification à l'échantillon près" */
static const wchar_t PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_FR[] = L"\x004d\x006f\x0064\x0069\x0066\x0069\x0063\x0061\x0074\x0069\x006f\x006e\x0020\x00e0\x0020\x006c\x0027\x00e9\x0063\x0068\x0061\x006e\x0074\x0069\x006c\x006c\x006f\x006e\x0020\x0070\x0072\x00e8\x0073\x0000";
static const char PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_FR[] = "\x4d\x6f\x64\x69\x66\x69\x63\x61\x74\x69\x6f\x6e\x20\xc3\xa0\x20\x6c\x27\xc3\xa9\x63\x68\x61\x6e\x74\x69\x6c\x6c\x6f\x6e\x20\x70\x72\xc3\xa8\x73";
/* Japanese : "サンプル精度編集" */
static const wchar_t PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_JA[] = L"\x30b5\x30f3\x30d7\x30eb\x7cbe\x5ea6\x7de8\x96c6\x0000";
/* Chinese (S) : "精确采样编辑" */
static const wchar_t PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ZH_CN[] = L"\x7cbe\x786e\x91c7\x6837\x7f16\x8f91\x0000";
/* Chinese (T) : "精確取樣編輯" */
static const wchar_t PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ZH_TW[] = L"\x7cbe\x78ba\x53d6\x6a23\x7de8\x8f2f\x0000";
static const char PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_JA[] = "\xe3\x82\xb5\xe3\x83\xb3\xe3\x83\x97\xe3\x83\xab\xe7\xb2\xbe\xe5\xba\xa6\xe7\xb7\xa8\xe9\x9b\x86";
/* Korean : "샘플 단위 정밀 편집" */
static const wchar_t PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_KO[] = L"\xc0d8\xd50c\x0020\xb2e8\xc704\x0020\xc815\xbc00\x0020\xd3b8\xc9d1\x0000";
static const char PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_KO[] = "\xec\x83\x98\xed\x94\x8c\x20\xeb\x8b\xa8\xec\x9c\x84\x20\xec\xa0\x95\xeb\xb0\x80\x20\xed\x8e\xb8\xec\xa7\x91";
/* Chinese (S) : "精确采样编辑" */
static const char PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ZH_CN[] = "\xe7\xb2\xbe\xe7\xa1\xae\xe9\x87\x87\xe6\xa0\xb7\xe7\xbc\x96\xe8\xbe\x91";
/* Chinese (T) : "精確取樣編輯" */
static const char PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ZH_TW[] = "\xe7\xb2\xbe\xe7\xa2\xba\xe5\x8f\x96\xe6\xa8\xa3\xe7\xb7\xa8\xe8\xbc\xaf";
#define debug(...) \
AAF_LOG (aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_DEBUG, __VA_ARGS__)
#define warning(...) \
AAF_LOG (aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_WARNING, __VA_ARGS__)
#define error(...) \
AAF_LOG (aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_ERROR, __VA_ARGS__)
static int
is_rendered_fade (const wchar_t* clipName);
is_rendered_fade (const char* clipName);
static int
is_sample_accurate_edit (const wchar_t* clipName);
is_sample_accurate_edit (const char* clipName);
static int
replace_clipfade_with_fade (AAF_Iface* aafi, aafiTimelineItem* Item);
remove_sampleAccurateEditClip (AAF_Iface* aafi, aafiAudioTrack* audioTrack, aafiTimelineItem* saeItem);
static int
replace_clipFade (AAF_Iface* aafi, aafiAudioTrack* audioTrack, aafiTimelineItem* fadeItem);
int
protools_AAF (struct AAF_Iface* aafi)
{
int probe = 0;
/* TODO: CompanyName is "Digidesign, Inc." in ProTools 10.3.10.613 AAF, but what about since ? */
/* NOTE: CompanyName is "Digidesign, Inc." at least since ProTools 10.3.10.613, and still today */
// if ( aafi->aafd->Identification.CompanyName && wcscmp( aafi->aafd->Identification.CompanyName, L"Digidesign, Inc." ) == 0 ) {
// probe++;
// }
if (aafi->aafd->Identification.ProductName && wcscmp (aafi->aafd->Identification.ProductName, L"ProTools") == 0) {
if (aafi->aafd->Identification.CompanyName && strcmp (aafi->aafd->Identification.CompanyName, "Digidesign, Inc.") == 0) {
probe++;
}
if (probe == 1) {
if (aafi->aafd->Identification.ProductName && strcmp (aafi->aafd->Identification.ProductName, "ProTools") == 0) {
probe++;
}
if (probe == 2) {
return 1;
}
@ -105,131 +94,291 @@ protools_AAF (struct AAF_Iface* aafi)
}
static int
is_rendered_fade (const wchar_t* clipName)
is_rendered_fade (const char* clipName)
{
return (memcmp (clipName, PROTOOLS_CLIP_NAME_FADE_EN, PROTOOLS_CLIP_NAME_FADE_EN_LEN) == 0) ||
(memcmp (clipName, PROTOOLS_CLIP_NAME_FADE_ES, PROTOOLS_CLIP_NAME_FADE_ES_LEN) == 0) ||
(memcmp (clipName, PROTOOLS_CLIP_NAME_FADE_FR, PROTOOLS_CLIP_NAME_FADE_FR_LEN) == 0) ||
(memcmp (clipName, PROTOOLS_CLIP_NAME_FADE_ZH_CN, PROTOOLS_CLIP_NAME_FADE_ZH_CN_LEN) == 0) ||
(memcmp (clipName, PROTOOLS_CLIP_NAME_FADE_ZH_TW, PROTOOLS_CLIP_NAME_FADE_ZH_TW_LEN) == 0) ||
(memcmp (clipName, PROTOOLS_CLIP_NAME_FADE_KO, PROTOOLS_CLIP_NAME_FADE_KO_LEN) == 0);
return (strcmp (clipName, PROTOOLS_CLIP_NAME_FADE_EN) == 0) ||
(strcmp (clipName, PROTOOLS_CLIP_NAME_FADE_ES) == 0) ||
(strcmp (clipName, PROTOOLS_CLIP_NAME_FADE_FR) == 0) ||
(strcmp (clipName, PROTOOLS_CLIP_NAME_FADE_ZH_CN) == 0) ||
(strcmp (clipName, PROTOOLS_CLIP_NAME_FADE_ZH_TW) == 0) ||
(strcmp (clipName, PROTOOLS_CLIP_NAME_FADE_KO) == 0);
}
static int
is_sample_accurate_edit (const wchar_t* clipName)
is_sample_accurate_edit (const char* clipName)
{
return (memcmp (clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_EN, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_EN_LEN) == 0) ||
(memcmp (clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_DE, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_DE_LEN) == 0) ||
(memcmp (clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ES, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ES_LEN) == 0) ||
(memcmp (clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_FR, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_FR_LEN) == 0) ||
(memcmp (clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_JA, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_JA_LEN) == 0) ||
(memcmp (clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ZH_CN, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ZH_CN_LEN) == 0) ||
(memcmp (clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ZH_TW, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ZH_TW_LEN) == 0) ||
(memcmp (clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_KO, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_KO_LEN) == 0);
return (strcmp (clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_EN) == 0) ||
(strcmp (clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_DE) == 0) ||
(strcmp (clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ES) == 0) ||
(strcmp (clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_FR) == 0) ||
(strcmp (clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_JA) == 0) ||
(strcmp (clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ZH_CN) == 0) ||
(strcmp (clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ZH_TW) == 0) ||
(strcmp (clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_KO) == 0);
}
static int
replace_clipfade_with_fade (AAF_Iface* aafi, aafiTimelineItem* Item)
remove_sampleAccurateEditClip (AAF_Iface* aafi, aafiAudioTrack* audioTrack, aafiTimelineItem* saeItem)
{
if (Item->type != AAFI_AUDIO_CLIP) {
return -1;
}
/*
* Note: In this function, we assume we need to expand a clip to remove an
* attached sample accurate edit. TODO: Ensure it's always possible with ProTools
*/
aafiAudioClip* audioClip = (aafiAudioClip*)Item->data;
aafiAudioClip* saeClip = saeItem->data;
aafPosition_t currentpos = audioClip->pos;
aafPosition_t currentlen = audioClip->len;
if (saeItem->prev) {
if (saeItem->prev->type == AAFI_AUDIO_CLIP) {
aafiAudioClip* leftClip = saeItem->prev->data;
aafiTimelineItem* transItem = calloc (sizeof (aafiTimelineItem) + sizeof (aafiTransition), sizeof (char));
if (saeClip->pos == (leftClip->pos + leftClip->len)) {
aafPosition_t essenceLength = aafi_convertUnit (leftClip->essencePointerList->essenceFile->length, leftClip->essencePointerList->essenceFile->samplerateRational, leftClip->track->edit_rate);
memset (transItem, 0x00, sizeof (aafiTimelineItem) + sizeof (aafiTransition));
if ((essenceLength - leftClip->essence_offset - leftClip->len) >= saeClip->len) {
debug ("Removing SAE \"%s\" : left clip \"%s\" goes from length %" PRIi64 " to %" PRIi64,
saeClip->essencePointerList->essenceFile->unique_name,
leftClip->essencePointerList->essenceFile->unique_name,
leftClip->len,
leftClip->len + saeClip->len);
transItem->type = AAFI_TRANS;
transItem->next = NULL;
transItem->prev = NULL;
leftClip->len += saeClip->len;
transItem->data = calloc (sizeof (aafiTransition), sizeof (char));
aafi_removeTimelineItem (aafi, saeItem);
aafiTransition* trans = transItem->data;
trans->len = audioClip->len;
trans->flags = AAFI_INTERPOL_NONE;
// debug( "%ls", audioClip->Essence->unique_file_name );
aafiAudioClip* prevClip = NULL;
aafiAudioClip* nextClip = NULL;
if (Item->prev != NULL) {
if (Item->prev->type == AAFI_AUDIO_CLIP) {
prevClip = (aafiAudioClip*)Item->prev->data;
// debug( "PREVIOUS POS %lu", prevClip->pos + prevClip->len );
// debug( "CURENT POS %lu", currentpos );
if (prevClip->pos + prevClip->len < currentpos - 1) {
prevClip = NULL;
audioTrack->clipCount--;
return 1;
}
// else {
// warning( L"Can't remove SAE \"%s\" : left clip \"%s\" has not enough right handle : %lu but %lu is required",
// saeClip->essencePointerList->essenceFile->unique_name,
// leftClip->essencePointerList->essenceFile->unique_name,
// (essenceLength - leftClip->essence_offset - leftClip->len),
// saeClip->len );
// }
}
}
}
if (Item->next != NULL) {
if (Item->next->type == AAFI_AUDIO_CLIP) {
nextClip = (aafiAudioClip*)Item->next->data;
if (saeItem->next) {
if (saeItem->next->type == AAFI_AUDIO_CLIP) {
aafiAudioClip* rightClip = saeItem->next->data;
if (is_sample_accurate_edit (nextClip->essencePointerList->essence->file_name)) {
if (Item->next->next != NULL) {
nextClip = (aafiAudioClip*)Item->next->next->data;
if ((saeClip->pos + saeClip->len) == rightClip->pos) {
if (rightClip->essence_offset >= saeClip->len) {
debug ("Removing SAE \"%s\" : right clip \"%s\" goes from length: %" PRIi64 " to %" PRIi64 ", pos: %" PRIi64 " to %" PRIi64 ", source offset: %" PRIi64 " to %" PRIi64,
saeClip->essencePointerList->essenceFile->unique_name,
rightClip->essencePointerList->essenceFile->unique_name,
rightClip->len,
rightClip->len + saeClip->len,
rightClip->pos,
rightClip->pos - saeClip->len,
rightClip->essence_offset,
rightClip->essence_offset - saeClip->len);
// debug( "NEXT POS %lu", nextClip->pos );
// debug( "CURENT POS %lu", currentpos + currentlen );
rightClip->pos -= saeClip->len;
rightClip->len += saeClip->len;
rightClip->essence_offset -= saeClip->len;
if (nextClip->pos != currentpos + currentlen + 1) {
aafi_removeTimelineItem (aafi, saeItem);
audioTrack->clipCount--;
return 1;
}
// else {
// warning( L"Can't remove SAE \"%s\" : right clip \"%s\" has not enough left handle : %lu but %lu is required",
// saeClip->essencePointerList->essenceFile->unique_name,
// rightClip->essencePointerList->essenceFile->unique_name,
// rightClip->essence_offset,
// saeClip->len );
// }
}
}
}
return 0;
}
static int
replace_clipFade (AAF_Iface* aafi, aafiAudioTrack* audioTrack, aafiTimelineItem* fadeItem)
{
aafiAudioClip* fadeClip = fadeItem->data;
aafiTimelineItem* prevItem1 = fadeItem->prev;
aafiTimelineItem* prevItem2 = (prevItem1 && prevItem1->prev) ? prevItem1->prev : NULL;
aafiTimelineItem* nextItem1 = fadeItem->next;
aafiTimelineItem* nextItem2 = (nextItem1 && nextItem1->next) ? nextItem1->next : NULL;
aafiAudioClip* prevClip = NULL;
aafiAudioClip* nextClip = NULL;
if (prevItem1 && prevItem1->type == AAFI_AUDIO_CLIP) {
prevClip = prevItem1->data;
if (fadeClip->pos == (prevClip->pos + prevClip->len)) {
/* a previous clip is touching this fadeClip on the left */
if (is_sample_accurate_edit (prevClip->essencePointerList->essenceFile->name)) {
remove_sampleAccurateEditClip (aafi, audioTrack, prevItem1);
if (prevItem2 && prevItem2->type == AAFI_AUDIO_CLIP) {
aafiAudioClip* prevClip2 = prevItem2->data;
if (fadeClip->pos == (prevClip2->pos + prevClip2->len)) {
prevClip = prevClip2;
debug ("Got a clip \"%s\" preceding fadeClip \"%s\"",
prevClip->essencePointerList->essenceFile->unique_name,
fadeClip->essencePointerList->essenceFile->unique_name);
} else {
prevClip = NULL;
}
} else {
prevClip = NULL;
}
} else {
debug ("Got a clip \"%s\" preceding fadeClip \"%s\"",
prevClip->essencePointerList->essenceFile->unique_name,
fadeClip->essencePointerList->essenceFile->unique_name);
}
} else {
prevClip = NULL;
}
}
if (nextItem1 && nextItem1->type == AAFI_AUDIO_CLIP) {
nextClip = nextItem1->data;
if ((fadeClip->pos + fadeClip->len) == nextClip->pos) {
/* a following clip is touching this fadeClip on the right */
if (is_sample_accurate_edit (nextClip->essencePointerList->essenceFile->name)) {
remove_sampleAccurateEditClip (aafi, audioTrack, nextItem1);
if (nextItem2 && nextItem2->type == AAFI_AUDIO_CLIP) {
aafiAudioClip* nextClip2 = nextItem2->data;
if ((fadeClip->pos + fadeClip->len) == nextClip2->pos) {
nextClip = nextClip2;
debug ("Got a clip \"%s\" following fadeClip \"%s\"",
nextClip->essencePointerList->essenceFile->unique_name,
fadeClip->essencePointerList->essenceFile->unique_name);
} else {
nextClip = NULL;
}
} else {
nextClip = NULL;
}
} else {
// nextClip = (aafiAudioClip*)Item->next->data;
// debug( "NEXT POS %lu", nextClip->pos );
// debug( "CURENT POS %lu", currentpos + currentlen );
if (nextClip->pos != currentpos + currentlen) {
nextClip = NULL;
}
debug ("Got a clip \"%s\" following fadeClip \"%s\"",
nextClip->essencePointerList->essenceFile->unique_name,
fadeClip->essencePointerList->essenceFile->unique_name);
}
} else {
nextClip = NULL;
}
}
if (!prevClip && !nextClip) {
debug ("FadeClip \"%s\" is not surrounding by any touching clip",
fadeClip->essencePointerList->essenceFile->unique_name);
return 0;
}
/*
* Ensures we have enough handle in surrounding clips to expand by fade length
*/
if (prevClip) {
aafPosition_t essenceLength = aafi_convertUnit (prevClip->essencePointerList->essenceFile->length, prevClip->essencePointerList->essenceFile->samplerateRational, prevClip->track->edit_rate);
if ((essenceLength - prevClip->essence_offset - prevClip->len) < fadeClip->len) {
warning ("Previous clip \"%s\" has not enough handle to build a fade in place of \"%s\"",
prevClip->essencePointerList->essenceFile->unique_name,
fadeClip->essencePointerList->essenceFile->unique_name);
return -1;
}
}
if (nextClip) {
if (nextClip->essence_offset < fadeClip->len) {
warning ("Next clip \"%s\" has not enough handle to build a fade in place of \"%s\"",
nextClip->essencePointerList->essenceFile->unique_name,
fadeClip->essencePointerList->essenceFile->unique_name);
return -1;
}
}
debug ("Replacing fadeClip \"%s\" with a %s transition of length %" PRIi64,
fadeClip->essencePointerList->essenceFile->unique_name,
(prevClip && nextClip) ? "X-Fade" : (nextClip) ? "FadeIn"
: "FadeOut",
fadeClip->len);
/*
* changes existing aafiTimelineItem from aafiAudioClip into aafiTransition
*/
aafPosition_t fadeClipLength = fadeClip->len;
fadeItem->type = AAFI_TRANS;
aafi_freeAudioClip (fadeItem->data);
fadeItem->data = calloc (1, sizeof (aafiTransition));
if (!fadeItem->data) {
error ("Out of memory");
aafi_removeTimelineItem (aafi, fadeItem);
audioTrack->clipCount--;
return 1; /* important ! */
}
aafiTransition* trans = fadeItem->data;
trans->len = fadeClipLength;
trans->flags = AAFI_INTERPOL_LINEAR;
trans->time_a = calloc (2, sizeof (aafRational_t));
trans->value_a = calloc (2, sizeof (aafRational_t));
trans->time_a[0].numerator = 0;
trans->time_a[0].denominator = 0;
trans->time_a[1].numerator = 1;
trans->time_a[1].denominator = 1;
if (!trans->time_a || !trans->value_a) {
error ("Out of memory");
aafi_removeTimelineItem (aafi, fadeItem);
audioTrack->clipCount--;
return 1; /* important ! */
}
if (prevClip && nextClip) {
// debug( ":: XFADE" );
prevClip->len += fadeClipLength;
nextClip->pos -= fadeClipLength;
nextClip->len += fadeClipLength;
nextClip->essence_offset -= fadeClipLength;
trans->flags |= AAFI_TRANS_XFADE;
trans->cut_pt = fadeClipLength / 2;
trans->value_a[0].numerator = 0;
trans->value_a[0].denominator = 0;
trans->value_a[1].numerator = 1;
trans->value_a[1].denominator = 1;
} else if (prevClip) {
// debug( ":: FADE OUT" );
prevClip->len += fadeClipLength;
trans->flags |= AAFI_TRANS_FADE_OUT;
trans->cut_pt = fadeClipLength;
trans->value_a[0].numerator = 1;
trans->value_a[0].denominator = 1;
trans->value_a[1].numerator = 0;
trans->value_a[1].denominator = 0;
} else if (nextClip) {
// debug( ":: FADE IN" );
nextClip->pos -= fadeClipLength;
nextClip->len += fadeClipLength;
nextClip->essence_offset -= fadeClipLength;
trans->flags |= AAFI_TRANS_FADE_IN;
trans->cut_pt = 0;
trans->value_a[0].numerator = 0;
trans->value_a[0].denominator = 0;
@ -237,43 +386,23 @@ replace_clipfade_with_fade (AAF_Iface* aafi, aafiTimelineItem* Item)
trans->value_a[1].denominator = 1;
}
if (Item->prev) {
Item->prev->next = transItem;
transItem->prev = Item->prev;
} else {
aafiAudioTrack* audioTrack = NULL;
audioTrack->clipCount--;
foreach_audioTrack (audioTrack, aafi)
{
if (audioTrack->Items == Item) {
audioTrack->Items = transItem;
}
}
transItem->prev = NULL;
}
if (Item->next) {
Item->next->prev = transItem;
}
transItem->next = Item->next;
aafi_freeTimelineItem (&Item);
return 0;
return 1;
}
int
protools_post_processing (AAF_Iface* aafi /*, enum protools_options flags*/)
protools_post_processing (AAF_Iface* aafi)
{
aafiAudioTrack* audioTrack = NULL;
foreach_audioTrack (audioTrack, aafi)
AAFI_foreachAudioTrack (aafi, audioTrack)
{
aafiTimelineItem* audioItem = audioTrack->Items;
aafiTimelineItem* audioItem = audioTrack->timelineItems;
while (audioItem != NULL) {
aafiTimelineItem* audioItemNext = audioItem->next;
if (audioItem->type != AAFI_AUDIO_CLIP) {
audioItem = audioItem->next;
continue;
@ -281,21 +410,23 @@ protools_post_processing (AAF_Iface* aafi /*, enum protools_options flags*/)
aafiAudioClip* audioClip = (aafiAudioClip*)audioItem->data;
wchar_t* clipName = audioClip->essencePointerList->essence->file_name;
char* clipName = audioClip->essencePointerList->essenceFile->name;
if ((aafi->ctx.options.protools & PROTOOLS_REPLACE_CLIP_FADES) && is_rendered_fade (clipName)) {
replace_clipfade_with_fade (aafi, audioItem);
audioItem = audioTrack->Items;
continue;
} else if ((aafi->ctx.options.protools & PROTOOLS_REMOVE_SAMPLE_ACCURATE_EDIT) && is_sample_accurate_edit (clipName)) {
aafi_removeTimelineItem (aafi, audioItem);
audioItem = audioTrack->Items;
continue;
if ((aafi->ctx.options.protools & AAFI_PROTOOLS_OPT_REPLACE_CLIP_FADES) &&
is_rendered_fade (clipName)) {
if (replace_clipFade (aafi, audioTrack, audioItem) > 0) {
audioItem = audioTrack->timelineItems;
continue;
}
} else if ((aafi->ctx.options.protools & AAFI_PROTOOLS_OPT_REMOVE_SAMPLE_ACCURATE_EDIT) &&
is_sample_accurate_edit (clipName)) {
if (remove_sampleAccurateEditClip (aafi, audioTrack, audioItem)) {
audioItem = audioTrack->timelineItems;
continue;
}
}
audioItem = audioItem->next;
audioItem = audioItemNext;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Adrien Gesta-Fline
* Copyright (C) 2023-2024 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
@ -18,7 +18,6 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@ -27,13 +26,13 @@
#include "aaf/RIFFParser.h"
#define debug(...) \
_dbg (dbg, NULL, DEBUG_SRC_ID_AAF_IFACE, VERB_DEBUG, __VA_ARGS__)
AAF_LOG (log, NULL, DEBUG_SRC_ID_AAF_IFACE, VERB_DEBUG, __VA_ARGS__)
#define warning(...) \
_dbg (dbg, NULL, DEBUG_SRC_ID_AAF_IFACE, VERB_WARNING, __VA_ARGS__)
AAF_LOG (log, NULL, DEBUG_SRC_ID_AAF_IFACE, VERB_WARNING, __VA_ARGS__)
#define error(...) \
_dbg (dbg, NULL, DEBUG_SRC_ID_AAF_IFACE, VERB_ERROR, __VA_ARGS__)
AAF_LOG (log, NULL, DEBUG_SRC_ID_AAF_IFACE, VERB_ERROR, __VA_ARGS__)
#define BE2LE32(val) \
(((val >> 24) & 0xff) | ((val << 8) & 0xff0000) | ((val >> 8) & 0xff00) | ((val << 24) & 0xff000000))
@ -45,10 +44,10 @@ static uint32_t
beExtended2leUint32 (const unsigned char numx[10]);
int
riff_writeWavFileHeader (FILE* fp, struct wavFmtChunk* wavFmt, struct wavBextChunk* wavBext, uint32_t audioDataSize, struct dbg* dbg)
laaf_riff_writeWavFileHeader (FILE* fp, struct wavFmtChunk* wavFmt, struct wavBextChunk* wavBext, uint32_t audioDataSize, struct aafLog* log)
{
(void)dbg;
uint32_t filesize = (4 /* WAVE */) + sizeof (struct wavFmtChunk) + ((wavBext) ? sizeof (struct wavBextChunk) : 0) + (8 /*data chunk header*/) + audioDataSize;
(void)log;
size_t filesize = (4 /* WAVE */) + sizeof (struct wavFmtChunk) + ((wavBext) ? sizeof (struct wavBextChunk) : 0) + (8 /*data chunk header*/) + audioDataSize;
size_t writtenBytes = fwrite ("RIFF", sizeof (unsigned char), 4, fp);
@ -75,7 +74,7 @@ riff_writeWavFileHeader (FILE* fp, struct wavFmtChunk* wavFmt, struct wavBextChu
wavFmt->cksz = sizeof (struct wavFmtChunk) - sizeof (struct riffChunk);
wavFmt->format_tag = 1; /* PCM */
wavFmt->avg_bytes_per_sec = wavFmt->samples_per_sec * wavFmt->channels * wavFmt->bits_per_sample / 8;
wavFmt->block_align = wavFmt->channels * wavFmt->bits_per_sample / 8;
wavFmt->block_align = wavFmt->channels * (wavFmt->bits_per_sample >> 3);
writtenBytes = fwrite ((unsigned char*)wavFmt, sizeof (unsigned char), sizeof (struct wavFmtChunk), fp);
@ -114,7 +113,7 @@ riff_writeWavFileHeader (FILE* fp, struct wavFmtChunk* wavFmt, struct wavBextChu
}
int
riff_parseAudioFile (struct RIFFAudioFile* RIFFAudioFile, enum RIFF_PARSER_FLAGS flags, size_t (*readerCallback) (unsigned char*, size_t, size_t, void*, void*, void*), void* user1, void* user2, void* user3, struct dbg* dbg)
laaf_riff_parseAudioFile (struct RIFFAudioFile* RIFFAudioFile, enum RIFF_PARSER_FLAGS flags, size_t (*readerCallback) (unsigned char*, size_t, size_t, void*, void*, void*), void* user1, void* user2, void* user3, struct aafLog* log)
{
struct riffChunk chunk;
struct riffHeaderChunk riff;
@ -123,7 +122,8 @@ riff_parseAudioFile (struct RIFFAudioFile* RIFFAudioFile, enum RIFF_PARSER_FLAGS
size_t bytesRead = readerCallback ((unsigned char*)&riff, 0, sizeof (riff), user1, user2, user3);
if (bytesRead < sizeof (riff)) {
if (bytesRead == RIFF_READER_ERROR ||
bytesRead < sizeof (riff)) {
error ("Could not read file header");
return -1;
}
@ -153,12 +153,14 @@ riff_parseAudioFile (struct RIFFAudioFile* RIFFAudioFile, enum RIFF_PARSER_FLAGS
}
size_t filesize = riff.cksz + sizeof (chunk);
size_t pos_sz = 0;
size_t pos = sizeof (struct riffHeaderChunk);
while (pos < filesize) {
bytesRead = readerCallback ((unsigned char*)&chunk, pos, sizeof (chunk), user1, user2, user3);
if (bytesRead < sizeof (chunk)) {
if (bytesRead == RIFF_READER_ERROR ||
bytesRead < sizeof (chunk)) {
error ("Could not read chunk \"%.4s\" @ %" PRIu64 " (%" PRIu64 " bytes returned)", chunk.ckid, pos, bytesRead);
break;
}
@ -179,7 +181,8 @@ riff_parseAudioFile (struct RIFFAudioFile* RIFFAudioFile, enum RIFF_PARSER_FLAGS
bytesRead = readerCallback ((unsigned char*)&wavFmtChunk, pos, sizeof (wavFmtChunk), user1, user2, user3);
if (bytesRead < sizeof (wavFmtChunk)) {
if (bytesRead == RIFF_READER_ERROR ||
bytesRead < sizeof (riff)) {
error ("Could not read chunk \"%.4s\" content @ %" PRIu64 " (%" PRIu64 " bytes returned)", chunk.ckid, pos, bytesRead);
break;
}
@ -199,6 +202,8 @@ riff_parseAudioFile (struct RIFFAudioFile* RIFFAudioFile, enum RIFF_PARSER_FLAGS
RIFFAudioFile->sampleCount = chunk.cksz / RIFFAudioFile->channels / (RIFFAudioFile->sampleSize / 8);
}
RIFFAudioFile->pcm_audio_start_offset = (pos + sizeof (struct riffChunk));
if (flags & RIFF_PARSE_AAF_SUMMARY) {
return 0;
}
@ -213,7 +218,8 @@ riff_parseAudioFile (struct RIFFAudioFile* RIFFAudioFile, enum RIFF_PARSER_FLAGS
bytesRead = readerCallback ((unsigned char*)&aiffCOMMChunk, pos, sizeof (aiffCOMMChunk), user1, user2, user3);
if (bytesRead < sizeof (aiffCOMMChunk)) {
if (bytesRead == RIFF_READER_ERROR ||
bytesRead < sizeof (riff)) {
error ("Could not read chunk \"%.4s\" content @ %" PRIu64 " (%" PRIu64 " bytes returned)", chunk.ckid, pos, bytesRead);
break;
}
@ -241,7 +247,8 @@ riff_parseAudioFile (struct RIFFAudioFile* RIFFAudioFile, enum RIFF_PARSER_FLAGS
debug ("Sample count retrieved from COMM chunk (%" PRIu64 ") does not match SSND chunk (%" PRIu64 ")", RIFFAudioFile->sampleCount, sampleCount);
}
RIFFAudioFile->sampleCount = sampleCount;
RIFFAudioFile->sampleCount = sampleCount;
RIFFAudioFile->pcm_audio_start_offset = pos + sizeof (struct aiffSSNDChunk);
if (flags & RIFF_PARSE_AAF_SUMMARY) {
return 0;
@ -249,7 +256,14 @@ riff_parseAudioFile (struct RIFFAudioFile* RIFFAudioFile, enum RIFF_PARSER_FLAGS
}
}
pos += chunk.cksz + sizeof (chunk);
pos_sz = chunk.cksz + sizeof (chunk);
if (pos_sz >= SIZE_MAX) {
error ("Parser position is bigger than RIFF_SIZE limits");
break;
}
pos += pos_sz;
}
return 0;
@ -293,7 +307,7 @@ beExtended2leUint32 (const unsigned char numx[10])
} else {
/* Otherwise it's denormal. It cannot be represented as double. Translate as singed zero. */
memcpy (&result, d, 8);
return result;
return (uint32_t)result;
}
} else {
/* Normal number. */
@ -301,7 +315,7 @@ beExtended2leUint32 (const unsigned char numx[10])
if (exponent <= -52) { /*< Too small to represent. Translate as (signed) zero. */
memcpy (&result, d, 8);
return result;
return (uint32_t)result;
} else if (exponent < 0) {
/* Denormal, exponent bits are already zero here. */
} else if (exponent >= 0x7FF) { /*< Too large to represent. Translate as infinite. */
@ -309,11 +323,11 @@ beExtended2leUint32 (const unsigned char numx[10])
d[6] = 0xF0;
memset (d, 0x00, 6);
memcpy (&result, d, 8);
return result;
return (uint32_t)result;
} else {
/* Representable number */
d[7] |= (exponent & 0x7F0) >> 4;
d[6] |= (exponent & 0xF) << 4;
d[6] |= (unsigned char)((exponent & 0xF) << 4);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Adrien Gesta-Fline
* Copyright (C) 2023-2024 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
@ -26,28 +26,28 @@
#include "aaf/AAFIParser.h"
#include "aaf/AAFToText.h"
#include "aaf/debug.h"
#include "aaf/libaaf.h"
#include "aaf/log.h"
#define debug(...) \
_dbg (aafi->dbg, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_DEBUG, __VA_ARGS__)
AAF_LOG (aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_DEBUG, __VA_ARGS__)
#define warning(...) \
_dbg (aafi->dbg, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_WARNING, __VA_ARGS__)
AAF_LOG (aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_WARNING, __VA_ARGS__)
#define error(...) \
_dbg (aafi->dbg, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_ERROR, __VA_ARGS__)
AAF_LOG (aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_ERROR, __VA_ARGS__)
int
resolve_AAF (struct AAF_Iface* aafi)
{
int probe = 0;
if (aafi->aafd->Identification.CompanyName && wcsncmp (aafi->aafd->Identification.CompanyName, L"Blackmagic Design", wcslen (L"Blackmagic Design")) == 0) {
if (aafi->aafd->Identification.CompanyName && strncmp (aafi->aafd->Identification.CompanyName, "Blackmagic Design", strlen ("Blackmagic Design")) == 0) {
probe++;
}
if (aafi->aafd->Identification.ProductName && wcsncmp (aafi->aafd->Identification.ProductName, L"DaVinci Resolve", wcslen (L"DaVinci Resolve")) == 0) {
if (aafi->aafd->Identification.ProductName && strncmp (aafi->aafd->Identification.ProductName, "DaVinci Resolve", strlen ("DaVinci Resolve")) == 0) {
probe++;
}
@ -57,166 +57,3 @@ resolve_AAF (struct AAF_Iface* aafi)
return 0;
}
int
resolve_parse_aafObject_Selector (struct AAF_Iface* aafi, aafObject* Selector, td* __ptd)
{
/*
* Resolve 18.5
*
* The Selector Object was only seen used to describe a disabled clip :
* - Selected property Object is an empty Filler
* - Alternate keeps track of the original clip.
*
03411 AAFClassID_Selector
01926 Selected --> AAFClassID_Filler
02359 Alternate -> AAFClassID_OperationGroup (OpIdent: AAFOperationDef_MonoAudioGain)
03822 AAFClassID_VaryingValue
02877 AAFClassID_SourceClip
02882 AAFClassID_MasterMob (UsageCode: n/a) : speech-sample.mp3 - disabled
04460 AAFClassID_TimelineMobSlot
03089 AAFClassID_SourceClip
04167 AAFClassID_SourceMob (UsageCode: n/a) : speech-sample.mp3 - disabled
01249 AAFClassID_PCMDescriptor
01455 AAFClassID_NetworkLocator : file:///C:/Users/user/Desktop/libAAF/test/res/speech-sample.mp3
*/
struct trace_dump __td;
__td_set (__td, __ptd, 0);
aafObject* Selected = aaf_get_propertyValue (Selector, PID_Selector_Selected, &AAFTypeID_SegmentStrongReference);
if (Selected == NULL) { /* req */
DUMP_OBJ_ERROR (aafi, Selector, &__td, "Missing PID_Selector_Selected");
return -1;
}
aafObject* Alternates = aaf_get_propertyValue (Selector, PID_Selector_Alternates, &AAFTypeID_SegmentStrongReferenceVector);
if (Alternates == NULL) { /* opt */
DUMP_OBJ_WARNING (aafi, Selector, &__td, "Missing PID_Selector_Alternates");
return -1;
}
void* ComponentAttributeList = aaf_get_propertyValue (Selector, aaf_get_PropertyIDByName (aafi->aafd, L"ComponentAttributeList"), &AAFUID_NULL);
if (ComponentAttributeList == NULL) {
DUMP_OBJ_ERROR (aafi, Selector, &__td, "Missing AAFClassID_Selector::ComponentAttributeList");
return -1;
}
DUMP_OBJ (aafi, Selector, &__td);
// aaf_dump_ObjectProperties( aafi->aafd, Selector );
// aaf_dump_ObjectProperties( aafi->aafd, ComponentAttributeList );
int ismuted = 0;
aafObject* ComponentAttribute = NULL;
aaf_foreach_ObjectInSet (&ComponentAttribute, ComponentAttributeList, NULL)
{
/* TODO implement retrieve_TaggedValue() */
wchar_t* name = aaf_get_propertyValue (ComponentAttribute, PID_TaggedValue_Name, &AAFTypeID_String);
if (name == NULL) { /* req */
DUMP_OBJ_ERROR (aafi, ComponentAttribute, &__td, "Missing PID_TaggedValue_Name");
continue;
}
aafIndirect_t* Indirect = aaf_get_propertyValue (ComponentAttribute, PID_TaggedValue_Value, &AAFTypeID_Indirect);
if (Indirect == NULL) {
DUMP_OBJ_ERROR (aafi, ComponentAttribute, &__td, "Missing PID_TaggedValue_Value");
free (name);
continue;
}
int32_t* value = aaf_get_indirectValue (aafi->aafd, Indirect, &AAFTypeID_Int32);
if (value == NULL) {
DUMP_OBJ_ERROR (aafi, ComponentAttribute, &__td, "Could not retrieve Indirect value for PID_TaggedValue_Value");
free (name);
continue;
}
// debug( "Tagged | Name: %ls Value : %u", name, *value );
if (aafi->ctx.options.resolve & RESOLVE_INCLUDE_DISABLED_CLIPS) {
if (wcsncmp (name, L"_DISABLE_CLIP_FLAG", wcslen (L"_DISABLE_CLIP_FLAG")) == 0 && *value == 1) {
ismuted = 1;
aafi->ctx.current_clip_is_muted = 1;
aafObject* Alternate = NULL;
int i = 0;
aaf_foreach_ObjectInSet (&Alternate, Alternates, NULL)
{
if (i == 0) { /* there should be only one Segment in set, but still. Let's be carefull */
aafi_parse_Segment (aafi, Alternate, &__td);
} else {
DUMP_OBJ_ERROR (aafi, Alternate, &__td, "Multiple Alternates in Davinci Resolve selector");
}
i++;
}
}
}
free (name);
}
/* aafi->ctx.current_clip_is_muted was already reset at this point */
if (ismuted == 0) {
return aafi_parse_Segment (aafi, Selected, &__td);
}
return 0;
}
int
resolve_parse_aafObject_DescriptiveMarker (struct AAF_Iface* aafi, aafObject* DescriptiveMarker, td* __ptd)
{
/*
* Resolve 18.5
*/
struct trace_dump __td;
__td_set (__td, __ptd, 1);
aafPosition_t* start = aaf_get_propertyValue (DescriptiveMarker, PID_Event_Position, &AAFTypeID_PositionType);
if (start == NULL) { /* req (TODO: conditional) */
DUMP_OBJ_ERROR (aafi, DescriptiveMarker, &__td, "Missing PID_Event_Position");
return -1;
}
aafPosition_t* length = aaf_get_propertyValue (DescriptiveMarker, PID_Component_Length, &AAFTypeID_PositionType);
wchar_t* comment = aaf_get_propertyValue (DescriptiveMarker, PID_Event_Comment, &AAFTypeID_String);
wchar_t* name = aaf_get_propertyValue (DescriptiveMarker, aaf_get_PropertyIDByName (aafi->aafd, L"CommentMarkerUser"), &AAFTypeID_String);
uint16_t* RGBColor = NULL;
aafProperty* RGBColorProp = aaf_get_property (DescriptiveMarker, aaf_get_PropertyIDByName (aafi->aafd, L"CommentMarkerColor"));
if (RGBColorProp) {
if (RGBColorProp->len != sizeof (uint16_t) * 3) {
error ("CommentMarkerColor has wrong size of %u", RGBColorProp->len);
} else {
RGBColor = RGBColorProp->val;
/* big endian to little endian */
RGBColor[0] = (RGBColor[0] >> 8) | (RGBColor[0] << 8);
RGBColor[1] = (RGBColor[1] >> 8) | (RGBColor[1] << 8);
RGBColor[2] = (RGBColor[2] >> 8) | (RGBColor[2] << 8);
}
}
aafi_newMarker (aafi, aafi->ctx.current_markers_edit_rate, *start, ((length) ? *length : 0), name, comment, &RGBColor);
DUMP_OBJ (aafi, DescriptiveMarker, &__td);
return 0;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Adrien Gesta-Fline
* Copyright (C) 2023-2024 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
@ -18,6 +18,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <assert.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdint.h>
@ -31,15 +32,16 @@ typedef SSIZE_T ssize_t;
#endif
#include "aaf/URIParser.h"
#include "aaf/utils.h"
#define debug(...) \
_dbg (dbg, NULL, DEBUG_SRC_ID_AAF_IFACE, VERB_DEBUG, __VA_ARGS__)
AAF_LOG (log, NULL, DEBUG_SRC_ID_AAF_IFACE, VERB_DEBUG, __VA_ARGS__)
#define warning(...) \
_dbg (dbg, NULL, DEBUG_SRC_ID_AAF_IFACE, VERB_WARNING, __VA_ARGS__)
AAF_LOG (log, NULL, DEBUG_SRC_ID_AAF_IFACE, VERB_WARNING, __VA_ARGS__)
#define error(...) \
_dbg (dbg, NULL, DEBUG_SRC_ID_AAF_IFACE, VERB_ERROR, __VA_ARGS__)
AAF_LOG (log, NULL, DEBUG_SRC_ID_AAF_IFACE, VERB_ERROR, __VA_ARGS__)
#define IS_LOWALPHA(c) \
((c >= 'a') && (c <= 'z'))
@ -89,52 +91,45 @@ typedef SSIZE_T ssize_t;
(uri->scheme_t != URI_SCHEME_T_FILE && \
!(uri->opts & URI_OPT_IGNORE_FRAGMENT))
#define URI_SET_STR(str, start, end) \
\
str = malloc (sizeof (char) * ((end - start) + 1)); \
\
if (NULL == str) { \
error ("URI allocation failed"); \
goto err; \
} \
\
snprintf (str, (end - start) + 1, "%s", start);
#define URI_SET_STR(str, start, end) \
\
str = malloc (sizeof (char) * (uint32_t) ((end - start) + 1)); \
\
if (!str) { \
error ("Out of memory"); \
goto err; \
} \
\
snprintf (str, (uint32_t) (end - start) + 1, "%s", start);
static char*
uriDecodeString (char* src, char* dst);
static int
uriIsIPv4 (const char* s, size_t size, char** err);
static int
uriIsIPv6 (const char* s, size_t size, char** err);
static int
_uri_parse_scheme (struct uri* uri, const char** pos, const char* end, struct dbg* dbg);
_uri_parse_scheme (struct uri* uri, const char** pos, const char* end, struct aafLog* log);
static int
_uri_parse_authority (struct uri* uri, const char** pos, const char* end, struct dbg* dbg);
_uri_parse_authority (struct uri* uri, const char** pos, const char* end, struct aafLog* log);
static int
_uri_parse_userinfo (struct uri* uri, const char** pos, const char* end, struct dbg* dbg);
_uri_parse_userinfo (struct uri* uri, const char** pos, const char* end, struct aafLog* log);
static int
_uri_parse_hostname (struct uri* uri, const char** pos, const char* end, struct dbg* dbg);
_uri_parse_hostname (struct uri* uri, const char** pos, const char* end, struct aafLog* log);
static int
_uri_parse_path (struct uri* uri, const char** pos, const char* end, struct dbg* dbg);
_uri_parse_path (struct uri* uri, const char** pos, const char* end, struct aafLog* log);
static int
_uri_parse_query (struct uri* uri, const char** pos, const char* end, struct dbg* dbg);
_uri_parse_query (struct uri* uri, const char** pos, const char* end, struct aafLog* log);
static int
_uri_parse_fragment (struct uri* uri, const char** pos, const char* end, struct dbg* dbg);
_uri_parse_fragment (struct uri* uri, const char** pos, const char* end, struct aafLog* log);
static void
_uri_scheme2schemeType (struct uri* uri);
static int
_laaf_util_snprintf_realloc (char** str, size_t* size, size_t offset, const char* format, ...);
#ifdef BUILD_URI_TEST // gcc -g -W -Wall ./URIParser.c -D BUILD_URI_TEST
static int
_uri_cmp (const struct uri* a, const struct uri* b);
static void
_uri_dump_diff (struct uri* a, struct uri* b, int totalDifferencies);
static int
_uri_test (const char* uristr, enum uri_option optflags, struct uri expectedRes, int line);
#endif // BUILD_URI_TEST
char*
static char*
uriDecodeString (char* src, char* dst)
{
int inpos = 0;
int outpos = 0;
if (src == NULL) {
return NULL;
}
@ -143,47 +138,39 @@ uriDecodeString (char* src, char* dst)
dst = src;
}
while (src[inpos]) {
if (src[inpos] == '%' && IS_HEX (src[inpos + 1]) && IS_HEX (src[inpos + 2])) {
int c = 0;
char* end = src + strlen (src);
char hex1 = src[inpos + 1];
while (*src) {
if (*src == '%' && src + 2 < end && IS_HEX (*(src + 1)) && IS_HEX (*(src + 2))) {
char d1 = *(src + 1);
char d2 = *(src + 2);
if ((hex1 >= '0') && (hex1 <= '9'))
c = (hex1 - '0');
else if ((hex1 >= 'a') && (hex1 <= 'f'))
c = (hex1 - 'a') + 10;
else if ((hex1 >= 'A') && (hex1 <= 'F'))
c = (hex1 - 'A') + 10;
int digit = 0;
char hex2 = src[inpos + 2];
digit = (d1 >= 'A' ? ((d1 & 0xdf) - 'A') + 10 : (d1 - '0'));
digit <<= 4;
digit += (d2 >= 'A' ? ((d2 & 0xdf) - 'A') + 10 : (d2 - '0'));
if ((hex2 >= '0') && (hex2 <= '9'))
c = c * 16 + (hex2 - '0');
else if ((hex2 >= 'a') && (hex2 <= 'f'))
c = c * 16 + (hex2 - 'a') + 10;
else if ((hex2 >= 'A') && (hex2 <= 'F'))
c = c * 16 + (hex2 - 'A') + 10;
assert (digit > CHAR_MIN && digit < UCHAR_MAX);
dst[outpos] = (char)c;
inpos += 3;
*dst = (char)digit;
src += 3;
dst++;
} else {
dst[outpos] = src[inpos];
inpos++;
*dst = *src;
src++;
dst++;
}
outpos++;
}
if (inpos > outpos) {
dst[outpos] = 0x00;
}
*dst = 0x00;
return dst;
}
static int
_uri_parse_scheme (struct uri* uri, const char** pos, const char* end, struct dbg* dbg)
_uri_parse_scheme (struct uri* uri, const char** pos, const char* end, struct aafLog* log)
{
const char* p = *pos;
@ -216,7 +203,12 @@ _uri_parse_scheme (struct uri* uri, const char** pos, const char* end, struct db
char* pp = uri->scheme;
while (*pp) {
*pp = tolower (*pp);
int charint = tolower (*pp);
assert (charint > CHAR_MIN && charint < CHAR_MAX);
*pp = (char)charint;
pp++;
}
@ -231,7 +223,7 @@ err:
}
static int
_uri_parse_authority (struct uri* uri, const char** pos, const char* end, struct dbg* dbg)
_uri_parse_authority (struct uri* uri, const char** pos, const char* end, struct aafLog* log)
{
/*
* RFC 3986 - Uniform Resource Identifier (URI): Generic Syntax
@ -298,7 +290,7 @@ err:
}
static int
_uri_parse_userinfo (struct uri* uri, const char** pos, const char* end, struct dbg* dbg)
_uri_parse_userinfo (struct uri* uri, const char** pos, const char* end, struct aafLog* log)
{
int hasUserinfo = 0;
int userinfoIllegalCharacters = 0;
@ -373,7 +365,7 @@ err:
}
static int
_uri_parse_hostname (struct uri* uri, const char** pos, const char* end, struct dbg* dbg)
_uri_parse_hostname (struct uri* uri, const char** pos, const char* end, struct aafLog* log)
{
const char* p = *pos;
@ -422,7 +414,7 @@ _uri_parse_hostname (struct uri* uri, const char** pos, const char* end, struct
p++;
}
// debug( " >>> %.*s", (int)(p-*pos), p );
// debug( L" >>> %.*s", (int)(p-*pos), p );
URI_SET_STR (uri->host, *pos, p);
}
@ -430,7 +422,7 @@ _uri_parse_hostname (struct uri* uri, const char** pos, const char* end, struct
// if ( !(uri->flags & URI_T_HOST_IPV6 || uri->flags & URI_T_HOST_EMPTY) ) {
if (!(uri->flags & URI_T_HOST_IPV6) && uri->host != NULL && *uri->host != 0x00) {
if (uriIsIPv4 (uri->host, strlen (uri->host), NULL)) {
uri->flags &= ~URI_T_HOST_MASK;
uri->flags &= ~(unsigned)URI_T_HOST_MASK;
uri->flags |= URI_T_HOST_IPV4;
if (strcmp (uri->host, "127.0.0.1") == 0) {
uri->flags |= URI_T_LOCALHOST;
@ -479,7 +471,7 @@ err:
}
static int
_uri_parse_path (struct uri* uri, const char** pos, const char* end, struct dbg* dbg)
_uri_parse_path (struct uri* uri, const char** pos, const char* end, struct aafLog* log)
{
int winDrive = 0;
@ -507,7 +499,7 @@ _uri_parse_path (struct uri* uri, const char** pos, const char* end, struct dbg*
p++;
}
// debug( " >>> (%i) %.*s", (int)(p-*pos), (int)(p-*pos), p );
// debug( L" >>> (%i) %.*s", (int)(p-*pos), (int)(p-*pos), p );
URI_SET_STR (uri->path, *pos, p);
@ -534,7 +526,7 @@ err:
}
static int
_uri_parse_query (struct uri* uri, const char** pos, const char* end, struct dbg* dbg)
_uri_parse_query (struct uri* uri, const char** pos, const char* end, struct aafLog* log)
{
const char* p = *pos;
@ -561,7 +553,7 @@ err:
}
static int
_uri_parse_fragment (struct uri* uri, const char** pos, const char* end, struct dbg* dbg)
_uri_parse_fragment (struct uri* uri, const char** pos, const char* end, struct aafLog* log)
{
/*
* https://datatracker.ietf.org/doc/html/draft-yevstifeyev-ftp-uri-scheme#section-3.2.4.2
@ -602,7 +594,7 @@ err:
}
struct uri*
uriParse (const char* uristr, enum uri_option optflags, struct dbg* dbg)
laaf_uri_parse (const char* uristr, enum uri_option optflags, struct aafLog* log)
{
if (uristr == NULL) {
return NULL;
@ -610,7 +602,8 @@ uriParse (const char* uristr, enum uri_option optflags, struct dbg* dbg)
struct uri* uri = calloc (1, sizeof (struct uri));
if (uri == NULL) {
if (!uri) {
error ("Out of memory");
return NULL;
}
@ -626,27 +619,27 @@ uriParse (const char* uristr, enum uri_option optflags, struct dbg* dbg)
const char* pos = uristr;
const char* end = pos + urilen;
_uri_parse_scheme (uri, &pos, end, dbg);
_uri_parse_scheme (uri, &pos, end, log);
if (_uri_parse_authority (uri, &pos, end, dbg)) {
_uri_parse_userinfo (uri, &pos, end, dbg);
_uri_parse_hostname (uri, &pos, end, dbg);
if (_uri_parse_authority (uri, &pos, end, log)) {
_uri_parse_userinfo (uri, &pos, end, log);
_uri_parse_hostname (uri, &pos, end, log);
}
_uri_parse_path (uri, &pos, end, dbg);
_uri_parse_path (uri, &pos, end, log);
if (SCHEME_ALLOW_QUERY (uri)) {
_uri_parse_query (uri, &pos, end, dbg);
_uri_parse_query (uri, &pos, end, log);
}
if (SCHEME_ALLOW_FRAGMENT (uri)) {
_uri_parse_fragment (uri, &pos, end, dbg);
_uri_parse_fragment (uri, &pos, end, log);
}
goto end;
err:
uriFree (uri);
laaf_uri_free (uri);
uri = NULL;
end:
@ -655,51 +648,34 @@ end:
}
void
uriFree (struct uri* uri)
laaf_uri_free (struct uri* uri)
{
if (uri == NULL) {
if (!uri) {
return;
}
if (NULL != uri->scheme) {
free (uri->scheme);
}
if (NULL != uri->userinfo) {
free (uri->userinfo);
}
if (NULL != uri->authority) {
free (uri->authority);
}
if (NULL != uri->user) {
free (uri->user);
}
if (NULL != uri->pass) {
free (uri->pass);
}
if (NULL != uri->host) {
free (uri->host);
}
if (NULL != uri->path) {
free (uri->path);
}
if (NULL != uri->query) {
free (uri->query);
}
if (NULL != uri->fragment) {
free (uri->fragment);
}
free (uri->scheme);
free (uri->userinfo);
free (uri->authority);
free (uri->user);
free (uri->pass);
free (uri->host);
free (uri->path);
free (uri->query);
free (uri->fragment);
free (uri);
}
int
uriIsIPv4 (const char* s, int size, char** err)
static int
uriIsIPv4 (const char* s, size_t size, char** err)
{
int octets = 0;
const char* currentOctetStart = s;
char prev = 0;
for (int i = 0; i <= size; i++) {
for (size_t i = 0; i <= size; i++) {
if (prev == 0) {
if (IS_DIGIT (*(s + i))) {
currentOctetStart = (s + i);
@ -709,7 +685,7 @@ uriIsIPv4 (const char* s, int size, char** err)
if (*(s + i) == '.') {
if (err) {
_laaf_util_snprintf_realloc (err, NULL, 0, "IPV4 parser error : can't start with a single '.'");
laaf_util_snprintf_realloc (err, NULL, 0, "IPV4 parser error : can't start with a single '.'");
}
return 0;
}
@ -724,7 +700,7 @@ uriIsIPv4 (const char* s, int size, char** err)
if (*(s + i) == '.') {
if (err) {
_laaf_util_snprintf_realloc (err, NULL, 0, "IPV4 parser error : can't have successive '.'");
laaf_util_snprintf_realloc (err, NULL, 0, "IPV4 parser error : can't have successive '.'");
}
return 0;
}
@ -740,14 +716,14 @@ uriIsIPv4 (const char* s, int size, char** err)
int octet = atoi (currentOctetStart);
if (octet > 255) {
if (err) {
_laaf_util_snprintf_realloc (err, NULL, 0, "IPV4 parser error : octet %i is too high : %.*s", (octets), (int)((s + i) - currentOctetStart), currentOctetStart);
laaf_util_snprintf_realloc (err, NULL, 0, "IPV4 parser error : octet %i is too high : %.*s", (octets), (int)((s + i) - currentOctetStart), currentOctetStart);
}
return 0;
}
if (i + 1 == size) {
if (err) {
_laaf_util_snprintf_realloc (err, NULL, 0, "IPV4 parser error : can't end with a single '.'");
laaf_util_snprintf_realloc (err, NULL, 0, "IPV4 parser error : can't end with a single '.'");
}
return 0;
}
@ -763,20 +739,20 @@ uriIsIPv4 (const char* s, int size, char** err)
}
if (err) {
_laaf_util_snprintf_realloc (err, NULL, 0, "IPV4 parser error : illegal char '%c' (0x%02x)", *(s + i), *(s + i));
laaf_util_snprintf_realloc (err, NULL, 0, "IPV4 parser error : illegal char '%c' (0x%02x)", *(s + i), *(s + i));
}
return 0;
}
if (octets > 4) {
if (err) {
_laaf_util_snprintf_realloc (err, NULL, 0, "IPV4 parser error : too many octets");
laaf_util_snprintf_realloc (err, NULL, 0, "IPV4 parser error : too many octets");
}
return 0;
}
if (octets < 4) {
if (err) {
_laaf_util_snprintf_realloc (err, NULL, 0, "IPV4 parser error : not enough octets");
laaf_util_snprintf_realloc (err, NULL, 0, "IPV4 parser error : not enough octets");
}
return 0;
}
@ -784,8 +760,8 @@ uriIsIPv4 (const char* s, int size, char** err)
return 1;
}
int
uriIsIPv6 (const char* s, int size, char** err)
static int
uriIsIPv6 (const char* s, size_t size, char** err)
{
int segmentCount = 0;
int emptySegmentCount = 0;
@ -798,7 +774,7 @@ uriIsIPv6 (const char* s, int size, char** err)
char prev = 0;
for (int i = 0; i <= size; i++) {
for (size_t i = 0; i <= size; i++) {
if (prev == 0) {
if (IS_HEX (*(s + i))) {
segmentCount++;
@ -826,7 +802,7 @@ uriIsIPv6 (const char* s, int size, char** err)
if (*(s + i) == ':') {
if (err) {
_laaf_util_snprintf_realloc (err, NULL, 0, "can't start with a single ':'");
laaf_util_snprintf_realloc (err, NULL, 0, "can't start with a single ':'");
}
return 0;
}
@ -852,11 +828,11 @@ uriIsIPv6 (const char* s, int size, char** err)
int octet = atoi (curSegmentStart);
if (octet > 255) {
if (err) {
_laaf_util_snprintf_realloc (err, NULL, 0, "ipv4 portion octet %i is too high : %.*s", (ipv4portion), curSegmentLength, curSegmentStart);
laaf_util_snprintf_realloc (err, NULL, 0, "ipv4 portion octet %i is too high : %.*s", (ipv4portion), curSegmentLength, curSegmentStart);
}
return 0;
}
// debug( "%i", octet );
// debug( L"%i", octet );
prev = 'p';
ipv4portion++;
continue;
@ -865,7 +841,7 @@ uriIsIPv6 (const char* s, int size, char** err)
if (i == size || *(s + i) == ':') {
if (curSegmentLength > 4) {
if (err) {
_laaf_util_snprintf_realloc (err, NULL, 0, "segment %i is too long : %.*s", (segmentCount - 1), curSegmentLength, curSegmentStart);
laaf_util_snprintf_realloc (err, NULL, 0, "segment %i is too long : %.*s", (segmentCount - 1), curSegmentLength, curSegmentStart);
}
return 0;
}
@ -879,7 +855,7 @@ uriIsIPv6 (const char* s, int size, char** err)
i++;
} else if (i + 1 == size) {
if (err) {
_laaf_util_snprintf_realloc (err, NULL, 0, "can't end with a single ':'");
laaf_util_snprintf_realloc (err, NULL, 0, "can't end with a single ':'");
}
return 0;
} else {
@ -910,7 +886,7 @@ uriIsIPv6 (const char* s, int size, char** err)
if (*(s + i) == ':') {
if (err) {
_laaf_util_snprintf_realloc (err, NULL, 0, "can't have more than two successive ':'");
laaf_util_snprintf_realloc (err, NULL, 0, "can't have more than two successive ':'");
}
return 0;
}
@ -925,14 +901,14 @@ uriIsIPv6 (const char* s, int size, char** err)
if (*(s + i) == '.') {
if (err) {
_laaf_util_snprintf_realloc (err, NULL, 0, "can't have successive '.'");
laaf_util_snprintf_realloc (err, NULL, 0, "can't have successive '.'");
}
return 0;
}
}
if (prev == 'd') {
if (IS_DIGIT (*(s + i))) {
if (IS_DIGIT (*(s + i)) && *(s + i + 1) != '\0' && i + 1 != size) {
prev = 'd';
continue;
}
@ -941,16 +917,16 @@ uriIsIPv6 (const char* s, int size, char** err)
int octet = atoi (curSegmentStart);
if (octet > 255) {
if (err) {
_laaf_util_snprintf_realloc (err, NULL, 0, "ipv4 portion octet %i is too high : %.*s", (ipv4portion), curSegmentLength, curSegmentStart);
laaf_util_snprintf_realloc (err, NULL, 0, "ipv4 portion octet %i is too high : %.*s", (ipv4portion), curSegmentLength, curSegmentStart);
}
return 0;
}
// debug( "%i", octet );
// debug( L"%i", octet );
if (i + 1 == size) {
if (err) {
_laaf_util_snprintf_realloc (err, NULL, 0, "can't end with a single '.'");
laaf_util_snprintf_realloc (err, NULL, 0, "can't end with a single '.'");
}
return 0;
}
@ -966,43 +942,43 @@ uriIsIPv6 (const char* s, int size, char** err)
}
if (err) {
_laaf_util_snprintf_realloc (err, NULL, 0, "illegal char '%c' (0x%02x)", *(s + i), *(s + i));
laaf_util_snprintf_realloc (err, NULL, 0, "illegal char '%c' (0x%02x)", *(s + i), *(s + i));
}
return 0;
}
// debug( "segments : %i", segmentCount );
// debug( "empty segments : %i", emptySegmentCount );
// debug( "ipv4portion : %i", ipv4portion );
// debug( L"segments : %i", segmentCount );
// debug( L"empty segments : %i", emptySegmentCount );
// debug( L"ipv4portion : %i", ipv4portion );
if (ipv4portion > 4) {
if (err) {
_laaf_util_snprintf_realloc (err, NULL, 0, "too many octets in ipv4 portion");
laaf_util_snprintf_realloc (err, NULL, 0, "too many octets in ipv4 portion : %i", ipv4portion);
}
return 0;
}
if (ipv4portion > 0 && ipv4portion < 4) {
if (err) {
_laaf_util_snprintf_realloc (err, NULL, 0, "not enough octets in ipv4 portion");
laaf_util_snprintf_realloc (err, NULL, 0, "not enough octets in ipv4 portion : %i", ipv4portion);
}
return 0;
}
if (emptySegmentCount + (segmentCount / 2) + ipv4portion > 8) {
if (err) {
_laaf_util_snprintf_realloc (err, NULL, 0, "too many segments");
laaf_util_snprintf_realloc (err, NULL, 0, "too many segments");
}
return 0;
}
if (emptySegmentCount == 0 && (((ipv4portion / 2) + segmentCount) < 8)) {
if (err) {
_laaf_util_snprintf_realloc (err, NULL, 0, "not enough segments");
laaf_util_snprintf_realloc (err, NULL, 0, "not enough segments");
}
return 0;
}
// debug( "LOCALHOST >>>>>>> %i", loopback );
// debug( L"LOCALHOST >>>>>>> %i", loopback );
/*
* 1: valid ipv6 address
@ -1059,261 +1035,3 @@ _uri_scheme2schemeType (struct uri* uri)
uri->scheme_t = URI_SCHEME_T_UNKNOWN;
}
}
static int
_laaf_util_snprintf_realloc (char** str, size_t* size, size_t offset, const char* format, ...)
{
size_t tmpsize = 0;
if (!size) {
size = &tmpsize;
}
int retval, needed;
va_list ap;
va_start (ap, format);
while (0 <= (retval = vsnprintf ((*str) + offset, (*size) - offset, format, ap)) && (int64_t) ((*size) - offset) < (needed = retval + 1)) {
va_end (ap);
*size *= 2;
if ((int64_t) ((*size) - offset) < needed)
*size = needed;
char* p = realloc (*str, *size);
if (p) {
*str = p;
} else {
free (*str);
*str = NULL;
*size = 0;
return -1;
}
va_start (ap, format);
}
va_end (ap);
return retval;
}
#ifdef BUILD_URI_TEST
static int
_uri_cmp (const struct uri* a, const struct uri* b)
{
int differenciesCount = 0;
if (a == NULL || b == NULL) {
return -1;
}
// if ( (strcmp((a->scheme) ? a->scheme : "", (b->scheme) ? b->scheme : "") != 0 ) ) {
// differenciesCount++;
// }
if ((strcmp ((a->userinfo) ? a->userinfo : "", (b->userinfo) ? b->userinfo : "") != 0)) {
differenciesCount++;
}
if ((strcmp ((a->user) ? a->user : "", (b->user) ? b->user : "") != 0)) {
differenciesCount++;
}
if ((strcmp ((a->pass) ? a->pass : "", (b->pass) ? b->pass : "") != 0)) {
differenciesCount++;
}
if ((strcmp ((a->host) ? a->host : "", (b->host) ? b->host : "") != 0)) {
differenciesCount++;
}
if ((strcmp ((a->path) ? a->path : "", (b->path) ? b->path : "") != 0)) {
differenciesCount++;
}
if ((strcmp ((a->query) ? a->query : "", (b->query) ? b->query : "") != 0)) {
differenciesCount++;
}
if ((strcmp ((a->fragment) ? a->fragment : "", (b->fragment) ? b->fragment : "") != 0)) {
differenciesCount++;
}
if (a->port != b->port) {
differenciesCount++;
}
if (a->scheme_t != b->scheme_t) {
differenciesCount++;
}
if (a->flags != b->flags) {
differenciesCount++;
}
return differenciesCount;
}
static void
_uri_dump_diff (struct uri* a, struct uri* b, int totalDifferencies)
{
int differenciesCount = 0;
if (a == NULL || b == NULL) {
return;
}
// if ( (strcmp((a->scheme) ? a->scheme : "", (b->scheme) ? b->scheme : "") != 0 ) ) {
// printf(" \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .scheme : \"%s\" (expected: \"%s\")\n", (++differenciesCount < totalDifferencies) ? "\u251c\u2500\u2500\u25fb" : "\u2514\u2500\u2500\u25fb", a->scheme, b->scheme );
// }
if ((strcmp ((a->userinfo) ? a->userinfo : "", (b->userinfo) ? b->userinfo : "") != 0)) {
printf (" \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .userinfo : \"%s\" (expected: \"%s\")\n", (++differenciesCount < totalDifferencies) ? "\u251c\u2500\u2500\u25fb" : "\u2514\u2500\u2500\u25fb", a->userinfo, b->userinfo);
}
if ((strcmp ((a->user) ? a->user : "", (b->user) ? b->user : "") != 0)) {
printf (" \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .user : \"%s\" (expected: \"%s\")\n", (++differenciesCount < totalDifferencies) ? "\u251c\u2500\u2500\u25fb" : "\u2514\u2500\u2500\u25fb", a->user, b->user);
}
if ((strcmp ((a->pass) ? a->pass : "", (b->pass) ? b->pass : "") != 0)) {
printf (" \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .pass : \"%s\" (expected: \"%s\")\n", (++differenciesCount < totalDifferencies) ? "\u251c\u2500\u2500\u25fb" : "\u2514\u2500\u2500\u25fb", a->pass, b->pass);
}
if ((strcmp ((a->host) ? a->host : "", (b->host) ? b->host : "") != 0)) {
printf (" \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .host : \"%s\" (expected: \"%s\")\n", (++differenciesCount < totalDifferencies) ? "\u251c\u2500\u2500\u25fb" : "\u2514\u2500\u2500\u25fb", a->host, b->host);
}
if ((strcmp ((a->path) ? a->path : "", (b->path) ? b->path : "") != 0)) {
printf (" \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .path : \"%s\" (expected: \"%s\")\n", (++differenciesCount < totalDifferencies) ? "\u251c\u2500\u2500\u25fb" : "\u2514\u2500\u2500\u25fb", a->path, b->path);
}
if ((strcmp ((a->query) ? a->query : "", (b->query) ? b->query : "") != 0)) {
printf (" \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .query : \"%s\" (expected: \"%s\")\n", (++differenciesCount < totalDifferencies) ? "\u251c\u2500\u2500\u25fb" : "\u2514\u2500\u2500\u25fb", a->query, b->query);
}
if ((strcmp ((a->fragment) ? a->fragment : "", (b->fragment) ? b->fragment : "") != 0)) {
printf (" \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .fragment : \"%s\" (expected: \"%s\")\n", (++differenciesCount < totalDifferencies) ? "\u251c\u2500\u2500\u25fb" : "\u2514\u2500\u2500\u25fb", a->fragment, b->fragment);
}
if (a->port != b->port) {
printf (" \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .port : %i (expected: %i)\n", (++differenciesCount < totalDifferencies) ? "\u251c\u2500\u2500\u25fb" : "\u2514\u2500\u2500\u25fb", a->port, b->port);
}
if (a->scheme_t != b->scheme_t) {
printf (" \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .scheme_t : %i (expected: %i)\n", (++differenciesCount < totalDifferencies) ? "\u251c\u2500\u2500\u25fb" : "\u2514\u2500\u2500\u25fb", a->scheme_t, b->scheme_t);
}
if (a->flags != b->flags) {
printf (" \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .flags : %i (expected: %i)\n", (++differenciesCount < totalDifferencies) ? "\u251c\u2500\u2500\u25fb" : "\u2514\u2500\u2500\u25fb", a->flags, b->flags);
}
}
static int
_uri_test (const char* uristr, enum uri_option optflags, struct uri expectedRes, int line)
{
struct uri* uri = uriParse (uristr, optflags);
int differenciesCount = 0;
if ((differenciesCount = _uri_cmp (uri, &expectedRes)) == 0) {
printf ("\x1b[38;5;242m"); // dark gray
printf ("%05i", line);
printf ("\x1b[0m");
printf ("\x1b[38;5;242m %s \x1b[0m", "\u2502");
printf ("\x1b[38;5;120m"); // green
printf ("[ok] ");
printf ("\x1b[0m");
printf ("\x1b[38;5;242m"); // dark gray
printf ("%s", uristr);
printf ("\x1b[0m");
printf ("\n");
} else {
printf ("\x1b[38;5;124m"); // red
printf ("%05i", line);
printf ("\x1b[0m");
printf ("\x1b[38;5;242m %s \x1b[0m", "\u2502");
printf ("\x1b[38;5;124m"); // red
printf ("[er] ");
printf ("\x1b[0m");
printf ("\x1b[38;5;242m"); // dark gray
printf ("%s", uristr);
printf ("\x1b[0m");
printf ("\n");
printf ("\x1b[38;5;124m"); // red
_uri_dump_diff (uri, &expectedRes, differenciesCount);
printf ("\x1b[0m");
printf (" \x1b[38;5;242m\u2502\x1b[0m\n");
}
uriFree (uri);
return differenciesCount;
}
int
main (void)
{
int rc = 0;
// rc += _uri_test( "", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_UNKNOWN, .host = NULL, .port = 0, .path = NULL, .query = NULL, .fragment = NULL }, __LINE__ );
rc += _uri_test ("https://www.server.com", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = NULL, .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__);
rc += _uri_test ("https://user:pass@www.server.com", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .userinfo = "user:pass", .user = "user", .pass = "pass", .host = "www.server.com", .port = 0, .path = NULL, .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__);
rc += _uri_test ("HTTPS://www.server.com", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = NULL, .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__);
rc += _uri_test ("hTtPs://www.server.com", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = NULL, .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__);
rc += _uri_test ("https://www.server.com:8080", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 8080, .path = NULL, .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__);
rc += _uri_test ("https://www.server.com:8080?foo=bar", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 8080, .path = NULL, .query = "foo=bar", .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__);
rc += _uri_test ("https://www.server.com:8080#anchor", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 8080, .path = NULL, .query = NULL, .fragment = "anchor", .flags = URI_T_HOST_REGNAME }, __LINE__);
rc += _uri_test ("https://www.server.com/", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = "/", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__);
rc += _uri_test ("https://www.server.com/?foo=bar", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = "/", .query = "foo=bar", .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__);
rc += _uri_test ("https://www.server.com/////?foo=bar", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = "/", .query = "foo=bar", .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__);
rc += _uri_test ("https://www.server.com///////", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = "/", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__);
rc += _uri_test ("https://www.server.com?foo=bar", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = NULL, .query = "foo=bar", .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__);
rc += _uri_test ("https://www.server.com#anchor", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = NULL, .query = NULL, .fragment = "anchor", .flags = URI_T_HOST_REGNAME }, __LINE__);
rc += _uri_test ("https://www.server.com/path/to/file.html?foo=bar&foo2=bar2#anchor", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = "/path/to/file.html", .query = "foo=bar&foo2=bar2", .fragment = "anchor", .flags = URI_T_HOST_REGNAME }, __LINE__);
rc += _uri_test ("https://www.server.com:80/", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 80, .path = "/", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__);
rc += _uri_test ("https://www.server.com:/", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = "/", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__);
rc += _uri_test ("https://www.server.com:", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = "", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__);
rc += _uri_test ("https://[8:3:1:2:1234:5678::]:8080/ipv6", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "8:3:1:2:1234:5678::", .port = 8080, .path = "/ipv6", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV6 }, __LINE__);
rc += _uri_test ("https://[2001:db8:0:85a3::ac1f:8001]:8080/ipv6", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "2001:db8:0:85a3::ac1f:8001", .port = 8080, .path = "/ipv6", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV6 }, __LINE__);
rc += _uri_test ("https://user:pass@[2001:db8:3333:4444:5555:6666:1.2.3.4]:8080/ipv6", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .userinfo = "user:pass", .user = "user", .pass = "pass", .host = "2001:db8:3333:4444:5555:6666:1.2.3.4", .port = 8080, .path = "/ipv6", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV6 }, __LINE__);
rc += _uri_test ("https://192.168.0.1:8080/ipv4", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "192.168.0.1", .port = 8080, .path = "/ipv4", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV4 }, __LINE__);
rc += _uri_test ("https://127.0.0.1:8080/ipv4loopback", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "127.0.0.1", .port = 8080, .path = "/ipv4loopback", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV4 | URI_T_LOCALHOST }, __LINE__);
rc += _uri_test ("https://localhost:8080/loopback", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "localhost", .port = 8080, .path = "/loopback", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__);
rc += _uri_test ("https://[0:0:0:0:0:0:0:1]:8080/ipv6loopback", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "0:0:0:0:0:0:0:1", .port = 8080, .path = "/ipv6loopback", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV6 | URI_T_LOCALHOST }, __LINE__);
rc += _uri_test ("https://[::0:0:0:1]:8080/ipv6loopback", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "::0:0:0:1", .port = 8080, .path = "/ipv6loopback", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV6 | URI_T_LOCALHOST }, __LINE__);
rc += _uri_test ("https://[::0:0000:0:001]:8080/ipv6loopback", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "::0:0000:0:001", .port = 8080, .path = "/ipv6loopback", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV6 | URI_T_LOCALHOST }, __LINE__);
rc += _uri_test ("https://[::1]:8080/ipv6loopback", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "::1", .port = 8080, .path = "/ipv6loopback", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV6 | URI_T_LOCALHOST }, __LINE__);
rc += _uri_test ("https://user:pass@192.168.0.1:8080/ipv4", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .userinfo = "user:pass", .user = "user", .pass = "pass", .host = "192.168.0.1", .port = 8080, .path = "/ipv4", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV4 }, __LINE__);
rc += _uri_test ("file://///C:/windows/path", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_FILE, .host = NULL, .port = 0, .path = "C:/windows/path", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__);
rc += _uri_test ("file:C:/windows/path", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_FILE, .host = NULL, .port = 0, .path = "C:/windows/path", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__);
rc += _uri_test ("file:/C:/windows/path", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_FILE, .host = NULL, .port = 0, .path = "C:/windows/path", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__);
rc += _uri_test ("file:///C:/windows/path", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_FILE, .host = NULL, .port = 0, .path = "C:/windows/path", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__);
rc += _uri_test ("file://?/C:/windows/path", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_FILE, .host = NULL, .port = 0, .path = "C:/windows/path", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__);
rc += _uri_test ("file://./C:/windows/path", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_FILE, .host = NULL, .port = 0, .path = "C:/windows/path", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__);
// Examples from AAF files external essences
rc += _uri_test ("file:///C:/Users/username/Downloads/441-16b.wav", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_FILE, .host = NULL, .port = 0, .path = "C:/Users/username/Downloads/441-16b.wav", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__);
rc += _uri_test ("file://?/E:/ADPAAF/Sequence A Rendu.mxf", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_FILE, .host = NULL, .port = 0, .path = "E:/ADPAAF/Sequence A Rendu.mxf", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__);
rc += _uri_test ("file:////C:/Users/username/Desktop/TEST2977052.aaf", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_FILE, .host = NULL, .port = 0, .path = "C:/Users/username/Desktop/TEST2977052.aaf", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__);
rc += _uri_test ("file://localhost/Users/username/Music/fonk_2_3#04.wav", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_FILE, .host = "localhost", .port = 0, .path = "/Users/username/Music/fonk_2_3#04.wav", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__);
rc += _uri_test ("file://10.87.230.71/mixage/DR2/Avid MediaFiles/MXF/1/3572607.mxf", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_FILE, .host = "10.87.230.71", .port = 0, .path = "/mixage/DR2/Avid MediaFiles/MXF/1/3572607.mxf", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV4 }, __LINE__);
rc += _uri_test ("file:///_system/Users/username/pt2MCCzmhsFRHQgdgsTMQX.mxf", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_FILE, .host = NULL, .port = 0, .path = "/_system/Users/username/pt2MCCzmhsFRHQgdgsTMQX.mxf", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__);
// URL Percent Decoding
rc += _uri_test ("https://www.server.com/NON_DECODING/%C2%B0%2B%29%3D%C5%93%21%3A%3B%2C%3F.%2F%C2%A7%C3%B9%2A%24%C2%B5%C2%A3%7D%5D%E2%80%9C%23%7B%5B%7C%5E%40%5D%3C%3E", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = "/NON_DECODING/%C2%B0%2B%29%3D%C5%93%21%3A%3B%2C%3F.%2F%C2%A7%C3%B9%2A%24%C2%B5%C2%A3%7D%5D%E2%80%9C%23%7B%5B%7C%5E%40%5D%3C%3E", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__);
rc += _uri_test ("https://www.server.com/DECODING/%C2%B0%2B%29%3D%C5%93%21%3A%3B%2C%3F.%2F%C2%A7%C3%B9%2A%24%C2%B5%C2%A3%7D%5D%E2%80%9C%23%7B%5B%7C%5E%40%5D%3C%3E", URI_OPT_DECODE_ALL, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = "/DECODING/°+)=œ!:;,?./§ù*$µ£}]“#{[|^@]<>", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__);
rc += _uri_test ("https://www.server.com/DECODING_UTF8/%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E7%B2%BE%E5%BA%A6%E7%B7%A8%E9%9B%86", URI_OPT_DECODE_ALL, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .userinfo = NULL, .user = NULL, .pass = NULL, .host = "www.server.com", .port = 0, .path = "/DECODING_UTF8/サンプル精度編集", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__);
// Examples from https://en.wikipedia.org/wiki/Uniform_Resource_Identifier
rc += _uri_test ("tel:+1-816-555-1212", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_TEL, .userinfo = NULL, .user = NULL, .pass = NULL, .host = NULL, .port = 0, .path = "+1-816-555-1212", .query = NULL, .fragment = NULL, .flags = 0 }, __LINE__);
rc += _uri_test ("mailto:John.Doe@example.com", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_MAILTO, .userinfo = NULL, .user = NULL, .pass = NULL, .host = NULL, .port = 0, .path = "John.Doe@example.com", .query = NULL, .fragment = NULL, .flags = 0 }, __LINE__);
rc += _uri_test ("urn:oasis:names:specification:docbook:dtd:xml:4.1.2", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_UNKNOWN, .userinfo = NULL, .user = NULL, .pass = NULL, .host = NULL, .port = 0, .path = "oasis:names:specification:docbook:dtd:xml:4.1.2", .query = NULL, .fragment = NULL, .flags = 0 }, __LINE__);
rc += _uri_test ("ldap://[2001:db8::7]/c=GB?objectClass?one", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_UNKNOWN, .userinfo = NULL, .user = NULL, .pass = NULL, .host = "2001:db8::7", .port = 0, .path = "/c=GB", .query = "objectClass?one", .fragment = NULL, .flags = URI_T_HOST_IPV6 }, __LINE__);
rc += _uri_test ("news:comp.infosystems.www.servers.unix", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_UNKNOWN, .userinfo = NULL, .user = NULL, .pass = NULL, .host = NULL, .port = 0, .path = "comp.infosystems.www.servers.unix", .query = NULL, .fragment = NULL, .flags = 0 }, __LINE__);
// rc += _uri_test( "xxxxxxxx", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_UNKNOWN, .userinfo = NULL, .user = NULL, .pass = NULL, .host = NULL, .port = 0, .path = NULL, .query = NULL, .fragment = NULL, .flags = 0 }, __LINE__ );
// rc += _uri_test( "xxxxxxxx", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_UNKNOWN, .userinfo = NULL, .user = NULL, .pass = NULL, .host = NULL, .port = 0, .path = NULL, .query = NULL, .fragment = NULL, .flags = 0 }, __LINE__ );
return rc;
}
#endif // BUILD_URI_TEST

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2017-2023 Adrien Gesta-Fline
* Copyright (C) 2017-2024 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
@ -119,15 +119,17 @@ typedef struct aafPropertyDefinition {
aafBoolean_t meta;
wchar_t* name;
char* name;
/*
* Looks like nobody cares about AAF standard TypeDefinition. All observed files
* had incorrect values for Type's Name and Identification, even Avid's files.
* Thus, PDef->type should NOT be trusted
* Thus, PDef->type should NOT be trusted.
*
* TODO: Should be set by attachNewProperty() in AAFClass.c
*/
aafUID_t type; // TODO: Should be set by attachNewProperty() in AAFClass.c
aafUID_t type;
/**
* Pointer to the next aafPropertyDef in the list.
@ -183,7 +185,7 @@ typedef struct aafclass {
* A Class is #CONCRETE if it can be retrieved as an
* object. Else, a Class is #ABSTRACT if it can't be
* directly retrieved and can only be inherited by
* another Class, so only its memebers can be retrieved.
* another Class, so only its members can be retrieved.
*/
aafBoolean_t isConcrete;
@ -206,7 +208,8 @@ typedef struct aafclass {
aafBoolean_t meta;
wchar_t* name; // this is set at runtime
/* name is set at runtime */
char* name;
/**
* Pointer to the next Class in the AAF_Data.Class list.
@ -297,10 +300,10 @@ typedef struct aafObject {
cfbNode* Node;
/**
* The name of the Node in the Compound File Tree : cfbNode._ab.
* UTF-8 name of the Node in the Compound File Tree, set from cfbNode._ab.
*/
wchar_t Name[CFB_NODE_NAME_SZ];
char* Name;
/**
* Pointer to an aafProperty list. This list holds the retrieved
@ -362,7 +365,8 @@ typedef struct aafObject {
struct aafObject* nextObj;
struct _aafData* aafd; // only to access aafd->verb
/* keeps track of aafd, mostly to access aafd->verb without having to pass aafd to some functions */
struct _aafData* aafd;
} aafObject;
@ -416,14 +420,14 @@ typedef struct _aafData {
struct Identification {
aafObject* obj;
wchar_t* CompanyName;
wchar_t* ProductName;
char* CompanyName;
char* ProductName;
aafProductVersion_t* ProductVersion;
wchar_t* ProductVersionString;
char* ProductVersionString;
aafUID_t* ProductID;
aafTimeStamp_t* Date;
aafProductVersion_t* ToolkitVersion;
wchar_t* Platform;
char* Platform;
aafUID_t* GenerationAUID;
} Identification;
@ -542,7 +546,7 @@ typedef struct _aafData {
aafObject* TaggedValueDefinition;
struct dbg* dbg;
struct aafLog* log;
} AAF_Data;
@ -586,7 +590,10 @@ typedef struct _aafData {
*/
#define aafRationalToFloat(r) \
(((r).denominator == 0) ? 0 : ((float)(r).numerator / (r).denominator))
(((r).denominator == 0) ? 0 : ((float)(r).numerator / (float)(r).denominator))
#define aafRationalToDouble(r) \
(((r).denominator == 0) ? 0 : ((double)(r).numerator / (r).denominator))
/**
* Converts an aafRational_t to a int64 number.
@ -596,6 +603,25 @@ typedef struct _aafData {
#define aafRationalToint64(r) \
(((r).denominator == 0) ? 0 : (int64_t) ((r).numerator / (r).denominator))
/**
* Loops through each aafPropertyIndexEntry_t of a "properties" node stream.
*
* @param Header Pointer to the stream's aafPropertyIndexHeader_t struct.
* @param Entry Pointer that will receive each aafPropertyIndexEntry_t struct.
* @param Value Pointer to each property's data value, of aafPropertyIndexEntry_t._length
* bytes length.
* @param i uint32_t iterator.
*/
#define foreachPropertyEntry(propStream, Header, Entry, Value, valueOffset, i) \
for (valueOffset = sizeof (aafPropertyIndexHeader_t) + (Header._entryCount * sizeof (aafPropertyIndexEntry_t)), \
i = 0; \
i < Header._entryCount && \
memcpy (&Entry, (propStream + ((sizeof (aafPropertyIndexHeader_t)) + (sizeof (aafPropertyIndexEntry_t) * i))), sizeof (aafPropertyIndexEntry_t)) && \
(Value = propStream + valueOffset); \
valueOffset += Entry._length, \
i++)
/**
* @name Initialisation functions
* @{
@ -608,7 +634,7 @@ typedef struct _aafData {
*/
AAF_Data*
aaf_alloc (struct dbg* dbg);
aaf_alloc (struct aafLog* log);
/**
* Loads an AAF file and sets the AAF_Data sructure accordingly.
@ -661,7 +687,7 @@ aaf_release (AAF_Data** aafd);
* @return Pointer to a null-terminated string holding the Object's path.
*/
wchar_t*
char*
aaf_get_ObjectPath (aafObject* Obj);
/**
@ -680,6 +706,21 @@ aafObject*
aaf_get_ObjectByWeakRef (aafObject* list,
aafWeakRef_t* ref);
aafUID_t*
aaf_get_InterpolationIdentificationByWeakRef (AAF_Data* aafd, aafWeakRef_t* InterpolationDefWeakRef);
aafUID_t*
aaf_get_OperationIdentificationByWeakRef (AAF_Data* aafd, aafWeakRef_t* OperationDefWeakRef);
aafUID_t*
aaf_get_ContainerIdentificationByWeakRef (AAF_Data* aafd, aafWeakRef_t* ContainerDefWeakRef);
aafUID_t*
aaf_get_DataIdentificationByWeakRef (AAF_Data* aafd, aafWeakRef_t* DataDefWeakRef);
aafObject*
aaf_get_ObjectAncestor (aafObject* Obj, const aafUID_t* ClassID);
int
aaf_ObjectInheritsClass (aafObject* Obj, const aafUID_t* classID);
/**
* Retrieves a Mob Object by its given MobID.
*
@ -698,6 +739,9 @@ aafObject*
aaf_get_MobSlotBySlotID (aafObject* MobSlots,
aafSlotID_t SlotID);
aafObject*
aaf_get_EssenceDataByMobID (AAF_Data* aafd, aafMobID_t* MobID);
/**
* Loops through each aafObject of a list, that is of a Set or Vector. It is also
* possible to filter the returned Object by ClassID.
@ -724,9 +768,12 @@ _aaf_foreach_ObjectInSet (aafObject** Obj,
* be used istead of directly calling _aaf_foreach_ObjectInSet().
*/
#define aaf_foreach_ObjectInSet(Obj, head, filter) \
#define AAF_foreach_ObjectInSet(Obj, head, filter) \
while (_aaf_foreach_ObjectInSet (Obj, head, filter))
void*
aaf_get_TaggedValueByName (AAF_Data* aafd, aafObject* TaggedValueVector, const char* name, const aafUID_t* type);
/**
* Retrieves an Object property by ID.
*
@ -741,6 +788,9 @@ aafProperty*
aaf_get_property (aafObject* Obj,
aafPID_t pid);
aafUID_t*
aaf_get_ParamDefIDByName (AAF_Data* aafd, const char* name);
/**
* Retrieves a Property ID by its name.
*
@ -752,8 +802,11 @@ aaf_get_property (aafObject* Obj,
*/
aafPID_t
aaf_get_PropertyIDByName (AAF_Data* aafd,
const wchar_t* name);
aaf_get_PropertyIDByName (AAF_Data* aafd,
const char* name);
aafUID_t*
aaf_get_OperationDefIDByName (AAF_Data* aafd, const char* OpDefName);
/**
* Retrieves an Object property by ID, and returns its value.
@ -781,7 +834,7 @@ aaf_get_propertyValue (aafObject* Obj,
/**
* Safely get an Indirect value, after it was retrieved using aaf_get_propertyValue().
* Function checks value type and in case of AAFTypeID_String, performs allocation
* and conversion to system wchar_t*.
* and UTF8 conversion.
*
* Caller must free the returned value, only if Indirect is of type
* AAFTypeID_String.
@ -790,7 +843,7 @@ aaf_get_propertyValue (aafObject* Obj,
* @param Indirect Pointer to the Indirect structure.
* @param typeDef Type definition expected from the Indirect.
*
* @return A pointer to the Indirect value, or a pointer to an allocated wchar_t if Indirect is AAFTypeID_String\n
* @return A pointer to the Indirect value, or a pointer to an allocated char if Indirect is AAFTypeID_String\n
* NULL in case of error.
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2017-2023 Adrien Gesta-Fline
* Copyright (C) 2017-2024 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
@ -26,27 +26,30 @@
#include "aaf/LibCFB.h"
void
aaf_dump_Header (AAF_Data* aafd);
aaf_dump_Header (AAF_Data* aafd, const char* padding);
void
aaf_dump_Identification (AAF_Data* aafd);
aaf_dump_Identification (AAF_Data* aafd, const char* padding);
void
aaf_dump_rawProperties (AAF_Data* aafd, aafByte_t* propStream);
aaf_dump_rawProperties (AAF_Data* aafd, aafByte_t* propStream, const char* padding);
void
aaf_dump_ObjectProperty (AAF_Data* aafd, aafProperty* Prop);
aaf_dump_ObjectProperty (AAF_Data* aafd, aafProperty* Prop, const char* padding);
void
aaf_dump_ObjectProperties (AAF_Data* aafd, aafObject* Obj);
aaf_dump_ObjectProperties (AAF_Data* aafd, aafObject* Obj, const char* padding);
void
aaf_dump_nodeStreamProperties (AAF_Data* aafd, cfbNode* node);
aaf_dump_TaggedValueSet (AAF_Data* aafd, aafObject* ObjCollection, const char* padding);
void
aaf_dump_MetaDictionary (AAF_Data* aafd);
aaf_dump_nodeStreamProperties (AAF_Data* aafd, cfbNode* node, const char* padding);
void
aaf_dump_Classes (AAF_Data* aafd);
aaf_dump_MetaDictionary (AAF_Data* aafd, const char* padding);
void
aaf_dump_Classes (AAF_Data* aafd, const char* padding);
#endif // ! __AAFDump_h__

View File

@ -0,0 +1,61 @@
/*
* Copyright (C) 2017-2024 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __AAFIEssenceFile_h__
#define __AAFIEssenceFile_h__
/**
* @file LibAAF/AAFIface/AAFIEssenceFile.h
* @brief AAF processing
* @author Adrien Gesta-Fline
* @version 0.1
* @date 27 june 2024
*
* @ingroup AAFIface
* @addtogroup AAFIface
* @{
*/
#include "aaf/AAFIface.h"
char*
aafi_locate_external_essence_file (AAF_Iface* aafi, const char* original_uri_filepath, const char* search_location);
/**
* Extract audio essence file.
*
* @param aafi XXXXXX
*/
int
aafi_extractAudioEssenceFile (AAF_Iface* aafi, aafiAudioEssenceFile* audioEssenceFile, enum aafiExtractFormat extractFormat, const char* outfilepath, uint64_t sampleOffset, uint64_t sampleLength, const char* forcedFileName, char** usable_file_path);
int
aafi_extractAudioClip (AAF_Iface* aafi, aafiAudioClip* audioClip, enum aafiExtractFormat extractFormat, const char* outfilepath);
int
aafi_parse_audio_essence (AAF_Iface* aafi, aafiAudioEssenceFile* audioEssenceFile);
int
aafi_build_unique_audio_essence_name (AAF_Iface* aafi, aafiAudioEssenceFile* audioEssenceFile);
/**
* @}
*/
#endif // !__AAFIEssenceFile_h__

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2017-2023 Adrien Gesta-Fline
* Copyright (C) 2017-2024 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
@ -50,8 +50,6 @@ typedef struct trace_dump {
int lv; // current level
int* ll; // level loop : each entry correspond to a level and tell if there is more to print
int eob; // end of branch
int hc; // have children
int sub;
} td;
#define __td_set(__td, __ptd, offset) \
@ -60,26 +58,28 @@ typedef struct trace_dump {
__td.lv = __ptd->lv + offset; \
__td.ll = __ptd->ll; \
__td.ll[__td.lv] = (offset > 0) ? 0 : __td.ll[__td.lv]; \
__td.eob = 0; \
__td.hc = 0; \
__td.sub = 0;
__td.eob = (offset) ? 0 : __ptd->eob;
#define DUMP_OBJ(aafi, Obj, __td) \
aafi_dump_obj (aafi, Obj, __td, TD_OK, __LINE__, "");
#define TRACE_OBJ(aafi, Obj, __td) \
aafi_dump_obj (aafi, Obj, __td, TD_OK, __func__, __LINE__, "");
#define DUMP_OBJ_INFO(aafi, Obj, __td, ...) \
aafi_dump_obj (aafi, Obj, __td, TD_OK, __LINE__, __VA_ARGS__);
#define TRACE_OBJ_INFO(aafi, Obj, __td, ...) \
aafi_dump_obj (aafi, Obj, __td, TD_INFO, __func__, __LINE__, __VA_ARGS__);
#define DUMP_OBJ_WARNING(aafi, Obj, __td, ...) \
aafi_dump_obj (aafi, Obj, __td, TD_WARNING, __LINE__, __VA_ARGS__);
#define TRACE_OBJ_WARNING(aafi, Obj, __td, ...) \
aafi_dump_obj (aafi, Obj, __td, TD_WARNING, __func__, __LINE__, __VA_ARGS__);
#define DUMP_OBJ_ERROR(aafi, Obj, __td, ...) \
(__td)->eob = 1; \
aafi_dump_obj (aafi, Obj, __td, TD_ERROR, __LINE__, __VA_ARGS__);
#define TRACE_OBJ_ERROR(aafi, Obj, __td, ...) \
(__td)->eob = 1; \
aafi_dump_obj (aafi, Obj, __td, TD_ERROR, __func__, __LINE__, __VA_ARGS__);
#define DUMP_OBJ_NO_SUPPORT(aafi, Obj, __td) \
(__td)->eob = 1; \
aafi_dump_obj_no_support (aafi, Obj, __td, __LINE__);
#define TRACE_OBJ_NO_SUPPORT(aafi, Obj, __td) \
aafi_dump_obj (aafi, Obj, __td, TD_NOT_SUPPORTED, __func__, __LINE__, "");
#define AAFI_foreach_ObjectInSet(Obj, head, i, __td) \
i = 0; \
while (_aaf_foreach_ObjectInSet (Obj, head, NULL) && \
(__td.ll[__td.lv] = (head->Header->_entryCount > 1) ? (int)(head->Header->_entryCount - i++) : 0) >= 0)
int
aafi_retrieveData (AAF_Iface* aafi);
@ -90,15 +90,9 @@ aafi_retrieveData (AAF_Iface* aafi);
*/
void
aafi_dump_obj (AAF_Iface* aafi, aafObject* Obj, struct trace_dump* __td, int state, int line, const char* fmt, ...);
void
aafi_dump_obj_no_support (AAF_Iface* aafi, aafObject* Obj, struct trace_dump* __td, int line);
aafi_dump_obj (AAF_Iface* aafi, aafObject* Obj, struct trace_dump* __td, int state, const char* func, int line, const char* fmt, ...);
void
aafi_trace_obj (AAF_Iface* aafi, aafObject* Obj, const char* color);
int
aafi_parse_Segment (AAF_Iface* aafi, aafObject* Segment, td* __ptd);
#endif // !__AAFIParser_h__

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2017-2023 Adrien Gesta-Fline
* Copyright (C) 2017-2024 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
@ -42,7 +42,13 @@ enum aafiEssenceType {
AAFI_ESSENCE_TYPE_WAVE = 0x02,
AAFI_ESSENCE_TYPE_AIFC = 0x03,
AAFI_ESSENCE_TYPE_BWAV = 0x04,
AAFI_ESSENCE_TYPE_UNK = 0xff, /* non-pcm */
AAFI_ESSENCE_TYPE_UNK = 0xff /* non-pcm */
};
enum aafiExtractFormat {
AAFI_EXTRACT_DEFAULT = 0,
AAFI_EXTRACT_WAV,
AAFI_EXTRACT_BWAV
};
/**
@ -50,8 +56,8 @@ enum aafiEssenceType {
*/
typedef enum aafiAudioGain_e {
AAFI_AUDIO_GAIN_CONSTANT = 1 << 0, //0x0001
AAFI_AUDIO_GAIN_VARIABLE = 1 << 1, //0x0002
AAFI_AUDIO_GAIN_CONSTANT = 1 << 0,
AAFI_AUDIO_GAIN_VARIABLE = 1 << 1,
} aafiAudioGain_e;
@ -63,12 +69,12 @@ typedef enum aafiAudioGain_e {
*/
typedef enum aafiTransition_e {
AAFI_TRANS_SINGLE_CURVE = 1 << 4, //0x0010
AAFI_TRANS_TWO_CURVE = 1 << 5, //0x0020
AAFI_TRANS_SINGLE_CURVE = 1 << 4,
AAFI_TRANS_TWO_CURVE = 1 << 5,
AAFI_TRANS_FADE_IN = 1 << 6, //0x0040
AAFI_TRANS_FADE_OUT = 1 << 7, //0x0080
AAFI_TRANS_XFADE = 1 << 8, //0x0100
AAFI_TRANS_FADE_IN = 1 << 6,
AAFI_TRANS_FADE_OUT = 1 << 7,
AAFI_TRANS_XFADE = 1 << 8,
} aafiTransition_e;
@ -83,17 +89,16 @@ typedef enum aafiTransition_e {
*/
typedef enum aafiInterpolation_e {
AAFI_INTERPOL_NONE = 1 << 10, //0x0400
AAFI_INTERPOL_LINEAR = 1 << 11, //0x0800
AAFI_INTERPOL_LOG = 1 << 12, //0x1000
AAFI_INTERPOL_CONSTANT = 1 << 13, //0x2000
AAFI_INTERPOL_POWER = 1 << 14, //0x4000
AAFI_INTERPOL_BSPLINE = 1 << 15, //0x8000
AAFI_INTERPOL_NONE = 1 << 10,
AAFI_INTERPOL_LINEAR = 1 << 11,
AAFI_INTERPOL_LOG = 1 << 12,
AAFI_INTERPOL_CONSTANT = 1 << 13,
AAFI_INTERPOL_POWER = 1 << 14,
AAFI_INTERPOL_BSPLINE = 1 << 15,
} aafiInterpolation_e;
#define AAFI_INTERPOL_MASK ( \
AAFI_INTERPOL_NONE | AAFI_INTERPOL_LINEAR | AAFI_INTERPOL_LOG | AAFI_INTERPOL_CONSTANT | AAFI_INTERPOL_POWER | AAFI_INTERPOL_BSPLINE)
#define AAFI_INTERPOL_MASK (unsigned)(AAFI_INTERPOL_NONE | AAFI_INTERPOL_LINEAR | AAFI_INTERPOL_LOG | AAFI_INTERPOL_CONSTANT | AAFI_INTERPOL_POWER | AAFI_INTERPOL_BSPLINE)
/**
* Specifies a Transition that can be a fade in, a fade out or a Cross fade, and that can
@ -109,12 +114,14 @@ typedef enum aafiInterpolation_e {
*/
typedef struct aafiTransition {
struct aafiTimelineItem* timelineItem;
/**
* Should hold the transition type (either single param or two param),
* the transition fade type (in, out, x) and the interpolation used.
*/
int flags;
uint32_t flags;
/**
* Length of the transition, in edit units.
@ -205,8 +212,8 @@ typedef struct aafiAudioGain {
* the interpolation used to calculate the values between two time points.
*/
uint16_t flags; // Type : Constant (single multiplier for entire clip) or
// Variable (automation)
uint32_t flags; // Type : Constant (single multiplier for entire clip) or
// Variable (automation)
// Interpolation : Linear, Log, Constant, Power, BSpline
/**
@ -214,7 +221,7 @@ typedef struct aafiAudioGain {
* gain automation, and is consequently the size of time[] and value[] arrays.
*/
int64_t pts_cnt;
unsigned int pts_cnt;
/**
* Array of time points, where the corresponding level value should apply.
@ -234,65 +241,130 @@ typedef struct aafiAudioGain {
typedef struct aafiAudioGain aafiAudioPan;
typedef struct aafiAudioEssence {
wchar_t* original_file_path; // NetworkLocator::URLString the original external essence URI holded in AAF
wchar_t* usable_file_path; // Holds a real usable file path, once an embedded essence has been extracted, or once en external essence has been found.
wchar_t* file_name; // MasterMob::Name the original file name. Might be NULL if MasterMob has no name. One should always use unique_file_name which is guaranted to be set.
wchar_t* unique_file_name; // unique name generated from file_name. Sometimes, multiple files share the same names so this unique name should be used on export.
typedef struct aafiMetaData {
char* name;
uint16_t clip_count; // number of clips using this essence
char* text;
/*
* total samples for 1 channel (no matter channel count).
* Might be retrieved from FileDescriptor::Length property,
* or from WAV/AIFF summary or file :
* (data chunk size / channels / samplesize / 8)
struct aafiMetaData* next;
} aafiMetaData;
/**
* Describe a single audio essence file.
*/
typedef struct aafiAudioEssenceFile {
/**
* Holds the name of essence file, as specified in MasterMob::Name.
* This is usually the name exposed in the original software.
* This name *might* not be unique accross all essences. For a
* unique name, use #aafiAudioEssenceFile.unique_name instead.
*/
uint64_t length;
cfbNode* node; // The node holding the audio stream if embedded
char* name;
/**
* This is the same as #aafiAudioEssenceFile.name, but this one is guaranted to
* be unique. If an AAF has different essence files sharing the same name,
* then libaaf will add a suffix to unique_name. Thus, unique_name can be used
* instead of name when exporting embedded essences.
*/
char* unique_name; // TODO: see creative_post.aaf
/**
* Holds the URI path to the essence file, as specified in NetworkLocator::URLString.
* This path is *not* uri-decoded.
*/
char* original_file_path;
/**
* Holds a usable filepath to the essence file. It is set, either when an
* embedded essence has been extracted using aafi_extractAudioEssenceFile() or
* when an external essence file has been successfully located by libaaf.
*/
char* usable_file_path;
/**
* Total sample count for 1 audio channel (no matter channel count).
*
* Might be retrieved from FileDescriptor::Length property, or from WAV/AIFF
* summary or file : `data chunk size / channels / samplesize / 8`
*
* `duration = length / samplerate`
*/
aafPosition_t length;
/**
* Data stream CFB node, containing essence data if it's embedded.
*/
cfbNode* node;
/**
* Flag to tell if essence data is embedded or external. It is set only if
* FileSourceMob contains EssenceData.
*/
uint8_t is_embedded;
aafObject* SourceMob;
aafMobID_t* sourceMobID; // Holds the SourceMob Mob::ID references this EssenceData
uint32_t sourceMobSlotID; // SlotID of the MobSlot inside MasterMob (CompoMob's Sequence SourceClip::SourceMobSlotID)
aafRational_t* sourceMobSlotEditRate;
aafPosition_t sourceMobSlotOrigin; // SourceMob TimelineMobSlot::Origin
aafMobID_t* sourceMobID; // Holds the SourceMob Mob::ID references this EssenceData
uint32_t sourceMobSlotID; // SlotID of the MobSlot inside MasterMob (CompoMob's Sequence SourceClip::SourceMobSlotID)
aafMobID_t* masterMobID; // Holds the MasterMob Mob::ID (used by CompoMob's Sequence SourceClip::SourceID)
uint32_t masterMobSlotID; // SlotID of the MobSlot inside MasterMob (CompoMob's Sequence SourceClip::SourceMobSlotID)
aafObject* SourceMob;
enum aafiEssenceType type; // depends on PCMDescriptor WAVEDescriptor AIFCDescriptor
/*
* is only set if FileSourceMob contains EssenceData
*/
uint8_t is_embedded;
aafProperty* summary; // WAVEDescriptor AIFCDescriptor
uint64_t pcm_audio_start_offset;
// uint32_t format;
uint32_t samplerate;
aafRational_t* samplerateRational; // eg. { 48000, 1 }
int16_t samplesize;
int16_t channels;
uint16_t samplesize;
aafRational_t* mobSlotEditRate;
/**
* Audio essence file channel count. Might be different of #aafiAudioClip.channels
*/
uint16_t channels;
// BWF BEXT chunk data
char description[256];
char originator[32]; // could be set with header::ProductName
char originatorReference[32];
uint64_t timeReference; // SourceMob TimelineMobSlot::Origin
aafPosition_t timeReference; // SourceMob TimelineMobSlot::Origin
unsigned char umid[64]; // SourceMob::MobID (32 Bytes, basic form)
char originationDate[10 + 1]; // SourceMob::CreationDate
char originationTime[8 + 1]; // SourceMob::CreationTime
void* user;
// TODO peakEnveloppe
struct aafiAudioEssence* next; // aafi->Audio->essences
} aafiAudioEssence;
/**
* Metadata retrieved from main MasterMob::UserComments
*/
aafiMetaData* metadata;
void* user;
/**
* Pointer to the next essence in global essence list #aafiAudio.essenceFiles
*/
struct aafiAudioEssenceFile* next;
} aafiAudioEssenceFile;
/**
* aafiAudioEssencePointer is used by aafiAudioClip, to points to one or more
* aafiAudioEssenceFile and specify which channel of essence file the clip uses.
*/
typedef struct aafiAudioEssencePointer {
aafiAudioEssence* essence; // single essence, not list !
int essenceChannel; // channel selector inside multichannel essence. If zero, then all essence channels must be used.
aafiAudioEssenceFile* essenceFile;
uint32_t essenceChannel; // channel selector inside multichannel essence. If zero, then all essence channels must be used.
void* user;
@ -304,12 +376,12 @@ typedef struct aafiAudioEssencePointer {
} aafiAudioEssencePointer;
typedef struct aafiVideoEssence {
wchar_t* original_file_path; // NetworkLocator::URLString should point to original essence file if external (and in some cases, points to the AAF itself if internal..)
wchar_t* usable_file_path; // TODO, not that used.. to be tweaked. ---- Holds the file path, once the essence has been exported, copied or linked.
wchar_t* file_name; // MasterMob::Name -> file name
wchar_t* unique_file_name; // unique name generated from file_name. Sometimes, multiple files share the same names so this unique name should be used on export.
char* original_file_path; // NetworkLocator::URLString should point to original essence file if external (and in some cases, points to the AAF itself if internal..)
char* usable_file_path; // TODO, not that used.. to be tweaked. ---- Holds the file path, once the essence has been exported, copied or linked.
char* name; // MasterMob::Name -> file name
char* unique_name; // unique name generated from aafiVideoEssence->name. Sometimes, multiple files share the same names so this unique name should be used on export.
uint64_t length; // Length of Essence Data
aafPosition_t length; // Length of Essence Data
cfbNode* node; // The node holding the audio stream if embedded
@ -328,6 +400,11 @@ typedef struct aafiVideoEssence {
aafProperty* summary;
/**
* Metadata retrieved from main MasterMob::UserComments
*/
aafiMetaData* metadata;
// TODO peakEnveloppe
struct aafiVideoEssence* next;
@ -338,10 +415,33 @@ struct aafiAudioTrack;
struct aafiVideoTrack;
typedef struct aafiAudioClip {
/**
* The track that audio clip is attached to.
*/
struct aafiAudioTrack* track;
int channels; // channel count of clip (might be different of essence->channels)
/**
* Audio channel count of audio clip. Might be different of #aafiAudioEssenceFile.channels
*/
int channels;
/**
* List of essence pointer that compose an audio clip.
*
* An audio clip can hold a single aafiAudioEssencePointer, if clip is mono or
* Each aafiAudioEssencePointer points to a single aafiAudioEssenceFile.
*
* If clip is mono, it has a single aafiAudioEssencePointer which points to a
* single aafiAudioEssenceFile.
*/
aafiAudioEssencePointer* essencePointerList;
/**
* SubCLip name is set in rare cases, when a SourceClip targets a SubClip
* CompositionMob with a name (see AAFUsage_SubClip)
*/
char* subClipName;
/*
* Some editors (like Resolve) support automation attached to a clip AND a fixed value clip gain
*/
@ -350,8 +450,6 @@ typedef struct aafiAudioClip {
int mute;
int channel_count;
aafPosition_t pos; /* in edit unit, edit rate definition is aafiAudioTrack->edit_rate */
aafPosition_t len; /* in edit unit, edit rate definition is aafiAudioTrack->edit_rate */
@ -378,7 +476,9 @@ typedef struct aafiAudioClip {
*/
aafPosition_t essence_offset;
struct aafiTimelineItem* Item; // Corresponding timeline item, currently used in ardour to retrieve fades/x-fades
aafiMetaData* metadata;
struct aafiTimelineItem* timelineItem; // Corresponding timeline item
} aafiAudioClip;
@ -395,6 +495,8 @@ typedef struct aafiVideoClip {
aafMobID_t* masterMobID; // MobID of the associated MasterMob (PID_SourceReference_SourceID)
struct aafiTimelineItem* timelineItem; // Corresponding timeline item
} aafiVideoClip;
typedef enum aafiTimelineItem_type_e {
@ -409,13 +511,30 @@ typedef enum aafiTimelineItem_type_e {
*/
typedef struct aafiTimelineItem {
int type;
/**
* Identifies timelineItem type.
*/
aafiTimelineItem_type_e type;
/**
* Item position on the timeline. Value is in edit unit, specified by #aafiAudioTrack.edit_rate.
*/
aafPosition_t pos;
/**
* Item length on the timeline. Value is in edit unit, specified by #aafiAudioTrack.edit_rate.
*/
aafPosition_t len;
/**
* The actual timelineItem object data. Can hold an aafiTransition, aafiAudioClip
* or aafiVideoClip structure, depending on #aafiTimelineItem.type value.
*/
void* data;
struct aafiTimelineItem* next;
struct aafiTimelineItem* prev;
void* data; /* aafiTransition or aafiAudioClip or aafiVideoClip */
} aafiTimelineItem;
/**
@ -471,8 +590,6 @@ struct aafiVideo;
typedef struct aafiAudioTrack {
/**
* Track number
* TODO Should it start at one ?
* TODO Optional, should have a guess (i++) option.
*/
uint32_t number;
@ -483,7 +600,7 @@ typedef struct aafiAudioTrack {
* Track name
*/
wchar_t* name;
char* name;
/**
* Holds the Gain to apply on that track, that is the track volume Fader.
@ -493,12 +610,16 @@ typedef struct aafiAudioTrack {
aafiAudioPan* pan;
char solo;
char mute;
/**
* Holds the timeline items of that track, that is aafiAudioClip and aafiTransition
* structures.
*/
struct aafiTimelineItem* Items;
struct aafiTimelineItem* timelineItems;
int clipCount;
/**
* The edit rate of all the contained Clips, Transitions, also lengths and track->current_pos;
@ -535,14 +656,14 @@ typedef struct aafiVideoTrack {
* Track name
*/
wchar_t* name;
char* name;
/**
* Holds the timeline items of that track, that is aafiVideoClip and aafiTransition
* structures.
*/
struct aafiTimelineItem* Items;
struct aafiTimelineItem* timelineItems;
/**
* The edit rate of all the contained Clips and Transitions.
@ -566,15 +687,6 @@ typedef struct aafiVideoTrack {
} aafiVideoTrack;
typedef struct aafiUserComment {
wchar_t* name;
wchar_t* text;
struct aafiUserComment* next;
} aafiUserComment;
typedef struct aafiAudio {
/**
* Holds the sequence start timecode.
@ -582,15 +694,16 @@ typedef struct aafiAudio {
aafPosition_t start;
int16_t samplesize;
int64_t samplerate;
uint16_t samplesize;
uint32_t samplerate;
aafRational_t* samplerateRational; // eg. { 48000, 1 }
/**
* Holds the Essence list.
*/
aafiAudioEssence* Essences;
int essenceCount;
aafiAudioEssenceFile* essenceFiles;
aafiAudioEssencePointer* essencePointerList;
/**
@ -613,7 +726,7 @@ typedef struct aafiVideo {
* Holds the Essence list.
*/
aafiVideoEssence* Essences;
aafiVideoEssence* essenceFiles;
/**
* Holds the Track list.
@ -632,8 +745,8 @@ typedef struct aafiMarker {
aafPosition_t length;
aafRational_t* edit_rate;
wchar_t* name;
wchar_t* comment;
char* name;
char* comment;
uint16_t RGBColor[3];
struct aafiMarker* prev;
@ -641,17 +754,7 @@ typedef struct aafiMarker {
} aafiMarker;
// typedef enum aafiCurrentTreeType_e
// {
// AAFI_TREE_TYPE_AUDIO = 0,
// AAFI_TREE_TYPE_VIDEO = 1
//
// } aafiCurrentTreeType_e;
typedef struct aafiContext {
/* Set in parse_MobSlot(), specifies if we're inside an audio or video context */
// aafiCurrentTreeType_e current_tree_type;
/*
* Current MobSlot Segment's DataDefinition
* Mob::Slots > MobSlot::Segment > Component::DataDefinition
@ -660,11 +763,10 @@ typedef struct aafiContext {
// aafUID_t *DataDef;
/* Clip */
aafObject* TopLevelCompositionMob;
aafiAudioTrack* current_track;
/* Must be casted to aafiAudioTrack or aafiVideoTrack, according to aafiContext::current_tree_type */
// void * current_track;
// int current_track_number; // used only when missing MobSlot::PhysicalTrackNumber
// aafPosition_t current_pos;
@ -673,41 +775,46 @@ typedef struct aafiContext {
int current_clip_is_muted;
int current_clip_is_combined; // Inside OperationGroup::AAFOperationDef_AudioChannelCombiner
int current_combined_clip_total_channel;
uint32_t current_combined_clip_total_channel;
int current_combined_clip_channel_num; // current SourceClip represents channel num
aafPosition_t current_combined_clip_forced_length;
/* Transition */
aafiTransition* current_transition;
char* subClipName;
int current_opgroup_affect_track;
/* Gain */
aafiAudioGain* current_clip_gain;
aafiAudioGain* current_clip_automation;
int clips_using_gain; // if none then free( current_clip_gain );
int clips_using_automation;
int current_clip_gain_is_used; // if not then free( current_clip_gain );
aafiAudioGain* current_clip_variable_gain;
int current_clip_variable_gain_is_used;
/* Essence */
// aafiAudioEssence *current_audioEssence;
// void *current_essence;
aafiAudioEssence* current_essence;
aafiVideoEssence* current_video_essence;
aafiAudioEssenceFile* current_audio_essence;
aafiVideoEssence* current_video_essence;
aafRational_t* current_markers_edit_rate;
int is_inside_derivation_chain;
aafRational_t* avid_warp_clip_edit_rate;
struct options {
int trace;
int trace_meta;
wchar_t* dump_class_aaf_properties;
wchar_t* dump_class_raw_properties;
char* media_location;
char forbid_nonlatin_filenames;
int trace;
int dump_meta;
int dump_tagged_value;
char* dump_class_aaf_properties;
char* dump_class_raw_properties;
char* media_location;
// int forbid_nonlatin_filenames;
int mobid_essence_filename;
/* vendor specific */
uint32_t resolve;
uint32_t protools;
int protools;
} options;
} aafiContext;
@ -729,7 +836,7 @@ typedef struct AAF_Iface {
aafiMarker* Markers;
wchar_t* compositionName;
char* compositionName;
aafPosition_t compositionStart; // sets from aafi->Timecode->start
aafRational_t* compositionStart_editRate;
@ -737,88 +844,242 @@ typedef struct AAF_Iface {
aafPosition_t compositionLength; // sets from the longest audio or video track->current_pos
aafRational_t* compositionLength_editRate; /* might be NULL if file empty ! */
aafiUserComment* Comments;
/**
* Metadata retrieved from main CompositionMob::UserComments
*/
aafiMetaData* metadata;
struct dbg* dbg;
struct aafLog* log;
} AAF_Iface;
#define foreach_audioTrack(audioTrack, aafi) \
for (audioTrack = aafi->Audio->Tracks; \
audioTrack != NULL; \
/**
* @name Function macros
* @{
*/
/**
* Loops through each audio track in AAF file.
*
* @param aafi Pointer to the current AAF_Iface struct.
* @param audioTrack NULL pointer to an aafiAudioTrack struct.
*/
#define AAFI_foreachAudioTrack(aafi, audioTrack) \
for (audioTrack = aafi->Audio->Tracks; \
audioTrack != NULL; \
audioTrack = audioTrack->next)
#define foreach_videoTrack(videoTrack, aafi) \
for (videoTrack = aafi->Video->Tracks; \
videoTrack != NULL; \
/**
* Loops through each video track in AAF file.
*
* @param aafi Pointer to the current AAF_Iface struct.
* @param videoTrack NULL pointer to an aafiVideoTrack struct.
*/
#define AAFI_foreachVideoTrack(aafi, videoTrack) \
for (videoTrack = aafi->Video->Tracks; \
videoTrack != NULL; \
videoTrack = videoTrack->next)
#define foreach_Item(item, track) \
for (item = track->Items; \
item != NULL; \
item = item->next)
/**
* Loops through each timelineItem of a track. Audio tracks can contain
* either clips (AAFI_AUDIO_CLIP) or crossfades (AAFI_TRANS).
*
* @param track Pointer to an aafiAudioTrack struct.
* @param timelineItem NULL pointer to an aafiTimelineItem struct.
*/
#define AAFI_foreachTrackItem(track, timelineItem) \
for (timelineItem = track->timelineItems; \
timelineItem != NULL; \
timelineItem = timelineItem->next)
#define AAFI_foreachAudioEssencePointerInFile(essencePointer, aafi) \
for (essencePointer = aafi->Audio->essencePointerList; essencePointer != NULL; essencePointer = essencePointer->aafiNext)
/**
* Loops through each audio essence pointer in AAF file.
*
* @param aafi Pointer to the current AAF_Iface struct.
* @param audioEssencePointer NULL pointer to an aafiAudioEssencePointer struct.
*/
#define AAFI_foreachAudioEssencePointer(aafi, audioEssencePointer) \
for (audioEssencePointer = aafi->Audio->essencePointerList; \
audioEssencePointer != NULL; \
audioEssencePointer = audioEssencePointer->aafiNext)
#define AAFI_foreachAudioEssencePointer(essencePointer, essencePtrList) \
for (essencePointer = essencePtrList; essencePointer != NULL; essencePointer = essencePointer->next)
/**
* Loops through each audio essence file in AAF file.
*
* @param aafi Pointer to the current AAF_Iface struct.
* @param audioEssenceFile NULL pointer to an aafiAudioEssenceFile struct.
*/
#define AAFI_foreachAudioEssenceFile(aafi, audioEssenceFile) \
for (audioEssenceFile = aafi->Audio->essenceFiles; \
audioEssenceFile != NULL; \
audioEssenceFile = audioEssenceFile->next)
#define foreachEssence(essence, essenceList) \
for (essence = essenceList; essence != NULL; essence = essence->next)
/**
* Loops through each video essence file in AAF file.
*
* @param aafi Pointer to the current AAF_Iface struct.
* @param videoEssenceFile NULL pointer to an aafiVideoEssence struct.
*/
#define AAFI_foreachVideoEssence(aafi, videoEssenceFile) \
for (videoEssenceFile = aafi->Video->essenceFiles; \
videoEssenceFile != NULL; \
videoEssenceFile = videoEssenceFile->next)
#define foreachMarker(marker, aafi) \
for (marker = aafi->Markers; marker != NULL; marker = marker->next)
/**
* Loops through each essence pointer in a list (usualy aafiAudioClip->essencePointerList).
*
* @param essencePointerList Pointer to any aafiAudioEssencePointer struct list.
* @param essencePointer NULL pointer to an aafiAudioEssencePointer struct.
*/
#define AAFI_foreachEssencePointer(essencePointerList, essencePointer) \
for (essencePointer = essencePointerList; \
essencePointer != NULL; \
essencePointer = essencePointer->next)
void
aafi_set_debug (AAF_Iface* aafi, verbosityLevel_e v, int ansicolor, FILE* fp, void (*callback) (struct dbg* dbg, void* ctxdata, int lib, int type, const char* srcfile, const char* srcfunc, int lineno, const char* msg, void* user), void* user);
#define AAFI_foreachEssence(essenceFileList, essenceFile) \
for (essenceFile = essenceFileList; \
essenceFile != NULL; \
essenceFile = essenceFile->next)
int
aafi_set_option_int (AAF_Iface* aafi, const char* optname, int val);
int
aafi_set_option_str (AAF_Iface* aafi, const char* optname, const char* val);
/**
* Loops through each marker in AAF file.
*
* @param aafi Pointer to the current AAF_Iface struct.
* @param marker NULL pointer to an aafiMarker struct.
*/
#define AAFI_foreachMarker(aafi, marker) \
for (marker = aafi->Markers; \
marker != NULL; \
marker = marker->next)
#define AAFI_foreachMetadata(metadataList, metadata) \
for (metadata = metadataList; \
metadata != NULL; \
metadata = metadata->next)
/**
* @}
*/
AAF_Iface*
aafi_alloc (AAF_Data* aafd);
void
aafi_release (AAF_Iface** aafi);
aafi_set_debug (AAF_Iface* aafi, verbosityLevel_e v, int ansicolor, FILE* fp, void (*callback) (struct aafLog* log, void* ctxdata, int lib, int type, const char* srcfile, const char* srcfunc, int lineno, const char* msg, void* user), void* user);
int
aafi_set_option_int (AAF_Iface* aafi, const char* optname, int val);
int
aafi_set_option_str (AAF_Iface* aafi, const char* optname, const char* val);
int
aafi_load_file (AAF_Iface* aafi, const char* file);
aafiTransition*
aafi_get_fadein (aafiTimelineItem* audioItem);
aafiTransition*
aafi_get_fadeout (aafiTimelineItem* audioItem);
aafiTransition*
aafi_get_xfade (aafiTimelineItem* audioItem);
aafiMarker*
aafi_newMarker (AAF_Iface* aafi, aafRational_t* editRate, aafPosition_t start, aafPosition_t length, wchar_t* name, wchar_t* comment, uint16_t* RGBColor[3]);
void
aafi_freeMarkers (aafiMarker** aafi);
aafi_release (AAF_Iface** aafi);
aafiAudioClip*
aafi_timelineItemToAudioClip (aafiTimelineItem* audioItem);
aafiTransition*
aafi_timelineItemToCrossFade (aafiTimelineItem* audioItem);
aafiTransition*
aafi_getFadeIn (aafiAudioClip* audioClip);
aafiTransition*
aafi_getFadeOut (aafiAudioClip* audioClip);
int
aafi_get_clipIndex (aafiAudioClip* audioClip);
aafPosition_t
aafi_convertUnit (aafPosition_t value, aafRational_t* valueEditRate, aafRational_t* destEditRate);
uint64_t
aafi_convertUnitUint64 (aafPosition_t value, aafRational_t* valueEditRate, aafRational_t* destEditRate);
int
aafi_removeTimelineItem (AAF_Iface* aafi, aafiTimelineItem* timelineItem);
int
aafi_getAudioEssencePointerChannelCount (aafiAudioEssencePointer* essencePointerList);
int
aafi_applyGainOffset (AAF_Iface* aafi, aafiAudioGain** gain, aafiAudioGain* offset);
aafiAudioTrack*
aafi_newAudioTrack (AAF_Iface* aafi);
void
aafi_freeAudioTracks (aafiAudioTrack** tracks);
aafiVideoTrack*
aafi_newVideoTrack (AAF_Iface* aafi);
aafiTimelineItem*
aafi_newTimelineItem (AAF_Iface* aafi, void* track, int itemType, void* data);
aafiAudioClip*
aafi_newAudioClip (AAF_Iface* aafi, aafiAudioTrack* track);
aafiVideoClip*
aafi_newVideoClip (AAF_Iface* aafi, aafiVideoTrack* track);
aafiTransition*
aafi_newTransition (AAF_Iface* aafi, aafiAudioTrack* track);
aafiMarker*
aafi_newMarker (AAF_Iface* aafi, aafRational_t* editRate, aafPosition_t start, aafPosition_t length, char* name, char* comment, uint16_t* RGBColor[]);
aafiMetaData*
aafi_newMetadata (AAF_Iface* aafi, aafiMetaData** CommentList);
aafiAudioEssencePointer*
aafi_newAudioEssencePointer (AAF_Iface* aafi, aafiAudioEssencePointer** list, aafiAudioEssenceFile* audioEssenceFile, uint32_t* essenceChannelNum);
aafiAudioEssenceFile*
aafi_newAudioEssence (AAF_Iface* aafi);
aafiVideoEssence*
aafi_newVideoEssence (AAF_Iface* aafi);
aafiAudioGain*
aafi_newAudioGain (AAF_Iface* aafi, enum aafiAudioGain_e type, enum aafiInterpolation_e interpol, aafRational_t* singleValue);
aafiAudioGain*
aafi_newAudioPan (AAF_Iface* aafi, enum aafiAudioGain_e type, enum aafiInterpolation_e interpol, aafRational_t* singleValue);
void
aafi_freeAudioTracks (aafiAudioTrack** tracks);
void
aafi_freeVideoTracks (aafiVideoTrack** tracks);
aafiTimelineItem*
aafi_newTimelineItem (AAF_Iface* aafi, void* track, int itemType);
void
aafi_freeTimelineItems (aafiTimelineItem** timelineItems);
int
aafi_removeTimelineItem (AAF_Iface* aafi, aafiTimelineItem* item);
void
aafi_freeTimelineItem (aafiTimelineItem* timelineItem);
void
aafi_freeAudioClip (aafiAudioClip* audioClip);
void
aafi_freeTransition (aafiTransition* trans);
void
aafi_freeMarkers (aafiMarker** aafi);
void
aafi_freeMetadata (aafiMetaData** CommentList);
void
aafi_freeAudioEssencePointer (aafiAudioEssencePointer* audioEssenceGroupEntry);
void
aafi_freeAudioEssences (aafiAudioEssenceFile** audioEssenceFiles);
void
aafi_freeVideoEssences (aafiVideoEssence** videoEssenceFile);
void
aafi_freeAudioGain (aafiAudioGain* gain);
@ -826,45 +1087,6 @@ aafi_freeAudioGain (aafiAudioGain* gain);
void
aafi_freeAudioPan (aafiAudioPan* pan);
void
aafi_freeAudioClip (aafiAudioClip* audioClip);
void
aafi_freeAudioEssencePointer (aafiAudioEssencePointer* audioEssenceGroupEntry);
void
aafi_freeTimelineItem (aafiTimelineItem** item);
void
aafi_freeTimelineItems (aafiTimelineItem** items);
aafiUserComment*
aafi_newUserComment (AAF_Iface* aafi, aafiUserComment** CommentList);
void
aafi_freeUserComments (aafiUserComment** CommentList);
void
aafi_freeTransition (aafiTransition* trans);
aafiAudioEssence*
aafi_newAudioEssence (AAF_Iface* aafi);
aafiAudioEssencePointer*
aafi_newAudioEssencePointer (AAF_Iface* aafi, aafiAudioEssencePointer** list, aafiAudioEssence* audioEssence, uint32_t* essenceChannelNum);
void
aafi_freeAudioEssences (aafiAudioEssence** essences);
aafiVideoEssence*
aafi_newVideoEssence (AAF_Iface* aafi);
void
aafi_freeVideoEssences (aafiVideoEssence** videoEssence);
int
aafi_getAudioEssencePointerChannelCount (aafiAudioEssencePointer* essencePointerList);
/**
* @}
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2017-2023 Adrien Gesta-Fline
* Copyright (C) 2017-2024 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
@ -21,9 +21,6 @@
#ifndef __AAFToText_h__
#define __AAFToText_h__
#include <stdio.h>
#include <wchar.h>
#include "aaf/AAFCore.h"
#include "aaf/AAFTypes.h"
#include "aaf/LibCFB.h"
@ -31,115 +28,118 @@
#define AUIDToText(auid) \
cfb_CLSIDToText ((const cfbCLSID_t*)auid)
const wchar_t*
const char*
aaft_MobIDToText (aafMobID_t* mobid);
const wchar_t*
const char*
aaft_TimestampToText (aafTimeStamp_t* ts);
const wchar_t*
const char*
aaft_VersionToText (aafVersionType_t* vers);
const wchar_t*
const char*
aaft_ProductVersionToText (aafProductVersion_t* vers);
const wchar_t*
const char*
aaft_FileKindToText (const aafUID_t* auid);
const wchar_t*
const char*
aaft_TapeCaseTypeToText (aafTapeCaseType_t t);
const wchar_t*
const char*
aaft_VideoSignalTypeToText (aafVideoSignalType_t v);
const wchar_t*
const char*
aaft_TapeFormatTypeToText (aafTapeFormatType_t t);
const wchar_t*
const char*
aaft_FilmTypeToText (aafFilmType_t f);
const wchar_t*
const char*
aaft_SignalStandardToText (aafSignalStandard_t s);
const wchar_t*
const char*
aaft_FieldNumberToText (aafFieldNumber_t f);
const wchar_t*
const char*
aaft_AlphaTransparencyToText (aafAlphaTransparency_t a);
const wchar_t*
const char*
aaft_FrameLayoutToText (aafFrameLayout_t f);
const wchar_t*
const char*
aaft_ColorSitingToText (aafColorSiting_t c);
const wchar_t*
const char*
aaft_ProductReleaseTypeToText (aafProductReleaseType_t t);
const wchar_t*
const char*
aaft_FadeTypeToText (aafFadeType_t f);
const wchar_t*
const char*
aaft_BoolToText (aafBoolean_t b);
const wchar_t*
const char*
aaft_OperationCategoryToText (const aafUID_t* auid);
const wchar_t*
const char*
aaft_PluginCategoryToText (const aafUID_t* auid);
const wchar_t*
const char*
aaft_ScanningDirectionToText (aafScanningDirection_t s);
const wchar_t*
const char*
aaft_ByteOrderToText (int16_t e);
const wchar_t*
const char*
aaft_ElectroSpatialToText (aafElectroSpatialFormulation_t e);
const wchar_t*
const char*
aaft_TypeIDToText (const aafUID_t* auid);
const wchar_t*
const char*
aaft_StoredFormToText (enum aafStoredForm_e sf);
const wchar_t*
const char*
aaft_OPDefToText (const aafUID_t* auid);
const wchar_t*
const char*
aaft_DataDefToText (AAF_Data* aafd, const aafUID_t* auid);
const wchar_t*
const char*
aaft_OperationDefToText (AAF_Data* aafd, const aafUID_t* auid);
const wchar_t*
const char*
aaft_InterpolationToText (const aafUID_t* auid);
const wchar_t*
const char*
aaft_ParameterToText (AAF_Data* aafd, const aafUID_t* auid);
const wchar_t*
const char*
aaft_TransferCharacteristicToText (const aafUID_t* auid);
const wchar_t*
const char*
aaft_CodingEquationsToText (const aafUID_t* auid);
const wchar_t*
const char*
aaft_ColorPrimariesToText (const aafUID_t* auid);
const wchar_t*
const char*
aaft_UsageCodeToText (const aafUID_t* auid);
const wchar_t*
const char*
aaft_PIDToText (AAF_Data* aafd, aafPID_t pid);
const wchar_t*
const char*
aaft_ClassIDToText (AAF_Data* aafd, const aafUID_t* auid);
const wchar_t*
const char*
aaft_ContainerToText (const aafUID_t* auid);
const wchar_t*
const char*
aaft_IndirectValueToText (AAF_Data* aafd, aafIndirect_t* Indirect);
const char*
aaft_CompressionToText (const aafUID_t* auid);
#endif // !__AAFToText_h__

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2017-2023 Adrien Gesta-Fline
* Copyright (C) 2017-2024 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
@ -184,6 +184,8 @@ typedef struct _aafUID_t {
static const aafUID_t AUID_NULL = { 0x00000000, 0x0000, 0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
static const aafUID_t AAFUID_NULL = { 0x00000000, 0x0000, 0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
typedef struct _aafMobID_t {
uint8_t SMPTELabel[12]; // 12-bytes of label prefix
uint8_t length;
@ -194,6 +196,8 @@ typedef struct _aafMobID_t {
} aafMobID_t; // 32 bytes total
static const aafMobID_t AAFMOBID_NULL = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x00, 0x00, 0x00, 0x00, { 0x00000000, 0x0000, 0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } };
typedef struct _aafIndirect_t {
/*
* byteOrder disabled for memory alignement and to avoid -Waddress-of-packed-member
@ -367,8 +371,6 @@ typedef struct _aafRGBAComponent_t {
//typedef aafRGBAComponent_t aafRGBALayout[8];
static const aafUID_t AAFUID_NULL = { 0x00000000, 0x0000, 0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
/**
* This structure map the first bytes in a **properties** stream
* node.

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2017-2023 Adrien Gesta-Fline
* Copyright (C) 2017-2024 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
@ -21,36 +21,33 @@
#ifndef __CFBDump_h__
#define __CFBDump_h__
#include <stdio.h>
#include <wchar.h>
#include "aaf/LibCFB.h"
void
cfb_dump_node (CFB_Data* cfbd, cfbNode* node, int print_stream);
cfb_dump_node (CFB_Data* cfbd, cfbNode* node, int print_stream, const char* padding);
void
cfb_dump_nodePath (CFB_Data* cfbd, const wchar_t* path, int print_stream);
cfb_dump_nodePath (CFB_Data* cfbd, const char* path, int print_stream, const char* padding);
void
cfb_dump_nodeStream (CFB_Data* cfbd, cfbNode* node);
cfb_dump_nodeStream (CFB_Data* cfbd, cfbNode* node, const char* padding);
void
cfb_dump_nodePathStream (CFB_Data* cfbd, const wchar_t* path);
cfb_dump_nodePathStream (CFB_Data* cfbd, const char* path, const char* padding);
void
cfb_dump_nodePaths (CFB_Data* cfbd, uint32_t prevPath, char* strArray[], uint32_t* str_i, cfbNode* node);
cfb_dump_nodePaths (CFB_Data* cfbd, uint32_t prevPath, char* strArray[], uint32_t* str_i, cfbNode* node, const char* padding, int firstIteration);
void
cfb_dump_header (CFB_Data* cfbd);
cfb_dump_header (CFB_Data* cfbd, const char* padding);
void
cfb_dump_FAT (CFB_Data* cfbd);
cfb_dump_FAT (CFB_Data* cfbd, const char* padding);
void
cfb_dump_MiniFAT (CFB_Data* cfbd);
cfb_dump_MiniFAT (CFB_Data* cfbd, const char* padding);
void
cfb_dump_DiFAT (CFB_Data* cfbd);
cfb_dump_DiFAT (CFB_Data* cfbd, const char* padding);
#endif // !__CFBDump_h__

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2017-2023 Adrien Gesta-Fline
* Copyright (C) 2017-2024 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
@ -22,18 +22,16 @@
#define __LibCFB_h__
#include <stdint.h>
#include <wchar.h>
#include <stdlib.h>
#include <string.h>
#include "aaf/debug.h"
#include "aaf/log.h"
#if defined(__linux__)
#include <limits.h>
#include <linux/limits.h>
#elif defined(__APPLE__)
#include <sys/syslimits.h>
#elif defined(_MSC_VER) // MSVC
#include <windows.h> // MAX_PATH
#include <limits.h>
#define PATH_MAX MAX_PATH // TODO: can we get rid of it ?
#elif defined(_WIN32)
#include <windows.h> // MAX_PATH
#include <limits.h>
@ -51,8 +49,6 @@
* @{
*/
#define CFB_W16TOWCHAR_STRLEN SIZE_MAX
/**
* Class Identifier structure.
*
@ -456,9 +452,6 @@ typedef struct StructuredStorageDirectoryEntry {
*
* A 64-byte array, for a maximum of 32 Unicode characters including a terminating
* Unicode NULL character. The string shall be padded with zeros to fill the array.
*
* Should be wchar_t, but on linux wchar_t is 32 bits wide as opposed to windows
* (and thus CFB) defining wchar_t to 16 bits. Conversion is done by cfb_w16towchar()
*/
uint16_t _ab[CFB_NODE_NAME_SZ];
@ -571,7 +564,7 @@ typedef struct CFB_Data {
* CFB file path.
*/
char file[PATH_MAX + 1];
char* file;
/**
* CFB file size.
@ -639,7 +632,7 @@ typedef struct CFB_Data {
cfbNode* nodes;
struct dbg* dbg;
struct aafLog* log;
} CFB_Data;
@ -657,7 +650,7 @@ typedef struct CFB_Data {
* @param id Index of the first sector in the Chain.
*/
#define cfb_foreachSectorInChain(cfbd, buf, id) \
#define CFB_foreachSectorInChain(cfbd, buf, id) \
for (buf = cfb_getSector (cfbd, id); \
id < CFB_MAX_REG_SECT && \
buf != NULL; \
@ -673,7 +666,7 @@ typedef struct CFB_Data {
* @param id Index of the first mini-sector in the Chain.
*/
#define cfb_foreachMiniSectorInChain(cfbd, buf, id) \
#define CFB_foreachMiniSectorInChain(cfbd, buf, id) \
for (buf = cfb_getMiniSector (cfbd, id); \
id < CFB_MAX_REG_SECT; \
id = cfbd->miniFat[id], \
@ -690,7 +683,7 @@ typedef struct CFB_Data {
* sector data.
*/
#define cfb_foreachSectorInDiFATChain(cfbd, buf, id) \
#define CFB_foreachSectorInDiFATChain(cfbd, buf, id) \
for (id = cfbd->hdr->_sectDifStart, \
buf = cfb_getSector (cfbd, id); \
id < CFB_MAX_REG_SECT; \
@ -705,7 +698,7 @@ typedef struct CFB_Data {
* @param id Index of each FAT sector.
*/
#define cfb_foreachFATSectorIDInDiFAT(cfbd, id) \
#define CFB_foreachFATSectorIDInDiFAT(cfbd, id) \
for (id = 0; \
id < cfbd->DiFAT_sz && \
id < cfbd->hdr->_csectFat; \
@ -716,21 +709,21 @@ typedef struct CFB_Data {
* When 512 bytes sectors we don't care about _ulSizeHigh.
*/
#define cfb_getNodeStreamLen(cfbd, node) \
#define CFB_getNodeStreamLen(cfbd, node) \
((cfbd->hdr->_uSectorShift > 9) ? (uint64_t) (((uint64_t) (node->_ulSizeHigh) << 32) | (node->_ulSizeLow)) : node->_ulSizeLow)
#define cfb_getStreamSectorShift(cfbd, node) \
((cfb_getNodeStreamLen (cfbd, node) < cfbd->hdr->_ulMiniSectorCutoff) ? cfbd->hdr->_uMiniSectorShift : cfbd->hdr->_uSectorShift)
#define CFB_getStreamSectorShift(cfbd, node) \
((CFB_getNodeStreamLen (cfbd, node) < cfbd->hdr->_ulMiniSectorCutoff) ? cfbd->hdr->_uMiniSectorShift : cfbd->hdr->_uSectorShift)
/*
* @}
*/
const wchar_t*
const char*
cfb_CLSIDToText (const cfbCLSID_t* clsid);
wchar_t*
cfb_w16towchar (wchar_t* buf, uint16_t* w16buf, size_t w16blen);
char*
cfb_w16toUTF8 (const uint16_t* w16buf, size_t w16blen);
/**
* @name Constructor function
@ -739,7 +732,7 @@ cfb_w16towchar (wchar_t* buf, uint16_t* w16buf, size_t w16blen);
*/
CFB_Data*
cfb_alloc (struct dbg* dbg);
cfb_alloc (struct aafLog* log);
/**
* @}
@ -783,7 +776,7 @@ cfb_getStream (CFB_Data* cfbd, cfbNode* node, unsigned char** stream, uint64_t*
int
cfb__foreachSectorInStream (CFB_Data* cfbd, cfbNode* node, unsigned char** buf, size_t* bytesRead, cfbSectorID_t* sectID);
#define cfb_foreachSectorInStream(cfbd, node, buf, bytesRead, sectID) \
#define CFB_foreachSectorInStream(cfbd, node, buf, bytesRead, sectID) \
while (cfb__foreachSectorInStream (cfbd, node, buf, bytesRead, sectID))
/**
@ -794,10 +787,10 @@ cfb__foreachSectorInStream (CFB_Data* cfbd, cfbNode* node, unsigned char** buf,
*/
cfbNode*
cfb_getNodeByPath (CFB_Data* cfbd, const wchar_t* name, cfbSID_t id);
cfb_getNodeByPath (CFB_Data* cfbd, const char* path, cfbSID_t id);
cfbNode*
cfb_getChildNode (CFB_Data* cfbd, const wchar_t* name, cfbNode* startNode);
cfb_getChildNode (CFB_Data* cfbd, const char* name, cfbNode* startNode);
/**
* @}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2017-2023 Adrien Gesta-Fline
* Copyright (C) 2024 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
@ -18,20 +18,16 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __AAFIAudioFiles_h__
#define __AAFIAudioFiles_h__
#include <wchar.h>
#ifndef __MediaComposer_h__
#define __MediaComposer_h__
#include "aaf/AAFIParser.h"
#include "aaf/AAFIface.h"
wchar_t*
aafi_locate_external_essence_file (AAF_Iface* aafi, const wchar_t* original_file_path, const char* search_location);
#define AVID_MEDIA_COMPOSER_CURVE_TYPE_LINEAR 0
#define AVID_MEDIA_COMPOSER_CURVE_TYPE_EQUAL_POWER 1
int
aafi_extract_audio_essence (AAF_Iface* aafi, aafiAudioEssence* audioEssence, const char* outfilepath, const wchar_t* forcedFileName);
mediaComposer_AAF (struct AAF_Iface* aafi);
int
aafi_parse_audio_essence (AAF_Iface* aafi, aafiAudioEssence* audioEssence);
#endif // !__AAFIAudioFiles_h__
#endif // !__MediaComposer_h__

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2017-2023 Adrien Gesta-Fline
* Copyright (C) 2017-2024 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
@ -25,11 +25,11 @@
#include "aaf/AAFIface.h"
enum protools_options {
PROTOOLS_REMOVE_SAMPLE_ACCURATE_EDIT = 1 << 0,
PROTOOLS_REPLACE_CLIP_FADES = 1 << 1,
AAFI_PROTOOLS_OPT_REMOVE_SAMPLE_ACCURATE_EDIT = 1 << 0,
AAFI_PROTOOLS_OPT_REPLACE_CLIP_FADES = 1 << 1,
};
#define PROTOOLS_ALL (PROTOOLS_REMOVE_SAMPLE_ACCURATE_EDIT | PROTOOLS_REPLACE_CLIP_FADES)
#define PROTOOLS_ALL_OPT (AAFI_PROTOOLS_OPT_REMOVE_SAMPLE_ACCURATE_EDIT | AAFI_PROTOOLS_OPT_REPLACE_CLIP_FADES)
int
protools_AAF (struct AAF_Iface* aafi);

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Adrien Gesta-Fline
* Copyright (C) 2023-2024 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
@ -21,7 +21,17 @@
#ifndef __RIFFParser__
#define __RIFFParser__
#include "aaf/debug.h"
#include "aaf/log.h"
#if defined(__linux__)
#include <limits.h>
#include <linux/limits.h>
#elif defined(__APPLE__)
#include <sys/syslimits.h>
#elif defined(_WIN32)
#include <windows.h> // MAX_PATH
#include <limits.h>
#endif
#ifdef __GNUC__
#define PACK(__Declaration__) __Declaration__ __attribute__ ((__packed__))
@ -31,6 +41,8 @@
#define PACK(__Declaration__) __pragma (pack (push, 1)) __Declaration__ __pragma (pack (pop))
#endif
#define RIFF_READER_ERROR SIZE_MAX
enum RIFF_PARSER_FLAGS {
RIFF_PARSE_ONLY_HEADER = (1 << 0),
RIFF_PARSE_AAF_SUMMARY = (1 << 1),
@ -42,6 +54,7 @@ struct RIFFAudioFile {
uint16_t sampleSize;
uint16_t channels;
uint64_t sampleCount; /* total samples for 1 channel (no matter channel count). (sampleCount / sampleRate) = duration in seconds */
size_t pcm_audio_start_offset;
};
PACK (struct riffHeaderChunk {
@ -60,7 +73,7 @@ PACK (struct riffChunk {
});
PACK (struct wavFmtChunk {
char ckid[4]; //'fmt '
char ckid[4]; /* 'fmt ' */
uint32_t cksz;
uint16_t format_tag;
@ -72,7 +85,7 @@ PACK (struct wavFmtChunk {
});
PACK (struct wavBextChunk {
char ckid[4]; //'bext'
char ckid[4]; /* 'bext' */
uint32_t cksz;
char description[256];
@ -114,7 +127,7 @@ PACK (struct wavBextChunk {
});
PACK (struct aiffCOMMChunk {
char ckid[4]; //'COMM'
char ckid[4]; /* 'COMM' */
uint32_t cksz;
uint16_t numChannels;
@ -123,10 +136,18 @@ PACK (struct aiffCOMMChunk {
unsigned char sampleRate[10]; // 80 bit IEEE Standard 754 floating point number
});
int
riff_parseAudioFile (struct RIFFAudioFile* RIFFAudioFile, enum RIFF_PARSER_FLAGS flags, size_t (*readerCallback) (unsigned char*, size_t, size_t, void*, void*, void*), void* user1, void* user2, void* user3, struct dbg* dbg);
PACK (struct aiffSSNDChunk {
char ckid[4]; /* 'SSND' */
uint32_t cksz;
uint32_t offset;
uint32_t blockSize;
});
int
riff_writeWavFileHeader (FILE* fp, struct wavFmtChunk* wavFmt, struct wavBextChunk* wavBext, uint32_t audioDataSize, struct dbg* dbg);
laaf_riff_parseAudioFile (struct RIFFAudioFile* RIFFAudioFile, enum RIFF_PARSER_FLAGS flags, size_t (*readerCallback) (unsigned char*, size_t, size_t, void*, void*, void*), void* user1, void* user2, void* user3, struct aafLog* log);
int
laaf_riff_writeWavFileHeader (FILE* fp, struct wavFmtChunk* wavFmt, struct wavBextChunk* wavBext, uint32_t audioDataSize, struct aafLog* log);
#endif // ! __RIFFParser__

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Adrien Gesta-Fline
* Copyright (C) 2023-2024 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
@ -24,19 +24,7 @@
#include "aaf/AAFIParser.h"
#include "aaf/AAFIface.h"
enum resolve_options {
RESOLVE_INCLUDE_DISABLED_CLIPS = 1 << 0,
};
#define RESOLVE_ALL (RESOLVE_INCLUDE_DISABLED_CLIPS)
int
resolve_AAF (struct AAF_Iface* aafi);
int
resolve_parse_aafObject_Selector (struct AAF_Iface* aafi, aafObject* Selector, td* __ptd);
int
resolve_parse_aafObject_DescriptiveMarker (struct AAF_Iface* aafi, aafObject* DescriptiveMarker, td* __ptd);
#endif // !__Resolve_h__

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Adrien Gesta-Fline
* Copyright (C) 2023-2024 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
@ -21,7 +21,17 @@
#ifndef URI_PARSER_H
#define URI_PARSER_H
#include "aaf/debug.h"
#include "aaf/log.h"
#if defined(__linux__)
#include <limits.h>
#include <linux/limits.h>
#elif defined(__APPLE__)
#include <sys/syslimits.h>
#elif defined(_WIN32)
#include <windows.h> // MAX_PATH
#include <limits.h>
#endif
#define MAX_URI_LENGTH 64000
@ -118,25 +128,9 @@ struct uri {
};
struct uri*
uriParse (const char*, enum uri_option, struct dbg* dbg);
laaf_uri_parse (const char*, enum uri_option, struct aafLog* log);
void
uriFree (struct uri*);
/*
* if dst is NULL of equals src, then encoded source string will be overwritten
* by decoded string.
*/
char*
uriDecodeString (char* src, char* dst);
char*
uriDecodeWString (wchar_t* src, wchar_t* dst);
int
uriIsIPv4 (const char* s, int size, char** err);
int
uriIsIPv6 (const char* s, int size, char** err);
laaf_uri_free (struct uri*);
#endif // ! URI_PARSER_H

View File

@ -1,116 +0,0 @@
/*
* Copyright (C) 2017-2023 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __debug_h__
#define __debug_h__
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "aaf/utils.h"
#define __FILENAME__ (strrchr (__FILE__, '/') ? strrchr (__FILE__, '/') + 1 : __FILE__)
enum debug_source_id {
DEBUG_SRC_ID_LIB_CFB,
DEBUG_SRC_ID_AAF_CORE,
DEBUG_SRC_ID_AAF_IFACE,
DEBUG_SRC_ID_TRACE,
DEBUG_SRC_ID_DUMP
};
typedef enum verbosityLevel_e {
VERB_QUIET = 0,
VERB_ERROR,
VERB_WARNING,
VERB_DEBUG,
MAX_VERB
} verbosityLevel_e;
struct dbg {
void (*debug_callback) (struct dbg* dbg, void* ctxdata, int lib, int type, const char* srcfile, const char* srcfunc, int lineno, const char* msg, void* user);
FILE* fp;
verbosityLevel_e verb;
int ansicolor;
char* _dbg_msg;
int _dbg_msg_size;
int _dbg_msg_pos;
char* _dbg_msg_tmp;
int _dbg_msg_pos_tmp;
void* user;
};
#define _dbg(dbg, ctxdata, lib, type, ...) \
{ \
const char* dbgfile = __FILENAME__; \
const char* dbgfunc = __func__; \
int dbgline = __LINE__; \
if (dbg && dbg->verb >= type && dbg->debug_callback) { \
if (dbg->_dbg_msg_pos) { \
dbg->_dbg_msg_pos_tmp = dbg->_dbg_msg_pos; \
dbg->_dbg_msg_tmp = laaf_util_c99strdup (dbg->_dbg_msg); \
} \
int msgsize = snprintf (NULL, 0, __VA_ARGS__) + 1; \
if (msgsize >= dbg->_dbg_msg_size) { \
char* msgtmp = realloc (dbg->_dbg_msg, msgsize); \
if (msgtmp) { \
dbg->_dbg_msg = msgtmp; \
dbg->_dbg_msg_size = msgsize; \
snprintf (dbg->_dbg_msg, dbg->_dbg_msg_size, __VA_ARGS__); \
dbg->debug_callback (dbg, (void*)ctxdata, lib, type, dbgfile, dbgfunc, dbgline, dbg->_dbg_msg, dbg->user); \
} else { \
/* realloc() error */ \
} \
} else { \
snprintf (dbg->_dbg_msg, dbg->_dbg_msg_size, __VA_ARGS__); \
dbg->debug_callback (dbg, (void*)ctxdata, lib, type, dbgfile, dbgfunc, dbgline, dbg->_dbg_msg, dbg->user); \
} \
if (dbg->_dbg_msg_pos_tmp) { \
dbg->_dbg_msg_pos = dbg->_dbg_msg_pos_tmp; \
strcpy (dbg->_dbg_msg, dbg->_dbg_msg_tmp); \
free (dbg->_dbg_msg_tmp); \
dbg->_dbg_msg_tmp = NULL; \
dbg->_dbg_msg_pos_tmp = 0; \
} \
} \
}
#define DBG_BUFFER_WRITE(dbg, ...) \
dbg->_dbg_msg_pos += laaf_util_snprintf_realloc (&dbg->_dbg_msg, &dbg->_dbg_msg_size, dbg->_dbg_msg_pos, __VA_ARGS__);
#define DBG_BUFFER_RESET(dbg) \
dbg->_dbg_msg_pos = 0;
struct dbg*
laaf_new_debug (void);
void
laaf_free_debug (struct dbg* dbg);
void
laaf_debug_callback (struct dbg* dbg, void* ctxdata, int lib, int type, const char* srcfile, const char* srcfunc, int lineno, const char* msg, void* user);
#endif // !__debug_h__

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2017-2023 Adrien Gesta-Fline
* Copyright (C) 2017-2024 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
@ -28,13 +28,14 @@ extern "C" {
#include "aaf/version.h"
#include "aaf/AAFCore.h"
#include "aaf/AAFIAudioFiles.h"
#include "aaf/AAFIEssenceFile.h"
#include "aaf/AAFIface.h"
#include "aaf/LibCFB.h"
#include "aaf/AAFDump.h"
#include "aaf/CFBDump.h"
#include "aaf/MediaComposer.h"
#include "aaf/ProTools.h"
#include "aaf/Resolve.h"

94
libs/aaf/aaf/log.h Normal file
View File

@ -0,0 +1,94 @@
/*
* Copyright (C) 2017-2024 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef laaf_log_h__
#define laaf_log_h__
#include <errno.h>
#include <inttypes.h> // PRIi64 PRIu64
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define __FILENAME__ (strrchr (__FILE__, '/') ? strrchr (__FILE__, '/') + 1 : __FILE__)
enum debug_source_id {
DEBUG_SRC_ID_LIB_CFB,
DEBUG_SRC_ID_AAF_CORE,
DEBUG_SRC_ID_AAF_IFACE,
DEBUG_SRC_ID_TRACE,
DEBUG_SRC_ID_DUMP
};
typedef enum verbosityLevel_e {
VERB_QUIET = 0,
VERB_ERROR,
VERB_WARNING,
VERB_DEBUG,
MAX_VERB
} verbosityLevel_e;
#define VERB_SUCCESS 99
struct aafLog {
void (*debug_callback) (struct aafLog* log, void* ctxdata, int lib, int type, const char* srcfile, const char* srcfunc, int lineno, const char* msg, void* user);
FILE* fp;
verbosityLevel_e verb;
int ansicolor;
const char* color_reset;
char* _msg;
size_t _msg_size;
size_t _msg_pos;
char* _previous_msg;
size_t _previous_pos;
int _tmp_dbg_msg_pos;
void* user;
};
#define AAF_LOG(log, ctxdata, lib, type, ...) \
laaf_write_log (log, ctxdata, lib, type, __FILENAME__, __func__, __LINE__, __VA_ARGS__)
#define LOG_BUFFER_WRITE(log, ...) \
log->_tmp_dbg_msg_pos = laaf_util_snprintf_realloc (&log->_msg, &log->_msg_size, log->_msg_pos, __VA_ARGS__); \
log->_msg_pos += (log->_tmp_dbg_msg_pos < 0) ? 0 : (size_t)log->_tmp_dbg_msg_pos;
#define DBG_BUFFER_RESET(log) \
log->_msg_pos = 0;
struct aafLog*
laaf_new_log (void);
void
laaf_free_log (struct aafLog* log);
void
laaf_log_callback (struct aafLog* log, void* ctxdata, int lib, int type, const char* srcfile, const char* srcfunc, int lineno, const char* msg, void* user);
void
laaf_write_log (struct aafLog* log, void* ctxdata, enum debug_source_id lib, enum verbosityLevel_e type, const char* dbgfile, const char* dbgfunc, int dbgline, const char* format, ...);
#endif // !laaf_log_h__

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2017-2023 Adrien Gesta-Fline
* Copyright (C) 2017-2024 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
@ -21,10 +21,11 @@
#ifndef __utils_h__
#define __utils_h__
#include "aaf/AAFTypes.h"
#include <stdarg.h>
#include <stdint.h>
#include "aaf/AAFTypes.h"
#ifdef __cplusplus
extern "C" {
#endif
@ -32,76 +33,89 @@ extern "C" {
#ifdef _WIN32
#define DIR_SEP '\\'
#define DIR_SEP_STR "\\"
/*
* swprintf() specific string format identifiers
* https://learn.microsoft.com/en-us/cpp/c-runtime-library/format-specification-syntax-printf-and-wprintf-functions?view=msvc-170#type
*/
#define WPRIs L"S" // char*
#ifdef XBUILD_WIN
#define WPRIws L"s" // wchar_t*
#else
#define WPRIws L"ls" // wchar_t*
#endif
#else
#define DIR_SEP '/'
#define DIR_SEP_STR "/"
/*
* swprintf() specific string format identifiers
* https://learn.microsoft.com/en-us/cpp/c-runtime-library/format-specification-syntax-printf-and-wprintf-functions?view=msvc-170#type
*/
#define WPRIs L"s" // char*
#define WPRIws L"ls" // wchar_t*
#endif
#if defined(__linux__)
#include <limits.h>
#include <linux/limits.h>
#elif defined(__APPLE__)
#include <sys/syslimits.h>
#elif defined(_WIN32)
#include <windows.h> // MAX_PATH
#include <limits.h>
#include <wchar.h>
#endif
#define AAF_DIR_SEP '/'
#define AAF_DIR_SEP_STR "/"
#define IS_DIR_SEP(c) \
((((c) == DIR_SEP) || ((c) == '/')))
#define ANSI_COLOR_RED(dbg) (((dbg)->ansicolor) ? "\033[38;5;124m" : "") //"\x1b[31m"
#define ANSI_COLOR_GREEN(dbg) (((dbg)->ansicolor) ? "\x1b[92m" : "")
#define ANSI_COLOR_YELLOW(dbg) (((dbg)->ansicolor) ? "\x1b[33m" : "") //"\x1b[93m"
#define ANSI_COLOR_ORANGE(dbg) (((dbg)->ansicolor) ? "\033[38;5;130m" : "")
#define ANSI_COLOR_BLUE(dbg) (((dbg)->ansicolor) ? "\x1b[34m" : "")
#define ANSI_COLOR_MAGENTA(dbg) (((dbg)->ansicolor) ? "\x1b[35m" : "")
#define ANSI_COLOR_CYAN(dbg) (((dbg)->ansicolor) ? "\033[38;5;81m" : "") //"\x1b[36m"
#define ANSI_COLOR_DARKGREY(dbg) (((dbg)->ansicolor) ? "\x1b[38;5;242m" : "")
#define ANSI_COLOR_BOLD(dbg) (((dbg)->ansicolor) ? "\x1b[1m" : "")
#define ANSI_COLOR_RESET(dbg) (((dbg)->ansicolor) ? "\x1b[0m" : "")
#define IS_ANY_DIR_SEP(c) \
((((c) == '/') || ((c) == '\\')))
aafPosition_t
laaf_util_converUnit (aafPosition_t value, aafRational_t* valueEditRate, aafRational_t* destEditRate);
#define ANSI_COLOR_RED(log) (((log)->ansicolor) ? "\x1b[38;5;124m" : "")
#define ANSI_COLOR_GREEN(log) (((log)->ansicolor) ? "\x1b[92m" : "")
#define ANSI_COLOR_YELLOW(log) (((log)->ansicolor) ? "\x1b[33m" : "")
#define ANSI_COLOR_ORANGE(log) (((log)->ansicolor) ? "\x1b[38;5;130m" : "")
#define ANSI_COLOR_BLUE(log) (((log)->ansicolor) ? "\x1b[34m" : "")
#define ANSI_COLOR_MAGENTA(log) (((log)->ansicolor) ? "\x1b[35m" : "")
#define ANSI_COLOR_CYAN(log) (((log)->ansicolor) ? "\x1b[38;5;81m" : "")
#define ANSI_COLOR_DARKGREY(log) (((log)->ansicolor) ? "\x1b[38;5;242m" : "")
#define ANSI_COLOR_BOLD(log) (((log)->ansicolor) ? "\x1b[1m" : "")
#define ANSI_COLOR_RESET(log) (((log)->ansicolor) ? (log->color_reset) ? log->color_reset : "\x1b[0m" : "")
#define TREE_LINE "\xe2\x94\x82" /* │ */
#define TREE_PADDED_LINE "\xe2\x94\x82\x20\x20" /* │ */
#define TREE_ENTRY "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80" /* ├── */
#define TREE_LAST_ENTRY "\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80" /* └── */
size_t
laaf_util_utf8strCharLen (const char* u8str);
char*
laaf_util_wstr2str (const wchar_t* wstr);
laaf_util_utf16Toutf8 (const uint16_t* u16str);
#ifdef _WIN32
wchar_t*
laaf_util_str2wstr (const char* str);
laaf_util_windows_utf8toutf16 (const char* str);
char*
laaf_util_windows_utf16toutf8 (const wchar_t* wstr);
#endif
int
laaf_util_wstr_contains_nonlatin (const wchar_t* str);
laaf_util_file_exists (const char* filepath);
char*
laaf_util_clean_filename (char* filename);
const char*
laaf_util_fop_get_file (const char* filepath);
int
laaf_util_fop_is_wstr_fileext (const wchar_t* filepath, const wchar_t* ext);
laaf_util_is_fileext (const char* filepath, const char* ext);
char*
laaf_util_build_path (const char* sep, const char* first, ...);
int
laaf_util_snprintf_realloc (char** str, int* size, size_t offset, const char* format, ...);
char*
laaf_util_relative_path (const char* filepath, const char* refpath);
int
laaf_util_vsnprintf_realloc (char** str, int* size, int offset, const char* fmt, va_list* args);
char*
laaf_util_absolute_path (const char* relpath);
char*
laaf_util_c99strdup (const char* src);
int
laaf_util_dump_hex (const unsigned char* stream, size_t stream_sz, char** buf, int* bufsz, int offset);
laaf_util_snprintf_realloc (char** str, size_t* size, size_t offset, const char* format, ...);
int
laaf_util_vsnprintf_realloc (char** str, size_t* size, size_t offset, const char* fmt, va_list args);
int
laaf_util_dump_hex (const unsigned char* stream, size_t stream_sz, char** buf, size_t* bufsz, size_t offset, const char* padding);
#ifdef __cplusplus
}

View File

@ -1,2 +1,2 @@
#pragma once
#define LIBAAF_VERSION "v0.6-45-g9171e40"
#define LIBAAF_VERSION "v1.0-1-gdef35bf"

View File

@ -1,102 +0,0 @@
#include <stdio.h>
#include "aaf/debug.h"
#include "aaf/AAFCore.h"
#include "aaf/AAFIParser.h"
#include "aaf/AAFIface.h"
#include "aaf/LibCFB.h"
#include "aaf/utils.h"
struct dbg*
laaf_new_debug (void)
{
struct dbg* dbg = calloc (sizeof (struct dbg), sizeof (char));
dbg->debug_callback = &laaf_debug_callback;
dbg->fp = stdout;
dbg->ansicolor = 0;
return dbg;
}
void
laaf_free_debug (struct dbg* dbg)
{
if (dbg->_dbg_msg) {
free (dbg->_dbg_msg);
}
free (dbg);
}
void
laaf_debug_callback (struct dbg* dbg, void* ctxdata, int libid, int type, const char* srcfile, const char* srcfunc, int lineno, const char* msg, void* user)
{
AAF_Iface* aafi = NULL;
AAF_Data* aafd = NULL;
CFB_Data* cfbd = NULL;
const char* lib = "";
const char* typestr = "";
const char* color = "";
if (dbg->fp == NULL) {
DBG_BUFFER_RESET (dbg);
return;
}
switch (libid) {
case DEBUG_SRC_ID_LIB_CFB:
lib = "libCFB";
aafi = (AAF_Iface*)ctxdata;
break;
case DEBUG_SRC_ID_AAF_CORE:
lib = "AAFCore";
aafd = (AAF_Data*)ctxdata;
break;
case DEBUG_SRC_ID_AAF_IFACE:
lib = "AAFIface";
cfbd = (CFB_Data*)ctxdata;
break;
case DEBUG_SRC_ID_TRACE:
lib = "trace";
aafi = (AAF_Iface*)ctxdata;
break;
case DEBUG_SRC_ID_DUMP:
lib = "dump";
break;
}
switch (type) {
case VERB_ERROR:
typestr = " error ";
color = ANSI_COLOR_RED (dbg);
break;
case VERB_WARNING:
typestr = "warning";
color = ANSI_COLOR_YELLOW (dbg);
break;
case VERB_DEBUG:
typestr = " debug ";
color = ANSI_COLOR_DARKGREY (dbg);
break;
}
if (libid != DEBUG_SRC_ID_TRACE && libid != DEBUG_SRC_ID_DUMP) {
fprintf (dbg->fp, "[%s%s%s] ", color, typestr, ANSI_COLOR_RESET (dbg));
fprintf (dbg->fp, "%s%s:%i in %s()%s : ", ANSI_COLOR_DARKGREY (dbg), srcfile, lineno, srcfunc, ANSI_COLOR_RESET (dbg));
}
fprintf (dbg->fp, "%s\n", msg);
DBG_BUFFER_RESET (dbg);
/* avoids -Wunused-parameter -Wunused-but-set-variable */
(void)aafi;
(void)aafd;
(void)cfbd;
(void)lib;
(void)user;
}

289
libs/aaf/log.c Normal file
View File

@ -0,0 +1,289 @@
/*
* Copyright (C) 2017-2024 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <stdio.h>
#ifdef _WIN32
#include <windows.h>
#include <io.h>
#include <fcntl.h>
#endif
#include "aaf/AAFCore.h"
#include "aaf/AAFIParser.h"
#include "aaf/AAFIface.h"
#include "aaf/LibCFB.h"
#include "aaf/log.h"
#include "aaf/utils.h"
/*
* swprintf() specific string format identifiers
* https://learn.microsoft.com/en-us/cpp/c-runtime-library/format-specification-syntax-printf-and-wprintf-functions?view=msvc-170#size-prefixes-for-printf-and-wprintf-format-type-specifiers
*/
#ifdef __MINGW32__
#define WPRIws L"ls" // wchar_t*
#define WPRIs L"s" // char*
#else
#define WPRIws L"ls" // wchar_t*
#define WPRIs L"S" // char*
#endif
struct aafLog*
laaf_new_log (void)
{
struct aafLog* log = calloc (1, sizeof (struct aafLog));
if (!log) {
return NULL;
}
log->debug_callback = &laaf_log_callback;
log->fp = stdout;
log->ansicolor = 0;
return log;
}
void
laaf_free_log (struct aafLog* log)
{
if (!log) {
return;
}
free (log->_msg);
free (log);
}
void
laaf_log_callback (struct aafLog* log, void* ctxdata, int libid, int type, const char* srcfile, const char* srcfunc, int lineno, const char* msg, void* user)
{
AAF_Iface* aafi = NULL;
AAF_Data* aafd = NULL;
CFB_Data* cfbd = NULL;
const char* lib = "";
const char* typestr = "";
const char* color = "";
if (log->fp == NULL) {
DBG_BUFFER_RESET (log);
return;
}
switch (libid) {
case DEBUG_SRC_ID_LIB_CFB:
lib = "libCFB";
aafi = (AAF_Iface*)ctxdata;
break;
case DEBUG_SRC_ID_AAF_CORE:
lib = "AAFCore";
aafd = (AAF_Data*)ctxdata;
break;
case DEBUG_SRC_ID_AAF_IFACE:
lib = "AAFIface";
cfbd = (CFB_Data*)ctxdata;
break;
case DEBUG_SRC_ID_TRACE:
lib = "trace";
aafi = (AAF_Iface*)ctxdata;
break;
case DEBUG_SRC_ID_DUMP:
lib = "dump";
break;
}
switch (type) {
case VERB_SUCCESS:
typestr = "success";
color = ANSI_COLOR_GREEN (log);
break;
case VERB_ERROR:
typestr = " error ";
color = ANSI_COLOR_RED (log);
break;
case VERB_WARNING:
typestr = "warning";
color = ANSI_COLOR_YELLOW (log);
break;
case VERB_DEBUG:
typestr = " debug ";
color = ANSI_COLOR_DARKGREY (log);
break;
}
const char* eol = "";
if (libid != DEBUG_SRC_ID_TRACE && libid != DEBUG_SRC_ID_DUMP) {
#ifdef __MINGW32__
fwprintf (log->fp, L"[%" WPRIs "%" WPRIs "%" WPRIs "] %" WPRIs "%" WPRIs ":%i in %" WPRIs "()%" WPRIs " : ",
color,
typestr,
ANSI_COLOR_RESET (log),
ANSI_COLOR_DARKGREY (log),
srcfile,
lineno,
srcfunc,
ANSI_COLOR_RESET (log));
#else
fprintf (log->fp, "[%s%s%s] %s%s:%i in %s()%s : ",
color,
typestr,
ANSI_COLOR_RESET (log),
ANSI_COLOR_DARKGREY (log),
srcfile,
lineno,
srcfunc,
ANSI_COLOR_RESET (log));
#endif
}
if (libid != DEBUG_SRC_ID_DUMP) {
eol = "\n";
}
#ifdef __MINGW32__
wchar_t* tmp = laaf_util_windows_utf8toutf16 (msg);
if (!tmp) {
return;
}
fwprintf (log->fp, L"%" WPRIws "%s", tmp, eol);
free (tmp);
#else
fprintf (log->fp, "%s%s", msg, eol);
#endif
fflush (log->fp);
DBG_BUFFER_RESET (log);
/* avoids -Wunused-parameter -Wunused-but-set-variable */
(void)aafi;
(void)aafd;
(void)cfbd;
(void)lib;
(void)user;
}
void
laaf_write_log (struct aafLog* log, void* ctxdata, enum debug_source_id lib, enum verbosityLevel_e type, const char* dbgfile, const char* dbgfunc, int dbgline, const char* format, ...)
{
if (!log) {
return;
}
if (!log->debug_callback) {
return;
}
if (type != VERB_SUCCESS && (log->verb == VERB_QUIET || type > log->verb)) {
return;
}
va_list ap;
int rc = 0;
size_t msgsize = 0;
va_start (ap, format);
#ifdef _WIN32
/* https://stackoverflow.com/a/4116308 */
FILE* dummy = fopen ("NUL", "wb");
if (!dummy) {
// fprintf( stderr, "Could not fopen() dummy null file\n" );
return;
}
rc = vfprintf (dummy, format, ap);
fclose (dummy);
if (rc < 0) {
// fprintf( stderr, "vfwprintf() error : %s\n", strerror(errno) );
va_end (ap);
return;
}
rc++;
rc *= (int)sizeof (wchar_t);
#else
rc = vsnprintf (NULL, 0, format, ap);
if (rc < 0) {
// fprintf( stderr, "vsnprintf() error : %s\n", strerror(errno) );
va_end (ap);
return;
}
rc++;
#endif
va_end (ap);
msgsize = (size_t)rc;
if (log->_msg_pos) {
log->_previous_pos = log->_msg_pos;
log->_previous_msg = laaf_util_c99strdup (log->_msg);
if (!log->_previous_msg) {
// fprintf( stderr, "Out of memory\n" );
return;
}
}
va_start (ap, format);
if (msgsize >= log->_msg_size) {
char* msgtmp = realloc (log->_msg, (msgsize * sizeof (char)));
if (!msgtmp) {
// fprintf( stderr, "Out of memory\n" );
va_end (ap);
return;
}
log->_msg = msgtmp;
log->_msg_size = msgsize;
}
rc = vsnprintf (log->_msg, log->_msg_size, format, ap);
if (rc < 0 || (size_t)rc >= log->_msg_size) {
// fprintf( stderr, "vsnprintf() error\n" );
va_end (ap);
return;
}
log->debug_callback (log, (void*)ctxdata, lib, type, dbgfile, dbgfunc, dbgline, log->_msg, log->user);
va_end (ap);
if (log->_previous_pos) {
log->_msg_pos = log->_previous_pos;
strcpy (log->_msg, log->_previous_msg);
free (log->_previous_msg);
log->_previous_msg = NULL;
log->_previous_pos = 0;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2017-2023 Adrien Gesta-Fline
* Copyright (C) 2017-2024 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
@ -18,104 +18,107 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#if defined(__linux__)
#include <linux/limits.h>
#include <arpa/inet.h>
#include <mntent.h>
#include <unistd.h> /* access() */
#elif defined(__APPLE__)
#include <sys/syslimits.h>
#include <unistd.h> /* access() */
#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
#include <limits.h>
#define R_OK 4 /* Test for read permission. */
#define W_OK 2 /* Test for write permission. */
#define F_OK 0 /* Test for existence. */
#ifndef _MSC_VER
#include <unistd.h> // access()
#endif
#endif
#include "aaf/utils.h"
#define BUILD_PATH_DEFAULT_BUF_SIZE 1024
aafPosition_t
laaf_util_converUnit (aafPosition_t value, aafRational_t* valueEditRate, aafRational_t* destEditRate)
static int
utf8CodeLen (const uint16_t* u16Code);
static int
utf16CodeLen (const uint16_t* u16Code);
static int
utf16CodeToUTF8 (const uint16_t* u16Code, char* u8Code, int* u16Len, int* u8Len);
static long
utf8strLen (const uint16_t* u16str);
#ifdef _WIN32
wchar_t*
laaf_util_windows_utf8toutf16 (const char* str)
{
if (!valueEditRate || !destEditRate) {
return value;
if (!str) {
return NULL;
}
if (valueEditRate->numerator == destEditRate->numerator &&
valueEditRate->denominator == destEditRate->denominator) {
/* same rate, no conversion */
return value;
int needed = MultiByteToWideChar (CP_UTF8, 0, str, -1, NULL, 0);
if (needed == 0) {
return NULL;
}
double valueEditRateFloat = ((valueEditRate->denominator == 0) ? 0.0 : ((float)valueEditRate->numerator / valueEditRate->denominator));
double destEditRateFloat = ((destEditRate->denominator == 0) ? 0.0 : ((float)destEditRate->numerator / destEditRate->denominator));
wchar_t* wbuf = malloc ((size_t)needed * sizeof (wchar_t));
if (valueEditRateFloat == 0) {
return 0;
if (!wbuf) {
return NULL;
}
return value * (destEditRateFloat / valueEditRateFloat);
int rc = MultiByteToWideChar (CP_UTF8, 0, str, -1, wbuf, needed);
if (rc == 0) {
free (wbuf);
return NULL;
}
return wbuf;
}
char*
laaf_util_wstr2str (const wchar_t* wstr)
laaf_util_windows_utf16toutf8 (const wchar_t* wstr)
{
if (wstr == NULL) {
if (!wstr) {
return NULL;
}
size_t strsz = wcslen (wstr) + 1;
char* str = malloc (strsz);
int needed = WideCharToMultiByte (CP_UTF8, 0, wstr, -1, NULL, 0, 0, 0);
if (str == NULL) {
// error( "Could not allocate memory : %s", strerror(errno) );
if (needed == 0) {
return NULL;
}
int rc = snprintf (str, strsz, "%ls", wstr);
char* buf = malloc ((size_t)needed * sizeof (char));
if (rc < 0 || (unsigned)rc >= strsz) {
// error( "Failed converting wide char str to byte char str%s", (reqlen < 0) ? " : encoding error" : "" );
free (str);
if (!buf) {
return NULL;
}
return str;
int rc = WideCharToMultiByte (CP_UTF8, 0, wstr, -1, buf, needed, 0, 0);
if (rc == 0) {
free (buf);
return NULL;
}
return buf;
}
wchar_t*
laaf_util_str2wstr (const char* str)
{
if (str == NULL) {
return NULL;
}
size_t strsz = strlen (str) + 1;
wchar_t* wstr = malloc (strsz * sizeof (wchar_t));
if (str == NULL) {
// error( "Could not allocate memory : %s", strerror(errno) );
return NULL;
}
int rc = swprintf (wstr, strsz, L"%" WPRIs, str);
if (rc < 0 || (unsigned)rc >= strsz) {
// error( "Failed converting byte char str to wide char str%s", (reqlen < 0) ? " : encoding error" : "" );
free (wstr);
return NULL;
}
return wstr;
}
int
laaf_util_wstr_contains_nonlatin (const wchar_t* str)
{
for (size_t i = 0; str[i] != 0x0000; i++) {
/* if char is out of the Basic Latin range */
if (str[i] > 0xff) {
return 1;
}
}
return 0;
}
#endif
char*
laaf_util_clean_filename (char* fname)
@ -124,62 +127,52 @@ laaf_util_clean_filename (char* fname)
* sanitize file/dir name
* https://stackoverflow.com/a/31976060
*/
size_t len = strlen (fname);
if (!fname) {
return NULL;
}
for (size_t i = 0; i < len; i++) {
unsigned char c = fname[i];
char* p = fname;
if (c == '/' ||
c == '<' ||
c == '>' ||
c == ':' ||
c == '"' ||
c == '|' ||
c == '?' ||
c == '*' ||
c == '\\' ||
(c > 0 && c < 0x20)) {
fname[i] = '_';
while (*p) {
if (*p == '/' ||
*p == '<' ||
*p == '>' ||
*p == ':' ||
*p == '"' ||
*p == '|' ||
*p == '?' ||
*p == '*' ||
*p == '\\' ||
(*p > 0 && *p < 0x20)) {
*p = '_';
}
p++;
}
/* windows filenames can't end with ' ' or '.' */
for (int i = len - 1; i > 0; i--) {
char c = fname[i];
if (c != ' ' && c != '.') {
break;
}
fname[i] = '_';
p = fname + strlen (fname) - 1;
while (*p && (*p == ' ' || *p == '.')) {
*p = '\0';
p--;
}
if (*fname == '\0')
return NULL;
return fname;
}
const char*
laaf_util_fop_get_file (const char* filepath)
{
if (filepath == NULL) {
return NULL;
}
const char* end = filepath + strlen (filepath);
while (end > filepath && !IS_DIR_SEP (*end)) {
--end;
}
return (IS_DIR_SEP (*end)) ? end + 1 : end;
}
int
laaf_util_fop_is_wstr_fileext (const wchar_t* filepath, const wchar_t* ext)
laaf_util_is_fileext (const char* filepath, const char* ext)
{
if (filepath == NULL) {
if (!filepath || !ext) {
return 0;
}
const wchar_t* end = filepath + wcslen (filepath);
size_t extlen = 0;
const char* end = filepath + strlen (filepath);
size_t extlen = 0;
while (end > filepath && (*end) != '.') {
--end;
@ -191,14 +184,11 @@ laaf_util_fop_is_wstr_fileext (const wchar_t* filepath, const wchar_t* ext)
extlen--;
}
if (extlen != wcslen (ext)) {
if (!extlen || extlen != strlen (ext)) {
return 0;
}
// printf(" end: %ls ext: %ls\n", end, ext );
for (size_t i = 0; i < extlen; i++) {
// printf("end: %c != %c\n", *(end+i), *(ext+i));
if (tolower (*(end + i)) != tolower (*(ext + i))) {
return 0;
}
@ -212,7 +202,7 @@ laaf_util_build_path (const char* sep, const char* first, ...)
{
char* str = malloc (BUILD_PATH_DEFAULT_BUF_SIZE);
if (str == NULL) {
if (!str) {
return NULL;
}
@ -232,13 +222,13 @@ laaf_util_build_path (const char* sep, const char* first, ...)
const char* arg = first;
do {
int arglen = strlen (arg);
int argstart = 0;
int has_leading_sep = 0;
size_t arglen = strlen (arg);
size_t argstart = 0;
int has_leading_sep = 0;
/* trim leading DIR_SEP */
for (int i = 0; arg[i] != 0x00; i++) {
if (IS_DIR_SEP (arg[i])) {
if (IS_ANY_DIR_SEP (arg[i])) {
has_leading_sep = 1;
argstart++;
} else {
@ -247,39 +237,41 @@ laaf_util_build_path (const char* sep, const char* first, ...)
}
/* trim trailing DIR_SEP */
for (int i = arglen - 1; i >= argstart; i--) {
if (IS_DIR_SEP (arg[i])) {
for (size_t i = arglen - 1; i >= argstart; i--) {
if (IS_ANY_DIR_SEP (arg[i])) {
arglen--;
} else {
break;
}
}
/* TODO ? */
if (element_count == 0 && has_leading_sep) {
} else {
}
size_t reqlen = snprintf (NULL, 0, "%.*s", arglen - argstart, arg + argstart) + 1;
size_t reqlen = (arglen - argstart) + 2;
if (offset + reqlen >= len) {
reqlen = ((offset + reqlen) > (len + BUILD_PATH_DEFAULT_BUF_SIZE)) ? (offset + reqlen) : (len + BUILD_PATH_DEFAULT_BUF_SIZE);
reqlen = ((offset + reqlen) > (len + BUILD_PATH_DEFAULT_BUF_SIZE)) ? (reqlen) : (len + BUILD_PATH_DEFAULT_BUF_SIZE);
char* tmp = realloc (str, (offset + reqlen));
if (tmp) {
str = tmp;
len = (offset + reqlen);
} else {
if (!tmp) {
free (str);
return NULL;
}
str = tmp;
len = (offset + reqlen);
}
offset += snprintf (str + offset, len - offset, "%s%.*s",
((element_count == 0 && has_leading_sep) || (element_count > 0)) ? sep : "",
arglen - argstart,
arg + argstart);
int written = snprintf (str + offset, len - offset, "%s%.*s",
((element_count == 0 && has_leading_sep) || (element_count > 0)) ? sep : "",
(uint32_t) (arglen - argstart),
arg + argstart);
if (written < 0 || (size_t)written >= (len - offset)) {
free (str);
return NULL;
}
offset += (size_t)written;
element_count++;
@ -287,29 +279,183 @@ laaf_util_build_path (const char* sep, const char* first, ...)
va_end (args);
/* do not mix between different dirseps and removes any consecutive dirseps */
char* i = str;
char* o = str;
int dirseppassed = 0;
while (*i) {
if (!dirseppassed && IS_ANY_DIR_SEP (*i)) {
*o = *sep;
o++;
dirseppassed = 1;
} else if (!IS_ANY_DIR_SEP (*i)) {
dirseppassed = 0;
*o = *i;
o++;
}
i++;
}
*o = '\0';
return str;
}
int
laaf_util_snprintf_realloc (char** str, int* size, size_t offset, const char* format, ...)
char*
laaf_util_relative_path (const char* filepath, const char* refpath)
{
int tmpsize = 0;
if (!filepath || !refpath || filepath[0] == '\0' || refpath[0] == '\0') {
return NULL;
}
// fprintf( stderr, "%s\n", filepath );
// fprintf( stderr, "%s\n", refpath );
int isWindowsPath = 0;
int aWindowsPath = 0;
int bWindowsPath = 0;
char* relpath = NULL;
if (filepath[0] != '\0' && isalpha (filepath[0]) && filepath[1] == ':') {
aWindowsPath = 1;
}
if (refpath[0] != '\0' && isalpha (refpath[0]) && refpath[1] == ':') {
bWindowsPath = 1;
}
isWindowsPath = (aWindowsPath + bWindowsPath);
if (isWindowsPath == 1) {
// fprintf( stderr, "Trying to make a relative path out of a windows path and a non-windows path\n" );
return NULL;
}
if (isWindowsPath == 2) {
if (tolower (filepath[0]) != tolower (refpath[0])) {
// fprintf( stderr, "Both paths target different drives\n" );
return NULL;
}
}
int winDriveLetterOffset = isWindowsPath;
if (strncmp (filepath + winDriveLetterOffset, refpath + winDriveLetterOffset, strlen (refpath)) == 0) {
relpath = laaf_util_build_path ("/", "./", filepath + strlen (refpath), NULL);
return relpath;
}
char* _filepath = laaf_util_build_path ("/", filepath, NULL);
char* _refpath = laaf_util_build_path ("/", refpath, "/", NULL); /* ensures there is always a trailing '/' */
if (!_filepath || !_refpath) {
return NULL;
}
char* parents = NULL;
size_t parentsLen = 0;
size_t parentsOffset = 0;
char* p = _refpath + strlen (_refpath);
while (p > (_refpath + winDriveLetterOffset)) {
while (p > (_refpath + winDriveLetterOffset) && !IS_DIR_SEP (*p)) {
*p = '\0';
p--;
}
if (strncmp (_filepath + winDriveLetterOffset, _refpath + winDriveLetterOffset, strlen (_refpath + winDriveLetterOffset)) == 0) {
if (!parents) {
relpath = laaf_util_build_path ("/", "./", _filepath + strlen (_refpath), NULL);
goto end;
} else {
relpath = laaf_util_build_path ("/", parents, _filepath + strlen (_refpath), NULL);
goto end;
}
}
int ret = laaf_util_snprintf_realloc (&parents, &parentsLen, parentsOffset, "../");
assert (ret >= 0);
parentsOffset += (size_t)ret;
p--;
}
end:
free (parents);
free (_filepath);
free (_refpath);
return relpath;
}
char*
laaf_util_absolute_path (const char* relpath)
{
if (!relpath) {
return NULL;
}
#ifdef _WIN32
// char *abspath = NULL;
wchar_t buf[_MAX_PATH];
wchar_t* wrelpath = laaf_util_windows_utf8toutf16 (relpath);
if (!wrelpath) {
return NULL;
}
if (!_wfullpath (buf, wrelpath, _MAX_PATH)) {
free (wrelpath);
return NULL;
}
char* abspath = laaf_util_windows_utf16toutf8 (buf);
if (!abspath) {
free (wrelpath);
return NULL;
}
free (wrelpath);
return abspath;
#else
char buf[PATH_MAX + 1];
if (!realpath (relpath, buf)) {
return NULL;
}
return laaf_util_c99strdup (buf);
#endif
}
int
laaf_util_snprintf_realloc (char** str, size_t* size, size_t offset, const char* format, ...)
{
size_t tmpsize = 0;
if (!size) {
size = &tmpsize;
}
int retval, needed;
int retval = 0;
size_t needed = 0;
va_list ap;
va_start (ap, format);
while (0 <= (retval = vsnprintf ((*str) + offset, (*size) - offset, format, ap)) && (int64_t) ((*size) - offset) < (needed = retval + 1)) {
while (0 <= (retval = vsnprintf ((*str) + offset, (*size) - offset, format, ap)) && ((*size) - offset) < (needed = (unsigned)retval + 1)) {
va_end (ap);
*size *= 2;
if ((int64_t) ((*size) - offset) < needed)
if (((*size) - offset) < needed)
*size = needed + offset;
char* p = realloc (*str, *size);
@ -320,7 +466,7 @@ laaf_util_snprintf_realloc (char** str, int* size, size_t offset, const char* fo
free (*str);
*str = NULL;
*size = 0;
return -1;
return 0;
}
va_start (ap, format);
@ -328,38 +474,254 @@ laaf_util_snprintf_realloc (char** str, int* size, size_t offset, const char* fo
va_end (ap);
return retval;
return (retval > 0) ? retval : 0;
}
int
laaf_util_vsnprintf_realloc (char** str, int* size, int offset, const char* fmt, va_list* args)
laaf_util_file_exists (const char* filepath)
{
va_list args2, args3;
#ifdef _WIN32
int needed = MultiByteToWideChar (CP_UTF8, 0, filepath, -1, NULL, 0);
va_copy (args2, *args);
va_copy (args3, *args);
if (needed == 0) {
return -1;
}
int needed = vsnprintf (NULL, 0, fmt, args2) + 1;
wchar_t* wfilepath = malloc ((size_t)needed * sizeof (wchar_t));
if (!wfilepath) {
return -1;
}
int rc = MultiByteToWideChar (CP_UTF8, 0, filepath, -1, wfilepath, needed);
if (rc == 0) {
free (wfilepath);
return -1;
}
if (_waccess (wfilepath, F_OK) == 0) {
free (wfilepath);
return 1;
}
free (wfilepath);
#else
if (access (filepath, F_OK) == 0) {
return 1;
}
#endif
return 0;
}
static int
utf8CodeLen (const uint16_t* u16Code)
{
if (u16Code[0] < 0x80) {
return 1;
} else if (u16Code[0] < 0x800) {
return 2;
} else if (u16Code[0] < 0xD800 ||
u16Code[0] > 0xDFFF) {
return 3;
} else if (((u16Code[0] & 0xFC00) == 0xD800) &&
((u16Code[1] & 0xFC00) == 0xDC00)) {
return 4;
} else {
return -1;
}
}
static int
utf16CodeLen (const uint16_t* u16Code)
{
if (u16Code[0] < 0xD800 ||
u16Code[0] > 0xDFFF) {
return 1;
} else if (((u16Code[0] & 0xFC00) == 0xD800) &&
((u16Code[1] & 0xFC00) == 0xDC00)) {
return 2;
} else {
return -1;
}
}
static int
utf16CodeToUTF8 (const uint16_t* u16Code, char* u8Code, int* u16Len, int* u8Len)
{
int len8 = utf8CodeLen (u16Code);
int len16 = utf16CodeLen (u16Code);
if (len8 < 0 || len16 < 0) {
return -1;
}
*u8Len = len8;
*u16Len = len16;
if (len8 == 1) {
u8Code[0] = (char)(u16Code[0]);
} else if (len8 == 2) {
u8Code[0] = (char)(0xC0 | (u16Code[0] >> 6));
u8Code[1] = (char)(0x80 | (u16Code[0] & 0x3F));
} else if (len8 == 3) {
u8Code[0] = (char)(0xE0 | (u16Code[0] >> 12));
u8Code[1] = (char)(0x80 | ((u16Code[0] >> 6) & 0x3F));
u8Code[2] = (char)(0x80 | (u16Code[0] & 0x3F));
} else {
uint32_t c = (u16Code[0] & 0x03FF) << 10;
c |= (u16Code[1] & 0x03FF);
c += 0x10000;
u8Code[0] = (char)(0xF0 | ((c >> 18) & 0x07));
u8Code[1] = (char)(0x80 | ((c >> 12) & 0x3F));
u8Code[2] = (char)(0x80 | ((c >> 6) & 0x3F));
u8Code[3] = (char)(0x80 | (c & 0x3F));
}
return *u8Len;
}
static long
utf8strLen (const uint16_t* u16str)
{
long len = 0;
const uint16_t* p = u16str;
while (*p != 0x0000) {
int u8CodeLen = utf8CodeLen (p);
int u16CodeLen = utf16CodeLen (p);
if (u8CodeLen < 0 || u16CodeLen < 0) {
len = -1;
break;
}
p += u16CodeLen;
len += u8CodeLen;
}
return len;
}
size_t
laaf_util_utf8strCharLen (const char* u8str)
{
size_t count = 0;
while (*u8str) {
count += (*u8str++ & 0xC0) != 0x80;
}
return count;
}
char*
laaf_util_utf16Toutf8 (const uint16_t* u16str)
{
long u8len = utf8strLen (u16str);
if (u8len < 0) {
return 0;
}
char* u8str = calloc ((size_t)u8len + 1, sizeof (char));
if (!u8str) {
return NULL;
}
const uint16_t* u16ptr = u16str;
char* u8ptr = u8str;
while (*u16ptr != 0x0000) {
int u8codelen = 0;
int u16codelen = 0;
utf16CodeToUTF8 (u16ptr, u8ptr, &u16codelen, &u8codelen);
if (u16codelen < 0 || u8codelen < 0) {
free (u8str);
return NULL;
}
u8ptr += u8codelen;
u16ptr += u16codelen;
}
*u8ptr = 0x00;
return u8str;
}
int
laaf_util_vsnprintf_realloc (char** str, size_t* size, size_t offset, const char* fmt, va_list args)
{
FILE* dummy = NULL;
va_list args1;
size_t tmpsize = 0;
if (size == NULL) {
size = &tmpsize;
}
va_copy (args1, args);
/* https://stackoverflow.com/a/4116308 */
#ifndef _WIN32
dummy = fopen ("/dev/null", "wb");
#else
dummy = fopen ("NUL", "wb");
#endif
if (!dummy) {
// fprintf( stderr, "Could not fopen() dummy null file\n" );
goto err;
}
int retval = vfprintf (dummy, fmt, args);
if (retval < 0) {
// fprintf( stderr, "vfprintf() error : %s\n", strerror(errno) );
goto err;
}
unsigned needed = (unsigned)retval + 1;
if (needed >= (*size) - offset) {
char* p = realloc (*str, offset + needed);
char* p = realloc (*str, (offset + needed) * sizeof (char));
if (p) {
*str = p;
*size = offset + needed;
} else {
/* If realloc() fails, the original block is left untouched; it is not freed or moved. */
va_end (args2);
va_end (args3);
return -1;
goto err;
}
}
va_end (args2);
int written = vsnprintf ((*str) + offset, (*size) - offset, fmt, args3);
int written = vsnprintf ((*str) + offset, (*size) - offset, fmt, args1);
va_end (args3);
// assert( written >= 0 && (size_t)written < (*size)-offset );
if (written < 0 && (size_t)written >= (*size) - offset) {
fprintf (stderr, "vsnprintf() error : %s\n", strerror (errno));
goto err;
}
goto end;
err:
written = -1;
end:
if (dummy) {
fclose (dummy);
}
return written;
}
@ -371,7 +733,7 @@ laaf_util_c99strdup (const char* src)
return NULL;
}
int len = 0;
size_t len = 0;
while (src[len]) {
len++;
@ -379,8 +741,9 @@ laaf_util_c99strdup (const char* src)
char* str = malloc (len + 1);
if (!str)
if (!str) {
return NULL;
}
char* p = str;
@ -394,24 +757,30 @@ laaf_util_c99strdup (const char* src)
}
int
laaf_util_dump_hex (const unsigned char* stream, size_t stream_sz, char** buf, int* bufsz, int offset)
laaf_util_dump_hex (const unsigned char* stream, size_t stream_sz, char** buf, size_t* bufsz, size_t offset, const char* padding)
{
if (stream == NULL) {
return -1;
}
int initialOffset = offset;
size_t initialOffset = offset;
uint32_t i = 0;
char hex[49];
char ascii[19];
uint32_t count = 0;
size_t count = 0;
offset += laaf_util_snprintf_realloc (buf, bufsz, offset, " ______________________________ Hex Dump ______________________________\n\n");
int rc = laaf_util_snprintf_realloc (buf, bufsz, offset, "%s______________________________ Hex Dump ______________________________\n\n", padding);
if (rc < 0) {
goto end;
}
offset += (size_t)rc;
while (count < stream_sz) {
uint32_t lineLen = (stream_sz - count) / 16;
size_t lineLen = (stream_sz - count) / 16;
if (lineLen <= 0)
lineLen = (stream_sz) % 16;
@ -424,22 +793,28 @@ laaf_util_dump_hex (const unsigned char* stream, size_t stream_sz, char** buf, i
uint32_t linepos = 0;
for (i = 0; i < lineLen; i++) {
linepos += snprintf (&hex[linepos], sizeof (hex) - (linepos), "%02x%s", *(const unsigned char*)(stream + count + i), (i == 7) ? " " : " ");
rc = snprintf (&hex[linepos], sizeof (hex) - (linepos), "%02x%s", *(const unsigned char*)(stream + count + i), (i == 7) ? " " : " ");
if (rc < 0) {
goto end;
}
linepos += (uint32_t)rc;
if (i < 8) {
if (isalnum (*(stream + count + i)))
ascii[i] = *(const unsigned char*)(stream + count + i);
ascii[i] = *(const char*)(stream + count + i);
else
ascii[i] = '.';
} else if (i > 8) {
if (isalnum (*(stream + count + i)))
ascii[i + 1] = *(const unsigned char*)(stream + count + i);
ascii[i + 1] = *(const char*)(stream + count + i);
else
ascii[i + 1] = '.';
} else {
if (isalnum (*(stream + count + i))) {
ascii[i] = ' ';
ascii[i + 1] = *(const unsigned char*)(stream + count + i);
ascii[i + 1] = *(const char*)(stream + count + i);
} else {
ascii[i] = ' ';
ascii[i + 1] = '.';
@ -459,10 +834,21 @@ laaf_util_dump_hex (const unsigned char* stream, size_t stream_sz, char** buf, i
count += lineLen;
offset += laaf_util_snprintf_realloc (buf, bufsz, offset, " %s | %s\n", hex, ascii);
rc = laaf_util_snprintf_realloc (buf, bufsz, offset, "%s%s | %s\n", padding, hex, ascii);
if (rc < 0) {
goto end;
}
offset += (size_t)rc;
}
offset += laaf_util_snprintf_realloc (buf, bufsz, offset, " ______________________________________________________________________\n\n");
rc = laaf_util_snprintf_realloc (buf, bufsz, offset, "%s______________________________________________________________________\n\n", padding);
return offset - initialOffset; /* bytes written */
if (rc < 0) {
goto end;
}
end:
return (int)(offset - initialOffset); /* bytes written */
}

View File

@ -19,18 +19,19 @@ libaaf_sources = [
'AAFClass.c',
'AAFCore.c',
'AAFDump.c',
'AAFIAudioFiles.c',
'AAFIEssenceFile.c',
'AAFIface.c',
'AAFIParser.c',
'AAFToText.c',
'CFBDump.c',
'LibCFB.c',
'ProTools.c',
'MediaComposer.c',
'Resolve.c',
'RIFFParser.c',
'URIParser.c',
'utils.c',
'debug.c',
'log.c',
]
def options(opt):