Example #1
0
void  Main_Write (void)
{
    USB_INT32S  fdw;
    USB_INT32S  fdr;
    USB_INT32U  tot_bytes_written;
    USB_INT32U  bytes_written;


    fdr = FILE_Open(FILENAME_R, RDONLY);
    if (fdr > 0) {
        FILE_Read(fdr, UserBuffer, MAX_BUFFER_SIZE);
        fdw = FILE_Open(FILENAME_W, RDWR);
        if (fdw > 0) {
            tot_bytes_written = 0;
            PRINT_Log("Writing to %s...\n", FILENAME_W);
            do {
                bytes_written = FILE_Write(fdw, UserBuffer, MAX_BUFFER_SIZE);
                tot_bytes_written += bytes_written;
            } while (tot_bytes_written < WRITE_SIZE);
            FILE_Close(fdw);
            PRINT_Log("Write completed\n");
        } else {
            PRINT_Log("Could not open file %s\n", FILENAME_W);
            return;
        }
        FILE_Close(fdr);
    } else {
        PRINT_Log("Could not open file %s\n", FILENAME_R);
        return;
    }
}
Example #2
0
void  Main_Copy (void)
{
    USB_INT32S  fdr;
    USB_INT32S  fdw;
    USB_INT32U  bytes_read;


    fdr = FILE_Open(FILENAME_R, RDONLY);
    if (fdr > 0) {
        fdw = FILE_Open(FILENAME_W, RDWR);
        if (fdw > 0) {
            PRINT_Log("Copying from %s to %s...\n", FILENAME_R, FILENAME_W);
            do {
                bytes_read = FILE_Read(fdr, UserBuffer, MAX_BUFFER_SIZE);
                FILE_Write(fdw, UserBuffer, bytes_read);
            } while (bytes_read);
            FILE_Close(fdw);
        } else {
            PRINT_Log("Could not open file %s\n", FILENAME_W);
            return;
        }
        FILE_Close(fdr);
        PRINT_Log("Copy completed\n");
    } else {
        PRINT_Log("Could not open file %s\n", FILENAME_R);
        return;
    }
}
Example #3
0
void  Main_Read (void)
{
    USB_INT32S  fdr;
    USB_INT32U  bytes_read;
    

    fdr = FILE_Open(FILENAME_R, RDONLY);
    if (fdr > 0) {
        PRINT_Log("Reading from %s...\n", FILENAME_R);
        do {
            bytes_read = FILE_Read(fdr, UserBuffer, MAX_BUFFER_SIZE);
        } while (bytes_read);

        FILE_Close(fdr);
        PRINT_Log("Read Complete\n");
    } else {
        PRINT_Log("Could not open file %s\n", FILENAME_R);
        return;
    }
}
Example #4
0
/**
 * Reads a byte from a gz_stream; update next_in and avail_in. 
 * Return zipEOF for end of file. Assumes that the stream zf has been 
 * sucessfully opened for reading.
 */
STATIC int ZipGetByte(Zip * zf)
{
    if (!(zf->zflags & (ZIP_IN_ERR | ZIP_IN_EOF))) {
        if (zf->in->avail_in == 0) {
            int nbytes = FILE_Read(zf->f, zf->inbuf, zf->bufsize);
            if (nbytes == 0) {
                zf->zflags |= ZIP_IN_EOF;
                return EOF;
            } else if (nbytes < 0) {
                zf->zflags |= ZIP_IN_ERR;
                return EOF;
            }
            zf->in->avail_in = nbytes;
            zf->in->next_in = zf->inbuf;
        }
        zf->in->avail_in--;
        return *((zf->in->next_in)++);
    }
    return EOF;
}
Example #5
0
/**
 * This routine runs EXPAT parser
 */
