+static int
+test_rc_datablock_unicode (rc_uint_type length, const bfd_byte *data)
+{
+ rc_uint_type i;
+ if ((length & 1) != 0)
+ return 0;
+
+ for (i = 0; i < length; i += 2)
+ {
+ if (data[i] == 0 && data[i + 1] == 0 && (i + 2) < length)
+ return 0;
+ if (data[i] == 0xff && data[i + 1] == 0xff)
+ return 0;
+ }
+ return 1;
+}
+
+static int
+test_rc_datablock_text (rc_uint_type length, const bfd_byte *data)
+{
+ int has_nl;
+ rc_uint_type c;
+ rc_uint_type i;
+
+ if (length <= 1)
+ return 0;
+
+ has_nl = 0;
+ for (i = 0, c = 0; i < length; i++)
+ {
+ if (! ISPRINT (data[i]) && data[i] != '\n'
+ && ! (data[i] == '\r' && (i + 1) < length && data[i + 1] == '\n')
+ && data[i] != '\t'
+ && ! (data[i] == 0 && (i + 1) != length))
+ {
+ if (data[i] <= 7)
+ return 0;
+ c++;
+ }
+ else if (data[i] == '\n') has_nl++;
+ }
+ if (length > 80 && ! has_nl)
+ return 0;
+ c = (((c * 10000) + (i / 100) - 1)) / i;
+ if (c >= 150)
+ return 0;
+ return 1;
+}
+
+static void
+write_rc_messagetable (FILE *e, rc_uint_type length, const bfd_byte *data)
+{
+ int has_error = 0;
+ const struct bin_messagetable *mt;
+
+ fprintf (e, "BEGIN\n");
+
+ write_rc_datablock (e, length, data, 0, 0, 0);
+
+ fprintf (e, "\n");
+ wr_printcomment (e, "MC syntax dump");
+ if (length < BIN_MESSAGETABLE_SIZE)
+ has_error = 1;
+ else
+ do
+ {
+ rc_uint_type m, i;
+
+ mt = (const struct bin_messagetable *) data;
+ m = windres_get_32 (&wrtarget, mt->cblocks, length);
+
+ if (length < (BIN_MESSAGETABLE_SIZE + m * BIN_MESSAGETABLE_BLOCK_SIZE))
+ {
+ has_error = 1;
+ break;
+ }
+ for (i = 0; i < m; i++)
+ {
+ rc_uint_type low, high, offset;
+ const struct bin_messagetable_item *mti;
+
+ low = windres_get_32 (&wrtarget, mt->items[i].lowid, 4);
+ high = windres_get_32 (&wrtarget, mt->items[i].highid, 4);
+ offset = windres_get_32 (&wrtarget, mt->items[i].offset, 4);
+
+ while (low <= high)
+ {
+ rc_uint_type elen, flags;
+ if ((offset + BIN_MESSAGETABLE_ITEM_SIZE) > length)
+ {
+ has_error = 1;
+ break;
+ }
+ mti = (const struct bin_messagetable_item *) &data[offset];
+ elen = windres_get_16 (&wrtarget, mti->length, 2);
+ flags = windres_get_16 (&wrtarget, mti->flags, 2);
+ if ((offset + elen) > length)
+ {
+ has_error = 1;
+ break;
+ }
+ wr_printcomment (e, "MessageId = 0x%x", low);
+ wr_printcomment (e, "");
+
+ if ((flags & MESSAGE_RESOURCE_UNICODE) == MESSAGE_RESOURCE_UNICODE)
+ {
+ /* PR 17512: file: 5c3232dc. */
+ if (elen > BIN_MESSAGETABLE_ITEM_SIZE * 2)
+ unicode_print (e, (const unichar *) mti->data,
+ (elen - BIN_MESSAGETABLE_ITEM_SIZE) / 2);
+ }
+ else
+ {
+ if (elen > BIN_MESSAGETABLE_ITEM_SIZE)
+ ascii_print (e, (const char *) mti->data,
+ (elen - BIN_MESSAGETABLE_ITEM_SIZE));
+ }
+
+ wr_printcomment (e,"");
+ ++low;
+ offset += elen;
+ }
+ }
+ }
+ while (0);
+
+ if (has_error)
+ wr_printcomment (e, "Illegal data");
+ wr_print_flush (e);
+ fprintf (e, "END\n");
+}
+
+static void
+write_rc_datablock (FILE *e, rc_uint_type length, const bfd_byte *data, int has_next,
+ int hasblock, int show_comment)
+{
+ int plen;
+
+ if (hasblock)
+ fprintf (e, "BEGIN\n");
+
+ if (show_comment == -1)
+ {
+ if (test_rc_datablock_text(length, data))
+ {
+ rc_uint_type i, c;
+ for (i = 0; i < length;)
+ {
+ indent (e, 2);
+ fprintf (e, "\"");
+
+ for (c = 0; i < length && c < 160 && data[i] != '\n'; c++, i++)
+ ;
+ if (i < length && data[i] == '\n')
+ ++i, ++c;
+ ascii_print(e, (const char *) &data[i - c], c);
+ fprintf (e, "\"");
+ if (i < length)
+ fprintf (e, "\n");
+ }
+
+ if (i == 0)
+ {
+ indent (e, 2);
+ fprintf (e, "\"\"");
+ }
+ if (has_next)
+ fprintf (e, ",");
+ fprintf (e, "\n");
+ if (hasblock)
+ fprintf (e, "END\n");
+ return;
+ }
+ if (test_rc_datablock_unicode (length, data))
+ {
+ rc_uint_type i, c;
+ for (i = 0; i < length;)
+ {
+ const unichar *u;
+
+ u = (const unichar *) &data[i];
+ indent (e, 2);
+ fprintf (e, "L\"");
+
+ for (c = 0; i < length && c < 160 && u[c] != '\n'; c++, i += 2)
+ ;
+ if (i < length && u[c] == '\n')
+ i += 2, ++c;
+ unicode_print (e, u, c);
+ fprintf (e, "\"");
+ if (i < length)
+ fprintf (e, "\n");
+ }
+
+ if (i == 0)
+ {
+ indent (e, 2);
+ fprintf (e, "L\"\"");
+ }
+ if (has_next)
+ fprintf (e, ",");
+ fprintf (e, "\n");
+ if (hasblock)
+ fprintf (e, "END\n");
+ return;
+ }
+
+ show_comment = 0;
+ }
+
+ if (length != 0)
+ {
+ rc_uint_type i, max_row;
+ int first = 1;
+
+ max_row = (show_comment ? 4 : 8);
+ indent (e, 2);
+ for (i = 0; i + 3 < length;)
+ {
+ rc_uint_type k;
+ rc_uint_type comment_start;
+
+ comment_start = i;
+
+ if (! first)
+ indent (e, 2);
+
+ for (k = 0; k < max_row && i + 3 < length; k++, i += 4)
+ {
+ if (k == 0)
+ plen = fprintf (e, "0x%lxL",
+ (unsigned long) windres_get_32 (&wrtarget, data + i, length - i));
+ else
+ plen = fprintf (e, " 0x%lxL",
+ (unsigned long) windres_get_32 (&wrtarget, data + i, length - i)) - 1;
+ if (has_next || (i + 4) < length)
+ {
+ if (plen>0 && plen < 11)
+ indent (e, 11 - plen);
+ fprintf (e, ",");
+ }
+ }
+ if (show_comment)
+ {
+ fprintf (e, "\t/* ");
+ ascii_print (e, (const char *) &data[comment_start], i - comment_start);
+ fprintf (e, ". */");
+ }
+ fprintf (e, "\n");
+ first = 0;
+ }
+
+ if (i + 1 < length)
+ {
+ if (! first)
+ indent (e, 2);
+ plen = fprintf (e, "0x%x",
+ (int) windres_get_16 (&wrtarget, data + i, length - i));
+ if (has_next || i + 2 < length)
+ {
+ if (plen > 0 && plen < 11)
+ indent (e, 11 - plen);
+ fprintf (e, ",");
+ }
+ if (show_comment)
+ {
+ fprintf (e, "\t/* ");
+ ascii_print (e, (const char *) &data[i], 2);
+ fprintf (e, ". */");
+ }
+ fprintf (e, "\n");
+ i += 2;
+ first = 0;
+ }
+
+ if (i < length)
+ {
+ if (! first)
+ indent (e, 2);
+ fprintf (e, "\"");
+ ascii_print (e, (const char *) &data[i], 1);
+ fprintf (e, "\"");
+ if (has_next)
+ fprintf (e, ",");
+ fprintf (e, "\n");
+ first = 0;
+ }
+ }
+ if (hasblock)
+ fprintf (e, "END\n");
+}
+