michael@0: /* michael@0: * Copyright (c) 2000,2001,2002 Japan Network Information Center. michael@0: * All rights reserved. michael@0: * michael@0: * By using this file, you agree to the terms and conditions set forth bellow. michael@0: * michael@0: * LICENSE TERMS AND CONDITIONS michael@0: * michael@0: * The following License Terms and Conditions apply, unless a different michael@0: * license is obtained from Japan Network Information Center ("JPNIC"), michael@0: * a Japanese association, Kokusai-Kougyou-Kanda Bldg 6F, 2-3-4 Uchi-Kanda, michael@0: * Chiyoda-ku, Tokyo 101-0047, Japan. michael@0: * michael@0: * 1. Use, Modification and Redistribution (including distribution of any michael@0: * modified or derived work) in source and/or binary forms is permitted michael@0: * under this License Terms and Conditions. michael@0: * michael@0: * 2. Redistribution of source code must retain the copyright notices as they michael@0: * appear in each source code file, this License Terms and Conditions. michael@0: * michael@0: * 3. Redistribution in binary form must reproduce the Copyright Notice, michael@0: * this License Terms and Conditions, in the documentation and/or other michael@0: * materials provided with the distribution. For the purposes of binary michael@0: * distribution the "Copyright Notice" refers to the following language: michael@0: * "Copyright (c) 2000-2002 Japan Network Information Center. All rights reserved." michael@0: * michael@0: * 4. The name of JPNIC may not be used to endorse or promote products michael@0: * derived from this Software without specific prior written approval of michael@0: * JPNIC. michael@0: * michael@0: * 5. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY JPNIC michael@0: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A michael@0: * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JPNIC BE LIABLE michael@0: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR michael@0: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF michael@0: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR michael@0: * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, michael@0: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR michael@0: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF michael@0: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. michael@0: */ michael@0: michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "nsIDNKitInterface.h" michael@0: michael@0: michael@0: #define RACE_2OCTET_MODE 0xd8 michael@0: #define RACE_ESCAPE 0xff michael@0: #define RACE_ESCAPE_2ND 0x99 michael@0: michael@0: /* michael@0: * Compression type. michael@0: */ michael@0: enum { michael@0: compress_one, /* all characters are in a single row */ michael@0: compress_two, /* row 0 and another row */ michael@0: compress_none /* nope */ michael@0: }; michael@0: michael@0: michael@0: idn_result_t michael@0: race_decode_decompress(const char *from, uint16_t *buf, size_t buflen) michael@0: { michael@0: uint16_t *p = buf; michael@0: unsigned int bitbuf = 0; michael@0: int bitlen = 0; michael@0: unsigned int i, j; michael@0: size_t len; michael@0: michael@0: while (*from != '\0') { michael@0: int c = *from++; michael@0: int x; michael@0: michael@0: if ('a' <= c && c <= 'z') michael@0: x = c - 'a'; michael@0: else if ('A' <= c && c <= 'Z') michael@0: x = c - 'A'; michael@0: else if ('2' <= c && c <= '7') michael@0: x = c - '2' + 26; michael@0: else michael@0: return (idn_invalid_encoding); michael@0: michael@0: bitbuf = (bitbuf << 5) + x; michael@0: bitlen += 5; michael@0: if (bitlen >= 8) { michael@0: *p++ = (bitbuf >> (bitlen - 8)) & 0xff; michael@0: bitlen -= 8; michael@0: } michael@0: } michael@0: len = p - buf; michael@0: michael@0: /* michael@0: * Now 'buf' holds the decoded string. michael@0: */ michael@0: michael@0: /* michael@0: * Decompress. michael@0: */ michael@0: if (buf[0] == RACE_2OCTET_MODE) { michael@0: if ((len - 1) % 2 != 0) michael@0: return (idn_invalid_encoding); michael@0: for (i = 1, j = 0; i < len; i += 2, j++) michael@0: buf[j] = (buf[i] << 8) + buf[i + 1]; michael@0: len = j; michael@0: } else { michael@0: uint16_t c = buf[0] << 8; /* higher octet */ michael@0: michael@0: for (i = 1, j = 0; i < len; j++) { michael@0: if (buf[i] == RACE_ESCAPE) { michael@0: if (i + 1 >= len) michael@0: return (idn_invalid_encoding); michael@0: else if (buf[i + 1] == RACE_ESCAPE_2ND) michael@0: buf[j] = c | 0xff; michael@0: else michael@0: buf[j] = buf[i + 1]; michael@0: i += 2; michael@0: michael@0: } else if (buf[i] == 0x99 && c == 0x00) { michael@0: /* michael@0: * The RACE specification says this is error. michael@0: */ michael@0: return (idn_invalid_encoding); michael@0: michael@0: } else { michael@0: buf[j] = c | buf[i++]; michael@0: } michael@0: } michael@0: len = j; michael@0: } michael@0: buf[len] = '\0'; michael@0: michael@0: return (idn_success); michael@0: } michael@0: michael@0: idn_result_t michael@0: race_compress_encode(const uint16_t *p, int compress_mode, michael@0: char *to, size_t tolen) michael@0: { michael@0: uint32_t bitbuf = *p++; /* bit stream buffer */ michael@0: int bitlen = 8; /* # of bits in 'bitbuf' */ michael@0: michael@0: while (*p != '\0' || bitlen > 0) { michael@0: unsigned int c = *p; michael@0: michael@0: if (c == '\0') { michael@0: /* End of data. Flush. */ michael@0: bitbuf <<= (5 - bitlen); michael@0: bitlen = 5; michael@0: } else if (compress_mode == compress_none) { michael@0: /* Push 16 bit data. */ michael@0: bitbuf = (bitbuf << 16) | c; michael@0: bitlen += 16; michael@0: p++; michael@0: } else {/* compress_mode == compress_one/compress_two */ michael@0: /* Push 8 or 16 bit data. */ michael@0: if (compress_mode == compress_two && michael@0: (c & 0xff00) == 0) { michael@0: /* Upper octet is zero (and not U1). */ michael@0: bitbuf = (bitbuf << 16) | 0xff00 | c; michael@0: bitlen += 16; michael@0: } else if ((c & 0xff) == 0xff) { michael@0: /* Lower octet is 0xff. */ michael@0: bitbuf = (bitbuf << 16) | michael@0: (RACE_ESCAPE << 8) | RACE_ESCAPE_2ND; michael@0: bitlen += 16; michael@0: } else { michael@0: /* Just output lower octet. */ michael@0: bitbuf = (bitbuf << 8) | (c & 0xff); michael@0: bitlen += 8; michael@0: } michael@0: p++; michael@0: } michael@0: michael@0: /* michael@0: * Output bits in 'bitbuf' in 5-bit unit. michael@0: */ michael@0: while (bitlen >= 5) { michael@0: int x; michael@0: michael@0: /* Get top 5 bits. */ michael@0: x = (bitbuf >> (bitlen - 5)) & 0x1f; michael@0: bitlen -= 5; michael@0: michael@0: /* Encode. */ michael@0: if (x < 26) michael@0: x += 'a'; michael@0: else michael@0: x = (x - 26) + '2'; michael@0: michael@0: if (tolen < 1) michael@0: return (idn_buffer_overflow); michael@0: michael@0: *to++ = x; michael@0: tolen--; michael@0: } michael@0: } michael@0: michael@0: if (tolen <= 0) michael@0: return (idn_buffer_overflow); michael@0: michael@0: *to = '\0'; michael@0: return (idn_success); michael@0: } michael@0: michael@0: int michael@0: get_compress_mode(uint16_t *p) { michael@0: int zero = 0; michael@0: unsigned int upper = 0; michael@0: uint16_t *modepos = p - 1; michael@0: michael@0: while (*p != '\0') { michael@0: unsigned int hi = *p++ & 0xff00; michael@0: michael@0: if (hi == 0) { michael@0: zero++; michael@0: } else if (hi == upper) { michael@0: ; michael@0: } else if (upper == 0) { michael@0: upper = hi; michael@0: } else { michael@0: *modepos = RACE_2OCTET_MODE; michael@0: return (compress_none); michael@0: } michael@0: } michael@0: *modepos = upper >> 8; michael@0: if (upper > 0 && zero > 0) michael@0: return (compress_two); michael@0: else michael@0: return (compress_one); michael@0: }