Bool XML_ParseStream(File * f, const XMLCallbacks * cb, void * ctx)
{
    XML_Parser parser;
    Bool ok = False;

    /* set up memory management functions */
    XML_Memory_Handling_Suite mem;
    memset(&mem, 0, sizeof(mem));
    mem.malloc_fcn = MEM_Alloc;
    mem.realloc_fcn = MEM_Realloc;
    mem.free_fcn = MEM_Free;
    
    /* create parser */
    parser = XML_ParserCreate_MM(NULL,&mem,NULL);
    if (parser) {
        int bufsize = 4096;
        void * buf = NULL;
        Bool done = False;

        /* initialize EXPAT */
        ExpatContext expat;
        expat.ctx = ctx;
        expat.cb = (*cb);
        STRBUF_Init(&expat.sb);
        BUFFER_Init(&expat.buf);
        VECTOR_Init(&expat.atts, 0, NULL, NULL);
        
        /* initialize the parser */
        XML_SetElementHandler(parser, EXPAT_StartElement, EXPAT_EndElement);
        XML_SetCharacterDataHandler(parser, EXPAT_Characters);
        XML_SetUserData(parser, &expat);

        /* 
         * By obtaining the buffer from Expat with the XML_GetBuffer,
         * we can avoid double copying of the input.
         */
        ok = True;
        while (ok && !done && (buf = XML_GetBuffer(parser,bufsize)) != NULL) {
            int len = -1;
            if (!FILE_Eof(f)) {
                len = FILE_Read(f, buf, bufsize);
            }
            if (len <= 0) {
                done = True;
                len = 0;
            }
            ok = XML_ParseBuffer(parser, len, done);
        }

#if DEBUG
        if (!ok) {
            enum XML_Error code = XML_GetErrorCode(parser);
            int l = XML_GetCurrentLineNumber(parser);
            int c = XML_GetCurrentColumnNumber(parser);
            Str fname = FILE_Name(f);
            const char * msg = XML_ErrorString(code);
            if (!fname) fname = TEXT("<noname>");
            if (!msg) msg = "<no message>";
#  ifdef _WIN32
            TRACE4("EXPAT: %s: line %d, column %d: %hs\n",fname,l,c,msg);
#  else  /* _WIN32 */
            TRACE4("EXPAT: %s: line %d, column %d: %s\n",fname,l,c,msg);
#  endif /* _WIN32 */
        }
#endif /* DEBUG */

        if (!buf) ok = False;

        /* deallocate parser */
        XML_ParserFree(parser);
        STRBUF_Destroy(&expat.sb);
        BUFFER_Destroy(&expat.buf);
        VECTOR_Destroy(&expat.atts);
    }

    return (ok);
}
Example #6
0
  static
  FT_Error  Load_Format_25( TT_Face    face,
                            FT_Stream  stream )
  {
    FT_Memory  memory = stream->memory;
    FT_Error   error;

    FT_Int     num_glyphs;
    FT_Char*   offset_table = 0;


    /* UNDOCUMENTED!  This value appears only in the Apple TT specs. */
    if ( READ_UShort( num_glyphs ) )
      goto Exit;

    /* check the number of glyphs */
    if ( num_glyphs > face->root.num_glyphs || num_glyphs > 258 )
    {
      error = TT_Err_Invalid_File_Format;
      goto Exit;
    }

    if ( ALLOC    ( offset_table, num_glyphs ) ||
         FILE_Read( offset_table, num_glyphs ) )
      goto Fail;

    /* now check the offset table */
    {
      FT_Int  n;


      for ( n = 0; n < num_glyphs; n++ )
      {
        FT_Long  index = (FT_Long)n + offset_table[n];


        if ( index < 0 || index > num_glyphs )
        {
          error = TT_Err_Invalid_File_Format;
          goto Fail;
        }
      }
    }

    /* OK, set table fields and exit successfuly */
    {
      TT_Post_25*  table = &face->postscript_names.names.format_25;


      table->num_glyphs = num_glyphs;
      table->offsets    = offset_table;
    }

    return TT_Err_Ok;

  Fail:
    FREE( offset_table );

  Exit:
    return error;
  }
