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.