/* AT91SAM7 USB string descriptor builder * (C) 2006 by Harald Welte * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Based on existing utf8_to_utf16le() function, * Copyright (C) 2003 David Brownell * * This program 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. */ #include #include #include #include #include #include static int utf8_to_utf16le(const char *s, uint16_t *cp, unsigned len) { int count = 0; uint8_t c; uint16_t uchar; /* this insists on correct encodings, though not minimal ones. * BUT it currently rejects legit 4-byte UTF-8 code points, * which need surrogate pairs. (Unicode 3.1 can use them.) */ while (len != 0 && (c = (uint8_t) *s++) != 0) { if (c & 0x80) { // 2-byte sequence: // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx if ((c & 0xe0) == 0xc0) { uchar = (c & 0x1f) << 6; c = (uint8_t) *s++; if ((c & 0xc0) != 0xc0) goto fail; c &= 0x3f; uchar |= c; // 3-byte sequence (most CJKV characters): // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx } else if ((c & 0xf0) == 0xe0) { uchar = (c & 0x0f) << 12; c = (uint8_t) *s++; if ((c & 0xc0) != 0xc0) goto fail; c &= 0x3f; uchar |= c << 6; c = (uint8_t) *s++; if ((c & 0xc0) != 0xc0) goto fail; c &= 0x3f; uchar |= c; /* no bogus surrogates */ if (0xd800 <= uchar && uchar <= 0xdfff) goto fail; // 4-byte sequence (surrogate pairs, currently rare): // 11101110wwwwzzzzyy + 110111yyyyxxxxxx // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx // (uuuuu = wwww + 1) // FIXME accept the surrogate code points (only) } else goto fail; } else uchar = c; *cp++ = uchar; count++; len--; } return count; fail: return -1; } #define COLUMNS 6 static int print_array16(uint16_t *buf, int len) { int i; for (i = 0; i < len; i++) { int mod = i % COLUMNS; char *suffix; char *prefix; switch (mod) { case 0: if (i == 0) prefix = "\t"; else prefix= "\t\t\t"; suffix = ", "; break; case COLUMNS-1: prefix = ""; suffix = ",\n"; break; default: prefix = ""; suffix = ", "; break; } printf("%s0x%04x%s", prefix, buf[i], suffix); } } static void print_structhdr(int i, int size) { printf( "static const struct {\n" "\tstruct usb_descriptor_header hdr;\n" "\tuint16_t wData[];\n" "} __attribute__((packed)) string%d = {\n" "\t.hdr = {\n" "\t\t.bLength = sizeof(struct usb_descriptor_header) + %u * sizeof(uint16_t),\n" "\t\t.bDescriptorType = USB_DT_STRING,\n" "\t},\n" "\t.wData = {", i, size); } static void print_structftr(void) { printf("},\n};\n\n"); } int main(int argc, char **argv) { char asciibuf[512+1]; uint16_t utf16buf[1024+1]; int len; int j, i = 1; printf("#ifndef _USB_STRINGS_H\n#define _USB_STRINGS_H\n\n"); printf("/* THIS FILE IS AUTOGENERATED, DO NOT MODIFY MANUALLY */\n\n"); printf("#include \n"); printf("#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))\n\n"); print_structhdr(0, 1); printf("0x0409 /* English */ "); print_structftr(); #if 0 printf("static const struct usb_string_descriptor string0 = {\n" "\t.bLength = sizeof(string0) + 1 * sizeof(uint16_t),\n" "\t.bDescriptorType = USB_DT_STRING,\n" "\t.wData[0] = 0x0409, /* English */\n" "};\n\n"); #endif while (scanf("%512[^\n]\n", asciibuf) != EOF) { len = strlen(asciibuf); printf("/* String %u \"%s\" */\n", i, asciibuf); /* FIXME: check return value */ utf8_to_utf16le(asciibuf, utf16buf, len); print_structhdr(i, len); #if 0 printf("static const struct usb_string_descriptor string%d = {\n" "\t.bLength = sizeof(string%d) + %d * sizeof(uint16_t),\n" "\t.bDescriptorType = USB_DT_STRING,\n" "\t.wData = {", i, i, len); #endif print_array16(utf16buf, len); print_structftr(); #if 0 printf("},\n};\n\n"); #endif i++; } printf("static const struct usb_descriptor_header *usb_strings[] = {\n"); for (j = 0; j < i; j++) printf("\t(struct usb_descriptor_header *) &string%d,\n", j); printf("};\n\n"); printf("#endif /* _USB_STRINGS_H */\n"); exit(0); }