Example #7
0
  static
  FT_Error  Load_Format_20( TT_Face    face,
                            FT_Stream  stream )
  {
    FT_Memory  memory = stream->memory;
    FT_Error   error;

    FT_Int     num_glyphs;
    FT_UShort  num_names;

    FT_UShort* glyph_indices = 0;
    FT_Char**  name_strings  = 0;


    if ( READ_UShort( num_glyphs ) )
      goto Exit;

    /* UNDOCUMENTED!  The number of glyphs in this table can be smaller */
    /* than the value in the maxp table (cf. cyberbit.ttf).             */

    /* There already exist fonts which have more than 32768 glyph names */
    /* in this table, so the test for this threshold has been dropped.  */

    if ( num_glyphs > face->root.num_glyphs )
    {
      error = TT_Err_Invalid_File_Format;
      goto Exit;
    }

    /* load the indices */
    {
      FT_Int  n;


      if ( ALLOC_ARRAY ( glyph_indices, num_glyphs, FT_UShort ) ||
           ACCESS_Frame( num_glyphs * 2L )                      )
        goto Fail;

      for ( n = 0; n < num_glyphs; n++ )
        glyph_indices[n] = GET_UShort();

      FORGET_Frame();
    }

    /* compute number of names stored in table */
    {
      FT_Int  n;


      num_names = 0;

      for ( n = 0; n < num_glyphs; n++ )
      {
        FT_Int  index;


        index = glyph_indices[n];
        if ( index >= 258 )
        {
          index -= 257;
          if ( index > num_names )
            num_names = index;
        }
      }
    }

    /* now load the name strings */
    {
      FT_UShort  n;


      if ( ALLOC_ARRAY( name_strings, num_names, FT_Char* ) )
        goto Fail;

      for ( n = 0; n < num_names; n++ )
      {
        FT_UInt  len;


        if ( READ_Byte  ( len )                               ||
             ALLOC_ARRAY( name_strings[n], len + 1, FT_Char ) ||
             FILE_Read  ( name_strings[n], len )              )
          goto Fail1;

        name_strings[n][len] = '\0';
      }
    }

    /* all right, set table fields and exit successfuly */
    {
      TT_Post_20*  table = &face->postscript_names.names.format_20;


      table->num_glyphs    = num_glyphs;
      table->num_names     = num_names;
      table->glyph_indices = glyph_indices;
      table->glyph_names   = name_strings;
    }
    return TT_Err_Ok;


  Fail1:
    {
      FT_UShort  n;


      for ( n = 0; n < num_names; n++ )
        FREE( name_strings[n] );
    }

  Fail:
    FREE( name_strings );
    FREE( glyph_indices );

  Exit:
    return error;
  }
Example #8
0
/**
 * Reads and uncompresses up to len bytes from the compressed stream.
 * Returns -1 in case of error, 0 if end of file has been reached (-1 on
 * subequent calls)
 */
STATIC int ZipRead(File * f, void * buf, int len)
{
    Zip * zf = ZipCast(f);

    /* check if input is transparent */
    if (!(zf->zflags & ZIP_IN)) {
        int nbytes = FILE_Read(zf->f, buf, len);
        if (nbytes == 0) {
            zf->zflags |= (ZIP_IN_EOF | ZIP_EOF);
        } else if (nbytes < 0) {
            zf->zflags |= ZIP_IN_ERR;
        }
        return nbytes;
    }

    /* check for error or end-of-file condition */
    if (zf->zflags & (ZIP_IN_ERR | ZIP_EOF)) {
        return -1;
    }

    /* report end-of-file condition to the caller */
    if (zf->zflags & ZIP_IN_END) {
        zf->zflags |= ZIP_EOF;
        return 0;
    }

    /* check if we can read from the low level file */
    if (!FILE_AllowsReads(zf->f)) {
        zf->zflags |= ZIP_IN_ERR;
        return -1;
    }

    /* "lazy" allocation of the input context */
    if (!zf->in) {
        if (!ZipInitIn(zf)) {
            return -1;
        }
    }

    /* read and inflate the data */
    zf->in->next_out = (Bytef*)buf;
    zf->in->avail_out = len;
    while (zf->in->avail_out > 0 && !(zf->zflags & (ZIP_IN_ERR|ZIP_IN_END))) {
        int zerr;
        if (zf->in->avail_in == 0 && !(zf->zflags & ZIP_IN_EOF)) {
            int nbytes = FILE_Read(zf->f, zf->inbuf, zf->bufsize);
            if (nbytes == 0) {
                zf->zflags |= ZIP_IN_EOF;
            } else if (nbytes < 0) {
                zf->zflags |= ZIP_IN_ERR;
                break;
            }
            zf->in->avail_in = nbytes;
            zf->in->next_in = zf->inbuf;
        }
        zerr = inflate(zf->in, Z_NO_FLUSH);
        if (zerr == Z_STREAM_END) {
            inflateReset(zf->in);
            zf->zflags |= ZIP_IN_END;
        } else  if (zerr != Z_OK) {
            zf->zflags |= ZIP_IN_ERR;
            break;
        }
    }

    /* 
     * return error or end-of-file condition if nothing has been 
     * decompressed, otherwise return the amount we have successfully
     * inflated.
     */
    if (len == (int)zf->in->avail_out) {
        if (zf->zflags & ZIP_IN_EOF) {
            zf->zflags |= ZIP_EOF;
            return 0;
        }
        if (zf->zflags & ZIP_IN_ERR) {
            return -1;
        }
        /* what would this mean? there's no data and yet it's not an error */
        zf->zflags |= ZIP_EOF;
        return 0;
    } else {
        zf->incrc = crc32(zf->incrc, (Bytef*)buf, len - zf->in->avail_out);
        return (len - zf->in->avail_out);
    }
}
Example #9
0
  FT_LOCAL_DEF
  FT_Error  TT_CharMap_Load( TT_Face        face,
                             TT_CMapTable*  cmap,
                             FT_Stream      stream )
  {
    FT_Error   error;
    FT_Memory  memory;
    FT_UShort  num_SH, num_Seg, i;

    FT_UShort  u, l;

    TT_CMap0*  cmap0;
    TT_CMap2*  cmap2;
    TT_CMap4*  cmap4;
    TT_CMap6*  cmap6;

    TT_CMap2SubHeader*  cmap2sub;
    TT_CMap4Segment*    segments;


    if ( cmap->loaded )
      return TT_Err_Ok;

    memory = stream->memory;

    if ( FILE_Seek( cmap->offset ) )
      return error;

    switch ( cmap->format )
    {
    case 0:
      cmap0 = &cmap->c.cmap0;

      if ( ALLOC( cmap0->glyphIdArray, 256L )            ||
           FILE_Read( cmap0->glyphIdArray, 256L ) )
         goto Fail;

      cmap->get_index = code_to_index0;
      break;

    case 2:
      num_SH = 0;
      cmap2  = &cmap->c.cmap2;

      /* allocate subheader keys */

      if ( ALLOC_ARRAY( cmap2->subHeaderKeys, 256, FT_UShort ) ||
           ACCESS_Frame( 512L )                                )
        goto Fail;

      for ( i = 0; i < 256; i++ )
      {
        u = GET_UShort() / 8;
        cmap2->subHeaderKeys[i] = u;

        if ( num_SH < u )
          num_SH = u;
      }

      FORGET_Frame();

      /* load subheaders */

      cmap2->numGlyphId = l =
        ( ( cmap->length - 2L * ( 256 + 3 ) - num_SH * 8L ) & 0xFFFF ) / 2;

      if ( ALLOC_ARRAY( cmap2->subHeaders,
                        num_SH + 1,
                        TT_CMap2SubHeader )    ||
           ACCESS_Frame( ( num_SH + 1 ) * 8L ) )
        goto Fail;

      cmap2sub = cmap2->subHeaders;

      for ( i = 0; i <= num_SH; i++ )
      {
        cmap2sub->firstCode     = GET_UShort();
        cmap2sub->entryCount    = GET_UShort();
        cmap2sub->idDelta       = GET_Short();
        /* we apply the location offset immediately */
        cmap2sub->idRangeOffset = GET_UShort() - ( num_SH - i ) * 8 - 2;

        cmap2sub++;
      }

      FORGET_Frame();

      /* load glyph IDs */

      if ( ALLOC_ARRAY( cmap2->glyphIdArray, l, FT_UShort ) ||
           ACCESS_Frame( l * 2L )                           )
        goto Fail;

      for ( i = 0; i < l; i++ )
        cmap2->glyphIdArray[i] = GET_UShort();

      FORGET_Frame();

      cmap->get_index = code_to_index2;
      break;

    case 4:
      cmap4 = &cmap->c.cmap4;

      /* load header */

      if ( ACCESS_Frame( 8L ) )
        goto Fail;

      cmap4->segCountX2    = GET_UShort();
      cmap4->searchRange   = GET_UShort();
      cmap4->entrySelector = GET_UShort();
      cmap4->rangeShift    = GET_UShort();

      num_Seg = cmap4->segCountX2 / 2;

      FORGET_Frame();

      /* load segments */

      if ( ALLOC_ARRAY( cmap4->segments,
                        num_Seg,
                        TT_CMap4Segment )           ||
           ACCESS_Frame( ( num_Seg * 4 + 1 ) * 2L ) )
        goto Fail;

      segments = cmap4->segments;

      for ( i = 0; i < num_Seg; i++ )
        segments[i].endCount      = GET_UShort();

      (void)GET_UShort();

      for ( i = 0; i < num_Seg; i++ )
        segments[i].startCount    = GET_UShort();

      for ( i = 0; i < num_Seg; i++ )
        segments[i].idDelta       = GET_Short();

      for ( i = 0; i < num_Seg; i++ )
        segments[i].idRangeOffset = GET_UShort();

      FORGET_Frame();

      cmap4->numGlyphId = l =
        ( ( cmap->length - ( 16L + 8L * num_Seg ) ) & 0xFFFF ) / 2;

      /* load IDs */

      if ( ALLOC_ARRAY( cmap4->glyphIdArray, l, FT_UShort ) ||
           ACCESS_Frame( l * 2L )                           )
        goto Fail;

      for ( i = 0; i < l; i++ )
        cmap4->glyphIdArray[i] = GET_UShort();

      FORGET_Frame();

      cmap->get_index = code_to_index4;

      cmap4->last_segment = cmap4->segments;
      break;

    case 6:
      cmap6 = &cmap->c.cmap6;

      if ( ACCESS_Frame( 4L ) )
        goto Fail;

      cmap6->firstCode  = GET_UShort();
      cmap6->entryCount = GET_UShort();

      FORGET_Frame();

      l = cmap6->entryCount;

      if ( ALLOC_ARRAY( cmap6->glyphIdArray,
                        cmap6->entryCount,
                        FT_Short )           ||
           ACCESS_Frame( l * 2L )            )
        goto Fail;

      for ( i = 0; i < l; i++ )
        cmap6->glyphIdArray[i] = GET_UShort();

      FORGET_Frame();
      cmap->get_index = code_to_index6;
      break;

    default:   /* corrupt character mapping table */
      return TT_Err_Invalid_CharMap_Format;

    }

    return TT_Err_Ok;

  Fail:
    TT_CharMap_Free( face, cmap );
    return error;
  }
