diff mupdf-source/thirdparty/harfbuzz/util/text-options.hh @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mupdf-source/thirdparty/harfbuzz/util/text-options.hh	Mon Sep 15 11:43:07 2025 +0200
@@ -0,0 +1,370 @@
+/*
+ * Copyright © 2011  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef TEXT_OPTIONS_HH
+#define TEXT_OPTIONS_HH
+
+#include "options.hh"
+
+struct text_options_t
+{
+  text_options_t ()
+  : gs (g_string_new (nullptr))
+  {}
+  ~text_options_t ()
+  {
+    g_free (text);
+    g_free (text_file);
+    if (gs)
+      g_string_free (gs, true);
+    if (in_fp && in_fp != stdin)
+      fclose (in_fp);
+  }
+
+  void add_options (option_parser_t *parser);
+
+  void post_parse (GError **error G_GNUC_UNUSED)
+  {
+    if (!text && !text_file)
+      text_file = g_strdup ("-");
+
+    if (text && text_file)
+    {
+      g_set_error (error,
+		   G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		   "Only one of text and text-file can be set");
+      return;
+    }
+
+    if (text_file)
+    {
+      if (0 != strcmp (text_file, "-"))
+	in_fp = fopen (text_file, "r");
+      else
+	in_fp = stdin;
+
+      if (!in_fp)
+	g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
+		     "Failed opening text file `%s': %s",
+		     text_file, strerror (errno));
+    }
+  }
+
+  const char *get_line (unsigned int *len);
+
+  int text_len = -1;
+  char *text = nullptr;
+  char *text_file = nullptr;
+
+  private:
+  FILE *in_fp = nullptr;
+  GString *gs = nullptr;
+  char *line = nullptr;
+  unsigned line_len = UINT_MAX;
+  hb_bool_t single_par = false;
+};
+
+struct shape_text_options_t : text_options_t
+{
+  ~shape_text_options_t ()
+  {
+    g_free (text_before);
+    g_free (text_after);
+  }
+
+  void add_options (option_parser_t *parser);
+
+  char *text_before = nullptr;
+  char *text_after = nullptr;
+};
+
+
+static gboolean
+parse_text (const char *name G_GNUC_UNUSED,
+	    const char *arg,
+	    gpointer    data,
+	    GError    **error G_GNUC_UNUSED)
+{
+  text_options_t *text_opts = (text_options_t *) data;
+
+  if (text_opts->text)
+  {
+    g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		 "Either --text or --unicodes can be provided but not both");
+    return false;
+  }
+
+  text_opts->text_len = -1;
+  text_opts->text = g_strdup (arg);
+  return true;
+}
+
+static bool
+encode_unicodes (const char *unicodes,
+		 GString    *gs,
+		 GError    **error)
+{
+#define DELIMITERS "<+-|>{},;&#\\xXuUnNiI\n\t\v\f\r "
+
+  char *s = (char *) unicodes;
+  char *p;
+
+  while (s && *s)
+  {
+    while (*s && strchr (DELIMITERS, *s))
+      s++;
+    if (!*s)
+      break;
+
+    errno = 0;
+    hb_codepoint_t u = strtoul (s, &p, 16);
+    if (errno || s == p)
+    {
+      g_string_free (gs, TRUE);
+      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		   "Failed parsing Unicode value at: '%s'", s);
+      return false;
+    }
+
+    g_string_append_unichar (gs, u);
+
+    s = p;
+  }
+
+#undef DELIMITERS
+
+  return true;
+}
+
+static gboolean
+parse_unicodes (const char *name G_GNUC_UNUSED,
+		const char *arg,
+		gpointer    data,
+		GError    **error G_GNUC_UNUSED)
+{
+  text_options_t *text_opts = (text_options_t *) data;
+
+  if (text_opts->text)
+  {
+    g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		 "Either --text or --unicodes can be provided but not both");
+    return false;
+  }
+
+  GString *gs = g_string_new (nullptr);
+  if (0 == strcmp (arg, "*"))
+    g_string_append_c (gs, '*');
+  else
+    if (!encode_unicodes (arg, gs, error))
+      return false;
+
+  text_opts->text_len = gs->len;
+  text_opts->text = g_string_free (gs, FALSE);
+  return true;
+}
+
+static gboolean
+parse_text_before (const char *name G_GNUC_UNUSED,
+		   const char *arg,
+		   gpointer    data,
+		   GError    **error)
+{
+  auto *opts = (shape_text_options_t *) data;
+
+  if (opts->text_before)
+  {
+    g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		 "Either --text-before or --unicodes-before can be provided but not both");
+    return false;
+  }
+
+  opts->text_before = g_strdup (arg);
+  fprintf(stderr, "%s\n", opts->text_before);
+  return true;
+}
+
+static gboolean
+parse_unicodes_before (const char *name G_GNUC_UNUSED,
+		       const char *arg,
+		       gpointer    data,
+		       GError    **error)
+{
+  auto *opts = (shape_text_options_t *) data;
+
+  if (opts->text_before)
+  {
+    g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		 "Either --text-before or --unicodes-before can be provided but not both");
+    return false;
+  }
+
+  GString *gs = g_string_new (nullptr);
+  if (!encode_unicodes (arg, gs, error))
+    return false;
+
+  opts->text_before = g_string_free (gs, FALSE);
+  return true;
+}
+
+static gboolean
+parse_text_after (const char *name G_GNUC_UNUSED,
+		  const char *arg,
+		  gpointer    data,
+		  GError    **error)
+{
+  auto *opts = (shape_text_options_t *) data;
+
+  if (opts->text_after)
+  {
+    g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		 "Either --text-after or --unicodes-after can be provided but not both");
+    return false;
+  }
+
+  opts->text_after = g_strdup (arg);
+  return true;
+}
+
+static gboolean
+parse_unicodes_after (const char *name G_GNUC_UNUSED,
+		      const char *arg,
+		      gpointer    data,
+		      GError    **error)
+{
+  auto *opts = (shape_text_options_t *) data;
+
+  if (opts->text_after)
+  {
+    g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		 "Either --text-after or --unicodes-after can be provided but not both");
+    return false;
+  }
+
+  GString *gs = g_string_new (nullptr);
+  if (!encode_unicodes (arg, gs, error))
+    return false;
+
+  opts->text_after = g_string_free (gs, FALSE);
+  return true;
+}
+
+const char *
+text_options_t::get_line (unsigned int *len)
+{
+  if (text)
+  {
+    if (!line)
+    {
+      line = text;
+      line_len = text_len;
+    }
+    if (line_len == UINT_MAX)
+      line_len = strlen (line);
+
+    if (!line_len)
+    {
+      *len = 0;
+      return nullptr;
+    }
+
+    const char *ret = line;
+    const char *p = single_par ? nullptr : (const char *) memchr (line, '\n', line_len);
+    unsigned int ret_len;
+    if (!p)
+    {
+      ret_len = line_len;
+      line += ret_len;
+      line_len = 0;
+    }
+    else
+    {
+      ret_len = p - ret;
+      line += ret_len + 1;
+      line_len -= ret_len + 1;
+    }
+
+    *len = ret_len;
+    return ret;
+  }
+
+  g_string_set_size (gs, 0);
+  char buf[BUFSIZ];
+  while (fgets (buf, sizeof (buf), in_fp))
+  {
+    unsigned bytes = strlen (buf);
+    if (!single_par && bytes && buf[bytes - 1] == '\n')
+    {
+      bytes--;
+      g_string_append_len (gs, buf, bytes);
+      break;
+    }
+    g_string_append_len (gs, buf, bytes);
+  }
+  if (ferror (in_fp))
+    fail (false, "Failed reading text: %s", strerror (errno));
+  *len = gs->len;
+  return !*len && feof (in_fp) ? nullptr : gs->str;
+}
+
+void
+text_options_t::add_options (option_parser_t *parser)
+{
+  GOptionEntry entries[] =
+  {
+    {"text",		0, 0, G_OPTION_ARG_CALLBACK,	(gpointer) &parse_text,		"Set input text",			"string"},
+    {"text-file",	0, 0, G_OPTION_ARG_STRING,	&this->text_file,		"Set input text file-name",		"filename"},
+    {"unicodes",      'u', 0, G_OPTION_ARG_CALLBACK,	(gpointer) &parse_unicodes,	"Set input Unicode codepoints",		"list of hex numbers"},
+    {"single-par",	0, 0, G_OPTION_ARG_NONE,	&this->single_par,		"Treat text as single paragraph",	nullptr},
+    {nullptr}
+  };
+  parser->add_group (entries,
+		     "text",
+		     "Text options:\n\nIf no text is provided, standard input is used for input.\n",
+		     "Options for the input text",
+		     this);
+}
+
+void
+shape_text_options_t::add_options (option_parser_t *parser)
+{
+  text_options_t::add_options (parser);
+
+  GOptionEntry entries[] =
+  {
+    {"text-before",	0, 0, G_OPTION_ARG_CALLBACK,	(gpointer) &parse_text_before,		"Set text context before each line",	"string"},
+    {"text-after",	0, 0, G_OPTION_ARG_CALLBACK,	(gpointer) &parse_text_after,		"Set text context after each line",	"string"},
+    {"unicodes-before",	0, 0, G_OPTION_ARG_CALLBACK,	(gpointer) &parse_unicodes_before,	"Set Unicode codepoints context before each line",	"list of hex numbers"},
+    {"unicodes-after",	0, 0, G_OPTION_ARG_CALLBACK,	(gpointer) &parse_unicodes_after,	"Set Unicode codepoints context after each line",	"list of hex numbers"},
+    {nullptr}
+  };
+  parser->add_group (entries,
+		     "text-context",
+		     "Textual context options:",
+		     "Options for the input context text",
+		     this);
+}
+
+#endif