chiark / gitweb /
Properly check for overflow in offsets
[elogind.git] / src / shared / utf8.c
index 5f9f3c60c52b6f9b4224964a74b2e8caf92935a3..655cc771d4030ad656993c2c3a4ca49381591bb7 100644 (file)
  * Copyright (C) 2000 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
+ * modify it under the terms of the GNU Library General Public
  * License as published by the Free Software Foundation; either
  * version 2 of the License, or (at your option) any later version.
  *
  * This library 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
- * Lesser General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
  *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #include <errno.h>
@@ -50,6 +49,7 @@
 #include <stdbool.h>
 
 #include "utf8.h"
+#include "util.h"
 
 #define FILTER_CHAR '_'
 
@@ -86,11 +86,11 @@ static bool is_unicode_control(uint32_t ch) {
           '\t' is in C0 range, but more or less harmless and commonly used.
         */
 
-        return (ch < ' ' && ch != '\t') ||
+        return (ch < ' ' && ch != '\t' && ch != '\n') ||
                 (0x7F <= ch && ch <= 0x9F);
 }
 
-char* utf8_is_printable_n(const char* str, size_t length) {
+bool utf8_is_printable(const char* str, size_t length) {
         uint32_t val = 0;
         uint32_t min = 0;
         const uint8_t *p;
@@ -113,40 +113,37 @@ char* utf8_is_printable_n(const char* str, size_t length) {
                                 min = (1 << 16);
                                 val = (uint32_t) (*p & 0x07);
                         } else
-                                goto error;
+                                return false;
 
                         p++;
                         length--;
                         if (!length || !is_continuation_char(*p))
-                                goto error;
+                                return false;
                         merge_continuation_char(&val, *p);
 
                 TWO_REMAINING:
                         p++;
                         length--;
                         if (!is_continuation_char(*p))
-                                goto error;
+                                return false;
                         merge_continuation_char(&val, *p);
 
                 ONE_REMAINING:
                         p++;
                         length--;
                         if (!is_continuation_char(*p))
-                                goto error;
+                                return false;
                         merge_continuation_char(&val, *p);
 
                         if (val < min)
-                                goto error;
+                                return false;
                 }
 
                 if (is_unicode_control(val))
-                        goto error;
+                        return false;
         }
 
-        return (char*) str;
-
-error:
-        return NULL;
+        return true;
 }
 
 static char* utf8_validate(const char *str, char *output) {
@@ -284,3 +281,39 @@ char *ascii_filter(const char *str) {
 
         return r;
 }
+
+char *utf16_to_utf8(const void *s, size_t length) {
+        char *r;
+        const uint8_t *f;
+        uint8_t *t;
+
+        r = new(char, (length*3+1)/2 + 1);
+        if (!r)
+                return NULL;
+
+        t = (uint8_t*) r;
+
+        for (f = s; f < (const uint8_t*) s + length; f += 2) {
+                uint16_t c;
+
+                c = (f[1] << 8) | f[0];
+
+                if (c == 0) {
+                        *t = 0;
+                        return r;
+                } else if (c < 0x80) {
+                        *(t++) = (uint8_t) c;
+                } else if (c < 0x800) {
+                        *(t++) = (uint8_t) (0xc0 | (c >> 6));
+                        *(t++) = (uint8_t) (0x80 | (c & 0x3f));
+                } else {
+                        *(t++) = (uint8_t) (0xe0 | (c >> 12));
+                        *(t++) = (uint8_t) (0x80 | ((c >> 6) & 0x3f));
+                        *(t++) = (uint8_t) (0x80 | (c & 0x3f));
+                }
+        }
+
+        *t = 0;
+
+        return r;
+}