Example #10
0
static
TT_Error  Load_Composite_End( UShort              n_points,
                              Short               n_contours,
                              PExecution_Context  exec,
                              PSubglyph_Record    subg,
                              UShort              load_flags,
                              TT_Stream           input )
{
    DEFINE_LOAD_LOCALS( input );

    UShort       k, n_ins;
    PGlyph_Zone  pts;


    if ( subg->is_hinted                    &&
            subg->element_flag & WE_HAVE_INSTR )
    {
        if ( ACCESS_Frame( 2L ) )
            return error;

        n_ins = GET_UShort();     /* read size of instructions */
        FORGET_Frame();

        PTRACE4(( " Instructions size: %d\n", n_ins ));

        if ( n_ins > exec->face->maxProfile.maxSizeOfInstructions )
        {
            PTRACE0(( "ERROR: Too many instructions in composite glyph %ld\n",
                      subg->index ));
            return TT_Err_Too_Many_Ins;
        }

        if ( FILE_Read( exec->glyphIns, n_ins ) )
            return error;

        error = Set_CodeRange( exec,
                               TT_CodeRange_Glyph,
                               exec->glyphIns,
                               n_ins );

        if ( error )
            return error;
    }
    else
        n_ins = 0;


    /* prepare the execution context */
    n_points += 2;
    exec->pts = subg->zone;
    pts       = &exec->pts;

    pts->n_points   = n_points;
    pts->n_contours = n_contours;

    /* add phantom points */
    pts->cur[n_points - 2] = subg->pp1;
    pts->cur[n_points - 1] = subg->pp2;

    pts->touch[n_points - 1] = 0;
    pts->touch[n_points - 2] = 0;

    /* if hinting, round the phantom points */
    if ( subg->is_hinted )
    {
        pts->cur[n_points - 2].x = (subg->pp1.x + 32) & -64;
        pts->cur[n_points - 1].x = (subg->pp2.x + 32) & -64;
    }

    for ( k = 0; k < n_points; k++ )
        pts->touch[k] &= TT_Flag_On_Curve;

    cur_to_org( n_points, pts );

    /* now consider hinting */
    if ( subg->is_hinted && n_ins > 0 )
    {
        exec->is_composite     = TRUE;
        exec->pedantic_hinting = load_flags & TTLOAD_PEDANTIC;

        error = Context_Run( exec, FALSE );
        if (error && exec->pedantic_hinting)
            return error;
    }

    /* save glyph origin and advance points */
    subg->pp1 = pts->cur[n_points - 2];
    subg->pp2 = pts->cur[n_points - 1];

    return TT_Err_Ok;
}
Example #11
0
static TT_Error  Load_Simple_Glyph( PExecution_Context  exec,
                                    TT_Stream           input,
                                    Short               n_contours,
                                    Short               left_contours,
                                    UShort              left_points,
                                    UShort              load_flags,
                                    PSubglyph_Record    subg )
{
    DEFINE_LOAD_LOCALS( input );

    PGlyph_Zone  pts;
    Short        k;
    UShort       j;
    UShort       n_points, n_ins;
    PFace        face;
    Byte*        flag;
    TT_Vector*   vec;
    TT_F26Dot6   x, y;


    face = exec->face;

    /* simple check */
    if ( n_contours > left_contours )
    {
        PTRACE0(( "ERROR: Glyph index %ld has %d contours > left %d\n",
                  subg->index, n_contours, left_contours ));
        return TT_Err_Too_Many_Contours;
    }


    /* preparing the execution context */
    mount_zone( &subg->zone, &exec->pts );

    /* reading the contours endpoints */
    if ( ACCESS_Frame( (n_contours + 1) * 2L ) )
        return error;

    PTRACE4(( " Contour endpoints:" ));

    for ( k = 0; k < n_contours; k++ )
    {
        exec->pts.contours[k] = GET_UShort();
        PTRACE4(( " %d", exec->pts.contours[k] ));
    }
    PTRACE4(( "\n" ));

    if ( n_contours > 0 )
        n_points = exec->pts.contours[n_contours - 1] + 1;
    else
        n_points = 0;

    n_ins = GET_UShort();

    FORGET_Frame();

    if ( n_points > left_points )
    {
        PTRACE0(( "ERROR: Too many points in glyph %ld\n", subg->index ));
        return TT_Err_Too_Many_Points;
    }

    /* loading instructions */

    PTRACE4(( " Instructions size: %d\n", n_ins ));

    if ( n_ins > face->maxProfile.maxSizeOfInstructions )
    {
        PTRACE0(( "ERROR: Too many instructions!\n" ));
        return TT_Err_Too_Many_Ins;
    }

    if ( FILE_Read( exec->glyphIns, n_ins ) )
        return error;

    if ( (error = Set_CodeRange( exec,
                                 TT_CodeRange_Glyph,
                                 exec->glyphIns,
                                 n_ins )) != TT_Err_Ok )
        return error;


    /* read the flags */

    if ( CHECK_AND_ACCESS_Frame( n_points * 5L ) )
        return error;

    j    = 0;
    flag = exec->pts.touch;

    while ( j < n_points )
    {
        Byte  c, cnt;

        flag[j] = c = GET_Byte();
        j++;

        if ( c & 8 )
        {
            cnt = GET_Byte();
            while( cnt > 0 )
            {
                flag[j++] = c;
                cnt--;
            }
        }
    }

    /* read the X */

    x    = 0;
    vec  = exec->pts.org;

    for ( j = 0; j < n_points; j++ )
    {
        if ( flag[j] & 2 )
        {
            if ( flag[j] & 16 )
                x += GET_Byte();
            else
                x -= GET_Byte();
        }
        else
        {
            if ( (flag[j] & 16) == 0 )
                x += GET_Short();
        }

        vec[j].x = x;
    }


    /* read the Y */

    y    = 0;

    for ( j = 0; j < n_points; j++ )
    {
        if ( flag[j] & 4 )
        {
            if ( flag[j] & 32 )
                y += GET_Byte();
            else
                y -= GET_Byte();
        }
        else
        {
            if ( (flag[j] & 32) == 0 )
                y += GET_Short();
        }

        vec[j].y = y;
    }

    FORGET_Frame();
    /* Now add the two shadow points at n and n + 1.    */
    /* We need the left side bearing and advance width. */

    /* pp1 = xMin - lsb */
    vec[n_points].x = subg->metrics.bbox.xMin - subg->metrics.horiBearingX;
    vec[n_points].y = 0;

    /* pp2 = pp1 + aw */
    vec[n_points+1].x = vec[n_points].x + subg->metrics.horiAdvance;
    vec[n_points+1].y = 0;

    /* clear the touch flags */

    for ( j = 0; j < n_points; j++ )
        exec->pts.touch[j] &= TT_Flag_On_Curve;

    exec->pts.touch[n_points    ] = 0;
    exec->pts.touch[n_points + 1] = 0;

    /* Note that we return two more points that are not */
    /* part of the glyph outline.                       */

    n_points += 2;

    /* now eventually scale and hint the glyph */

    pts = &exec->pts;
    pts->n_points   = n_points;
    pts->n_contours = n_contours;

    if ( (load_flags & TTLOAD_SCALE_GLYPH) == 0 )
    {
        /* no scaling, just copy the orig arrays into the cur ones */
        org_to_cur( n_points, pts );
    }
    else
    {
        /* first scale the glyph points */

        for ( j = 0; j < n_points; j++ )
        {
            pts->org[j].x = Scale_X( &exec->metrics, pts->org[j].x );
            pts->org[j].y = Scale_Y( &exec->metrics, pts->org[j].y );
        }

        /* if hinting, round pp1, and shift the glyph accordingly */
        if ( subg->is_hinted )
        {
            x = pts->org[n_points - 2].x;
            x = ((x+32) & -64) - x;
            translate_array( n_points, pts->org, x, 0 );

            org_to_cur( n_points, pts );

            pts->cur[n_points - 1].x = (pts->cur[n_points - 1].x + 32) & -64;

            /* now consider hinting */
            if ( n_ins > 0 )
            {
                exec->is_composite     = FALSE;
                exec->pedantic_hinting = load_flags & TTLOAD_PEDANTIC;

                error = Context_Run( exec, FALSE );
                if (error && exec->pedantic_hinting)
                    return error;
            }
        }
        else
            org_to_cur( n_points, pts );
    }

    /* save glyph phantom points */
    if (!subg->preserve_pps)
    {
        subg->pp1 = pts->cur[n_points - 2];
        subg->pp2 = pts->cur[n_points - 1];
    }

    return TT_Err_Ok;
}