#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>

#include <libelf.h>
#include <gelf.h>

#include <gio/gio.h>

int
main (int argc, char *argv[])
{
  int fd;
  Elf *elf;
  size_t scnidx;
  Elf_Scn *scn;
  GElf_Shdr *shdr, shdr_mem;
  size_t shstrndx, shnum;
  char *section_name;
  char *file, *c_name, *resource_path;
  gboolean found;
  char *contents;
  gsize page_size, page_offset;

  if (argc < 4)
    {
      g_printerr ("Usage: dump-resource <library> <name> <resource path>\n");
      return -1;
    }

  file = argv[1];
  c_name = argv[2];
  resource_path = argv[3];
  
  
  if (elf_version (EV_CURRENT) == EV_NONE )
    {
      /* library out of date */
      g_printerr ("Elf library out of date!\n");
      return -1;
    }
  
  fd = open (file, O_RDONLY);
  if (fd < 0)
    {
      g_printerr ("Can't open %s\n", file);
      return -1;
    }

  elf = elf_begin (fd, ELF_C_READ, NULL);
  if (elf == NULL)
    {
      g_printerr ("Cannot read elf header from %s\n", file);
      return -1;
    }

  /* Get the index of the section-header-strings-table section. */
  elf_getshdrstrndx (elf, &shstrndx);
  g_assert (shstrndx >= 0);
    
  elf_getshdrnum (elf, &shnum);
  g_assert (shnum >= 0);

  found = FALSE;
  for (scnidx = 1; !found && scnidx < shnum; scnidx++)
    {
      scn = elf_getscn (elf, scnidx);
      if (scn == NULL)
	continue;
      
      shdr = gelf_getshdr (scn, &shdr_mem);
      if (shdr == NULL)
	continue;

      if (shdr->sh_type != SHT_PROGBITS)
	continue;
      
      section_name = elf_strptr (elf, shstrndx, shdr->sh_name);
      if (section_name == NULL ||
	  !g_str_has_prefix (section_name, ".gresource."))
	continue;
      
      if (strcmp (section_name + strlen (".gresource."), c_name) != 0)
	continue;

      found = TRUE;
      
      page_size = sysconf(_SC_PAGE_SIZE);
      page_offset = shdr->sh_offset % page_size;
      contents = mmap (NULL,  shdr->sh_size + page_offset,
		       PROT_READ, MAP_PRIVATE, fd, shdr->sh_offset - page_offset);
      if (contents != MAP_FAILED)
	{
	  GBytes *bytes;
	  GResource *resource;
		
	  bytes = g_bytes_new_static (contents + page_offset, shdr->sh_size);
	  resource = g_resource_new_from_data (bytes, NULL);
	  g_bytes_unref (bytes);
	  
	  if (resource != NULL)
	    {
	      g_print ("Parsed resource\n");
	      bytes = g_resource_lookup_data (resource,
					      resource_path, 0, NULL);
	      
	      if (bytes != NULL) {
		g_print ("%s", (char *)g_bytes_get_data (bytes, NULL));
		g_bytes_unref (bytes);
	      } else {
		g_printerr ("Can't find resource path %s\n", resource_path);
	      }
	      
	      g_resource_unref (resource);
	    }
	  munmap (contents, shdr->sh_size + page_offset);
	}
      else
	{
	  g_printerr ("Can't mmap resource section");
	}
    }

  elf_end (elf);
  close (fd);

  return 0;
}
