⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gconv_cache.c

📁 Newlib 嵌入式 C库 标准实现代码
💻 C
字号:
/* Cache handling for iconv modules.   Copyright (C) 2001 Free Software Foundation, Inc.   This file is part of the GNU C Library.   Contributed by Ulrich Drepper <drepper@cygnus.com>, 2001.   The GNU C Library is free software; you can redistribute it and/or   modify it under the terms of the GNU Lesser General Public   License as published by the Free Software Foundation; either   version 2.1 of the License, or (at your option) any later version.   The GNU C Library 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   Lesser General Public License for more details.   You should have received a copy of the GNU Lesser General Public   License along with the GNU C Library; if not, write to the Free   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA   02111-1307 USA.  */#include <dlfcn.h>#include <fcntl.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/mman.h>#include <sys/stat.h>#include <gconv_int.h>#include <iconvconfig.h>#include "hash-string.h"void *__gconv_cache;static size_t cache_size;static int cache_malloced;intinternal_function__gconv_load_cache (void){  int fd;  struct stat64 st;  struct gconvcache_header *header;  /* We cannot use the cache if the GCONV_PATH environment variable is     set.  */  __gconv_path_envvar = getenv ("GCONV_PATH");  if (__gconv_path_envvar != NULL)    return -1;  /* See whether the cache file exists.  */  fd = open (GCONV_MODULES_CACHE, O_RDONLY);  if (__builtin_expect (fd, 0) == -1)    /* Not available.  */    return -1;#ifdef	_POSIX_ASYNC_IO  /* Get information about the file.  */  if (__builtin_expect (fstat64 (fd, &st), 0) < 0      /* We do not have to start looking at the file if it cannot contain	 at least the cache header.  */      || st.st_size < sizeof (struct gconvcache_header))    {#endif    close_and_exit:      close (fd);      return -1;#ifdef	_POSIX_ASYNC_IO    }#endif  /* Make the file content available.  */  cache_size = st.st_size;#ifdef _POSIX_MAPPED_FILES  __gconv_cache = mmap (NULL, cache_size, PROT_READ, MAP_SHARED, fd, 0);  if (__builtin_expect (__gconv_cache == MAP_FAILED, 0))#endif    {      size_t already_read;      __gconv_cache = malloc (cache_size);      if (__gconv_cache == NULL)	goto close_and_exit;      already_read = 0;      do	{	  ssize_t n = read (fd, (char *) __gconv_cache + already_read,			      cache_size - already_read);	  if (__builtin_expect (n, 0) == -1)	    {	      free (__gconv_cache);	      __gconv_cache = NULL;	      goto close_and_exit;	    }	  already_read += n;	}      while (already_read < cache_size);      cache_malloced = 1;    }  /* We don't need the file descriptor anymore.  */  close (fd);  /* Check the consistency.  */  header = (struct gconvcache_header *) __gconv_cache;  if (__builtin_expect (header->magic, GCONVCACHE_MAGIC) != GCONVCACHE_MAGIC      || __builtin_expect (header->string_offset >= cache_size, 0)      || __builtin_expect (header->hash_offset >= cache_size, 0)      || __builtin_expect (header->hash_size == 0, 0)      || __builtin_expect ((header->hash_offset			    + header->hash_size * sizeof (struct hash_entry))			   > cache_size, 0)      || __builtin_expect (header->module_offset >= cache_size, 0)      || __builtin_expect (header->otherconv_offset > cache_size, 0))    {      if (cache_malloced)	{	  free (__gconv_cache);	  cache_malloced = 0;	}#ifdef _POSIX_MAPPED_FILES      else	__munmap (__gconv_cache, cache_size);#endif      __gconv_cache = NULL;      return -1;    }  /* That worked.  */  return 0;}static intinternal_functionfind_module_idx (const char *str, size_t *idxp){  unsigned int idx;  unsigned int hval;  unsigned int hval2;  const struct gconvcache_header *header;  const char *strtab;  const struct hash_entry *hashtab;  unsigned int limit;  header = (const struct gconvcache_header *) __gconv_cache;  strtab = (char *) __gconv_cache + header->string_offset;  hashtab = (struct hash_entry *) ((char *) __gconv_cache				   + header->hash_offset);  hval = hash_string (str);  idx = hval % header->hash_size;  hval2 = 1 + hval % (header->hash_size - 2);  limit = cache_size - header->string_offset;  while (hashtab[idx].string_offset != 0)    if (hashtab[idx].string_offset < limit	&& strcmp (str, strtab + hashtab[idx].string_offset) == 0)      {	*idxp = hashtab[idx].module_idx;	return 0;      }    else      if ((idx += hval2) >= header->hash_size)	idx -= header->hash_size;  /* Nothing found.  */  return -1;}#ifndef STATIC_GCONVstatic intinternal_functionfind_module (const char *directory, const char *filename,	     struct __gconv_step *result){  size_t dirlen = strlen (directory);  size_t fnamelen = strlen (filename) + 1;  char fullname[dirlen + fnamelen];  int status = __GCONV_NOCONV;  char *tmp;  tmp = mempcpy (fullname, directory, dirlen);  tmp += dirlen;  memcpy (tmp, filename, fnamelen);  result->__shlib_handle = __gconv_find_shlib (fullname);  if (result->__shlib_handle != NULL)    {      status = __GCONV_OK;      result->__modname = NULL;      result->__fct = result->__shlib_handle->fct;      result->__init_fct = result->__shlib_handle->init_fct;      result->__end_fct = result->__shlib_handle->end_fct;      result->__data = NULL;      if (result->__init_fct != NULL)	status = result->__init_fct (result);    }  return status;}#endifintinternal_function__gconv_compare_alias_cache (const char *name1, const char *name2, int *result){  size_t name1_idx;  size_t name2_idx;  if (__gconv_cache == NULL)    return -1;  if (find_module_idx (name1, &name1_idx) != 0      || find_module_idx (name2, &name2_idx) != 0)    *result = strcmp (name1, name2);  else    *result = (int) (name1_idx - name2_idx);  return 0;}intinternal_function__gconv_lookup_cache (const char *toset, const char *fromset,		      struct __gconv_step **handle, size_t *nsteps, int flags){  const struct gconvcache_header *header;  const char *strtab;  size_t fromidx;  size_t toidx;  const struct module_entry *modtab;  const struct module_entry *from_module;  const struct module_entry *to_module;  struct __gconv_step *result;  if (__gconv_cache == NULL)    /* We have no cache available.  */    return __GCONV_NODB;  header = (const struct gconvcache_header *) __gconv_cache;  strtab = (char *) __gconv_cache + header->string_offset;  modtab = (const struct module_entry *) ((char *) __gconv_cache					  + header->module_offset);  if (find_module_idx (fromset, &fromidx) != 0      || (header->module_offset + (fromidx + 1) * sizeof (struct module_entry)	  > cache_size))    return __GCONV_NOCONV;  from_module = &modtab[fromidx];  if (find_module_idx (toset, &toidx) != 0      || (header->module_offset + (toidx + 1) * sizeof (struct module_entry)	  > cache_size))    return __GCONV_NOCONV;  to_module = &modtab[toidx];  /* Avoid copy-only transformations if the user requests.   */  if (__builtin_expect (flags & GCONV_AVOID_NOCONV, 0) && fromidx == toidx)    return __GCONV_NOCONV;  /* If there are special conversions available examine them first.  */  if (fromidx != 0 && toidx != 0      && __builtin_expect (from_module->extra_offset, 0) != 0)    {      /* Search through the list to see whether there is a module	 matching the destination character set.  */      const struct extra_entry *extra;      /* Note the -1.  This is due to the offset added in iconvconfig.	 See there for more explanations.  */      extra = (const struct extra_entry *) ((char *) __gconv_cache					    + header->otherconv_offset					    + from_module->extra_offset - 1);      while (extra->module_cnt != 0	     && extra->module[extra->module_cnt - 1].outname_offset != toidx)	extra = (const struct extra_entry *) ((char *) extra					      + sizeof (struct extra_entry)					      + (extra->module_cnt						 * sizeof (struct extra_entry_module)));      if (extra->module_cnt != 0)	{	  /* Use the extra module.  First determine how many steps.  */	  char *fromname;	  int idx;	  *nsteps = extra->module_cnt;	  *handle = result =	    (struct __gconv_step *) malloc (extra->module_cnt					    * sizeof (struct __gconv_step));	  if (result == NULL)	    return __GCONV_NOMEM;	  fromname = (char *) strtab + from_module->canonname_offset;	  idx = 0;	  do	    {	      result[idx].__from_name = fromname;	      fromname = result[idx].__to_name =		(char *) strtab + modtab[extra->module[idx].outname_offset].canonname_offset;	      result[idx].__counter = 1;	      result[idx].__data = NULL;#ifndef STATIC_GCONV	      if (strtab[extra->module[idx].dir_offset] != '\0')		{		  /* Load the module, return handle for it.  */		  int res;		  res = find_module (strtab + extra->module[idx].dir_offset,				     strtab + extra->module[idx].name_offset,				     &result[idx]);		  if (__builtin_expect (res, __GCONV_OK) != __GCONV_OK)		    {		      /* Something went wrong.  */		      free (result);		      goto try_internal;		    }		}	      else#endif		/* It's a builtin transformation.  */		__gconv_get_builtin_trans (strtab					   + extra->module[idx].name_offset,					   &result[idx]);	    }	  while (++idx < extra->module_cnt);	  return __GCONV_OK;	}    } try_internal:  /* See whether we can convert via the INTERNAL charset.  */  if ((fromidx != 0 && __builtin_expect (from_module->fromname_offset, 1) == 0)      || (toidx != 0 && __builtin_expect (to_module->toname_offset, 1) == 0)      || (fromidx == 0 && toidx == 0))    /* Not possible.  Nothing we can do.  */    return __GCONV_NOCONV;  /* We will use up to two modules.  Always allocate room for two.  */  result = (struct __gconv_step *) malloc (2 * sizeof (struct __gconv_step));  if (result == NULL)    return __GCONV_NOMEM;  *handle = result;  *nsteps = 0;  /* Generate data structure for conversion to INTERNAL.  */  if (fromidx != 0)    {      result[0].__from_name = (char *) strtab + from_module->canonname_offset;      result[0].__to_name = (char *) "INTERNAL";      result[0].__counter = 1;      result[0].__data = NULL;#ifndef STATIC_GCONV      if (strtab[from_module->todir_offset] != '\0')	{	  /* Load the module, return handle for it.  */	  int res = find_module (strtab + from_module->todir_offset,				 strtab + from_module->toname_offset,				 &result[0]);	  if (__builtin_expect (res, __GCONV_OK) != __GCONV_OK)	    {	      /* Something went wrong.  */	      free (result);	      return res;	    }	}      else#endif	/* It's a builtin transformation.  */	__gconv_get_builtin_trans (strtab + from_module->toname_offset,				   &result[0]);      ++*nsteps;    }  /* Generate data structure for conversion from INTERNAL.  */  if (toidx != 0)    {      int idx = *nsteps;      result[idx].__from_name = (char *) "INTERNAL";      result[idx].__to_name = (char *) strtab + to_module->canonname_offset;      result[idx].__counter = 1;      result[idx].__data = NULL;#ifndef STATIC_GCONV      if (strtab[to_module->fromdir_offset] != '\0')	{	  /* Load the module, return handle for it.  */	  int res = find_module (strtab + to_module->fromdir_offset,				 strtab + to_module->fromname_offset,				 &result[idx]);	  if (__builtin_expect (res, __GCONV_OK) != __GCONV_OK)	    {	      /* Something went wrong.  */	      if (idx != 0)		__gconv_release_step (&result[0]);	      free (result);	      return res;	    }	}      else#endif	/* It's a builtin transformation.  */	__gconv_get_builtin_trans (strtab + to_module->fromname_offset,				   &result[idx]);      ++*nsteps;    }  return __GCONV_OK;}/* Free memory allocated for the transformation record.  */voidinternal_function__gconv_release_cache (struct __gconv_step *steps, size_t nsteps){  if (__gconv_cache != NULL)    /* The only thing we have to deallocate is the record with the       steps.  */    free (steps);}/* Free all resources if necessary.  */static void __attribute__ ((unused))free_mem (void){  if (cache_malloced)    free (__gconv_cache);#ifdef _POSIX_MAPPED_FILES  else    __munmap (__gconv_cache, cache_size);#endif}text_set_element (__libc_subfreeres, free_mem);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -