lace.c revision 04bdb234571448ed6194e1d4048e6512f2446f1c
75b02323f467087cf9ccd3acb95da902d6be1cf4Bob Halley#ifndef lint
75b02323f467087cf9ccd3acb95da902d6be1cf4Bob Halleystatic char *rcsid = "$Id: lace.c,v 1.4 2000/11/22 01:52:18 ishisone Exp $";
75b02323f467087cf9ccd3acb95da902d6be1cf4Bob Halley#endif
75b02323f467087cf9ccd3acb95da902d6be1cf4Bob Halley
75b02323f467087cf9ccd3acb95da902d6be1cf4Bob Halley/*
75b02323f467087cf9ccd3acb95da902d6be1cf4Bob Halley * Copyright (c) 2000 Japan Network Information Center. All rights reserved.
75b02323f467087cf9ccd3acb95da902d6be1cf4Bob Halley *
75b02323f467087cf9ccd3acb95da902d6be1cf4Bob Halley * By using this file, you agree to the terms and conditions set forth bellow.
75b02323f467087cf9ccd3acb95da902d6be1cf4Bob Halley *
75b02323f467087cf9ccd3acb95da902d6be1cf4Bob Halley * LICENSE TERMS AND CONDITIONS
75b02323f467087cf9ccd3acb95da902d6be1cf4Bob Halley *
75b02323f467087cf9ccd3acb95da902d6be1cf4Bob Halley * The following License Terms and Conditions apply, unless a different
75b02323f467087cf9ccd3acb95da902d6be1cf4Bob Halley * license is obtained from Japan Network Information Center ("JPNIC"),
75b02323f467087cf9ccd3acb95da902d6be1cf4Bob Halley * a Japanese association, Fuundo Bldg., 1-2 Kanda Ogawamachi, Chiyoda-ku,
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * Tokyo, Japan.
08a768e82ad64ede97f640c88e02984b59122753Michael Graff *
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson * 1. Use, Modification and Redistribution (including distribution of any
64e41159a919b0711321fe688ca5da4f4d1b7d80Bob Halley * modified or derived work) in source and/or binary forms is permitted
a5d43b72413db3edd6b36a58f9bdf2cf6ff692f2Bob Halley * under this License Terms and Conditions.
a5d43b72413db3edd6b36a58f9bdf2cf6ff692f2Bob Halley *
a5d43b72413db3edd6b36a58f9bdf2cf6ff692f2Bob Halley * 2. Redistribution of source code must retain the copyright notices as they
a5d43b72413db3edd6b36a58f9bdf2cf6ff692f2Bob Halley * appear in each source code file, this License Terms and Conditions.
a5d43b72413db3edd6b36a58f9bdf2cf6ff692f2Bob Halley *
a5d43b72413db3edd6b36a58f9bdf2cf6ff692f2Bob Halley * 3. Redistribution in binary form must reproduce the Copyright Notice,
ccdac53c027e8964753b36c4d8c7b0e98af501c2Michael Graff * this License Terms and Conditions, in the documentation and/or other
ccdac53c027e8964753b36c4d8c7b0e98af501c2Michael Graff * materials provided with the distribution. For the purposes of binary
ccdac53c027e8964753b36c4d8c7b0e98af501c2Michael Graff * distribution the "Copyright Notice" refers to the following language:
ccdac53c027e8964753b36c4d8c7b0e98af501c2Michael Graff * "Copyright (c) Japan Network Information Center. All rights reserved."
ccdac53c027e8964753b36c4d8c7b0e98af501c2Michael Graff *
ccdac53c027e8964753b36c4d8c7b0e98af501c2Michael Graff * 4. Neither the name of JPNIC may be used to endorse or promote products
ccdac53c027e8964753b36c4d8c7b0e98af501c2Michael Graff * derived from this Software without specific prior written approval of
ccdac53c027e8964753b36c4d8c7b0e98af501c2Michael Graff * JPNIC.
75a4dd0d377dca2f85cea44e28bf110314c1fe8cDavid Lawrence *
75a4dd0d377dca2f85cea44e28bf110314c1fe8cDavid Lawrence * 5. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY JPNIC
75a4dd0d377dca2f85cea44e28bf110314c1fe8cDavid Lawrence * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
75a4dd0d377dca2f85cea44e28bf110314c1fe8cDavid Lawrence * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
75a4dd0d377dca2f85cea44e28bf110314c1fe8cDavid Lawrence * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JPNIC BE LIABLE
8e06cea14c857429ab7e7299af2dce5eeeaa5ff0Michael Graff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
8e06cea14c857429ab7e7299af2dce5eeeaa5ff0Michael Graff * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
8e06cea14c857429ab7e7299af2dce5eeeaa5ff0Michael Graff * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence *
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * 6. Indemnification by Licensee
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * Any person or entities using and/or redistributing this Software under
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * this License Terms and Conditions shall defend indemnify and hold
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * harmless JPNIC from and against any and all judgements damages,
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * expenses, settlement liabilities, cost and other liabilities of any
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * kind as a result of use and redistribution of this Software or any
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * claim, suite, action, litigation or proceeding by any third party
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * arising out of or relates to this License Terms and Conditions.
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence *
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * 7. Governing Law, Jurisdiction and Venue
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * This License Terms and Conditions shall be governed by and and
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * construed in accordance with the law of Japan. Any person or entities
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * using and/or redistributing this Software under this License Terms and
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * Conditions hereby agrees and consent to the personal and exclusive
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * jurisdiction and venue of Tokyo District Court of Japan.
ae4cbb69eef32ced103fe4561e8d2031ee4c3497David Lawrence */
ae4cbb69eef32ced103fe4561e8d2031ee4c3497David Lawrence
ae4cbb69eef32ced103fe4561e8d2031ee4c3497David Lawrence#include <config.h>
ae4cbb69eef32ced103fe4561e8d2031ee4c3497David Lawrence
ae4cbb69eef32ced103fe4561e8d2031ee4c3497David Lawrence#include <stddef.h>
ae4cbb69eef32ced103fe4561e8d2031ee4c3497David Lawrence#include <stdlib.h>
ae4cbb69eef32ced103fe4561e8d2031ee4c3497David Lawrence#include <string.h>
ae4cbb69eef32ced103fe4561e8d2031ee4c3497David Lawrence
ae4cbb69eef32ced103fe4561e8d2031ee4c3497David Lawrence#include <mdn/result.h>
ae4cbb69eef32ced103fe4561e8d2031ee4c3497David Lawrence#include <mdn/assert.h>
ae4cbb69eef32ced103fe4561e8d2031ee4c3497David Lawrence#include <mdn/logmacro.h>
ae4cbb69eef32ced103fe4561e8d2031ee4c3497David Lawrence#include <mdn/converter.h>
ae4cbb69eef32ced103fe4561e8d2031ee4c3497David Lawrence#include <mdn/utf8.h>
ae4cbb69eef32ced103fe4561e8d2031ee4c3497David Lawrence#include <mdn/debug.h>
ae4cbb69eef32ced103fe4561e8d2031ee4c3497David Lawrence#include <mdn/lace.h>
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence#include <mdn/util.h>
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence#ifdef DEBUG
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence/* Be paranoid. */
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence#define PARANOID
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence#endif
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence#ifndef MDN_LACE_PREFIX
0293ad13207aa29bd5844cdc87d085ffc009d749David Lawrence#define MDN_LACE_PREFIX "bq--"
0293ad13207aa29bd5844cdc87d085ffc009d749David Lawrence#endif
0293ad13207aa29bd5844cdc87d085ffc009d749David Lawrence#define LACE_PREFIX_LEN (strlen(MDN_LACE_PREFIX))
0293ad13207aa29bd5844cdc87d085ffc009d749David Lawrence
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence#define LACE_BUF_SIZE 128 /* more than enough */
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrencestatic mdn_result_t lace_l2u(const char *from, const char *end,
0293ad13207aa29bd5844cdc87d085ffc009d749David Lawrence char *to, size_t tolen, size_t *clenp);
0293ad13207aa29bd5844cdc87d085ffc009d749David Lawrencestatic mdn_result_t lace_u2l(const char *from, const char *end,
0293ad13207aa29bd5844cdc87d085ffc009d749David Lawrence char *to, size_t tolen, size_t *clenp);
0293ad13207aa29bd5844cdc87d085ffc009d749David Lawrencestatic mdn_result_t lace_decode(const char *from, size_t fromlen,
0293ad13207aa29bd5844cdc87d085ffc009d749David Lawrence char *to, size_t tolen);
0293ad13207aa29bd5844cdc87d085ffc009d749David Lawrencestatic mdn_result_t lace_decode_utf16(const char *from, size_t fromlen,
0293ad13207aa29bd5844cdc87d085ffc009d749David Lawrence unsigned short *buf, size_t *lenp);
0293ad13207aa29bd5844cdc87d085ffc009d749David Lawrencestatic mdn_result_t lace_encode(const char *from, size_t fromlen,
0293ad13207aa29bd5844cdc87d085ffc009d749David Lawrence char *to, size_t tolen);
0293ad13207aa29bd5844cdc87d085ffc009d749David Lawrencestatic mdn_result_t lace_encode_utf16(const unsigned short *p,
0293ad13207aa29bd5844cdc87d085ffc009d749David Lawrence size_t len, char *to, size_t tolen,
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence int compress);
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrencestatic int is_compress_effective(unsigned short *p, size_t len);
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence/* ARGSUSED */
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrencemdn_result_t
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrencemdn__lace_open(mdn_converter_t ctx, mdn_converter_dir_t dir) {
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence return (mdn_success);
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence}
657ce0b9d84fbd66514df53d61a087e8f1161187Michael Graff
657ce0b9d84fbd66514df53d61a087e8f1161187Michael Graff/* ARGSUSED */
657ce0b9d84fbd66514df53d61a087e8f1161187Michael Graffmdn_result_t
657ce0b9d84fbd66514df53d61a087e8f1161187Michael Graffmdn__lace_close(mdn_converter_t ctx, mdn_converter_dir_t dir) {
657ce0b9d84fbd66514df53d61a087e8f1161187Michael Graff return (mdn_success);
1ce985ab3c6670662d555c108b35fed84a6a1001David Lawrence}
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrencemdn_result_t
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrencemdn__lace_convert(mdn_converter_t ctx, mdn_converter_dir_t dir,
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence const char *from, char *toorg, size_t tolen)
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence{
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence char *to = toorg;
4bcaefbcd3ced942139fdc830e007c6ea2b8d2feDavid Lawrence
4bcaefbcd3ced942139fdc830e007c6ea2b8d2feDavid Lawrence assert(ctx != NULL &&
4bcaefbcd3ced942139fdc830e007c6ea2b8d2feDavid Lawrence (dir == mdn_converter_l2u || dir == mdn_converter_u2l));
4bcaefbcd3ced942139fdc830e007c6ea2b8d2feDavid Lawrence
4bcaefbcd3ced942139fdc830e007c6ea2b8d2feDavid Lawrence TRACE(("mdn__lace_convert(dir=%s,from=\"%s\")\n",
4bcaefbcd3ced942139fdc830e007c6ea2b8d2feDavid Lawrence dir == mdn_converter_l2u ? "l2u" : "u2l",
4bcaefbcd3ced942139fdc830e007c6ea2b8d2feDavid Lawrence mdn_debug_xstring(from, 20)));
4bcaefbcd3ced942139fdc830e007c6ea2b8d2feDavid Lawrence
4bcaefbcd3ced942139fdc830e007c6ea2b8d2feDavid Lawrence for (;;) {
4bcaefbcd3ced942139fdc830e007c6ea2b8d2feDavid Lawrence const char *end;
4bcaefbcd3ced942139fdc830e007c6ea2b8d2feDavid Lawrence size_t convlen;
4bcaefbcd3ced942139fdc830e007c6ea2b8d2feDavid Lawrence mdn_result_t r;
4bcaefbcd3ced942139fdc830e007c6ea2b8d2feDavid Lawrence
4bcaefbcd3ced942139fdc830e007c6ea2b8d2feDavid Lawrence /*
4bcaefbcd3ced942139fdc830e007c6ea2b8d2feDavid Lawrence * Find the end of this component (label).
4bcaefbcd3ced942139fdc830e007c6ea2b8d2feDavid Lawrence */
657ce0b9d84fbd66514df53d61a087e8f1161187Michael Graff if ((end = strchr(from, '.')) == NULL)
657ce0b9d84fbd66514df53d61a087e8f1161187Michael Graff end = from + strlen(from);
657ce0b9d84fbd66514df53d61a087e8f1161187Michael Graff
657ce0b9d84fbd66514df53d61a087e8f1161187Michael Graff /*
657ce0b9d84fbd66514df53d61a087e8f1161187Michael Graff * Convert it.
657ce0b9d84fbd66514df53d61a087e8f1161187Michael Graff */
657ce0b9d84fbd66514df53d61a087e8f1161187Michael Graff if (dir == mdn_converter_l2u)
657ce0b9d84fbd66514df53d61a087e8f1161187Michael Graff r = lace_l2u(from, end, to, tolen, &convlen);
657ce0b9d84fbd66514df53d61a087e8f1161187Michael Graff else
657ce0b9d84fbd66514df53d61a087e8f1161187Michael Graff r = lace_u2l(from, end, to, tolen, &convlen);
e915367e40b579d18ac13c9c58c15fec614d9890Michael Graff if (r != mdn_success)
e915367e40b579d18ac13c9c58c15fec614d9890Michael Graff return (r);
e915367e40b579d18ac13c9c58c15fec614d9890Michael Graff
e915367e40b579d18ac13c9c58c15fec614d9890Michael Graff /*
e915367e40b579d18ac13c9c58c15fec614d9890Michael Graff * Copy '.' or NUL.
e915367e40b579d18ac13c9c58c15fec614d9890Michael Graff */
08a768e82ad64ede97f640c88e02984b59122753Michael Graff if (tolen <= convlen)
e915367e40b579d18ac13c9c58c15fec614d9890Michael Graff return (mdn_buffer_overflow);
e915367e40b579d18ac13c9c58c15fec614d9890Michael Graff
08a768e82ad64ede97f640c88e02984b59122753Michael Graff to += convlen;
08a768e82ad64ede97f640c88e02984b59122753Michael Graff *to++ = *end;
08a768e82ad64ede97f640c88e02984b59122753Michael Graff tolen -= convlen + 1;
e915367e40b579d18ac13c9c58c15fec614d9890Michael Graff
08a768e82ad64ede97f640c88e02984b59122753Michael Graff if (*end == '\0')
e915367e40b579d18ac13c9c58c15fec614d9890Michael Graff break;
e915367e40b579d18ac13c9c58c15fec614d9890Michael Graff
08a768e82ad64ede97f640c88e02984b59122753Michael Graff from = end + 1;
08a768e82ad64ede97f640c88e02984b59122753Michael Graff }
08a768e82ad64ede97f640c88e02984b59122753Michael Graff
08a768e82ad64ede97f640c88e02984b59122753Michael Graff DUMP(("mdn__lace_convert: \"%s\"\n", mdn_debug_xstring(toorg, 70)));
08a768e82ad64ede97f640c88e02984b59122753Michael Graff
08a768e82ad64ede97f640c88e02984b59122753Michael Graff return (mdn_success);
08a768e82ad64ede97f640c88e02984b59122753Michael Graff}
08a768e82ad64ede97f640c88e02984b59122753Michael Graff
08a768e82ad64ede97f640c88e02984b59122753Michael Graffstatic mdn_result_t
08a768e82ad64ede97f640c88e02984b59122753Michael Grafflace_l2u(const char *from, const char *end,
08a768e82ad64ede97f640c88e02984b59122753Michael Graff char *to, size_t tolen, size_t *clenp)
08a768e82ad64ede97f640c88e02984b59122753Michael Graff{
08a768e82ad64ede97f640c88e02984b59122753Michael Graff size_t len = end - from;
08a768e82ad64ede97f640c88e02984b59122753Michael Graff size_t prefix_len = LACE_PREFIX_LEN;
08a768e82ad64ede97f640c88e02984b59122753Michael Graff
08a768e82ad64ede97f640c88e02984b59122753Michael Graff if (len >= prefix_len &&
08a768e82ad64ede97f640c88e02984b59122753Michael Graff mdn_util_casematch(from, MDN_LACE_PREFIX, prefix_len)) {
08a768e82ad64ede97f640c88e02984b59122753Michael Graff /*
08a768e82ad64ede97f640c88e02984b59122753Michael Graff * LACE encoding prefix found.
08a768e82ad64ede97f640c88e02984b59122753Michael Graff */
e915367e40b579d18ac13c9c58c15fec614d9890Michael Graff mdn_result_t r;
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence r = lace_decode(from + prefix_len,
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence len - prefix_len, to, tolen);
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence if (r == mdn_invalid_encoding)
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence goto copy;
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson else if (r != mdn_success)
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson return (r);
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson len = strlen(to);
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson } else {
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson /*
8a9b755d32a4f6ace792ac3fd17c968cf96d2487David Lawrence * Not LACE encoded. Copy verbatim.
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson */
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson copy:
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson if (mdn_util_domainspan(from, end) < end) {
8a9b755d32a4f6ace792ac3fd17c968cf96d2487David Lawrence /* invalid character found */
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson return (mdn_invalid_encoding);
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson }
971d1fe83172bce09d6319c5735d243d68d8cb47Andreas Gustafsson
971d1fe83172bce09d6319c5735d243d68d8cb47Andreas Gustafsson if (tolen < len)
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence return (mdn_buffer_overflow);
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence (void)memcpy(to, from, len);
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson }
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson *clenp = len;
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson return (mdn_success);
971d1fe83172bce09d6319c5735d243d68d8cb47Andreas Gustafsson}
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafssonstatic mdn_result_t
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafssonlace_u2l(const char *from, const char *end,
971d1fe83172bce09d6319c5735d243d68d8cb47Andreas Gustafsson char *to, size_t tolen, size_t *clenp) {
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson size_t len = end - from;
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson size_t prefix_len = LACE_PREFIX_LEN;
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson /*
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson * See if encoding is necessary.
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson */
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson if (mdn_util_domainspan(from, end) < end) {
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson /*
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson * Conversion is necessary.
971d1fe83172bce09d6319c5735d243d68d8cb47Andreas Gustafsson */
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson mdn_result_t r;
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson /* Set prefix. */
00751e888018f130a562c9c7287d837e9abf13eeDavid Lawrence if (tolen < prefix_len)
00751e888018f130a562c9c7287d837e9abf13eeDavid Lawrence return (mdn_buffer_overflow);
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson (void)memcpy(to, MDN_LACE_PREFIX, prefix_len);
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson to += prefix_len;
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson tolen -= prefix_len;
971d1fe83172bce09d6319c5735d243d68d8cb47Andreas Gustafsson
971d1fe83172bce09d6319c5735d243d68d8cb47Andreas Gustafsson r = lace_encode(from, len, to, tolen);
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence if (r != mdn_success)
2c7e99b941c3f1ffa29f9034c710f358c09f13c9Michael Graff return (r);
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson len = prefix_len + strlen(to);
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson } else {
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson /*
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson * Conversion is NOT necessary.
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson * Copy verbatim.
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson */
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson if (tolen < len)
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson return (mdn_buffer_overflow);
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson (void)memcpy(to, from, len);
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson }
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson *clenp = len;
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson return (mdn_success);
a5d43b72413db3edd6b36a58f9bdf2cf6ff692f2Bob Halley}
13494a4d4bead37f22eb6c4779c73310109f7e4aJames Brister
a5d43b72413db3edd6b36a58f9bdf2cf6ff692f2Bob Halleystatic mdn_result_t
a5d43b72413db3edd6b36a58f9bdf2cf6ff692f2Bob Halleylace_decode(const char *from, size_t fromlen, char *to, size_t tolen) {
7bb707a34778fc4bd9624d6c5de95675424ea59fDavid Lawrence unsigned short *buf;
a5d43b72413db3edd6b36a58f9bdf2cf6ff692f2Bob Halley unsigned short local_buf[LACE_BUF_SIZE];
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence size_t len, reslen;
7b2db4b8d13e3d8bc81419ffcc8b39de8193ef63David Lawrence mdn_result_t r;
7b2db4b8d13e3d8bc81419ffcc8b39de8193ef63David Lawrence
7b2db4b8d13e3d8bc81419ffcc8b39de8193ef63David Lawrence /*
7b2db4b8d13e3d8bc81419ffcc8b39de8193ef63David Lawrence * Allocate sufficient buffer.
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence */
bba4edf671cc3f0d5b0d3eabfaf28d96aadf23ffDavid Lawrence if (fromlen > LACE_BUF_SIZE) {
7b2db4b8d13e3d8bc81419ffcc8b39de8193ef63David Lawrence if ((buf = malloc(sizeof(*buf) * fromlen)) == NULL)
7b2db4b8d13e3d8bc81419ffcc8b39de8193ef63David Lawrence return (mdn_nomemory);
2b556032fd78aff37e80e755044b944a017245cdDavid Lawrence } else {
35c842e05dc6382ce1d9161a658d3ff4b2c3d4c9Bob Halley /* Use local buffer. */
2b556032fd78aff37e80e755044b944a017245cdDavid Lawrence buf = local_buf;
7b2db4b8d13e3d8bc81419ffcc8b39de8193ef63David Lawrence }
c195f74e092cb8a29f144c8e81012bd9c61a79a2Michael Graff
c195f74e092cb8a29f144c8e81012bd9c61a79a2Michael Graff /*
c195f74e092cb8a29f144c8e81012bd9c61a79a2Michael Graff * Decode base32 and decompress.
c195f74e092cb8a29f144c8e81012bd9c61a79a2Michael Graff */
bba4edf671cc3f0d5b0d3eabfaf28d96aadf23ffDavid Lawrence r = lace_decode_utf16(from, fromlen, buf, &len);
7b2db4b8d13e3d8bc81419ffcc8b39de8193ef63David Lawrence if (r != mdn_success)
2b556032fd78aff37e80e755044b944a017245cdDavid Lawrence goto ret;
35c842e05dc6382ce1d9161a658d3ff4b2c3d4c9Bob Halley
2b556032fd78aff37e80e755044b944a017245cdDavid Lawrence /*
a5d43b72413db3edd6b36a58f9bdf2cf6ff692f2Bob Halley * Now 'buf' holds the decompressed string, which must contain
a5d43b72413db3edd6b36a58f9bdf2cf6ff692f2Bob Halley * UTF-16 characters. Convert them into UTF-8.
a5d43b72413db3edd6b36a58f9bdf2cf6ff692f2Bob Halley */
a5d43b72413db3edd6b36a58f9bdf2cf6ff692f2Bob Halley r = mdn_util_utf16toutf8(buf, len, to, tolen, &reslen);
a5d43b72413db3edd6b36a58f9bdf2cf6ff692f2Bob Halley if (r != mdn_success)
a2171e092382f8f8a72b1f73436ddf93918c7719Bob Halley goto ret;
a2171e092382f8f8a72b1f73436ddf93918c7719Bob Halley
7c0876aa42e6abaa8779bcb83962ccf20a9f4da3Bob Halley /*
a2171e092382f8f8a72b1f73436ddf93918c7719Bob Halley * Terminate with NUL.
491b48ec3f3ef014312688776ddbd4eab8a2c10cMichael Graff */
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence if (tolen <= reslen) {
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence r = mdn_buffer_overflow;
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence goto ret;
12ccbb032ec1b5f6b93aac923f2645a19fc90c75David Lawrence }
facb97777a972f6c8035ca3e762a6a9248c12897Bob Halley
12ccbb032ec1b5f6b93aac923f2645a19fc90c75David Lawrence to += reslen;
12ccbb032ec1b5f6b93aac923f2645a19fc90c75David Lawrence *to = '\0';
12ccbb032ec1b5f6b93aac923f2645a19fc90c75David Lawrence tolen -= reslen;
12ccbb032ec1b5f6b93aac923f2645a19fc90c75David Lawrence
facb97777a972f6c8035ca3e762a6a9248c12897Bob Halley r = mdn_success;
facb97777a972f6c8035ca3e762a6a9248c12897Bob Halley
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrenceret:
566a01eb745d49bd866971062388cd11d525b60dDavid Lawrence if (buf != local_buf)
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence free(buf);
a505a3f6e09218bebac020fc49105b2e6cd9e25cBob Halley return (r);
566a01eb745d49bd866971062388cd11d525b60dDavid Lawrence}
566a01eb745d49bd866971062388cd11d525b60dDavid Lawrence
566a01eb745d49bd866971062388cd11d525b60dDavid Lawrencestatic mdn_result_t
a505a3f6e09218bebac020fc49105b2e6cd9e25cBob Halleylace_decode_utf16(const char *from, size_t fromlen,
a505a3f6e09218bebac020fc49105b2e6cd9e25cBob Halley unsigned short *buf, size_t *lenp)
a505a3f6e09218bebac020fc49105b2e6cd9e25cBob Halley{
566a01eb745d49bd866971062388cd11d525b60dDavid Lawrence unsigned short *p, *q;
566a01eb745d49bd866971062388cd11d525b60dDavid Lawrence unsigned int bitbuf = 0;
566a01eb745d49bd866971062388cd11d525b60dDavid Lawrence int bitlen = 0;
566a01eb745d49bd866971062388cd11d525b60dDavid Lawrence size_t len;
566a01eb745d49bd866971062388cd11d525b60dDavid Lawrence
566a01eb745d49bd866971062388cd11d525b60dDavid Lawrence /*
566a01eb745d49bd866971062388cd11d525b60dDavid Lawrence * Decode Base32 and put the result bytes to 'buf'.
566a01eb745d49bd866971062388cd11d525b60dDavid Lawrence * Since decoded string will be shorter in length, and
566a01eb745d49bd866971062388cd11d525b60dDavid Lawrence * the caller allocated 'buf' so that its length is not
566a01eb745d49bd866971062388cd11d525b60dDavid Lawrence * less than 'fromlen', we don't have to worry about overflow.
566a01eb745d49bd866971062388cd11d525b60dDavid Lawrence */
566a01eb745d49bd866971062388cd11d525b60dDavid Lawrence p = buf;
566a01eb745d49bd866971062388cd11d525b60dDavid Lawrence while (fromlen-- > 0) {
566a01eb745d49bd866971062388cd11d525b60dDavid Lawrence int c = *from++;
566a01eb745d49bd866971062388cd11d525b60dDavid Lawrence int x;
566a01eb745d49bd866971062388cd11d525b60dDavid Lawrence
1ce985ab3c6670662d555c108b35fed84a6a1001David Lawrence if ('a' <= c && c <= 'z')
facb97777a972f6c8035ca3e762a6a9248c12897Bob Halley x = c - 'a';
facb97777a972f6c8035ca3e762a6a9248c12897Bob Halley else if ('A' <= c && c <= 'Z')
facb97777a972f6c8035ca3e762a6a9248c12897Bob Halley x = c - 'A';
facb97777a972f6c8035ca3e762a6a9248c12897Bob Halley else if ('2' <= c && c <= '7')
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence x = c - '2' + 26;
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence else
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence return (mdn_invalid_encoding);
d8dcd6ad4617cc8d7df979bd62101fa9c4bac1bcBob Halley
d8dcd6ad4617cc8d7df979bd62101fa9c4bac1bcBob Halley bitbuf = (bitbuf << 5) + x;
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence bitlen += 5;
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence if (bitlen >= 8) {
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence *p++ = (bitbuf >> (bitlen - 8)) & 0xff;
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence bitlen -= 8;
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence }
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence }
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence#ifdef PARANOID
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence /* Check if the padding bits are all zero. */
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence if (bitlen > 0 && (bitbuf & ((1 << bitlen) - 1)) != 0) {
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence WARNING(("mdn__lace_convert: non-zero padding\n"));
882350d11c90de9de6fc1cead25690c8114b0b95Michael Graff return (mdn_invalid_encoding);
882350d11c90de9de6fc1cead25690c8114b0b95Michael Graff }
882350d11c90de9de6fc1cead25690c8114b0b95Michael Graff#endif
882350d11c90de9de6fc1cead25690c8114b0b95Michael Graff len = p - buf;
882350d11c90de9de6fc1cead25690c8114b0b95Michael Graff
882350d11c90de9de6fc1cead25690c8114b0b95Michael Graff if (len == 0)
882350d11c90de9de6fc1cead25690c8114b0b95Michael Graff return (mdn_invalid_encoding);
882350d11c90de9de6fc1cead25690c8114b0b95Michael Graff
64ba6e4cc3a0ccf8c8c6349fa75b937ca9bad9a6Michael Graff /*
694c897b20f06f8a5349fd9ac5df93947f6f5a2aBob Halley * Now 'buf' holds the decoded bytes. Rebuild the
694c897b20f06f8a5349fd9ac5df93947f6f5a2aBob Halley * original UTF-16 string.
a5d43b72413db3edd6b36a58f9bdf2cf6ff692f2Bob Halley */
491b48ec3f3ef014312688776ddbd4eab8a2c10cMichael Graff if (buf[0] == 0xff) {
9fbc1afb8b08432e3a1adda1f41d5575620e9785Bob Halley /*
1443aa0adf4d262abdf2721a5239acd4812cdc06Bob Halley * Not compressed.
1443aa0adf4d262abdf2721a5239acd4812cdc06Bob Halley */
1443aa0adf4d262abdf2721a5239acd4812cdc06Bob Halley len--; /* skip first byte (0xff) */
1443aa0adf4d262abdf2721a5239acd4812cdc06Bob Halley if (len % 2 != 0) {
083699db84de2f7cc534c06ed3502248329145d4Bob Halley /* number of bytes must be even. */
083699db84de2f7cc534c06ed3502248329145d4Bob Halley return (mdn_invalid_encoding);
083699db84de2f7cc534c06ed3502248329145d4Bob Halley }
1ce985ab3c6670662d555c108b35fed84a6a1001David Lawrence for (p = buf + 1, q = buf; len > 0; p += 2, q++, len -= 2) {
9fbc1afb8b08432e3a1adda1f41d5575620e9785Bob Halley *q = (p[0] << 8) | p[1];
9fbc1afb8b08432e3a1adda1f41d5575620e9785Bob Halley }
9fbc1afb8b08432e3a1adda1f41d5575620e9785Bob Halley#ifdef PARANOID
a5d43b72413db3edd6b36a58f9bdf2cf6ff692f2Bob Halley if (is_compress_effective(buf, q - buf)) {
a5d43b72413db3edd6b36a58f9bdf2cf6ff692f2Bob Halley /*
a2171e092382f8f8a72b1f73436ddf93918c7719Bob Halley * This string must have been compressed.
68e46ce9ee6bbbc0e61e93f1705657d3ef83127bBob Halley */
694c897b20f06f8a5349fd9ac5df93947f6f5a2aBob Halley WARNING(("mdn__lace_convert: decoded string is not "
a5d43b72413db3edd6b36a58f9bdf2cf6ff692f2Bob Halley "compressed, though it should be.\n"));
1ce985ab3c6670662d555c108b35fed84a6a1001David Lawrence return (mdn_invalid_encoding);
9fbc1afb8b08432e3a1adda1f41d5575620e9785Bob Halley }
694c897b20f06f8a5349fd9ac5df93947f6f5a2aBob Halley#endif
694c897b20f06f8a5349fd9ac5df93947f6f5a2aBob Halley } else {
9fbc1afb8b08432e3a1adda1f41d5575620e9785Bob Halley /*
7c0876aa42e6abaa8779bcb83962ccf20a9f4da3Bob Halley * Compressed.
16c46f3cf540d6e0fff38410ce04a0f26a8f883fBob Halley */
9ca8ad2a26061acc92f224354f1496a339a41a9eBob Halley int count = 0;
7c0876aa42e6abaa8779bcb83962ccf20a9f4da3Bob Halley unsigned short high = 0; /* initialize for lint */
a5d43b72413db3edd6b36a58f9bdf2cf6ff692f2Bob Halley
a5d43b72413db3edd6b36a58f9bdf2cf6ff692f2Bob Halley for (p = q = buf; len > 0; p++, q++, len--) {
694c897b20f06f8a5349fd9ac5df93947f6f5a2aBob Halley if (count == 0) {
694c897b20f06f8a5349fd9ac5df93947f6f5a2aBob Halley if (len < 3 || p[0] == 0)
694c897b20f06f8a5349fd9ac5df93947f6f5a2aBob Halley return (mdn_invalid_encoding);
491b48ec3f3ef014312688776ddbd4eab8a2c10cMichael Graff /* Get COUNT and HIGH. */
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence count = p[0];
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence high = p[1] << 8;
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence p += 2;
28ed3013196c373745dbde87b75a490148dab840Bob Halley len -= 2;
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson }
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence *q = high | *p;
ee7c4a9d17435299f152c4753f0a0dfc890e800aMichael Graff count--;
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson }
28ed3013196c373745dbde87b75a490148dab840Bob Halley if (count != 0)
a5d43b72413db3edd6b36a58f9bdf2cf6ff692f2Bob Halley return (mdn_invalid_encoding);
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence#ifdef PARANOID
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence if (!is_compress_effective(buf, q - buf)) {
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence /*
1922518d7f7b5e3e77b8e1c92569c98268b9c192Andreas Gustafsson * This string must not have been compressed.
9cda9dc86efa0dde8f906759c4e3279da028b5f4Bob Halley */
9cda9dc86efa0dde8f906759c4e3279da028b5f4Bob Halley WARNING(("mdn__lace_convert: decoded string is "
9cda9dc86efa0dde8f906759c4e3279da028b5f4Bob Halley "compressed, though it shouldn't.\n"));
70eb7879553eaa57c391f07e439911bfdaff7124Bob Halley return (mdn_invalid_encoding);
9cda9dc86efa0dde8f906759c4e3279da028b5f4Bob Halley }
35c842e05dc6382ce1d9161a658d3ff4b2c3d4c9Bob Halley#endif
35c842e05dc6382ce1d9161a658d3ff4b2c3d4c9Bob Halley }
9cda9dc86efa0dde8f906759c4e3279da028b5f4Bob Halley
35c842e05dc6382ce1d9161a658d3ff4b2c3d4c9Bob Halley *lenp = q - buf;
35c842e05dc6382ce1d9161a658d3ff4b2c3d4c9Bob Halley return (mdn_success);
51917258dbb23cfe6069ae1cf2b7fc5aefc1e0c2Bob Halley}
35c842e05dc6382ce1d9161a658d3ff4b2c3d4c9Bob Halley
9cda9dc86efa0dde8f906759c4e3279da028b5f4Bob Halleystatic mdn_result_t
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrencelace_encode(const char *from, size_t fromlen, char *to, size_t tolen) {
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence unsigned short *buf;
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence unsigned short local_buf[LACE_BUF_SIZE]; /* UTF-16 */
4c5faa6bcf41d8ba253b872a04105a2fcc88c07bMichael Graff mdn_result_t r;
4c5faa6bcf41d8ba253b872a04105a2fcc88c07bMichael Graff size_t buflen, len;
4c5faa6bcf41d8ba253b872a04105a2fcc88c07bMichael Graff
4c5faa6bcf41d8ba253b872a04105a2fcc88c07bMichael Graff /*
4c5faa6bcf41d8ba253b872a04105a2fcc88c07bMichael Graff * Convert to UTF-16.
4c5faa6bcf41d8ba253b872a04105a2fcc88c07bMichael Graff */
51917258dbb23cfe6069ae1cf2b7fc5aefc1e0c2Bob Halley buf = local_buf;
4c5faa6bcf41d8ba253b872a04105a2fcc88c07bMichael Graff buflen = LACE_BUF_SIZE;
51917258dbb23cfe6069ae1cf2b7fc5aefc1e0c2Bob Halley for (;;) {
51917258dbb23cfe6069ae1cf2b7fc5aefc1e0c2Bob Halley r = mdn_util_utf8toutf16(from, fromlen,
4c5faa6bcf41d8ba253b872a04105a2fcc88c07bMichael Graff buf, buflen, &len);
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence if (r == mdn_buffer_overflow) {
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence buflen *= 2;
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence if (buf == local_buf)
8671e8306b3f18abf0e19c2fb9d49205962e7ab7David Lawrence buf = malloc(sizeof(*buf) * buflen);
8671e8306b3f18abf0e19c2fb9d49205962e7ab7David Lawrence else
6c327669ba1d9eca870572b930c46f43e781d4a3Andreas Gustafsson buf = realloc(buf, sizeof(*buf) * buflen);
8671e8306b3f18abf0e19c2fb9d49205962e7ab7David Lawrence if (buf == NULL)
8671e8306b3f18abf0e19c2fb9d49205962e7ab7David Lawrence return (mdn_nomemory);
8671e8306b3f18abf0e19c2fb9d49205962e7ab7David Lawrence } else if (r == mdn_success) {
51917258dbb23cfe6069ae1cf2b7fc5aefc1e0c2Bob Halley break;
8671e8306b3f18abf0e19c2fb9d49205962e7ab7David Lawrence } else {
51917258dbb23cfe6069ae1cf2b7fc5aefc1e0c2Bob Halley goto ret;
51917258dbb23cfe6069ae1cf2b7fc5aefc1e0c2Bob Halley }
8671e8306b3f18abf0e19c2fb9d49205962e7ab7David Lawrence }
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence /*
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * Compress, encode in base-32 and output.
c7620c99f1139b77f14678e21a44f7c8c4236a7bMark Andrews */
c7620c99f1139b77f14678e21a44f7c8c4236a7bMark Andrews r = lace_encode_utf16(buf, len, to, tolen,
c7620c99f1139b77f14678e21a44f7c8c4236a7bMark Andrews is_compress_effective(buf, len));
c7620c99f1139b77f14678e21a44f7c8c4236a7bMark Andrews
c7620c99f1139b77f14678e21a44f7c8c4236a7bMark Andrewsret:
c7620c99f1139b77f14678e21a44f7c8c4236a7bMark Andrews if (buf != local_buf)
c7620c99f1139b77f14678e21a44f7c8c4236a7bMark Andrews free(buf);
c7620c99f1139b77f14678e21a44f7c8c4236a7bMark Andrews return (r);
40f24178432de09181bc603cc90110546a0ddca2Mark Andrews}
40f24178432de09181bc603cc90110546a0ddca2Mark Andrews
40f24178432de09181bc603cc90110546a0ddca2Mark Andrewsstatic mdn_result_t
40f24178432de09181bc603cc90110546a0ddca2Mark Andrewslace_encode_utf16(const unsigned short *p, size_t len,
40f24178432de09181bc603cc90110546a0ddca2Mark Andrews char *to, size_t tolen, int compress)
40f24178432de09181bc603cc90110546a0ddca2Mark Andrews{
40f24178432de09181bc603cc90110546a0ddca2Mark Andrews unsigned long bitbuf = 0; /* bit stream buffer */
40f24178432de09181bc603cc90110546a0ddca2Mark Andrews int bitlen = 0; /* # of bits in 'bitbuf' */
40f24178432de09181bc603cc90110546a0ddca2Mark Andrews int compress_count = 0;
40f24178432de09181bc603cc90110546a0ddca2Mark Andrews int i, j;
40f24178432de09181bc603cc90110546a0ddca2Mark Andrews
40f24178432de09181bc603cc90110546a0ddca2Mark Andrews if (!compress) {
40f24178432de09181bc603cc90110546a0ddca2Mark Andrews /* prepend non-compression mark */
40f24178432de09181bc603cc90110546a0ddca2Mark Andrews bitbuf = 0xff;
40f24178432de09181bc603cc90110546a0ddca2Mark Andrews bitlen = 8;
6182613ef54ebb8369d951ffa4431c49b75cec51Mark Andrews }
40f24178432de09181bc603cc90110546a0ddca2Mark Andrews
40f24178432de09181bc603cc90110546a0ddca2Mark Andrews for (i = 0; i <= len; i++) {
40f24178432de09181bc603cc90110546a0ddca2Mark Andrews if (i == len) {
40f24178432de09181bc603cc90110546a0ddca2Mark Andrews /*
40f24178432de09181bc603cc90110546a0ddca2Mark Andrews * End of data. Flush. The current draft (-00)
40f24178432de09181bc603cc90110546a0ddca2Mark Andrews * doesn't seem to define which value to use for
afb4ad8f988591bccae0ee2ac73b2fef5d969366Mark Andrews * padding (which it should). We assume zero.
afb4ad8f988591bccae0ee2ac73b2fef5d969366Mark Andrews */
afb4ad8f988591bccae0ee2ac73b2fef5d969366Mark Andrews if (bitlen % 5 == 0)
afb4ad8f988591bccae0ee2ac73b2fef5d969366Mark Andrews break;
afb4ad8f988591bccae0ee2ac73b2fef5d969366Mark Andrews bitbuf <<= 5 - (bitlen % 5); /* padding with zero */
afb4ad8f988591bccae0ee2ac73b2fef5d969366Mark Andrews bitlen += 5 - (bitlen % 5);
afb4ad8f988591bccae0ee2ac73b2fef5d969366Mark Andrews } else if (compress) {
afb4ad8f988591bccae0ee2ac73b2fef5d969366Mark Andrews if (compress_count == 0) {
afb4ad8f988591bccae0ee2ac73b2fef5d969366Mark Andrews /*
afb4ad8f988591bccae0ee2ac73b2fef5d969366Mark Andrews * Get the number of consecutive characters
afb4ad8f988591bccae0ee2ac73b2fef5d969366Mark Andrews * with the same high byte.
0e7e4562fd8222047b8ccf3a508d95df4f81bc47Mark Andrews */
0e7e4562fd8222047b8ccf3a508d95df4f81bc47Mark Andrews unsigned short high = p[i] & 0xff00;
0e7e4562fd8222047b8ccf3a508d95df4f81bc47Mark Andrews
0e7e4562fd8222047b8ccf3a508d95df4f81bc47Mark Andrews compress_count = 1;
0e7e4562fd8222047b8ccf3a508d95df4f81bc47Mark Andrews for (j = i + 1; j < len; j++) {
0e7e4562fd8222047b8ccf3a508d95df4f81bc47Mark Andrews if ((p[j] & 0xff00) != high)
0e7e4562fd8222047b8ccf3a508d95df4f81bc47Mark Andrews break;
0e7e4562fd8222047b8ccf3a508d95df4f81bc47Mark Andrews compress_count++;
40f24178432de09181bc603cc90110546a0ddca2Mark Andrews }
40f24178432de09181bc603cc90110546a0ddca2Mark Andrews bitbuf = (bitbuf << 16) |
23693a38979a5f30334176bd3ddd1c42004f55b2Mark Andrews (compress_count << 8) |
23693a38979a5f30334176bd3ddd1c42004f55b2Mark Andrews (high >> 8);
23693a38979a5f30334176bd3ddd1c42004f55b2Mark Andrews bitlen += 16;
23693a38979a5f30334176bd3ddd1c42004f55b2Mark Andrews }
23693a38979a5f30334176bd3ddd1c42004f55b2Mark Andrews bitbuf = (bitbuf << 8) | (p[i] & 0xff);
23693a38979a5f30334176bd3ddd1c42004f55b2Mark Andrews bitlen += 8;
23693a38979a5f30334176bd3ddd1c42004f55b2Mark Andrews compress_count--;
23693a38979a5f30334176bd3ddd1c42004f55b2Mark Andrews } else {
b21d8bac45b614c39a106c9ee8137589328ea075Andreas Gustafsson bitbuf = (bitbuf << 16) | p[i];
23693a38979a5f30334176bd3ddd1c42004f55b2Mark Andrews bitlen += 16;
a272a556314a892c0bd73bc302e08249f3d99ec2Mark Andrews }
700f1442882eda0cce05a51e8c6f820c51054e8eMark Andrews
700f1442882eda0cce05a51e8c6f820c51054e8eMark Andrews /*
a272a556314a892c0bd73bc302e08249f3d99ec2Mark Andrews * Output bits in 'bitbuf' in 5-bit unit.
700f1442882eda0cce05a51e8c6f820c51054e8eMark Andrews */
700f1442882eda0cce05a51e8c6f820c51054e8eMark Andrews while (bitlen >= 5) {
700f1442882eda0cce05a51e8c6f820c51054e8eMark Andrews int x;
700f1442882eda0cce05a51e8c6f820c51054e8eMark Andrews
700f1442882eda0cce05a51e8c6f820c51054e8eMark Andrews /* Get top 5 bits. */
40f24178432de09181bc603cc90110546a0ddca2Mark Andrews x = (bitbuf >> (bitlen - 5)) & 0x1f;
40f24178432de09181bc603cc90110546a0ddca2Mark Andrews bitlen -= 5;
6182613ef54ebb8369d951ffa4431c49b75cec51Mark Andrews
6182613ef54ebb8369d951ffa4431c49b75cec51Mark Andrews /* Encode. */
6182613ef54ebb8369d951ffa4431c49b75cec51Mark Andrews if (x < 26)
6182613ef54ebb8369d951ffa4431c49b75cec51Mark Andrews x += 'a';
6182613ef54ebb8369d951ffa4431c49b75cec51Mark Andrews else
6182613ef54ebb8369d951ffa4431c49b75cec51Mark Andrews x = (x - 26) + '2';
6182613ef54ebb8369d951ffa4431c49b75cec51Mark Andrews
6182613ef54ebb8369d951ffa4431c49b75cec51Mark Andrews if (tolen < 1)
6182613ef54ebb8369d951ffa4431c49b75cec51Mark Andrews return (mdn_buffer_overflow);
6182613ef54ebb8369d951ffa4431c49b75cec51Mark Andrews
c7620c99f1139b77f14678e21a44f7c8c4236a7bMark Andrews *to++ = x;
c7620c99f1139b77f14678e21a44f7c8c4236a7bMark Andrews tolen--;
c7620c99f1139b77f14678e21a44f7c8c4236a7bMark Andrews }
c7620c99f1139b77f14678e21a44f7c8c4236a7bMark Andrews }
c7620c99f1139b77f14678e21a44f7c8c4236a7bMark Andrews
c7620c99f1139b77f14678e21a44f7c8c4236a7bMark Andrews if (tolen <= 0)
c7620c99f1139b77f14678e21a44f7c8c4236a7bMark Andrews return (mdn_buffer_overflow);
c7620c99f1139b77f14678e21a44f7c8c4236a7bMark Andrews
c7620c99f1139b77f14678e21a44f7c8c4236a7bMark Andrews *to = '\0';
c7620c99f1139b77f14678e21a44f7c8c4236a7bMark Andrews return (mdn_success);
c7620c99f1139b77f14678e21a44f7c8c4236a7bMark Andrews}
c7620c99f1139b77f14678e21a44f7c8c4236a7bMark Andrews
c7620c99f1139b77f14678e21a44f7c8c4236a7bMark Andrewsstatic int
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrenceis_compress_effective(unsigned short *p, size_t len) {
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence unsigned short last_high = 0x1; /* initialize with an invalid value */
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence int nhigh = 0;
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson int i;
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson /*
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson * Find the number of HIGH value in the compressed string.
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson */
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson for (i = 0; i < len; i++) {
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson unsigned short high = p[i] & 0xff00;
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson if (high != last_high)
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson nhigh++;
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson last_high = high;
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson }
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson /*
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * Compressed string would take 2 * 'nhigh' + 'len' bytes,
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * while the original (uncomressed) string would take 2 * 'len'.
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * So the difference is 2 * 'nhigh' - len.
64e41159a919b0711321fe688ca5da4f4d1b7d80Bob Halley */
8a9b755d32a4f6ace792ac3fd17c968cf96d2487David Lawrence if (2 * nhigh <= len)
64e41159a919b0711321fe688ca5da4f4d1b7d80Bob Halley return (1); /* Compression is effective. */
64e41159a919b0711321fe688ca5da4f4d1b7d80Bob Halley else
64e41159a919b0711321fe688ca5da4f4d1b7d80Bob Halley return (0); /* Nope. */
64e41159a919b0711321fe688ca5da4f4d1b7d80Bob Halley}
64e41159a919b0711321fe688ca5da4f4d1b7d80Bob Halley