From 6055173a0f2733ea4fc2825afd295156143fca79 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Tue, 24 Sep 2013 22:07:47 +0000 Subject: [PATCH] Add localedef --big-endian and --little-endian options. --- ChangeLog | 39 ++++ NEWS | 4 + locale/programs/ld-collate.c | 4 + locale/programs/localedef.c | 12 ++ locale/programs/locarchive.c | 420 +++++++++++++++++++++++-------------------- locale/programs/locfile.c | 9 + locale/programs/locfile.h | 37 ++++ 7 files changed, 335 insertions(+), 190 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7bb059e9f2..8126706d91 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,42 @@ +2013-09-24 Joseph Myers + Richard Sandiford + + * locale/programs/locfile.h: Include and . + (swap_endianness_p): New extern variable. + (set_big_endian): New inline function. + (maybe_swap_uint32): Likewise. + (maybe_swap_uint32_array): Likewise. + (maybe_swap_uint32_obstack): Likewise. + * locale/programs/locfile.c: Include . + (swap_endianness_p): New variable. + (add_locale_uint32): Call maybe_swap_uint32. + (add_locale_uint32_array): Call maybe_swap_uint32_obstack. + (write_locale_data): Call maybe_swap_uint32_array. + * locale/programs/ld-collate.c (obstack_int32_grow): Call + maybe_swap_uint32. + (obstack_int32_grow_fast): Likewise. + (output_weightwc): Call maybe_swap_uint32_obstack. + (collate_output): Likewise. + * locale/programs/localedef.c (OPT_LITTLE_ENDIAN): New macro. + (OPT_LITTLE_ENDIAN): Likewise. + (options): Add --little-endian and --big-endian options. + (parse_opt): Handle OPT_LITTLE_ENDIAN and OPT_BIG_ENDIAN. + * locale/programs/locarchive.c: Include "locfile.h". + (GET): New macro. + (SET): Likewise. + (INC): Likewise. + (create_archive): Use the new macros to access fields of + structures directly mapped from or written to locale archives. + (oldlocrecentcmp): Likewise. + (enlarge_archive): Likewise. + (insert_name): Likewise. + (add_alias): Likewise. + (add_locale): Likewise. + (delete_locales_from_archive): Likewise. + (show_archive_content): Likewise. + (add_locale_to_archive): Likewise. Use maybe_swap_uint32 on + locale data. + 2013-09-24 Roland McGrath * manual/freemanuals.texi: Updated from (newly) canonical copy at diff --git a/NEWS b/NEWS index 8753077bfe..7f193a40aa 100644 --- a/NEWS +++ b/NEWS @@ -48,6 +48,10 @@ Version 2.19 * ISO 1427 definitions were updated. +* The localedef utility now supports --big-endian and --little-endian + command-line options to generate locales for a different system from that + for which the C library was built. + * The configure option --disable-versioning has been removed. Builds with --disable-versioning had not worked for several years. diff --git a/locale/programs/ld-collate.c b/locale/programs/ld-collate.c index c4d7e3d3d2..e610389b0c 100644 --- a/locale/programs/ld-collate.c +++ b/locale/programs/ld-collate.c @@ -44,6 +44,7 @@ static inline void __attribute ((always_inline)) obstack_int32_grow (struct obstack *obstack, int32_t data) { + data = maybe_swap_uint32 (data); if (sizeof (int32_t) == sizeof (int)) obstack_int_grow (obstack, data); else @@ -54,6 +55,7 @@ static inline void __attribute ((always_inline)) obstack_int32_grow_fast (struct obstack *obstack, int32_t data) { + data = maybe_swap_uint32 (data); if (sizeof (int32_t) == sizeof (int)) obstack_int_grow_fast (obstack, data); else @@ -1955,6 +1957,7 @@ output_weightwc (struct obstack *pool, struct locale_collate_t *collate, obstack_int32_grow (pool, j); obstack_grow (pool, buf, j * sizeof (int32_t)); + maybe_swap_uint32_obstack (pool, j); } return retval | ((elem->section->ruleidx & 0x7f) << 24); @@ -2479,6 +2482,7 @@ collate_output (struct localedef_t *locale, const struct charmap_t *charmap, obstack_int32_grow (&extrapool, runp->nwcs); obstack_grow (&extrapool, runp->wcs, runp->nwcs * sizeof (uint32_t)); + maybe_swap_uint32_obstack (&extrapool, runp->nwcs); obstack_int32_grow (&extrapool, runp->wcseqorder); } diff --git a/locale/programs/localedef.c b/locale/programs/localedef.c index 5a14f2ce32..8b9866ab29 100644 --- a/locale/programs/localedef.c +++ b/locale/programs/localedef.c @@ -112,6 +112,8 @@ void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version; #define OPT_REPLACE 307 #define OPT_DELETE_FROM_ARCHIVE 308 #define OPT_LIST_ARCHIVE 309 +#define OPT_LITTLE_ENDIAN 400 +#define OPT_BIG_ENDIAN 401 /* Definitions of arguments for argp functions. */ static const struct argp_option options[] = @@ -144,6 +146,10 @@ static const struct argp_option options[] = { "list-archive", OPT_LIST_ARCHIVE, NULL, 0, N_("List content of archive") }, { "alias-file", 'A', N_("FILE"), 0, N_("locale.alias file to consult when making archive")}, + { "little-endian", OPT_LITTLE_ENDIAN, NULL, 0, + N_("Generate little-endian output") }, + { "big-endian", OPT_BIG_ENDIAN, NULL, 0, + N_("Generate big-endian output") }, { NULL, 0, NULL, 0, NULL } }; @@ -326,6 +332,12 @@ parse_opt (int key, char *arg, struct argp_state *state) case OPT_LIST_ARCHIVE: list_archive = true; break; + case OPT_LITTLE_ENDIAN: + set_big_endian (false); + break; + case OPT_BIG_ENDIAN: + set_big_endian (true); + break; case 'c': force_output = 1; break; diff --git a/locale/programs/locarchive.c b/locale/programs/locarchive.c index d8df39a8e6..13dba0fb26 100644 --- a/locale/programs/locarchive.c +++ b/locale/programs/locarchive.c @@ -46,6 +46,7 @@ #include "../localeinfo.h" #include "../locarchive.h" #include "localedef.h" +#include "locfile.h" /* Define the hash function. We define the function as static inline. We must change the name so as not to conflict with simple-hash.h. */ @@ -74,6 +75,13 @@ static const char *locnames[] = #define INITIAL_NUM_SUMS 2000 +/* Get and set values (possibly endian-swapped) in structures mapped + from or written directly to locale archives. */ +#define GET(FIELD) maybe_swap_uint32 (FIELD) +#define SET(FIELD, VALUE) ((FIELD) = maybe_swap_uint32 (VALUE)) +#define INC(FIELD, INCREMENT) SET (FIELD, GET (FIELD) + (INCREMENT)) + + /* Size of the reserved address space area. */ #define RESERVE_MMAP_SIZE 512 * 1024 * 1024 @@ -125,27 +133,31 @@ create_archive (const char *archivefname, struct locarhandle *ah) error (EXIT_FAILURE, errno, _("cannot create temporary file: %s"), fname); /* Create the initial content of the archive. */ - head.magic = AR_MAGIC; - head.serial = 0; - head.namehash_offset = sizeof (struct locarhead); - head.namehash_used = 0; - head.namehash_size = next_prime (INITIAL_NUM_NAMES); - - head.string_offset = (head.namehash_offset - + head.namehash_size * sizeof (struct namehashent)); - head.string_used = 0; - head.string_size = INITIAL_SIZE_STRINGS; - - head.locrectab_offset = head.string_offset + head.string_size; - head.locrectab_used = 0; - head.locrectab_size = INITIAL_NUM_LOCREC; - - head.sumhash_offset = (head.locrectab_offset - + head.locrectab_size * sizeof (struct locrecent)); - head.sumhash_used = 0; - head.sumhash_size = next_prime (INITIAL_NUM_SUMS); - - total = head.sumhash_offset + head.sumhash_size * sizeof (struct sumhashent); + SET (head.magic, AR_MAGIC); + SET (head.serial, 0); + SET (head.namehash_offset, sizeof (struct locarhead)); + SET (head.namehash_used, 0); + SET (head.namehash_size, next_prime (INITIAL_NUM_NAMES)); + + SET (head.string_offset, + (GET (head.namehash_offset) + + GET (head.namehash_size) * sizeof (struct namehashent))); + SET (head.string_used, 0); + SET (head.string_size, INITIAL_SIZE_STRINGS); + + SET (head.locrectab_offset, + GET (head.string_offset) + GET (head.string_size)); + SET (head.locrectab_used, 0); + SET (head.locrectab_size, INITIAL_NUM_LOCREC); + + SET (head.sumhash_offset, + (GET (head.locrectab_offset) + + GET (head.locrectab_size) * sizeof (struct locrecent))); + SET (head.sumhash_used, 0); + SET (head.sumhash_size, next_prime (INITIAL_NUM_SUMS)); + + total = (GET (head.sumhash_offset) + + GET (head.sumhash_size) * sizeof (struct sumhashent)); /* Write out the header and create room for the other data structures. */ if (TEMP_FAILURE_RETRY (write (fd, &head, sizeof (head))) != sizeof (head)) @@ -240,10 +252,10 @@ oldlocrecentcmp (const void *a, const void *b) for (cnt = 0; cnt < __LC_LAST; ++cnt) if (cnt != LC_ALL) { - if (la->record[cnt].offset < start_a) - start_a = la->record[cnt].offset; - if (la->record[cnt].offset + la->record[cnt].len > end_a) - end_a = la->record[cnt].offset + la->record[cnt].len; + if (GET (la->record[cnt].offset) < start_a) + start_a = GET (la->record[cnt].offset); + if (GET (la->record[cnt].offset) + GET (la->record[cnt].len) > end_a) + end_a = GET (la->record[cnt].offset) + GET (la->record[cnt].len); } assert (start_a != (uint32_t)-1); assert (end_a != 0); @@ -251,10 +263,10 @@ oldlocrecentcmp (const void *a, const void *b) for (cnt = 0; cnt < __LC_LAST; ++cnt) if (cnt != LC_ALL) { - if (lb->record[cnt].offset < start_b) - start_b = lb->record[cnt].offset; - if (lb->record[cnt].offset + lb->record[cnt].len > end_b) - end_b = lb->record[cnt].offset + lb->record[cnt].len; + if (GET (lb->record[cnt].offset) < start_b) + start_b = GET (lb->record[cnt].offset); + if (GET (lb->record[cnt].offset) + GET (lb->record[cnt].len) > end_b) + end_b = GET (lb->record[cnt].offset) + GET (lb->record[cnt].len); } assert (start_b != (uint32_t)-1); assert (end_b != 0); @@ -371,38 +383,42 @@ enlarge_archive (struct locarhandle *ah, const struct locarhead *head) /* Create the new archive header. The sizes of the various tables should be double from what is currently used. */ - newhead.namehash_size = MAX (next_prime (2 * newhead.namehash_used), - newhead.namehash_size); + SET (newhead.namehash_size, + MAX (next_prime (2 * GET (newhead.namehash_used)), + GET (newhead.namehash_size))); if (verbose) printf ("name: size: %u, used: %d, new: size: %u\n", - head->namehash_size, head->namehash_used, newhead.namehash_size); + GET (head->namehash_size), + GET (head->namehash_used), GET (newhead.namehash_size)); - newhead.string_offset = (newhead.namehash_offset - + (newhead.namehash_size - * sizeof (struct namehashent))); + SET (newhead.string_offset, (GET (newhead.namehash_offset) + + (GET (newhead.namehash_size) + * sizeof (struct namehashent)))); /* Keep the string table size aligned to 4 bytes, so that all the struct { uint32_t } types following are happy. */ - newhead.string_size = MAX ((2 * newhead.string_used + 3) & -4, - newhead.string_size); + SET (newhead.string_size, MAX ((2 * GET (newhead.string_used) + 3) & -4, + GET (newhead.string_size))); - newhead.locrectab_offset = newhead.string_offset + newhead.string_size; - newhead.locrectab_size = MAX (2 * newhead.locrectab_used, - newhead.locrectab_size); + SET (newhead.locrectab_offset, + GET (newhead.string_offset) + GET (newhead.string_size)); + SET (newhead.locrectab_size, MAX (2 * GET (newhead.locrectab_used), + GET (newhead.locrectab_size))); - newhead.sumhash_offset = (newhead.locrectab_offset - + (newhead.locrectab_size - * sizeof (struct locrecent))); - newhead.sumhash_size = MAX (next_prime (2 * newhead.sumhash_used), - newhead.sumhash_size); + SET (newhead.sumhash_offset, (GET (newhead.locrectab_offset) + + (GET (newhead.locrectab_size) + * sizeof (struct locrecent)))); + SET (newhead.sumhash_size, + MAX (next_prime (2 * GET (newhead.sumhash_used)), + GET (newhead.sumhash_size))); - total = (newhead.sumhash_offset - + newhead.sumhash_size * sizeof (struct sumhashent)); + total = (GET (newhead.sumhash_offset) + + GET (newhead.sumhash_size) * sizeof (struct sumhashent)); /* The new file is empty now. */ - newhead.namehash_used = 0; - newhead.string_used = 0; - newhead.locrectab_used = 0; - newhead.sumhash_used = 0; + SET (newhead.namehash_used, 0); + SET (newhead.string_used, 0); + SET (newhead.locrectab_used, 0); + SET (newhead.sumhash_used, 0); /* Write out the header and create room for the other data structures. */ if (TEMP_FAILURE_RETRY (write (fd, &newhead, sizeof (newhead))) @@ -453,17 +469,17 @@ enlarge_archive (struct locarhandle *ah, const struct locarhead *head) /* Walk through the hash name hash table to find out what data is still referenced and transfer it into the new file. */ oldnamehashtab = (struct namehashent *) ((char *) ah->addr - + head->namehash_offset); + + GET (head->namehash_offset)); /* Sort the old locrec table in order of data position. */ - struct oldlocrecent oldlocrecarray[head->namehash_size]; - for (cnt = 0, loccnt = 0; cnt < head->namehash_size; ++cnt) - if (oldnamehashtab[cnt].locrec_offset != 0) + struct oldlocrecent oldlocrecarray[GET (head->namehash_size)]; + for (cnt = 0, loccnt = 0; cnt < GET (head->namehash_size); ++cnt) + if (GET (oldnamehashtab[cnt].locrec_offset) != 0) { oldlocrecarray[loccnt].cnt = cnt; oldlocrecarray[loccnt++].locrec = (struct locrecent *) ((char *) ah->addr - + oldnamehashtab[cnt].locrec_offset); + + GET (oldnamehashtab[cnt].locrec_offset)); } qsort (oldlocrecarray, loccnt, sizeof (struct oldlocrecent), oldlocrecentcmp); @@ -479,9 +495,9 @@ enlarge_archive (struct locarhandle *ah, const struct locarhead *head) for (idx = 0; idx < __LC_LAST; ++idx) if (idx != LC_ALL) { - old_data[idx].size = oldlocrec->record[idx].len; + old_data[idx].size = GET (oldlocrec->record[idx].len); old_data[idx].addr - = ((char *) ah->addr + oldlocrec->record[idx].offset); + = ((char *) ah->addr + GET (oldlocrec->record[idx].offset)); __md5_buffer (old_data[idx].addr, old_data[idx].size, old_data[idx].sum); @@ -491,20 +507,23 @@ enlarge_archive (struct locarhandle *ah, const struct locarhead *head) { const char *oldname = ((char *) ah->addr - + oldnamehashtab[oldlocrecarray[cnt - 1].cnt].name_offset); - - add_alias (&new_ah, - ((char *) ah->addr - + oldnamehashtab[oldlocrecarray[cnt].cnt].name_offset), - 0, oldname, &last_locrec_offset); + + GET (oldnamehashtab[oldlocrecarray[cnt + - 1].cnt].name_offset)); + + add_alias + (&new_ah, + ((char *) ah->addr + + GET (oldnamehashtab[oldlocrecarray[cnt].cnt].name_offset)), + 0, oldname, &last_locrec_offset); continue; } last_locrec_offset = - add_locale (&new_ah, - ((char *) ah->addr - + oldnamehashtab[oldlocrecarray[cnt].cnt].name_offset), - old_data, 0); + add_locale + (&new_ah, + ((char *) ah->addr + + GET (oldnamehashtab[oldlocrecarray[cnt].cnt].name_offset)), + old_data, 0); if (last_locrec_offset == 0) error (EXIT_FAILURE, 0, _("cannot extend locale archive file")); } @@ -672,26 +691,28 @@ insert_name (struct locarhandle *ah, { const struct locarhead *const head = ah->addr; struct namehashent *namehashtab - = (struct namehashent *) ((char *) ah->addr + head->namehash_offset); + = (struct namehashent *) ((char *) ah->addr + + GET (head->namehash_offset)); unsigned int insert_idx, idx, incr; /* Hash value of the locale name. */ uint32_t hval = archive_hashval (name, name_len); insert_idx = -1; - idx = hval % head->namehash_size; - incr = 1 + hval % (head->namehash_size - 2); + idx = hval % GET (head->namehash_size); + incr = 1 + hval % (GET (head->namehash_size) - 2); /* If the name_offset field is zero this means this is a deleted entry and therefore no entry can be found. */ - while (namehashtab[idx].name_offset != 0) + while (GET (namehashtab[idx].name_offset) != 0) { - if (namehashtab[idx].hashval == hval - && strcmp (name, - (char *) ah->addr + namehashtab[idx].name_offset) == 0) + if (GET (namehashtab[idx].hashval) == hval + && (strcmp (name, + (char *) ah->addr + GET (namehashtab[idx].name_offset)) + == 0)) { /* Found the entry. */ - if (namehashtab[idx].locrec_offset != 0 && ! replace) + if (GET (namehashtab[idx].locrec_offset) != 0 && ! replace) { if (! be_quiet) error (0, 0, _("locale '%s' already exists"), name); @@ -701,26 +722,27 @@ insert_name (struct locarhandle *ah, break; } - if (namehashtab[idx].hashval == hval && ! be_quiet) + if (GET (namehashtab[idx].hashval) == hval && ! be_quiet) { error (0, 0, "hash collision (%u) %s, %s", - hval, name, (char *) ah->addr + namehashtab[idx].name_offset); + hval, name, + (char *) ah->addr + GET (namehashtab[idx].name_offset)); } /* Remember the first place we can insert the new entry. */ - if (namehashtab[idx].locrec_offset == 0 && insert_idx == -1) + if (GET (namehashtab[idx].locrec_offset) == 0 && insert_idx == -1) insert_idx = idx; idx += incr; - if (idx >= head->namehash_size) - idx -= head->namehash_size; + if (idx >= GET (head->namehash_size)) + idx -= GET (head->namehash_size); } /* Add as early as possible. */ if (insert_idx != -1) idx = insert_idx; - namehashtab[idx].hashval = hval; /* no-op if replacing an old entry. */ + SET (namehashtab[idx].hashval, hval); /* no-op if replacing an old entry. */ return &namehashtab[idx]; } @@ -736,12 +758,13 @@ add_alias (struct locarhandle *ah, const char *alias, bool replace, if (namehashent == NULL && ! replace) return; - if (namehashent->name_offset == 0) + if (GET (namehashent->name_offset) == 0) { /* We are adding a new hash entry for this alias. Determine whether we have to resize the file. */ - if (head->string_used + name_len + 1 > head->string_size - || 100 * head->namehash_used > 75 * head->namehash_size) + if (GET (head->string_used) + name_len + 1 > GET (head->string_size) + || (100 * GET (head->namehash_used) + > 75 * GET (head->namehash_size))) { /* The current archive is not large enough. */ enlarge_archive (ah, head); @@ -749,9 +772,9 @@ add_alias (struct locarhandle *ah, const char *alias, bool replace, /* The locrecent might have moved, so we have to look up the old name afresh. */ namehashent = insert_name (ah, oldname, strlen (oldname), true); - assert (namehashent->name_offset != 0); - assert (namehashent->locrec_offset != 0); - *locrec_offset_p = namehashent->locrec_offset; + assert (GET (namehashent->name_offset) != 0); + assert (GET (namehashent->locrec_offset) != 0); + *locrec_offset_p = GET (namehashent->locrec_offset); /* Tail call to try the whole thing again. */ add_alias (ah, alias, replace, oldname, locrec_offset_p); @@ -759,26 +782,27 @@ add_alias (struct locarhandle *ah, const char *alias, bool replace, } /* Add the name string. */ - memcpy (ah->addr + head->string_offset + head->string_used, + memcpy (ah->addr + GET (head->string_offset) + GET (head->string_used), alias, name_len + 1); - namehashent->name_offset = head->string_offset + head->string_used; - head->string_used += name_len + 1; + SET (namehashent->name_offset, + GET (head->string_offset) + GET (head->string_used)); + INC (head->string_used, name_len + 1); - ++head->namehash_used; + INC (head->namehash_used, 1); } - if (namehashent->locrec_offset != 0) + if (GET (namehashent->locrec_offset) != 0) { /* Replacing an existing entry. Mark that we are no longer using the old locrecent. */ struct locrecent *locrecent = (struct locrecent *) ((char *) ah->addr - + namehashent->locrec_offset); - --locrecent->refs; + + GET (namehashent->locrec_offset)); + INC (locrecent->refs, -1); } /* Point this entry at the locrecent installed for the main name. */ - namehashent->locrec_offset = locrec_offset; + SET (namehashent->locrec_offset, locrec_offset); } static int /* qsort comparator used below */ @@ -819,7 +843,7 @@ add_locale (struct locarhandle *ah, head = ah->addr; sumhashtab = (struct sumhashent *) ((char *) ah->addr - + head->sumhash_offset); + + GET (head->sumhash_offset)); memset (file_offsets, 0, sizeof (file_offsets)); @@ -877,10 +901,10 @@ add_locale (struct locarhandle *ah, table. */ hval = archive_hashval (data[cnt].sum, 16); - idx = hval % head->sumhash_size; - incr = 1 + hval % (head->sumhash_size - 2); + idx = hval % GET (head->sumhash_size); + incr = 1 + hval % (GET (head->sumhash_size) - 2); - while (sumhashtab[idx].file_offset != 0) + while (GET (sumhashtab[idx].file_offset) != 0) { if (memcmp (data[cnt].sum, sumhashtab[idx].sum, 16) == 0) { @@ -890,40 +914,42 @@ add_locale (struct locarhandle *ah, Unfortunately the sumhashent record does not include the size of the stored data. So we have to search for it. */ - locrecent = (struct locrecent *) ((char *) ah->addr - + head->locrectab_offset); + locrecent + = (struct locrecent *) ((char *) ah->addr + + GET (head->locrectab_offset)); size_t iloc; - for (iloc = 0; iloc < head->locrectab_used; ++iloc) - if (locrecent[iloc].refs != 0 - && (locrecent[iloc].record[cnt].offset - == sumhashtab[idx].file_offset)) + for (iloc = 0; iloc < GET (head->locrectab_used); ++iloc) + if (GET (locrecent[iloc].refs) != 0 + && (GET (locrecent[iloc].record[cnt].offset) + == GET (sumhashtab[idx].file_offset))) break; - if (iloc != head->locrectab_used - && data[cnt].size == locrecent[iloc].record[cnt].len + if (iloc != GET (head->locrectab_used) + && data[cnt].size == GET (locrecent[iloc].record[cnt].len) /* We have to compare the content. Either we can have the data mmaped or we have to read from the file. */ - && (file_data_available_p (ah, sumhashtab[idx].file_offset, - data[cnt].size) + && (file_data_available_p + (ah, GET (sumhashtab[idx].file_offset), + data[cnt].size) ? memcmp (data[cnt].addr, (char *) ah->addr - + sumhashtab[idx].file_offset, + + GET (sumhashtab[idx].file_offset), data[cnt].size) == 0 : compare_from_file (ah, data[cnt].addr, - sumhashtab[idx].file_offset, + GET (sumhashtab[idx].file_offset), data[cnt].size) == 0)) { /* Found it. */ - file_offsets[cnt] = sumhashtab[idx].file_offset; + file_offsets[cnt] = GET (sumhashtab[idx].file_offset); --num_new_offsets; break; } } idx += incr; - if (idx >= head->sumhash_size) - idx -= head->sumhash_size; + if (idx >= GET (head->sumhash_size)) + idx -= GET (head->sumhash_size); } } @@ -933,11 +959,14 @@ add_locale (struct locarhandle *ah, return 0; /* Determine whether we have to resize the file. */ - if (100 * (head->sumhash_used + num_new_offsets) > 75 * head->sumhash_size - || (namehashent->locrec_offset == 0 - && (head->locrectab_used == head->locrectab_size - || head->string_used + name_len + 1 > head->string_size - || 100 * head->namehash_used > 75 * head->namehash_size))) + if ((100 * (GET (head->sumhash_used) + num_new_offsets) + > 75 * GET (head->sumhash_size)) + || (GET (namehashent->locrec_offset) == 0 + && (GET (head->locrectab_used) == GET (head->locrectab_size) + || (GET (head->string_used) + name_len + 1 + > GET (head->string_size)) + || (100 * GET (head->namehash_used) + > 75 * GET (head->namehash_size))))) { /* The current archive is not large enough. */ enlarge_archive (ah, head); @@ -1000,20 +1029,20 @@ add_locale (struct locarhandle *ah, /* Add the hash value to the hash table. */ md5hval = archive_hashval (data[cnt].sum, 16); - idx = md5hval % head->sumhash_size; - incr = 1 + md5hval % (head->sumhash_size - 2); + idx = md5hval % GET (head->sumhash_size); + incr = 1 + md5hval % (GET (head->sumhash_size) - 2); - while (sumhashtab[idx].file_offset != 0) + while (GET (sumhashtab[idx].file_offset) != 0) { idx += incr; - if (idx >= head->sumhash_size) - idx -= head->sumhash_size; + if (idx >= GET (head->sumhash_size)) + idx -= GET (head->sumhash_size); } memcpy (sumhashtab[idx].sum, data[cnt].sum, 16); - sumhashtab[idx].file_offset = file_offsets[cnt]; + SET (sumhashtab[idx].file_offset, file_offsets[cnt]); - ++head->sumhash_used; + INC (head->sumhash_used, 1); } lastoffset = file_offsets[LC_ALL]; @@ -1024,25 +1053,28 @@ add_locale (struct locarhandle *ah, lastoffset += (data[cnt].size + 15) & -16; } - if (namehashent->name_offset == 0) + if (GET (namehashent->name_offset) == 0) { /* Add the name string. */ - memcpy ((char *) ah->addr + head->string_offset + head->string_used, + memcpy ((char *) ah->addr + GET (head->string_offset) + + GET (head->string_used), name, name_len + 1); - namehashent->name_offset = head->string_offset + head->string_used; - head->string_used += name_len + 1; - ++head->namehash_used; + SET (namehashent->name_offset, + GET (head->string_offset) + GET (head->string_used)); + INC (head->string_used, name_len + 1); + INC (head->namehash_used, 1); } - if (namehashent->locrec_offset == 0) + if (GET (namehashent->locrec_offset == 0)) { /* Allocate a name location record. */ - namehashent->locrec_offset = (head->locrectab_offset - + (head->locrectab_used++ - * sizeof (struct locrecent))); + SET (namehashent->locrec_offset, (GET (head->locrectab_offset) + + (GET (head->locrectab_used) + * sizeof (struct locrecent)))); + INC (head->locrectab_used, 1); locrecent = (struct locrecent *) ((char *) ah->addr - + namehashent->locrec_offset); - locrecent->refs = 1; + + GET (namehashent->locrec_offset)); + SET (locrecent->refs, 1); } else { @@ -1050,27 +1082,29 @@ add_locale (struct locarhandle *ah, we still need a new one. If not, reuse the old one. */ locrecent = (struct locrecent *) ((char *) ah->addr - + namehashent->locrec_offset); - if (locrecent->refs > 1) + + GET (namehashent->locrec_offset)); + if (GET (locrecent->refs) > 1) { - --locrecent->refs; - namehashent->locrec_offset = (head->locrectab_offset - + (head->locrectab_used++ - * sizeof (struct locrecent))); - locrecent = (struct locrecent *) ((char *) ah->addr - + namehashent->locrec_offset); - locrecent->refs = 1; + INC (locrecent->refs, -1); + SET (namehashent->locrec_offset, (GET (head->locrectab_offset) + + (GET (head->locrectab_used) + * sizeof (struct locrecent)))); + INC (head->locrectab_used, 1); + locrecent + = (struct locrecent *) ((char *) ah->addr + + GET (namehashent->locrec_offset)); + SET (locrecent->refs, 1); } } /* Fill in the table with the locations of the locale data. */ for (cnt = 0; cnt < __LC_LAST; ++cnt) { - locrecent->record[cnt].offset = file_offsets[cnt]; - locrecent->record[cnt].len = data[cnt].size; + SET (locrecent->record[cnt].offset, file_offsets[cnt]); + SET (locrecent->record[cnt].len, data[cnt].size); } - return namehashent->locrec_offset; + return GET (namehashent->locrec_offset); } @@ -1129,7 +1163,8 @@ add_locale_to_archive (ah, name, data, replace) unsigned int strindex[0]; } *filedata = data[LC_CTYPE].addr; codeset = (char *) filedata - + filedata->strindex[_NL_ITEM_INDEX (_NL_CTYPE_CODESET_NAME)]; + + maybe_swap_uint32 (filedata->strindex[_NL_ITEM_INDEX + (_NL_CTYPE_CODESET_NAME)]); char *normalized_codeset_name = NULL; normalized_codeset = _nl_normalize_codeset (codeset, strlen (codeset)); @@ -1492,7 +1527,7 @@ delete_locales_from_archive (nlist, list) head = ah.addr; namehashtab = (struct namehashent *) ((char *) ah.addr - + head->namehash_offset); + + GET (head->namehash_offset)); while (nlist-- > 0) { @@ -1504,30 +1539,31 @@ delete_locales_from_archive (nlist, list) /* Search for this locale in the archive. */ hval = archive_hashval (locname, strlen (locname)); - idx = hval % head->namehash_size; - incr = 1 + hval % (head->namehash_size - 2); + idx = hval % GET (head->namehash_size); + incr = 1 + hval % (GET (head->namehash_size) - 2); /* If the name_offset field is zero this means this is no deleted entry and therefore no entry can be found. */ - while (namehashtab[idx].name_offset != 0) + while (GET (namehashtab[idx].name_offset) != 0) { - if (namehashtab[idx].hashval == hval + if (GET (namehashtab[idx].hashval) == hval && (strcmp (locname, - (char *) ah.addr + namehashtab[idx].name_offset) + ((char *) ah.addr + + GET (namehashtab[idx].name_offset))) == 0)) { /* Found the entry. Now mark it as removed by zero-ing the reference to the locale record. */ - namehashtab[idx].locrec_offset = 0; + SET (namehashtab[idx].locrec_offset, 0); break; } idx += incr; - if (idx >= head->namehash_size) - idx -= head->namehash_size; + if (idx >= GET (head->namehash_size)) + idx -= GET (head->namehash_size); } - if (namehashtab[idx].name_offset == 0 && ! be_quiet) + if (GET (namehashtab[idx].name_offset) == 0 && ! be_quiet) error (0, 0, _("locale \"%s\" not in archive"), locname); } @@ -1590,17 +1626,17 @@ show_archive_content (int verbose) head = ah.addr; - names = (struct nameent *) xmalloc (head->namehash_used + names = (struct nameent *) xmalloc (GET (head->namehash_used) * sizeof (struct nameent)); namehashtab = (struct namehashent *) ((char *) ah.addr - + head->namehash_offset); - for (cnt = used = 0; cnt < head->namehash_size; ++cnt) - if (namehashtab[cnt].locrec_offset != 0) + + GET (head->namehash_offset)); + for (cnt = used = 0; cnt < GET (head->namehash_size); ++cnt) + if (GET (namehashtab[cnt].locrec_offset) != 0) { - assert (used < head->namehash_used); - names[used].name = ah.addr + namehashtab[cnt].name_offset; - names[used++].locrec_offset = namehashtab[cnt].locrec_offset; + assert (used < GET (head->namehash_used)); + names[used].name = ah.addr + GET (namehashtab[cnt].name_offset); + names[used++].locrec_offset = GET (namehashtab[cnt].locrec_offset); } /* Sort the names. */ @@ -1612,17 +1648,17 @@ show_archive_content (int verbose) struct sumhashent *sumhashtab; int sumused; - files = (struct dataent *) xmalloc (head->sumhash_used + files = (struct dataent *) xmalloc (GET (head->sumhash_used) * sizeof (struct dataent)); sumhashtab = (struct sumhashent *) ((char *) ah.addr - + head->sumhash_offset); - for (cnt = sumused = 0; cnt < head->sumhash_size; ++cnt) - if (sumhashtab[cnt].file_offset != 0) + + GET (head->sumhash_offset)); + for (cnt = sumused = 0; cnt < GET (head->sumhash_size); ++cnt) + if (GET (sumhashtab[cnt].file_offset) != 0) { - assert (sumused < head->sumhash_used); + assert (sumused < GET (head->sumhash_used)); files[sumused].sum = (const unsigned char *) sumhashtab[cnt].sum; - files[sumused].file_offset = sumhashtab[cnt].file_offset; + files[sumused].file_offset = GET (sumhashtab[cnt].file_offset); files[sumused++].nlink = 0; } @@ -1638,18 +1674,19 @@ show_archive_content (int verbose) locrec = (struct locrecent *) ((char *) ah.addr + names[cnt].locrec_offset); for (idx = 0; idx < __LC_LAST; ++idx) - if (locrec->record[LC_ALL].offset != 0 + if (GET (locrec->record[LC_ALL].offset) != 0 ? (idx == LC_ALL - || (locrec->record[idx].offset - < locrec->record[LC_ALL].offset) - || (locrec->record[idx].offset + locrec->record[idx].len - > (locrec->record[LC_ALL].offset - + locrec->record[LC_ALL].len))) + || (GET (locrec->record[idx].offset) + < GET (locrec->record[LC_ALL].offset)) + || ((GET (locrec->record[idx].offset) + + GET (locrec->record[idx].len)) + > (GET (locrec->record[LC_ALL].offset) + + GET (locrec->record[LC_ALL].len)))) : idx != LC_ALL) { struct dataent *data, dataent; - dataent.file_offset = locrec->record[idx].offset; + dataent.file_offset = GET (locrec->record[idx].offset); data = (struct dataent *) bsearch (&dataent, files, sumused, sizeof (struct dataent), dataentcmp); @@ -1671,21 +1708,24 @@ show_archive_content (int verbose) { struct dataent *data, dataent; - dataent.file_offset = locrec->record[idx].offset; - if (locrec->record[LC_ALL].offset != 0 - && dataent.file_offset >= locrec->record[LC_ALL].offset - && (dataent.file_offset + locrec->record[idx].len - <= (locrec->record[LC_ALL].offset - + locrec->record[LC_ALL].len))) - dataent.file_offset = locrec->record[LC_ALL].offset; + dataent.file_offset = GET (locrec->record[idx].offset); + if (GET (locrec->record[LC_ALL].offset) != 0 + && (dataent.file_offset + >= GET (locrec->record[LC_ALL].offset)) + && (dataent.file_offset + GET (locrec->record[idx].len) + <= (GET (locrec->record[LC_ALL].offset) + + GET (locrec->record[LC_ALL].len)))) + dataent.file_offset = GET (locrec->record[LC_ALL].offset); data = (struct dataent *) bsearch (&dataent, files, sumused, sizeof (struct dataent), dataentcmp); printf ("%6d %7x %3d%c ", - locrec->record[idx].len, locrec->record[idx].offset, + GET (locrec->record[idx].len), + GET (locrec->record[idx].offset), data->nlink, - dataent.file_offset == locrec->record[LC_ALL].offset + (dataent.file_offset + == GET (locrec->record[LC_ALL].offset)) ? '+' : ' '); for (i = 0; i < 16; i += 4) printf ("%02x%02x%02x%02x", diff --git a/locale/programs/locfile.c b/locale/programs/locfile.c index cb53bbc406..4969391bf5 100644 --- a/locale/programs/locfile.c +++ b/locale/programs/locfile.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -538,6 +539,10 @@ compare_files (const char *filename1, const char *filename2, size_t size, return ret; } +/* True if the locale files use the opposite endianness to the + machine running localedef. */ +bool swap_endianness_p; + /* When called outside a start_locale_structure/end_locale_structure or start_locale_prelude/end_locale_prelude block, record that the next byte in FILE's obstack will be the first byte of a new element. @@ -624,6 +629,7 @@ add_locale_uint32 (struct locale_file *file, uint32_t value) { align_locale_data (file, sizeof (uint32_t)); record_offset (file); + value = maybe_swap_uint32 (value); obstack_grow (&file->data, &value, sizeof (value)); } @@ -636,6 +642,7 @@ add_locale_uint32_array (struct locale_file *file, align_locale_data (file, sizeof (uint32_t)); record_offset (file); obstack_grow (&file->data, data, n_elems * sizeof (uint32_t)); + maybe_swap_uint32_obstack (&file->data, n_elems); } /* Record that FILE's next element is the single byte given by VALUE. */ @@ -708,6 +715,8 @@ write_locale_data (const char *output_path, int catidx, const char *category, vec[1].iov_base = file->offsets; vec[2].iov_len = obstack_object_size (&file->data); vec[2].iov_base = obstack_finish (&file->data); + maybe_swap_uint32_array (vec[0].iov_base, 2); + maybe_swap_uint32_array (vec[1].iov_base, file->n_elements); n_elem = 3; if (! no_archive) { diff --git a/locale/programs/locfile.h b/locale/programs/locfile.h index bdd87cc426..cb3e22fd87 100644 --- a/locale/programs/locfile.h +++ b/locale/programs/locfile.h @@ -18,6 +18,8 @@ #ifndef _LOCFILE_H #define _LOCFILE_H 1 +#include +#include #include #include @@ -67,6 +69,41 @@ extern void write_all_categories (struct localedef_t *definitions, const char *locname, const char *output_path); +extern bool swap_endianness_p; + +/* Change the output to be big-endian if BIG_ENDIAN is true and + little-endian otherwise. */ +static inline void +set_big_endian (bool big_endian) +{ + swap_endianness_p = (big_endian != (__BYTE_ORDER == __BIG_ENDIAN)); +} + +/* Munge VALUE so that, when stored, it has the correct byte order + for the output files. */ +static inline uint32_t +maybe_swap_uint32 (uint32_t value) +{ + return swap_endianness_p ? bswap_32 (value) : value; +} + +/* Likewise, but munge an array of N uint32_ts starting at ARRAY. */ +static inline void +maybe_swap_uint32_array (uint32_t *array, size_t n) +{ + if (swap_endianness_p) + while (n-- > 0) + array[n] = bswap_32 (array[n]); +} + +/* Like maybe_swap_uint32_array, but the array of N elements is at + the end of OBSTACK's current object. */ +static inline void +maybe_swap_uint32_obstack (struct obstack *obstack, size_t n) +{ + maybe_swap_uint32_array ((uint32_t *) obstack_next_free (obstack) - n, n); +} + /* Write out the data. */ extern void init_locale_data (struct locale_file *file, size_t n_elements); extern void align_locale_data (struct locale_file *file, size_t boundary); -- 2.11.4.GIT