27 #define _DEFAULT_SOURCE
30 #define _POSIX_C_SOURCE 200809L
34 #include <sys/types.h>
52 #include "tinycthread/source/tinycthread.h"
55 #define SQUASH_STRTOK_R(str,delim,saveptr) strtok_r(str,delim,saveptr)
56 #define squash_strndup(s,n) strndup(s,n)
58 static char* squash_strndup(
const char* s,
size_t n);
59 #define SQUASH_STRTOK_R(str,delim,saveptr) strtok_s(str,delim,saveptr)
79 static SquashCodecRef*
80 squash_context_get_codec_ref (SquashContext* context,
const char* codec) {
81 SquashCodec key_codec = { 0, };
82 SquashCodecRef key = { &key_codec, };
84 assert (context != NULL);
85 assert (codec != NULL);
87 key_codec.name = (
char*) codec;
89 return SQUASH_TREE_FIND (&(context->codecs), _SquashCodecRef, tree, &key);
92 static SquashCodecRef*
93 squash_context_get_codec_ref_from_extension (SquashContext* context,
const char* extension) {
94 SquashCodec key_codec = { 0, };
95 SquashCodecRef key = { &key_codec, };
97 assert (context != NULL);
98 assert (extension != NULL);
100 key_codec.extension = (
char*) extension;
102 return SQUASH_TREE_FIND (&(context->extensions), _SquashCodecRef, tree, &key);
115 const char* sep_pos = strchr (codec,
':');
116 if (sep_pos != NULL) {
117 char* plugin_name = (
char*) malloc ((sep_pos - codec) + 1);
119 strncpy (plugin_name, codec, sep_pos - codec);
120 plugin_name[sep_pos - codec] = 0;
130 SquashCodecRef* codec_ref = squash_context_get_codec_ref (context, codec);
131 if (codec_ref != NULL) {
162 SquashCodecRef* codec_ref = squash_context_get_codec_ref_from_extension (context, extension);
163 if (codec_ref != NULL) {
191 SquashPlugin plugin_dummy = { 0, };
193 assert (context != NULL);
194 assert (plugin != NULL);
196 plugin_dummy.name = (
char*) plugin;
198 return SQUASH_TREE_FIND (&(context->plugins),
_SquashPlugin, tree, &plugin_dummy);
214 squash_codec_ref_compare (SquashCodecRef* a, SquashCodecRef* b) {
215 return squash_codec_compare (a->codec, b->codec);
219 squash_codec_ref_extension_compare (SquashCodecRef* a, SquashCodecRef* b) {
220 return squash_codec_extension_compare (a->codec, b->codec);
224 squash_context_add_plugin (SquashContext* context,
char* name,
char* directory) {
225 SquashPlugin* plugin = NULL;
226 SquashPlugin plugin_dummy = { 0, };
228 assert (context != NULL);
229 assert (name != NULL);
230 assert (directory != NULL);
232 plugin_dummy.name = name;
234 plugin = SQUASH_TREE_FIND (&(context->plugins),
_SquashPlugin, tree, &plugin_dummy);
235 if (plugin == NULL) {
236 plugin = squash_plugin_new (name, directory, context);
238 SQUASH_TREE_INSERT(&(context->plugins),
_SquashPlugin, tree, plugin);
263 squash_context_add_codec (SquashContext* context, SquashCodec* codec) {
264 SquashCodecRef* codec_ref;
266 assert (context != NULL);
267 assert (codec != NULL);
269 codec_ref = squash_context_get_codec_ref (context, codec->name);
270 if (codec_ref == NULL) {
272 codec_ref = (SquashCodecRef*) malloc (
sizeof (SquashCodecRef));
273 codec_ref->codec = codec;
274 SQUASH_TREE_ENTRY_INIT(codec_ref->tree);
275 SQUASH_TREE_INSERT (&(context->codecs), _SquashCodecRef, tree, codec_ref);
276 }
else if (codec->priority > codec_ref->codec->priority) {
278 codec_ref->codec = codec;
281 if (codec->extension != NULL) {
282 codec_ref = squash_context_get_codec_ref_from_extension (context, codec->extension);
283 if (codec_ref == NULL) {
284 codec_ref = (SquashCodecRef*) malloc (
sizeof (SquashCodecRef));
285 codec_ref->codec = codec;
286 SQUASH_TREE_ENTRY_INIT(codec_ref->tree);
287 SQUASH_TREE_INSERT (&(context->extensions), _SquashCodecRef, tree, codec_ref);
288 }
else if (codec->priority > codec_ref->codec->priority) {
289 codec_ref->codec = codec;
297 typedef struct _SquashCodecsFileParser {
298 SquashPlugin* plugin;
300 } SquashCodecsFileParser;
303 squash_codecs_file_parser_callback (
const char* section,
308 SquashCodecsFileParser* parser = (SquashCodecsFileParser*) user_data;
311 if (parser->codec != NULL)
312 squash_plugin_add_codec (parser->plugin, parser->codec);
313 parser->codec = squash_codec_new (parser->plugin, section);
315 if (strcasecmp (key,
"license") == 0) {
317 if (parser->plugin->license != NULL) {
318 free (parser->plugin->license);
319 parser->plugin->license = NULL;
322 char* licenses = strdup (value);
323 char* saveptr = NULL;
324 char* license = strtok_r (licenses,
";", &saveptr);
326 while (license != NULL) {
327 SquashLicense license_value = squash_license_from_string (license);
328 if (license_value != SQUASH_LICENSE_UNKNOWN) {
329 parser->plugin->license = realloc (parser->plugin->license, sizeof (SquashLicense) * (n + 2));
330 parser->plugin->license[n++] = squash_license_from_string (license);
331 parser->plugin->license[n] = SQUASH_LICENSE_UNKNOWN;
336 license = strtok_r (NULL,
";", &saveptr);
340 }
else if (strcasecmp (key,
"priority") == 0) {
342 long priority = strtol (value, &endptr, 0);
343 if (*endptr ==
'\0') {
344 squash_codec_set_priority (parser->codec, (
unsigned int) priority);
346 }
else if (strcasecmp (key,
"extension") == 0) {
347 squash_codec_set_extension (parser->codec, value);
355 squash_codecs_file_parser_init (SquashCodecsFileParser* parser, SquashPlugin* plugin) {
356 SquashCodecsFileParser _parser = { plugin, NULL };
362 squash_codecs_file_parser_parse (SquashCodecsFileParser* parser, FILE* input) {
363 bool res = squash_ini_parse (input, squash_codecs_file_parser_callback, parser);
365 if (res && parser->codec != NULL) {
366 squash_plugin_add_codec (parser->plugin, parser->codec);
375 squash_strndup(
const char* s,
size_t n) {
376 const char* eos = (
const char*) memchr (s,
'\0', n);
377 const size_t res_len = (eos == NULL) ? n : (
size_t) (eos - s);
378 char* res = (
char*) malloc (res_len + 1);
379 memcpy (res, s, res_len);
387 squash_context_check_directory_for_plugin (SquashContext* context,
const char* directory_name,
const char* plugin_name) {
388 size_t directory_name_length = strlen (directory_name);
389 size_t plugin_name_length = strlen (plugin_name);
391 size_t codecs_file_name_length = directory_name_length + (plugin_name_length * 2) + 10;
392 char* codecs_file_name = (
char*) malloc (codecs_file_name_length + 1);
393 snprintf (codecs_file_name, codecs_file_name_length,
"%s/%s/squash.ini",
394 directory_name, plugin_name);
396 FILE* codecs_file = fopen (codecs_file_name,
"r");
398 if (codecs_file != NULL) {
399 size_t plugin_directory_name_length = directory_name_length + plugin_name_length + 1;
400 char* plugin_directory_name = (
char*) malloc (plugin_directory_name_length + 1);
401 snprintf (plugin_directory_name, plugin_directory_name_length + 1,
"%s/%s",
402 directory_name, plugin_name);
404 SquashPlugin* plugin = squash_context_add_plugin (context, squash_strndup (plugin_name, 32), plugin_directory_name);
405 if (plugin != NULL) {
406 SquashCodecsFileParser parser;
408 squash_codecs_file_parser_init (&parser, plugin);
409 squash_codecs_file_parser_parse (&parser, codecs_file);
412 fclose (codecs_file);
415 free (codecs_file_name);
419 squash_context_find_plugins_in_directory (SquashContext* context,
const char* directory_name) {
421 DIR* directory = opendir (directory_name);
422 struct dirent* result = NULL;
423 struct dirent* entry = NULL;
425 if (directory == NULL) {
428 long name_max = pathconf (directory_name, _PC_NAME_MAX);
431 entry = (
struct dirent*) malloc (offsetof (
struct dirent, d_name) + name_max + 1);
434 while ( readdir_r (directory, entry, &result) == 0 && result != NULL ) {
435 #ifdef _DIRENT_HAVE_D_TYPE
436 if ( entry->d_type != DT_DIR &&
437 entry->d_type != DT_UNKNOWN &&
438 entry->d_type != DT_LNK )
442 if (strcmp (entry->d_name,
"..") == 0 ||
443 strcmp (entry->d_name,
".") == 0)
446 squash_context_check_directory_for_plugin (context, directory_name, entry->d_name);
450 closedir (directory);
452 WIN32_FIND_DATA entry;
453 TCHAR* directory_query = NULL;
454 size_t directory_query_length;
455 HANDLE directory_handle = INVALID_HANDLE_VALUE;
457 StringCchLength (directory_name, MAX_PATH, &directory_query_length);
458 directory_query_length += 3;
460 if (directory_query_length > MAX_PATH) {
464 directory_query = (TCHAR*) malloc (directory_query_length *
sizeof(TCHAR));
466 StringCchCopy (directory_query, directory_query_length, directory_name);
467 StringCchCat (directory_query, directory_query_length, TEXT(
"\\*"));
469 directory_handle = FindFirstFile (directory_query, &entry);
471 if (INVALID_HANDLE_VALUE == directory_handle) {
476 if (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
477 if (strcmp (entry.cFileName,
"..") == 0 ||
478 strcmp (entry.cFileName,
".") == 0)
481 squash_context_check_directory_for_plugin (context, directory_name, entry.cFileName);
484 while (FindNextFile (directory_handle, &entry) != 0);
486 FindClose(directory_handle);
487 free (directory_query);
492 squash_context_find_plugins (SquashContext* context) {
495 assert (context != NULL);
497 directories = getenv (
"SQUASH_PLUGINS");
499 if (directories != NULL) {
500 char* saveptr = NULL;
501 char* directory_name = NULL;
503 directories = strdup (directories);
505 for ( directory_name = SQUASH_STRTOK_R (directories,
":", &saveptr) ;
506 directory_name != NULL ;
507 directory_name = SQUASH_STRTOK_R (NULL,
":", &saveptr) ) {
508 squash_context_find_plugins_in_directory (context, directory_name);
513 squash_context_find_plugins_in_directory (context, SQUASH_PLUGIN_DIR);
526 SQUASH_TREE_FORWARD_APPLY(&(context->plugins),
_SquashPlugin, tree, func, data);
530 squash_context_foreach_codec_ref (SquashContext* context,
void(*func)(SquashCodecRef*,
void*),
void* data) {
531 SQUASH_TREE_FORWARD_APPLY(&(context->codecs), _SquashCodecRef, tree, func, data);
537 struct SquashContextForeachCodecRefCbData {
543 squash_context_foreach_codec_ref_cb (SquashCodecRef* codec_ref,
void* data) {
544 struct SquashContextForeachCodecRefCbData* cb_data = (
struct SquashContextForeachCodecRefCbData*) data;
546 cb_data->func (codec_ref->codec, cb_data->data);
565 struct SquashContextForeachCodecRefCbData cb_data = { func, data };
567 squash_context_foreach_codec_ref (context, squash_context_foreach_codec_ref_cb, &cb_data);
601 static SquashContext*
602 squash_context_new (
void) {
603 SquashContext* context = (SquashContext*) malloc (
sizeof (SquashContext));
604 SquashContext _context = { { 0, }, };
606 assert (context != NULL);
609 SQUASH_TREE_INIT(&(context->codecs), squash_codec_ref_compare);
610 SQUASH_TREE_INIT(&(context->plugins), squash_plugin_compare);
611 SQUASH_TREE_INIT(&(context->extensions), squash_codec_ref_extension_compare);
613 squash_context_find_plugins (context);
618 static SquashContext* squash_context_default = NULL;
621 squash_context_create_default (
void) {
622 assert (squash_context_default == NULL);
624 squash_context_default = (SquashContext*) squash_context_new ();
639 static once_flag once = ONCE_FLAG_INIT;
641 call_once (&once, squash_context_create_default);
643 assert (squash_context_default != NULL);
645 return squash_context_default;
SquashPlugin * squash_context_get_plugin(SquashContext *context, const char *plugin)
Retrieve a SquashPlugin from a SquashContext.
SquashCodec * squash_get_codec(const char *codec)
Retrieve a SquashCodec.
void(* SquashPluginForeachFunc)(SquashPlugin *plugin, void *data)
Squashlback to be invoked on each SquashPlugin in a set.
SquashCodec * squash_get_codec_from_extension(const char *extension)
Retrieve a codec based on an extension.
SquashContext * squash_context_get_default(void)
Retrieve the default SquashContext.
SquashStatus squash_codec_init(SquashCodec *codec)
Initialize a codec.
SquashPlugin * squash_get_plugin(const char *plugin)
Retrieve a SquashPlugin.
SquashStatus
Status codes.
void squash_context_foreach_codec(SquashContext *context, SquashCodecForeachFunc func, void *data)
Execute a callback for every loaded codec.
SquashCodec * squash_context_get_codec(SquashContext *context, const char *codec)
Retrieve a SquashCodec from a SquashContext.
SquashStatus squash_error(SquashStatus status)
Emit an error.
void(* SquashCodecForeachFunc)(SquashCodec *codec, void *data)
Squashlback to be invoked on each SquashCodec in a set.
SquashCodec * squash_context_get_codec_from_extension(SquashContext *context, const char *extension)
Retrieve a codec from a context based on an extension.
void squash_foreach_codec(SquashCodecForeachFunc func, void *data)
Execute a callback for every loaded codec in the default context.
SquashCodec * squash_plugin_get_codec(SquashPlugin *plugin, const char *codec)
Get a codec from a plugin by name.
void squash_context_foreach_plugin(SquashContext *context, SquashPluginForeachFunc func, void *data)
Execute a callback for every loaded plugin.
Operation completed successfully.
void squash_foreach_plugin(SquashPluginForeachFunc func, void *data)
Execute a callback for every loaded plugin in the default context.