gt:             code <<= 8;
context: /*
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to You under the Apache License, Version 2.0
   * (the "License"); you may not use this file except in compliance with
   * the License.  You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package org.apache.pdfbox.pdmodel.font;
  
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.UnsupportedEncodingException;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  
  import org.apache.fontbox.afm.AFMParser;
  import org.apache.fontbox.afm.FontMetric;
  import org.apache.fontbox.cmap.CMapParser;
  import org.apache.fontbox.cmap.CMap;
  
  import org.apache.pdfbox.encoding.Encoding;
  
  import org.apache.pdfbox.cos.COSArray;
  import org.apache.pdfbox.cos.COSBase;
  import org.apache.pdfbox.cos.COSDictionary;
  import org.apache.pdfbox.cos.COSFloat;
  import org.apache.pdfbox.cos.COSInteger;
  import org.apache.pdfbox.cos.COSName;
  import org.apache.pdfbox.cos.COSString;
  
  import org.apache.pdfbox.pdmodel.common.COSArrayList;
  import org.apache.pdfbox.pdmodel.common.COSObjectable;
  import org.apache.pdfbox.pdmodel.common.PDMatrix;
  import org.apache.pdfbox.pdmodel.common.PDRectangle;
  
  import org.apache.pdfbox.util.ResourceLoader;
  
  import java.awt.Graphics;
  import java.awt.geom.AffineTransform;
  
  /**
   * This is the base class for all PDF fonts.
   *
   * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
   * 
   */
  public abstract class PDFont implements COSObjectable
  {
  
      /**
       * The cos dictionary for this font.
       */
      protected COSDictionary font;
  
      /**
       * This is only used if this is a font object and it has an encoding.
       */
      private Encoding fontEncoding = null;
  
      /**
       *  The descriptor of the font.
       */
      private PDFontDescriptor fontDescriptor = null;
  
      /**
       *  The font matrix.
       */
      protected PDMatrix fontMatrix = null;
  
      /**
       * This is only used if this is a font object and it has an encoding and it is
       * a type0 font with a cmap.
       */
      protected CMap cmap = null;
  
      /**
       * The CMap holding the ToUnicode mapping.
       */
      protected CMap toUnicodeCmap = null;
      
      private boolean hasToUnicode = false;
  
      protected static Map<String, CMap> cmapObjects =
          Collections.synchronizedMap( new HashMap<String, CMap>() );
  
      /**
       *  A list a floats representing the widths.
       */
      private List<Float> widths = null;
  
      /**
       * The static map of the default Adobe font metrics.
       */
      private static final Map<String, FontMetric> afmObjects =
          Collections.unmodifiableMap( getAdobeFontMetrics() );
  
      // TODO move the Map to PDType1Font as these are the 14 Standard fonts
      // which are definitely Type 1 fonts
      private static Map<String, FontMetric> getAdobeFontMetrics()
      {
          Map<String, FontMetric> metrics = new HashMap<String, FontMetric>();
          addAdobeFontMetric( metrics, "Courier-Bold" );
          addAdobeFontMetric( metrics, "Courier-BoldOblique" );
          addAdobeFontMetric( metrics, "Courier" );
          addAdobeFontMetric( metrics, "Courier-Oblique" );
          addAdobeFontMetric( metrics, "Helvetica" );
          addAdobeFontMetric( metrics, "Helvetica-Bold" );
          addAdobeFontMetric( metrics, "Helvetica-BoldOblique" );
          addAdobeFontMetric( metrics, "Helvetica-Oblique" );
          addAdobeFontMetric( metrics, "Symbol" );
          addAdobeFontMetric( metrics, "Times-Bold" );
          addAdobeFontMetric( metrics, "Times-BoldItalic" );
          addAdobeFontMetric( metrics, "Times-Italic" );
          addAdobeFontMetric( metrics, "Times-Roman" );
          addAdobeFontMetric( metrics, "ZapfDingbats" );
          return metrics;
      }
  
      protected static final String resourceRootCMAP = "org/apache/pdfbox/resources/cmap/";
      private static final String resourceRootAFM = "org/apache/pdfbox/resources/afm/";
  
      private static void addAdobeFontMetric(
              Map<String, FontMetric> metrics, String name )
      {
          try
          {
              String resource = resourceRootAFM + name + ".afm";
              InputStream afmStream = ResourceLoader.loadResource( resource );
              if( afmStream != null )
              {
                  try
                  {
                      AFMParser parser = new AFMParser( afmStream );
                      parser.parse();
                      metrics.put( name, parser.getResult() );
                  }
                  finally
                  {
                      afmStream.close();
                  }
              }
          }
          catch (Exception e)
          {
              // ignore
          }
      }
  
      /**
       * This will clear AFM resources that are stored statically.
       * This is usually not a problem unless you want to reclaim
       * resources for a long running process.
       *
       * SPECIAL NOTE: The font calculations are currently in COSObject, which
       * is where they will reside until PDFont is mature enough to take them over.
       * PDFont is the appropriate place for them and not in COSObject but we need font
       * calculations for text extraction.  THIS METHOD WILL BE MOVED OR REMOVED
       * TO ANOTHER LOCATION IN A FUTURE VERSION OF PDFBOX.
       */
      public static void clearResources()
      {
          cmapObjects.clear();
      }
  
      /**
       * Constructor.
       */
      public PDFont()
      {
          font = new COSDictionary();
          font.setItem( COSName.TYPE, COSName.FONT );
      }
  
      /**
       * Constructor.
       *
       * @param fontDictionary The font dictionary according to the PDF specification.
       */
      public PDFont( COSDictionary fontDictionary )
      {
          font = fontDictionary;
          determineEncoding();
      }
  
      /**
       * This will get the font descriptor for this font.
       *
       * @return The font descriptor for this font.
       *
       */
      public PDFontDescriptor getFontDescriptor()
      {
          if(fontDescriptor == null)
          {
              COSDictionary fd = (COSDictionary)font.getDictionaryObject( COSName.FONT_DESC );
              if (fd != null)
              {
                  fontDescriptor = new PDFontDescriptorDictionary( fd );
              }
              else
              {
                  getAFM();
                  if( afm != null )
                  {
                      fontDescriptor = new PDFontDescriptorAFM( afm );
                  }
              }
          }
          return fontDescriptor;
      }
  
      /**
       * This will set the font descriptor.
       *
       * @param fdDictionary The font descriptor.
       */
      public void setFontDescriptor( PDFontDescriptorDictionary fdDictionary )
      {
          COSDictionary dic = null;
          if( fdDictionary != null )
          {
              dic = fdDictionary.getCOSDictionary();
          }
          font.setItem( COSName.FONT_DESC, dic );
          fontDescriptor = fdDictionary;
      }
  
      /**
       * Determines the encoding for the font.
       * This method as to be overwritten, as there are different
       * possibilities to define a mapping.
       */
      protected abstract void determineEncoding();
  
      /**
       * {@inheritDoc}
       */
      public COSBase getCOSObject()
      {
          return font;
      }
  
      /**
       * This will get the font width for a character.
       *
       * @param c The character code to get the width for.
       * @param offset The offset into the array.
       * @param length The length of the data.
       *
       * @return The width is in 1000 unit of text space, ie 333 or 777
       *
       * @throws IOException If an error occurs while parsing.
       */
      public abstract float getFontWidth( byte[] c, int offset, int length ) throws IOException;
  
      /**
       * This will get the font width for a character.
       *
       * @param c The character code to get the width for.
       * @param offset The offset into the array.
       * @param length The length of the data.
       *
       * @return The width is in 1000 unit of text space, ie 333 or 777
       *
       * @throws IOException If an error occurs while parsing.
       */
      public abstract float getFontHeight( byte[] c, int offset, int length ) throws IOException;
  
      /**
       * This will get the width of this string for this font.
       *
       * @param string The string to get the width of.
       *
       * @return The width of the string in 1000 units of text space, ie 333 567...
       *
       * @throws IOException If there is an error getting the width information.
       */
      public float getStringWidth( String string ) throws IOException
      {
          byte[] data = string.getBytes("ISO-8859-1");
          float totalWidth = 0;
          for( int i=0; i<data.length; i++ )
          {
              totalWidth+=getFontWidth( data, i, 1 );
          }
          return totalWidth;
      }
  
      /**
       * This will get the average font width for all characters.
       *
       * @return The width is in 1000 unit of text space, ie 333 or 777
       *
       * @throws IOException If an error occurs while parsing.
       */
      public abstract float getAverageFontWidth() throws IOException;
  
      /**
       * This will draw a string on a canvas using the font.
       *
       * @param string The string to draw.
       * @param g The graphics to draw onto.
       * @param fontSize The size of the font to draw.
       * @param at The transformation matrix with all information for scaling and shearing of the font.
       * @param x The x coordinate to draw at.
       * @param y The y coordinate to draw at.
       *
       * @throws IOException If there is an error drawing the specific string.
       * @deprecated use {@link PDFont#drawString(String, int[], Graphics, float, AffineTransform, float, float)} instead
       */
      public void drawString( String string, Graphics g, float fontSize, AffineTransform at, float x, float y ) 
      throws IOException
      {
          drawString(string, null, g, fontSize, at, x, y);
      }
  
      /**
       * This will draw a string on a canvas using the font.
       *
       * @param string The string to draw.
       * @param codePoints The codePoints of the given string.
       * @param g The graphics to draw onto.
       * @param fontSize The size of the font to draw.
       * @param at The transformation matrix with all information for scaling and shearing of the font.
       * @param x The x coordinate to draw at.
       * @param y The y coordinate to draw at.
       *
       * @throws IOException If there is an error drawing the specific string.
       */
      public abstract void drawString( String string, int[] codePoints, Graphics g, float fontSize,
          AffineTransform at, float x, float y ) throws IOException;
      
      /**
       * Used for multibyte encodings.
       *
       * @param data The array of data.
       * @param offset The offset into the array.
       * @param length The number of bytes to use.
       *
       * @return The int value of data from the array.
       */
      public int getCodeFromArray( byte[] data, int offset, int length )
      {
          int code = 0;
          for( int i=0; i<length; i++ )
          {
  