text: /****************************************************************************
   * tools/bdf-converter.c
   *
   *   Copyright (C) 2011 NX Engineering, S.A., All rights reserved.
   *   Author: Jose Pablo Carballo Gomez <jcarballo@nx-engineering.com>
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   * 3. Neither the name NuttX nor the names of its contributors may be
   *    used to endorse or promote products derived from this software
   *    without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
   * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   * POSSIBILITY OF SUCH DAMAGE.
   *
   ****************************************************************************/
  
  /*
   * Based one the "Glyph Bitmap Distribution Format (BDF) Specification",
   * Version 2.2, by Adobe Systems Incorporated.
   *
   */
  
  /****************************************************************************
   * Included Files
   ****************************************************************************/
  
  #include <stdint.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <stdbool.h>
  #include <string.h>
  #include <ctype.h>
  
  /****************************************************************************
   * Pre-processor Definitions
   ****************************************************************************/
  
  /*
  #define VERBOSE
  #define DBG
  */
  
  // BDF Specification Version 2.2:
  // This version lifts the restriction on line length. In this version, the new
  // maximum length of a value of the type string is 65535 characters, and hence
  // lines may now be at least this long.
  
  #define BDF_MAX_LINE_LENGTH 65535
  
  /* Ranges of 7-bit and 8-bit fonts */
  
  #define NXFONT_MIN7BIT 33
  #define NXFONT_MAX7BIT 126
  
  #define NXFONT_MIN8BIT 161
  #define NXFONT_MAX8BIT 255
  
  /****************************************************************************
   * Public Types
   ****************************************************************************/
  
  /* This structure holds information about a glyph */
  
  typedef struct glyphinfo_s
  {
    char *name;       /* Name for they glyph */
    int   encoding;   /* The Adobe Standard Encoding value */
    int   dw_x0;      /* Width in x of the vector indicating
                       * the position of the next glyph's origin
                       * relative to the origin of this glyph */
    int   dw_y0;      /* Width in y of the vector indicating
                       * the position of the next glyph's origin
                       * relative to the origin of this glyph */
    int   bb_w;       /* The width of the black pixels in x */
    int   bb_h;       /* The height of the black pixels in y */
    int   bb_x_off;   /* X displacement of the lower left corner
                       * of the bitmap from origin 0 */
    int   bb_y_off;   /* Y displacement of the lower left corner
                       * of the bitmap from origin 0 */
    uint64_t *bitmap; /* Hexadecimal data for the character bitmap */
  } glyphinfo_t;
  
  /* This structures provides the metrics for one glyph */
  
  typedef struct nx_fontmetric_s
  {
    uint32_t stride   : 3;    /* Width of one font row in bytes */
    uint32_t width    : 6;    /* Width of the font in bits */
    uint32_t height   : 6;    /* Height of the font in rows */
    uint32_t xoffset  : 6;    /* Top, left-hand corner X-offset in pixels */
    uint32_t yoffset  : 6;    /* Top, left-hand corner y-offset in pixels */
    uint32_t unused   : 5;
  } nx_fontmetric_t;
  
  /****************************************************************************
   * Private Functions
   ****************************************************************************/
  
  /****************************************************************************
   * Name: MY_strtok_r
   *
   * Description:
   *    MinGW does not seem to provide strtok_r
   *
   ****************************************************************************/
  
  #ifndef HAVE_STRTOK_R
  static char *MY_strtok_r(char *str, const char *delim, char **saveptr)
  {
    char *pbegin;
    char *pend = NULL;
  
    /* Decide if we are starting a new string or continuing from
     * the point we left off.
     */
  
    if (str)
      {
        pbegin = str;
      }
    else if (saveptr && *saveptr)
      {
        pbegin = *saveptr;
      }
    else
      {
        return NULL;
      }
  
    /* Find the beginning of the next token */
  
    for (;
         *pbegin && strchr(delim, *pbegin) != NULL;
         pbegin++);
  
    /* If we are at the end of the string with nothing
     * but delimiters found, then return NULL.
     */
  
    if (!*pbegin)
      {
        return NULL;
      }
  
    /* Find the end of the token */
  
    for (pend = pbegin + 1;
         *pend && strchr(delim, *pend) == NULL;
         pend++);
  
    /* pend either points to the end of the string or to
     * the first delimiter after the string.
     */
  
    if (*pend)
      {
        /* Turn the delimiter into a null terminator */
  
        *pend++ = '\0';
      }
  
    /* Save the pointer where we left off and return the
     * beginning of the token.
     */
  
    if (saveptr)
      {
        *saveptr = pend;
      }
    return pbegin;
  }
  
  #undef strtok_r
  #define strtok_r MY_strtok_r
  #endif
  
  /****************************************************************************
   * Name: trimLine
   *
   * Description:
   *   Trims the line removing space characters at the front and at the end
   *   of the line.
   *
   * Input Parameters:
   *   line  - The line to trim
   *
   ****************************************************************************/
  
  static void trimLine(char *line)
  {
    char *str;
    str = line;
    char *strEnd;
    for (strEnd = str + strlen(str) - 1;
         strEnd >= str && isspace((int)(*strEnd));
         strEnd--);
    *(strEnd + 1) = 0;
  }
  
  /****************************************************************************
   * Name: bdf_parseIntLine
   *
   * Description:
   *   Parses a line containing a BDF property followed by integers. It will
   *   ignore the first token that corresponds to the property name.
   *
   * Input Parameters:
   *   line  - A line with a BDF property followed by integers, i.e.:
   *                  "FONTBOUNDINGBOX 8 13 0 -2"
   *   count - How many integers are specified by the BDF property. In the
   *           example above, count = 4.
   *   info  - A pointer to memory provided by the caller in which to
   *           return the array of integers. For the example above:
   *                info[0] =  8
   *                info[1] = 13
   *                info[2] =  0
   *                info[3] = -2
   *
   ****************************************************************************/
  
  static void bdf_parseintline(char *line, unsigned int count, int *info)
  {
    char *str, *token, *saveptr1;
    str = line;
  
    /* Ignore the key */
  
    token = (char *)strtok_r(str, " ", &saveptr1);
  
    while ((token = (char *)strtok_r(NULL, " ", &saveptr1)) && count--)
      {
        *(info++) = atoi(token);
      }
  }
  
  /****************************************************************************
   * Name: bdf_printglyphinfo
   *
   * Description:
   *   Prints the information available for a glyph.
   *
   * Input Parameters:
   *   ginfo  - A glyphinfo_t struct with the glyph's information.
   *
   ****************************************************************************/
  
  #ifdef DBG
  static void bdf_printglyphinfo(const glyphinfo_t *ginfo)
  {
    printf("NAME     = %s\n", ginfo->name);
    printf("ENCODING = %d\n", ginfo->encoding);
    printf("DW_X0    = %d\n", ginfo->dw_x0);
    printf("DW_Y0    = %d\n", ginfo->dw_y0);
    printf("BB_W     = %d\n", ginfo->bb_w);
    printf("BB_H     = %d\n", ginfo->bb_h);
    printf("BB_X_OFF = %d\n", ginfo->bb_x_off);
    printf("BB_Y_OFF = %d\n", ginfo->bb_y_off);
    int i;
    for (i = 0; i < ginfo->bb_h; i++)
      {
        printf("BITMAP[%d] = %x\n", i, ginfo->bitmap[i]);
      }
  }
  #endif /* DBG */
  
  /****************************************************************************
   * Name: bdf_printnxmetricinfo
   *
   * Description:
   *   Prints the information available for a glyph's metric in the NX
   *   graphics system.
   *
   * Input Parameters:
   *   info  - A nx_fontmetric_t struct with the glyph's information.
   *
   ****************************************************************************/
  
  #ifdef DBG
  static void bdf_printnxmetricinfo(const nx_fontmetric_t *info)
  {
    printf("STRIDE  = %d\n", info->stride);
    printf("WIDTH   = %d\n", info->width);
    printf("HEIGHT  = %d\n", info->height);
    printf("XOFFSET = %d\n", info->xoffset);
    printf("YOFFSET = %d\n", info->yoffset);
  }
  #endif /* DBG */
  
  /****************************************************************************
   * Name: bdf_getglyphinfo
   *
   * Description:
   *   Obtains the information for an individual glyph. The BDF properties
   *   taken into account are:
   *     - ENCODING
   *     - DWIDTH
   *     - BBX
   *   BDF properties ignored:
   *     - SWIDTH
   *     - SWIDTH1
   *     - DWIDTH1
   *     - VVECTOR
   *
   * Input Parameters:
   *   file  - The input file stream pointing to the first line of the
   *           glyph's information (right after STARTCHAR).
   *   ginfo - A glyphinfo_t struct to fill with the glyph's information.
   *
   ****************************************************************************/
  
  static void bdf_getglyphinfo(FILE *file, glyphinfo_t *ginfo)
  {
    char line[BDF_MAX_LINE_LENGTH];
    char lineCopy[BDF_MAX_LINE_LENGTH];
    char *str, *token, *saveptr1;
    bool done;
  
    done = false;
  
    while (fgets(line, BDF_MAX_LINE_LENGTH, file) != NULL && !done)
      {
        trimLine(line);
        strcpy(lineCopy, line);
        str = line;
  
        while ((token = (char *)strtok_r(str, " ", &saveptr1)))
          {
  
            /* ENCODING information */
  
            if (strcmp(token, "ENCODING") == 0)
              {
                token = (char *)strtok_r(NULL, " ", &saveptr1);
                ginfo->encoding = atoi(token);
              }
  
            /* DWIDTH information */
  
            if (strcmp(token, "DWIDTH") == 0)
              {
                token = (char *)strtok_r(NULL, " ", &saveptr1);
                ginfo->dw_x0 = atoi(token);
                token = (char *)strtok_r(NULL, " ", &saveptr1);
                ginfo->dw_y0 = atoi(token);
              }
  
            /* BBX information */
  
            else if (strcmp(token, "BBX") == 0)
              {
                int bbxinfo[4];
                bdf_parseintline(lineCopy, 4, bbxinfo);
                ginfo->bb_w     = bbxinfo[0];
                ginfo->bb_h     = bbxinfo[1];
                ginfo->bb_x_off = bbxinfo[2];
                ginfo->bb_y_off = bbxinfo[3];
  
                /* This is the last BDF property of interest*/
  
                done = true;
              }
  
            str = NULL;
          }
      }
  }
  
  /****************************************************************************
   * Name: bdf_getglyphbitmap
   *
   * Description:
   *   Obtains the character bitmap information for an individual glyph.
   *
   * Input Parameters:
   *   file  - The input file stream pointing to the first line of the
   *           glyph's bitmap (right after BITMAP).
   *   ginfo - A glyphinfo_t struct to fill with the glyph's bitmap.
   *
   ****************************************************************************/
  
  static void bdf_getglyphbitmap(FILE *file, glyphinfo_t *ginfo)
  {
    char line[BDF_MAX_LINE_LENGTH];
    uint64_t *bitmap;
    bool readingbitmap;
  
    bitmap = ginfo->bitmap;
    readingbitmap = true;
  
    while (readingbitmap)
      {
        if (fgets(line, BDF_MAX_LINE_LENGTH, file) != NULL)
          {
            trimLine(line);
  
            if (strcmp(line, "ENDCHAR") == 0)
              {
                readingbitmap = false;
              }
            else
              {
                char *endptr;
                *bitmap = strtoul(line, &endptr, 16);
                bitmap++;
              }
          }
        else
          {
            /* error condition */
  
            readingbitmap = false;
          }
      }
  }
  
  /****************************************************************************
   * Name: bdf_getstride
   *
   * Description:
   *   Obtains the stride for an individual glyph. The stride is the width
   *   of one glyph's bitmap row in bytes.
   *
   * Input Parameters:
   *   ginfo  - A glyphinfo_t struct with the glyph's information.
   *   stride - A pointer to memory provided by the caller in which to
   *            return the stride.
   *
   ****************************************************************************/
  static void bdf_getstride(glyphinfo_t *ginfo, uint32_t *stride)
  {
    *stride = (ginfo->bb_w % 8 == 0) ? ginfo->bb_w / 8 : ginfo->bb_w / 8 + 1;
  }
  
  /****************************************************************************
   * Name: bdf_printoutput
   *
   * Description:
   *   Prints to the output stream the information of an individual glyph in
   *   the NuttX font format.
   *
   * Input Parameters:
   *   out       - The output stream.
   *   ginfo     - A glyphinfo_t struct with the glyph's information.
   *   nxmetric  - A nx_fontmetric_t struct with the glyph's information.
   *
   ****************************************************************************/
  static void bdf_printoutput(FILE *out,
                              glyphinfo_t *ginfo,
                              nx_fontmetric_t *nxmetric)
  {
  
    /* Only interested in the 7 and 8 bit ranges */
  
    if ((ginfo->encoding >= NXFONT_MIN7BIT  &&
         ginfo->encoding <= NXFONT_MAX7BIT) ||
        (ginfo->encoding >= NXFONT_MIN8BIT  &&
         ginfo->encoding <= NXFONT_MAX8BIT))
      {
        /* Glyph general info */
  
        if (ginfo->bb_x_off < 0)
          {
            fprintf(out,
                    "/* %s (%d) -- NOTE: Xoffset should be %d, not 0. */\n",
                    ginfo->name,
                    ginfo->encoding,
                    ginfo->bb_x_off);
          }
        else
          {
            fprintf(out, "/* %s (%d) */\n", ginfo->name, ginfo->encoding);
          }
  
        /* Glyph metrics */
  
        fprintf(out,
                "#define NXFONT_METRICS_%d {%d, %d, %d, %d, %d, 0}\n",
                ginfo->encoding,
                nxmetric->stride,
                nxmetric->width,
                nxmetric->height,
                nxmetric->xoffset,
                nxmetric->yoffset);
  
        /* Glyph bitmap */
  
        fprintf(out, "#define NXFONT_BITMAP_%d {", ginfo->encoding);
        int i, j;
        for (i = 0; i < ginfo->bb_h - 1; i++)
          {
            for (j = 1; j <= nxmetric->stride; j++)
              {
                int nxbyteoffset;
                uint8_t  nxbyte = 0;
                uint64_t tempbitmap = ginfo->bitmap[i];
  
                /* Get the next byte */
  
                nxbyteoffset = (nxmetric->stride - j) * 8;
                nxbyte = (uint8_t)(tempbitmap >> nxbyteoffset);
                fprintf(out, "0x%x, ", nxbyte);
              }
          }
  
        /* Different behavior for the last bitmap */
  
        for (j = 1; j <= nxmetric->stride; j++)
          {
            int nxbyteoffset;
            uint8_t  nxbyte = 0;
            uint64_t tempbitmap = ginfo->bitmap[i];
  
            /* Get the next byte */
  
            nxbyteoffset = (nxmetric->stride - j) * 8;
            nxbyte = (uint8_t)(tempbitmap >> nxbyteoffset);
  
            if (j == nxmetric->stride)
              {
                fprintf(out, "0x%x}\n", nxbyte);
              }
            else
              {
                fprintf(out, "0x%x, ", nxbyte);
              }
          }
  
        fprintf(out, "\n");
      }
  }
  
  /****************************************************************************
   * Main
   ****************************************************************************/
  
  int main(int argc, char **argv)
  {
    FILE *file, *out;
    char line[BDF_MAX_LINE_LENGTH];
    char lineCopy[BDF_MAX_LINE_LENGTH];
    char *str, *token, *saveptr1;
    char *input, *output;
  
    /* FONTBOUNDINGBOX properties*/
  
    int fbb_x     = 0;
    int fbb_y     = 0;
  //int fbb_x_off = 0;
    int fbb_y_off = 0;
  
    /* Input BDF file */
  
    input = argv[1];
  
    if (input == NULL)
      {
        printf("%s: no input file\n", argv[0]);
        exit(0);
      }
  
    file = fopen(input, "r");
  
    if (file == NULL)
      {
        printf("%s: error opening file %s\n", argv[0], input);
        exit(0);
      }
    else
      {
  #ifdef VERBOSE
        printf("Opening \"%s\"\n", input);
  #endif /* VERBOSE */
      }
  
    /* Output file */
  
    if (argv[2])
      {
        output = argv[2];
      }
    else
      {
        output = "nxfonts_myfont.h";
      }
  
    out  = fopen(output, "w");
  
    if (out == NULL)
      {
        printf("%s: error opening file %s\n", argv[0], output);
        fclose(file);
        exit(0);
      }
    else
      {
        while (fgets(line, BDF_MAX_LINE_LENGTH, file) != NULL)
          {
  
  #ifdef DBG
            printf("--\n");
  #endif /* DBG */
  
            // Save a copy of the line
  
            strcpy(lineCopy,line);
  
            // Clean it
  
            trimLine(line);
            str = line;
  
            while ((token = (char *)strtok_r(str, " ", &saveptr1)))
              {
  
                /* FONTBOUNDINGBOX - Global font information */
  
                if (strcmp(token, "FONTBOUNDINGBOX") == 0)
                  {
                    int fbbinfo[4];
                    bdf_parseintline(lineCopy, 4, fbbinfo);
                    fbb_x     = fbbinfo[0];
                    fbb_y     = fbbinfo[1];
                  //fbb_x_off = fbbinfo[2];
                    fbb_y_off = fbbinfo[3];
  
                    /* Print FONTBOUNDINGBOX information */
  
                    fprintf(out, "/* Maximum height and width of any");
                    fprintf(out, " glyph in the set */\n\n");
                    fprintf(out, "#define NXFONT_MAXHEIGHT  %d\n", fbb_y);
                    fprintf(out, "#define NXFONT_MAXWIDTH   %d\n\n", fbb_x);
                  }
  
                /* STARTCHAR - Individual glyph information */
  
                if (strcmp(token, "STARTCHAR") == 0)
                  {
                    glyphinfo_t ginfo;
  
                    /* Glyph name */
  
                    ginfo.name = (char *)strtok_r(NULL, " ", &saveptr1);
  
  #ifdef VERBOSE
                    printf("Processing glyph: %s\n", ginfo.name);
  #endif /* VERBOSE */
  
                    /* Glyph information:
                    *    ENCODING
                    *    DWIDTH
                    *    BBX
                    */
  
                    ginfo.encoding = 0;
                    ginfo.dw_x0    = 0;
                    ginfo.dw_y0    = 0;
                    ginfo.bb_w     = 0;
                    ginfo.bb_h     = 0;
                    ginfo.bb_x_off = 0;
                    ginfo.bb_y_off = 0;
                    bdf_getglyphinfo(file, &ginfo);
  
                    /* Glyph bitmap */
  
                    ginfo.bitmap = malloc(sizeof(uint64_t) * ginfo.bb_h);
                    bdf_getglyphbitmap(file, &ginfo);
  
  #ifdef DBG
                    bdf_printglyphinfo(&ginfo);
  #endif /* DBG */
  
                    /* Convert to nxfonts */
  
                    nx_fontmetric_t nxmetric;
                    uint32_t stride;
                    bdf_getstride(&ginfo, &stride);
                    nxmetric.stride  = stride;
                    nxmetric.width   = ginfo.bb_w;
                    nxmetric.height  = ginfo.bb_h;
  
                    /* The NuttX font format does not support
                     * negative X offsets. */
  
                    if (ginfo.bb_x_off < 0)
                      {
                        nxmetric.xoffset = 0;
                        printf("%s: ignoring negative x offset for "
                               "glyph '%s' (%d)\n",
                               argv[0],
                               ginfo.name,
                               ginfo.encoding);
                      }
                    else
                      {
                        nxmetric.xoffset = ginfo.bb_x_off;
                      }
  
                    nxmetric.yoffset = fbb_y + fbb_y_off -
                                       ginfo.bb_y_off - ginfo.bb_h;
  
  #ifdef DBG
                    bdf_printnxmetricinfo(&nxmetric);
  #endif /* DBG */
  
                    /* The space (32) character is treated differently */
  
                    if (ginfo.encoding == 32)
                      {
                        fprintf(out, "/* The width of a space */\n\n");
                        fprintf(out, "#define NXFONT_SPACEWIDTH %d\n\n", ginfo.dw_x0);
                      }
                    else
                      {
                        bdf_printoutput(out, &ginfo, &nxmetric);
                      }
  
                    /* Free memory */
  
                    free(ginfo.bitmap);
  
                  }
  
                str = NULL;
              }
  
          }
  
        fclose(file);
        fclose(out);
  
        /* The End */
  
        printf("Generated \"%s\"\n", output);
  
      }
  
    return EXIT_SUCCESS;
  }
  