Update libaaf to v1.0-1-gdef35bf
This commit is contained in:
parent
2b1349ffc2
commit
bd937366fd
|
@ -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
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
1318
libs/aaf/AAFIface.c
1318
libs/aaf/AAFIface.c
File diff suppressed because it is too large
Load Diff
2355
libs/aaf/AAFToText.c
2355
libs/aaf/AAFToText.c
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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, §orID )
|
||||
* CFB_foreachSectorInStream( cfbd, properties, &stream, &stream_sz, §orID )
|
||||
* {
|
||||
* // 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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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__
|
|
@ -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__
|
||||
|
|
|
@ -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);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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);
|
||||
|
||||
/**
|
||||
* @}
|
||||
|
|
|
@ -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__
|
|
@ -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);
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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__
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
#pragma once
|
||||
#define LIBAAF_VERSION "v0.6-45-g9171e40"
|
||||
#define LIBAAF_VERSION "v1.0-1-gdef35bf"
|
||||
|
|
102
libs/aaf/debug.c
102
libs/aaf/debug.c
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
716
libs/aaf/utils.c
716
libs/aaf/utils.c
|
@ -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 */
|
||||
}
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Reference in New Issue