blob: 60b0bc4c46437d59b09ec91127d227a3de22c435 [file] [log] [blame]
/*
genpeimg - Modify Portable Executable flags and properties.
Copyright (C) 2009-2016 mingw-w64 project
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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "img.h"
file_image *
fimg_create (void)
{
file_image *r = (file_image *) malloc (sizeof (file_image));
if (r)
memset (r, 0, sizeof (file_image));
return r;
}
static void
fimg_free_content (file_image *pimg)
{
if (!pimg)
return;
if (pimg->data)
free (pimg->data);
if (pimg->filename)
free (pimg->filename);
memset (pimg, 0, sizeof (file_image));
}
void
fimg_free (file_image *pimg)
{
if (!pimg)
return;
if (pimg->want_save && pimg->is_modified)
fimg_save_as (pimg, pimg->filename, pimg->data_len);
fimg_free_content (pimg);
free (pimg);
}
int fimg_load (file_image *pimg, const char *fname)
{
FILE *fp;
size_t r;
fp = fopen (fname, "rb");
if (!pimg || !fp)
return 0;
fimg_free_content (pimg);
pimg->filename = strdup (fname);
if (pimg->filename == NULL)
{
fclose (fp);
return 0;
}
fseek (fp, 0, SEEK_END);
pimg->data_len = (size_t) ftell (fp);
fseek (fp, 0, SEEK_SET);
if (pimg->data_len == FIMG_POS_END)
{
fclose (fp);
fimg_free_content (pimg);
return 0;
}
if (pimg->data_len == 0)
{
fclose (fp);
return 1;
}
pimg->data = (unsigned char *) malloc (pimg->data_len);
if (pimg->data == NULL)
{
fclose (fp);
fimg_free_content (pimg);
return 0;
}
r = fread (pimg->data, 1, pimg->data_len, fp);
fclose (fp);
return r == pimg->data_len;
}
int
fimg_rename (file_image *pimg, const char *newfname)
{
char *n = NULL;
if (!pimg)
return 0;
if (newfname)
{
n = strdup (newfname);
if (!n)
return 0;
}
if (pimg->filename)
free (pimg->filename);
pimg->filename = n;
return 1;
}
int
fimg_save_as (file_image *pimg, const char *fname, size_t length)
{
FILE *fp;
if (!fname || *fname == 0)
return 0;
fp = fopen (fname, "wb");
if (!fp)
return 0;
if (length != 0)
fwrite (pimg->data, 1, length, fp);
fclose (fp);
pimg->is_modified = 0;
return 1;
}
int fimg_save (file_image *pimg)
{
return fimg_save_as (pimg, pimg->filename, pimg->data_len);
}
file_image *
fimg_clone (const file_image *pimg)
{
file_image *r = fimg_create ();
if (!r)
return NULL;
r->filename = (pimg->filename ? strdup (pimg->filename) : NULL);
if (pimg->filename && r->filename == NULL)
{
fimg_free (r);
return NULL;
}
r->data_len = pimg->data_len;
if (r->data_len)
{
r->data = (unsigned char *) malloc (r->data_len);
if (r->data == NULL)
{
fimg_free (r);
return NULL;
}
memcpy (r->data, pimg->data, r->data_len);
}
r->is_modified = 1;
r->want_save = 0;
return r;
}
int
fimg_resize (file_image *pimg, size_t new_size)
{
unsigned char *h;
if (!pimg)
return 0;
if (pimg->data_len >= new_size)
{
pimg->data_len = new_size;
pimg->is_modified = 1;
return 1;
}
h = (unsigned char *) realloc (pimg->data, new_size);
if (!h)
return 0;
pimg->data = h;
memset (h + pimg->data_len, 0, (new_size - pimg->data_len));
pimg->data_len = new_size;
pimg->is_modified = 1;
return 1;
}
int
fimg_replace_at (file_image *pimg, const void *dta, size_t pos, size_t length)
{
size_t end = pos + length;
if (end > pimg->data_len)
{
if (!fimg_resize (pimg, end))
return 0;
}
if (!length)
return 1;
if (!dta)
memset (pimg->data + pos, 0, length);
else
memcpy (pimg->data + pos, dta, length);
pimg->is_modified = 1;
return 1;
}
int
fimg_insert_at (file_image *pimg, const void *dta, size_t pos, size_t length)
{
size_t new_size, old_end, sv_len = length;
if (!pimg)
return 0;
new_size = pimg->data_len + length;
if (pos > pimg->data_len)
length += pos - pimg->data_len;
if (!length)
return 1;
old_end = pimg->data_len;
if (!fimg_resize (pimg,new_size))
return 0;
if (pos < old_end)
memmove (pimg->data + pos + length, pimg->data + pos, (old_end - pos));
if (!dta && sv_len)
memset (pimg->data + pos, 0, sv_len);
else if (dta && sv_len)
memcpy (pimg->data + pos, dta, sv_len);
pimg->is_modified = 1;
return 1;
}
int
fimg_remove_at (file_image *pimg, size_t pos, size_t length)
{
size_t emax = pos + length;
if (!pimg)
return 0;
if (pos > pimg->data_len)
return 1;
if (emax > pimg->data_len)
length = pimg->data_len - pos;
if (!length)
return 1;
if (pimg->data_len > (pos + length))
memmove (pimg->data + pos, pimg->data + pos + length, (pimg->data_len - (pos + length)));
fimg_resize (pimg, pimg->data_len - length);
return 1;
}
unsigned char
fimg_get_uchar_at (const file_image *pimg, size_t pos)
{
if (!pimg || pos >= pimg->data_len)
return 0;
return pimg->data[pos];
}
int
fimg_set_uchar_at (file_image *pimg, unsigned char val, size_t pos)
{
return fimg_replace_at (pimg, &val, pos, 1);
}
unsigned short
fimg_get_ushort_at (const file_image *pimg, size_t pos, int big_endian)
{
unsigned short r, r1;
r = (unsigned short) fimg_get_uchar_at (pimg, pos);
r1 = (unsigned short) fimg_get_uchar_at (pimg, pos + 1);
if (big_endian)
r <<= 8;
else
r1 <<= 8;
return r | r1;
}
int
fimg_set_ushort_at (file_image *pimg, unsigned short val, size_t pos, int big_endian)
{
int r = 1;
if (big_endian)
{
r &= fimg_set_uchar_at (pimg, (unsigned char) ((val >> 8) & 0xff), pos);
r &= fimg_set_uchar_at (pimg, (unsigned char) (val & 0xff), pos + 1);
}
else
{
r &= fimg_set_uchar_at (pimg, (unsigned char) ((val >> 8) & 0xff), pos + 1);
r &= fimg_set_uchar_at (pimg, (unsigned char) (val & 0xff), pos);
}
return r;
}
unsigned int
fimg_get_uint_at (const file_image *pimg, size_t pos, int big_endian)
{
unsigned int r1, r2;
r1 = (unsigned int) fimg_get_ushort_at (pimg, pos, big_endian);
r2 = (unsigned int) fimg_get_ushort_at (pimg, pos + 2, big_endian);
if (big_endian)
r1 <<= 16;
else
r2 <<= 16;
return r1 | r2;
}
int
fimg_set_uint_at (file_image *pimg, unsigned int val, size_t pos, int big_endian)
{
int r = 1;
if (big_endian)
{
r &= fimg_set_ushort_at (pimg, (unsigned short) ((val >> 16) & 0xffff), pos, 1);
r &= fimg_set_ushort_at (pimg, (unsigned short) (val & 0xffff), pos + 2, 1);
}
else
{
r &= fimg_set_ushort_at (pimg, (unsigned short) ((val >> 16) & 0xffff), pos + 2, 0);
r &= fimg_set_ushort_at (pimg, (unsigned short) (val & 0xffff), pos, 0);
}
return r;
}
unsigned long long
fimg_get_uquad_at (const file_image *pimg, size_t pos, int big_endian)
{
unsigned long long r1, r2;
r1 = (unsigned long long) fimg_get_uint_at (pimg, pos, big_endian);
r2 = (unsigned long long) fimg_get_uint_at (pimg, pos + 4, big_endian);
if (big_endian)
r1 <<= 32;
else
r2 <<= 32;
return r1 | r2;
}
int fimg_set_uquad_at (file_image *pimg, unsigned long long val, size_t pos, int big_endian)
{
int r = 1;
if (big_endian)
{
r &= fimg_set_uint_at (pimg, (unsigned short) ((val >> 32) & 0xffffffffULL), pos, 1);
r &= fimg_set_uint_at (pimg, (unsigned short) (val & 0xffffffffULL), pos + 4, 1);
}
else
{
r &= fimg_set_uint_at (pimg, (unsigned short) ((val >> 32) & 0xffffffffULL), pos + 4, 1);
r &= fimg_set_uint_at (pimg, (unsigned short) (val & 0xffffffffULL), pos, 1);
}
return r;
}
void
fimg_show_stats (const file_image *pimg)
{
fprintf (stderr, "fimg: %p", pimg);
if (pimg)
{
fprintf (stderr, "{ data:%p, len:%#"PRIxPTR", name:\"%s\", mod:%s, want_save:%s }",
pimg->data, pimg->data_len, (pimg->filename ? pimg->filename : "<unnamed>"),
pimg->is_modified ? "yes" : "no",
pimg->want_save ? "yes" : "no");
}
fprintf (stderr, "\n");
}
void
fimg_dump_mem (const file_image *pimg, size_t len, FILE *out)
{
size_t off = 0, i;
if (!pimg)
return;
while (off < len)
{
fprintf (out, "%#08"PRIXPTR":", off);
for (i = 0; i < 16 && off < len; i++, off++)
{
fprintf (out," %02X", fimg_get_uchar_at (pimg, off));
}
fprintf (out,"\n");
}
}
#if 0
int main (int argc,char **argv)
{
file_image *p = fimg_create ();
if (!fimg_load (p, argv[0]))
{
fprintf (stderr, "Failed to load %s\n", argv[0]);
fimg_free (p);
return 0;
}
fimg_show_stats (p);
fimg_dump_mem (p, 32, stderr);
fprintf (stderr, "Remove leading 4 bytes\n");
fimg_remove_at (p, 0, 4);
fimg_show_stats (p);
fimg_dump_mem (p, 32, stderr);
fprintf (stderr, "Remove at pos 2 the next 10 bytes\n");
fimg_remove_at (p, 2, 10);
fimg_show_stats (p);
fimg_dump_mem (p, 32, stderr);
fprintf (stderr, "Remove at end-pos the next 10 bytes\n");
fimg_remove_at (p, p->data_len, 10);
fimg_show_stats (p);
fimg_dump_mem (p, 32, stderr);
fimg_free (p);
return 1;
}
#endif