/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 WARP source code is provided to you solely for  */
/*    the purpose of assisting you in your development of OS/2 WARP device   */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
/*    Copyright statement may not be removed.                                */
/*                                                                           */
/*****************************************************************************/
/**********************************************************************/
/*   Module	      : EDDJSUB.C				      */
/*								      */
/*   Description      : PM Display Driver DBCS handling routine       */
/*			Subroutines for DBCS handling		      */
/*								      */
/*   Created	      : 12/11/91				      */
/*   Author	      : Yohji Nakamura (JL04328 at YMTVM6)	      */
/*								      */
/*   Notes	      : 					      */
/*								      */
/*   History	      : 					      */
/*								      */
/*			OCO Source Materials			      */
/*			XXXX-XXX				      */
/**********************************************************************/
#include <eddinclt.h>
#include <eddttypt.h>
#include <eddjdef.h>
#include <eddjfm.h>
#include <eddjfont.h>
#include <eddjsub.h>

/*====================================================================*/
/* external variables						      */
/*====================================================================*/
extern BOOL flDrvDbcsProportional;     /*			      */

/*====================================================================*/
/* global variables						      */
/*====================================================================*/
/*--------------------------------------------------------------------*/
/* buffer for unified DBCS string				      */
/*	They should be used by several functions.		      */
/*--------------------------------------------------------------------*/
USHORT ausString[WORK_BUFFER_SIZE];    /* buffer for U-DBCS string    */
USHORT ausWidth[WORK_BUFFER_SIZE];     /* buffer for char widths      */
USHORT ausGlyph[WORK_BUFFER_SIZE];     /* buffer for glyph indexes    */
SHORT  asCIndex[WORK_BUFFER_SIZE];     /* buffer for cache indexes    */
LONG   alVector[WORK_BUFFER_SIZE];     /* buffer for U-DBCS vectors   */
SHORT  asDVector[WORK_BUFFER_SIZE];    /* buffer for U-DBCS vectors   */
				       /*   in device coordinates     */

/*====================================================================*/
/* local macros 						      */
/*====================================================================*/
#define EVEN(x) ((x) & ~1)

#define CHKRANGE(val,min,max,def)		\
		(((val)<(min)) || ((max)<(val)) ? (def) : (val))
				       /* if value is within range,   */
				       /* returns the value, otherwise*/
				       /* returns default value       */

/*====================================================================*/
/* local types							      */
/*====================================================================*/
typedef union
    {
      ABC_CHAR_DEFN *pABC;
      NON_ABC_CHAR_DEFN *pNonABC;
    } PCHARDEFINITION;		       /* ptr to handle CharDef       */


/*====================================================================*/
/* local functions						      */
/*====================================================================*/
ULONG GlyphToWidth( PUSHORT pusGlyphIndex,
		    ULONG ulGlyphCount,
		    PFOCAFONT pFont );

/*===================== Exported Routine =============================*/
/*	eddj_UnifiedDBCS					      */
/*								      */
/* Convert given DBCS/MBCS string into unified DBCS string, of which  */
/* all characters are represented by 2 bytes.  Single byte char is    */
/* expanded to 2 bytes by padding high-byte with 0.  Returns when     */
/* given buffer is full, or when all source string is converted.      */
/*								      */
/*								      */
/* Entry      : 						      */
/*	      - ptr to current font's FONTDETAILS structure           */
/*	      - ptr to source string				      */
/*	      - length of source string in bytes		      */
/*	      - ptr to vector array (may be NULL)		      */
/*	      - ptr to the buffer where result string are returned    */
/*		  (May be NULL) 				      */
/*	      - size of result buffer				      */
/*	      - ptr to converted vector array			      */
/*		  (not used when ptr to vector array is NULL)	      */
/*	      - ptr to buffer where result string length is returned  */
/*		(in chars, i.e. #bytes/2)			      */
/*								      */
/* Returns    : 						      */
/*	      - number of processed codepoints is returned in bytes   */
/*	      - result string are returned in given buffer	      */
/*	      - converted vector is returned in given vector buffer   */
/*								      */
/* Error Returns :	None					      */
/*								      */
/* Note       : 						      */
/*	      - The concept of Unified DBCS is based on an assumption */
/*		that there is a value (i.e. x'00') which cannot be    */
/*		used for a DBCS leading byte with any MBCS CP.	      */
/*		This seems TRUE for all known countries...	      */
/*								      */
/*	      - Assumes that noone would call this routine when       */
/*		NLSCA_UNIFIED_DBCS bit in NLSParseFlag is OFF.	      */
/*		That means, when entering this function, we assume:   */
/*		      - Current CP is MBCS or DBCS		      */
/*		      - given string contains at least 1 DBCS char    */
/*								      */
/*	      - Caller must ensure that only EVEN length of string    */
/*		is allowed in DBCS codepage case.		      */
/*								      */
/*	      - Note the most popular case is MBCS CP/MBCS FONT.      */
/*		We have no DBCS font for the time being, so much      */
/*		consideration for performance should be unnecessary   */
/*		for DBCS font case...				      */
/*								      */
/*	      - We also do basic range check for codepoints.	      */
/*								      */
/*		(1) CP=DBCS, FONT=SBCS				      */
/*		      Convert all codepoints to SBCS default char     */
/*		(2) CP=MBCS, FONT=SBCS				      */
/*		      Convert all 2-byte codepoints to SBCS default   */
/*		      char					      */
/*		(3) CP=MBCS, FONT=DBCS				      */
/*		      Convert all 1-byte codepoints to DBCS default   */
/*		      char					      */
/*		(4) CP=SBCS, FONT=DBCS				      */
/*		      Convert all codepoints to DBCS default char     */
/*								      */
/*		(1) and (2) are done in this routine.		      */
/*		By executing this conversion in this stage, (rather   */
/*		than on conversion-to-glyph-index stage) we can make  */
/*		cache management easier.  (See eddj_LocateInCache in  */
/*		EDDJCACH.C)					      */
/*								      */
/*		As for (3) and (4), nothing is done here.  (In (4)    */
/*		case, this function is not called at all.)  Required  */
/*		conversion will be executed by DBCS font manager.     */
/*								      */
/*								      */
/*								      */
/*====================================================================*/
LONG eddj_UnifiedDBCS( PFONTDETAILS pFontDtl,
		       PCHAR pchCodepoint,
		       ULONG ulSrcLength,
		       PLONG plSrcVector,
		       PUSHORT pusResult,
		       ULONG ulDstLength,
		       PLONG plDstVector,
		       PULONG pulResultCount )
{				       /* top of func: eddj_UnifiedDBC*/
  /*------------------------------------------------------------------*/
  /* work variables						      */
  /*------------------------------------------------------------------*/
  PCHAR pch, pchLast;
  PUSHORT pus, pusLast;
  PLONG plS, plD;

  const USHORT NLSParseFlag = pFontDtl->NLSParseFlag;
  const USHORT NLSFontFlag = pFontDtl->NLSFontFlag;

#ifdef FIREWALLS
  if ((NLSParseFlag & (NLSCA_SBCS | NLSCA_DBCS)) ||
      !(NLSParseFlag & NLSCA_MAP_DBCS) ||
      !(NLSParseFlag & NLSCA_UNIFIED_DBCS))
    {				       /* should not call!!	      */
      haltproc();		       /*			      */
    }				       /* end of if:		      */
#endif

  pch = pchCodepoint;
  pus = pusResult;
  plS = plSrcVector;		       /*			      */
  plD = plDstVector;
  pchLast = pch + ulSrcLength;	       /* next of last codepoint      */
  pusLast = pus + ulDstLength;	       /* next of last buffer entry   */

  /*------------------------------------------------------------------*/
  /* case 1:  DBCS CP						      */
  /*------------------------------------------------------------------*/
  if (NLSParseFlag & NLSCA_DBCS)       /* if current CP is DBCS       */
    {				       /*			      */
      ulDstLength = min( ulSrcLength / 2, ulDstLength );
				       /* decide how many we will fill*/
				       /* assume src length not even  */
      for ( ; ulDstLength; ulDstLength --)
	{			       /*			      */
	  if (NLSFontFlag & NLSCA_FONT_SBCS)
	    {			       /* if font has no DBCS chars   */
				       /* fill buffer with default    */
	      *(pus ++) = (USHORT)pFontDtl->ulDefCodepoint;
	    }			       /* end of if:		      */
	  else			       /* or if font has DBCS part    */
	    {
	      *(pus ++) = MAKEUSHORT( *(pch+1), *pch );
	      pch += 2; 	       /* swap hi/lo bytes	      */
	    }			       /* end of else:		      */

	  if (plSrcVector)	       /* adjust vector if given      */
	    {			       /*			      */
	      *(plD ++) = *plS;        /*			      */
	      plS += 2; 	       /* discard vector for trailing */
				       /*   byte		      */
	    }			       /* end of if:		      */
	}			       /* end of for:		      */
    }				       /* end of if:		      */
  /*------------------------------------------------------------------*/
  /* case 2 : MBCS CP						      */
  /*------------------------------------------------------------------*/
  else				       /* or if current CP is MBCS    */
    {
      while ((pch != pchLast) && (pus != pusLast))
	{			       /*			      */
	  if (pFontDtl->pDBCSMap[*pch])
	    {			       /* if DBCS leading byte	      */
	      /*------------------------------------------------------*/
	      /* DBCS leading byte in the last			      */
	      /*------------------------------------------------------*/
	      if (pch+1 == pchLast)    /* if it is the last byte      */
		{		       /*			      */
		  *(pus++) = (USHORT)pFontDtl->ulDefCodepoint;
				       /* if font is DBCS, Font Mgr   */
				       /* should convert it to DBCS   */
				       /* defalut font, as it is not  */
				       /* a valid 2-byte codepoint.   */
		  pch ++;	       /* need to inc: be used later  */
		  if (plSrcVector)     /*			      */
		    {		       /*			      */
		      *plD = *plS;     /*			      */
		    }		       /* end of if:		      */

		  break;	       /* end of scan anyway	      */
		}		       /* end of if:		      */

	      /*------------------------------------------------------*/
	      /* DBCS leading byte, not last			      */
	      /*------------------------------------------------------*/
	      if (NLSFontFlag & NLSCA_FONT_SBCS)
		{		       /*			      */
		  *(pus++) = (USHORT)pFontDtl->ulDefCodepoint;
		}		       /* end of if:		      */
	      else		       /*			      */
		{
		  *(pus++) = MAKEUSHORT( *(pch+1), *pch );
		}		       /* end of else:		      */

	      pch += 2; 	       /* use those 2 bytes	      */

	      if (plSrcVector)	       /*			      */
		{		       /*			      */
		  *(plD++) = *plS;
		  plS += 2;	       /* skip vector for trailing    */
		}		       /* end of if:		      */
	    }			       /* end of if:		      */
	  else			       /* not DBCS leading->SBCS      */
	    {			       /*			      */
	      /*------------------------------------------------------*/
	      /* SBCS codepoint 				      */
	      /*------------------------------------------------------*/
	      *(pus++) = (USHORT)*(pch++);

	      if (plSrcVector)
		{
		  *(plD++) = *(plS++); /*			      */
		}		       /* end of if:		      */
	    }			       /* end of else:		      */
	}			       /* end of while: 	      */
    }				       /* end of else:		      */

  *pulResultCount = pus - pusResult;   /* this is returned string len */
  return pch - pchCodepoint;	       /* and this is processed byte  */
}				       /* end of func: eddj_UnifiedDBC*/

/*===================== Exported Routine =============================*/
/*	eddj_ChopString 					      */
/*								      */
/* Get a substring from given string for given # of chars.	      */
/*								      */
/* Entry      : 						      */
/*	      - Ptr to FONTDETAILS structure			      */
/*	      - Ptr to string (not U-DBCS)			      */
/*	      - Length of string (in bytes)			      */
/*	      - Length of desired substring (in chars)		      */
/*								      */
/* Returns    : 						      */
/*	      - Returns # of bytes contained in target substring      */
/*								      */
/* Error Returns :	None					      */
/*								      */
/* Note       : 						      */
/*	      - Assumes NLSCA_SBC_ONLY is properly set before call.   */
/*	      - Does not care if odd length string is given for       */
/*		DBCS codepage.					      */
/*====================================================================*/
ULONG eddj_ChopString( PFONTDETAILS pFontDtl,
		       PCHAR pchString,
		       ULONG ulSrcBytes,
		       ULONG ulDstChars )
{				       /* top of func: eddj_ChopString*/
  ULONG ulDstBytes;		       /*			      */

  if (pFontDtl->NLSParseFlag & NLSCA_DBCS)
    {				       /*			      */
      return min( ulDstChars * 2, ulSrcBytes );
				       /* always 1 char = 2 bytes     */
    }				       /* end of if:		      */
  else if (pFontDtl->NLSParseFlag & NLSCA_SBC_ONLY)
    {				       /*			      */
      return min( ulDstChars, ulSrcBytes );
				       /* always 1 char = 1 byte      */
    }				       /* end of if:		      */

  ulDstBytes = 0;		       /*			      */
  while (ulDstChars)
    {				       /*			      */
      if (pFontDtl->pDBCSMap[*pchString])
	{			       /* if DBCS leading byte	      */
	  if (ulSrcBytes <= 2)	       /*			      */
	    {			       /*			      */
	      return ulDstBytes + ulSrcBytes;
	    }			       /* end of if:		      */

	  ulDstBytes += 2;	       /* it's 2 bytes char           */
	  ulSrcBytes -= 2;	       /*			      */
	  pchString += 2;	       /*			      */
	}			       /* end of if:		      */
      else			       /* or if it is SBCS char       */
	{			       /*			      */
	  if (ulSrcBytes <= 1)	       /*			      */
	    {			       /*			      */
	      return ulDstBytes + 1;   /*			      */
	    }			       /* end of if:		      */

	  ulDstBytes ++;	       /* it is 1 byte char	      */
	  ulSrcBytes --;	       /*			      */
	  pchString ++; 	       /*			      */
	}			       /* end of else:		      */

      ulDstChars --;		       /* 1 char was found	      */
    }				       /* end of while: 	      */

  return ulDstBytes;		       /*			      */
}				       /* end of func: eddj_ChopString*/

/*===================== Exported Routine =============================*/
/*	eddj_CodepointToGlyph					      */
/*								      */
/* Convert given unified DBCS codepoint into glyph index	      */
/*								      */
/* Entry      : 						      */
/*	      - ptr to current font's FONTDETAILS structure           */
/*	      - codepoint					      */
/*								      */
/* Returns    : 						      */
/*	      - glyph index is returned.			      */
/*								      */
/* Error Returns :	None					      */
/*								      */
/* Note       : 						      */
/*								      */
/* Calls      : 						      */
/*								      */
/*====================================================================*/
USHORT eddj_CodepointToGlyph( PFONTDETAILS pFontDtl,
			      USHORT usCodepoint )
{				       /* top of func: eddj_CodepointT*/
  /*------------------------------------------------------------------*/
  /* performance variables					      */
  /*------------------------------------------------------------------*/
  const USHORT NLSParseFlag = pFontDtl->NLSParseFlag;
				       /*			      */
  const USHORT usFirstGlyph
    = pFontDtl->pFocaFont->fmMetrics.usFirstChar;
  const USHORT usLastGlyph
    = pFontDtl->pFocaFont->fmMetrics.usLastChar + usFirstGlyph;
  const USHORT usDefaultGlyph
    = pFontDtl->pFocaFont->fmMetrics.usDefaultChar + usFirstGlyph;


  if (NLSParseFlag & NLSCA_DBCS)
    {				       /* DBCS case:		      */
//	Maybe this was not a good idea, since when 00-ff codepoint is
//	is given for DBCS (not MBCS!) font, we should return DBCS
//	default char instead of SBCS default char, so that AVIO routine
//	can handle it as DBCS char.
//
//    if (!HIBYTE(usCodepoint))        /*			      */
//	{
//	  return usDefaultGlyph;       /*   should be SBCS default chr*/
//	}			       /* end of if:		      */

      if (!eddj_MapCharGlyph( pFontDtl->usECodePage, sizeof(USHORT),
			      pFontDtl->pFocaFont, &usCodepoint ))
	{			       /*			      */
	  return usDefaultGlyph;       /* this is our best effort...  */
				       /* Should not fail since if it */
				       /* is invalid code, FM returns */
				       /* index to default glyph      */
	}			       /* end of if:		      */
      else			       /*			      */
	{			       /*			      */
	  return usCodepoint;	       /* glyph index is returned here*/
	}			       /* end of else:		      */
    }				       /* end of if:		      */
  else				       /*			      */
    {				       /* SBCS/MBCS case:	      */
      /*--------------------------------------------------------------*/
      /* Codepage: MBCS or SBCS 				      */
      /*	--> SBCS codepoint -> SBCS glyph index (if map needed)*/
      /*			   -> as is  (if map is not needed)   */
      /*			   -> SBCS default (if out of range)  */
      /*	    DBCS codepoint -> as is			      */
      /*--------------------------------------------------------------*/
      if (HIBYTE(usCodepoint))	       /* if DBCS codepoint	      */
	{			       /* (Must not happen for SB-CP) */
	  return usCodepoint;	       /* this is also glyph index    */
	}			       /*			      */

      if (NLSParseFlag & NLSCA_MAP_SBCS)
	{			       /* if mapping is required      */
	  usCodepoint = pFontDtl->pCodePageVector[usCodepoint];
	}			       /* set glyph index here now... */

      if ((usCodepoint < usFirstGlyph)
       || (usLastGlyph	< usCodepoint))
	{			       /* if it is out of range       */
	  return usDefaultGlyph;       /* return SBCS default	      */
	}			       /* end of if:		      */
      else			       /*			      */
	{			       /*			      */
	  return usCodepoint;	       /*			      */
	}			       /* end of else:		      */
    }				       /* end of else:		      */
}				       /* end of func: eddj_CodepointT*/

#ifdef OMIT
/*===================== Exported Routine =============================*/
/*	eddj_UnifiedDBCSVector					      */
/*								      */
/* Convert given vector array for DBCS/MBCS string to more easy-to-   */
/* handle format by removing invalid part (vector values for DBCS     */
/* trailing byte).  This is also done in eddj_UnifiedDBCS, but this   */
/* function does nothing for string itself, thus should be faster     */
/* (and should be enough for QueryTextBox type function)	      */
/*								      */
/* Entry      : 						      */
/*	      - ptr to current font's FONTDETAILS structure           */
/*	      - ptr to source string				      */
/*	      - length of source string in bytes		      */
/*	      - ptr to buffer where number of result vectors is set   */
/*	      - ptr to vector array				      */
/*								      */
/* Returns    : 						      */
/*	      - number of processed codepoints is returned in bytes   */
/*		(may be 1 less than given length if NLSCA_CONCAT flag */
/*		 is set in NLSParseFlag, and the last byte is DBCS    */
/*		 leading byte. See Note.)			      */
/*	      - number of result vectors (not #bytes) is returned in  */
/*		given buffer					      */
/*	      - converted vector is returned where vector is supplied */
/*								      */
/* Error Returns :						      */
/*	      - returns ERROR_NEG (-1) if error is found	      */
/*	      - If the last byte of given string is DBCS leading byte,*/
/*		  if NLSCA_CONCAT is ON : leave it unprocessed	      */
/*		  if NLSCA_CONCAT is OFF: include its vector to result*/
/*								      */
/* Note       : 						      */
/*	      - Caller should check odd length of string is not       */
/*		passed when DBCS CP.				      */
/*								      */
/* Calls      : 						      */
/*								      */
/*====================================================================*/
LONG eddj_UnifiedDBCSVector( PFONTDETAILS pFontDtl,
			     PCHAR pchCodepoint,
			     ULONG ulLength,
			     PLONG plVectorCount,
			     PLONG plVector )
{				       /* top of func: eddj_UnifiedDBC*/
  /*------------------------------------------------------------------*/
  /* work variables						      */
  /*------------------------------------------------------------------*/
  ULONG index;
  PCHAR pch, pchLast;
  PLONG plS, plD;

  /*------------------------------------------------------------------*/
  /* performance variables					      */
  /*------------------------------------------------------------------*/
  USHORT NLSParseFlag = pFontDtl->NLSParseFlag;
  USHORT NLSFontFlag = pFontDtl->NLSFontFlag;

  if (!plVector)		       /*			      */
    {				       /*			      */
      return ERROR_NEG; 	       /* why call me?		      */
    }				       /* end of if:		      */

  if (!(NLSParseFlag & NLSCA_UNIFIED_DBCS))
    {				       /*			      */
      *plVectorCount = ulLength;       /*			      */
      return ulLength;		       /*			      */
    }				       /* end of if:		      */

  if (NLSParseFlag & NLSCA_DBCS)
    {				       /* DBCS case:		      */
      for (index = 1; index < ulLength/2; index++)
	{			       /*			      */
	  plVector[index] = plVector[index*2];
				       /* discard vector for trailing */
				       /*   byte		      */
	}			       /* end of for:		      */
    }				       /* end of if:		      */
  else				       /*			      */
    {				       /* MBCS case:		      */
      /*--------------------------------------------------------------*/
      /* Codepage: MBCS 					      */
      /*--------------------------------------------------------------*/
#ifdef FIREWALLS
      if (!(NLSParseFlag & NLSCA_MAP_DBCS))
	{			       /* no DBCS leading map? NOOOOO!*/
	  return ERROR_NEG;	       /* then we can do nothing      */
	}			       /* end of if:		      */
#endif /*FIREWALLS*/

      pch = pchCodepoint;
      plS = plD = plVector;
      pchLast = pch + ulLength;        /* next of last codepoint      */
      while (pch != pchLast)	       /*			      */
	{			       /*			      */
	  if (pFontDtl->pDBCSMap[*pch])
	    {			       /* if DBCS leading byte	      */
	      /*------------------------------------------------------*/
	      /* DBCS leading byte in the last			      */
	      /*------------------------------------------------------*/
	      if (pch+1 == pchLast)    /* if it is the last byte      */
		{		       /*			      */
		  pch++;	       /* need to advance them since  */
				       /*   will be used later	      */
		  *plD++ = *plS++;     /* store vector for this byte  */

		  break;	       /* end of scan anyway	      */
		}		       /* end of if:		      */

	      /*------------------------------------------------------*/
	      /* DBCS leading byte, not last			      */
	      /*------------------------------------------------------*/
	      *(plD++) = *plS;
	      plS += 2; 	       /* skip vector for trailing    */
	    }			       /* end of if:		      */
	  else			       /* not DBCS leading->SBCS      */
	    {			       /*			      */
	      /*------------------------------------------------------*/
	      /* SBCS codepoint 				      */
	      /*------------------------------------------------------*/
	      pch++;
	      *(plD++) = *(plS++);
	    }			       /* end of else:		      */
	}			       /* end of while: 	      */

      *plVectorCount = plD - plVector; /* this is returned vector #   */
      return pch - pchCodepoint;       /* and this is processed byte  */
    }				       /* end of else:		      */
}				       /* end of func: eddj_UnifiedDBC*/

/*===================== Exported Routine =============================*/
/*	eddj_GlyphIndex 					      */
/*								      */
/* Convert given SBCS/DBCS/MBCS string into glyph index array.	      */
/*								      */
/* Entry      : 						      */
/*	      - ptr to current font's FONTDETAILS structure           */
/*	      - ptr to source string				      */
/*	      - ptr to the buffer where glyph indexes are returned    */
/*	      - length of source string in bytes		      */
/*	      - ptr to buffer where result string length is returned  */
/*		(in chars, i.e. #bytes/2)			      */
/*	      - ptr to vector array (may be NULL)		      */
/*								      */
/* Returns    : 						      */
/*	      - number of processed codepoints is returned in bytes   */
/*		(may be 1 less than given length if NLSCA_CONCAT flat */
/*		 is set in NLSParseFlag, and the last byte is DBCS    */
/*		 leading byte. See Note.)			      */
/*	      - result array is returned in given buffer	      */
/*	      - converted vector is returned where vector is supplied */
/*								      */
/* Error Returns :						      */
/*	      - returns ERROR_NEG (-1) if error is found	      */
/*								      */
/* Note       : 						      */
/*	      - caller must prepare at least ulLength*2 bytes of      */
/*		buffer. 					      */
/*	      - If the last byte of given string is DBCS leading byte,*/
/*		  if NLSCA_CONCAT is ON : leave it unprocessed	      */
/*		  if NLSCA_CONCAT is OFF: change it to SBCS default   */
/*					  codepoint		      */
/*	      - In the cases below, codepoint is changed to SBCS      */
/*		default char.					      */
/*			- When SBCS font is used for DBCS CP	      */
/*				(All chars -> SBCS default)	      */
/*			- When SBCS font is used for MBCS CP	      */
/*				(DBCS chars -> SBCS default)	      */
/*			- Last byte is DBCS leading (See above)       */
/*				(The last byte -> SBCS default)       */
/* Calls      : 						      */
/*								      */
/*====================================================================*/
LONG eddj_GlyphIndex( PFONTDETAILS pFontDtl,
		      PCHAR pchCodepoint,
		      PUSHORT pusGlyphIndexes,
		      ULONG ulLength,
		      PLONG plResultCount,
		      PLONG plVector )
{				       /* top of func: eddj_GlyphIndex*/
#define TFUNC "eddj_GlyphIndex"

  /*------------------------------------------------------------------*/
  /* work variables						      */
  /*------------------------------------------------------------------*/
  USHORT usGlyph;
  ULONG index;
  PCHAR pch, pchLast;
  PUSHORT pus;
  PLONG plS, plD;

  /*------------------------------------------------------------------*/
  /* performance variables					      */
  /*------------------------------------------------------------------*/
  const USHORT usSBCSFirst
    = pFontDtl->pFocaFont->fmMetrics.usFirstChar;
  const USHORT usSBCSLast
    = pFontDtl->pFocaFont->fmMetrics.usLastChar + usSBCSFirst;
  const USHORT usSBCSDefault
    = pFontDtl->pFocaFont->fmMetrics.usDefaultChar + usSBCSFirst;
				       /* these are glyph indexes for */
				       /* first/last of valid range,  */
				       /* and default char	      */
  const USHORT NLSParseFlag = pFontDtl->NLSParseFlag;
  const USHORT NLSFontFlag = pFontDtl->NLSFontFlag;

  /*------------------------------------------------------------------*/
  /* SBCS codepage case:					      */
  /*------------------------------------------------------------------*/
  if (NLSParseFlag & NLSCA_SBCS)       /* if SBCS codepage,	      */
    {				       /*			      */
      /*--------------------------------------------------------------*/
      /* convert string to glyph indexes			      */
      /*--------------------------------------------------------------*/
      if (NLSParseFlag & NLSCA_MAP_SBCS)
	{			       /* if SBCS mapping vector exist*/
	  for (index = 0; index < ulLength; index ++)
	    {			       /*			      */
	      usGlyph = pFontDtl->pCodePageVector[pchCodepoint[index]];

	      pusGlyphIndexes[index]
		= CHKRANGE( usGlyph, usSBCSFirst,
			    usSBCSLast, usSBCSDefault );
				       /* if out of range, use default*/
	    }			       /* end of for:		      */
	}			       /* end of if:		      */
      else			       /* or if no mapping vector     */
	{			       /*			      */
	  for (index = 0; index < ulLength; index ++)
	    {			       /*			      */
	      usGlyph = (USHORT)pchCodepoint[index];

	      pusGlyphIndexes[index]
		= CHKRANGE( usGlyph, usSBCSFirst,
			    usSBCSLast, usSBCSDefault );
				       /* if out of range, use default*/
	    }			       /* end of for:		      */
	}			       /* end of else:		      */

      /*--------------------------------------------------------------*/
      /* we have nothing to do with vector, even if supplied	      */
      /*--------------------------------------------------------------*/
      *plResultCount = ulLength;       /*			      */
      return ulLength;		       /* always process all chars    */
    }				       /* end of if:		      */
  /*------------------------------------------------------------------*/
  /* DBCS codepage case:					      */
  /*------------------------------------------------------------------*/
  else if (NLSParseFlag & NLSCA_DBCS)  /*			      */
    {
      if (NLSFontFlag & NLSCA_SBCS)
	{
	  /*----------------------------------------------------------*/
	  /* Codepage: DBCS, Font: SBCS 			      */
	  /*	--> Fill with SBCS default chars		      */
	  /*----------------------------------------------------------*/
	  for (index = 0; index < ulLength/2; index++)
	    {
	      pusGlyphIndexes[index] = usSBCSDefault;
	    }			       /* end of for:		      */
	}			       /* end of if:		      */
      else			       /*			      */
	{			       /*			      */
	  /*----------------------------------------------------------*/
	  /* Codepage: DBCS, Font: DBCS or MBCS 		      */
	  /*	--> we request Font Manager to convert to Glyph Index */
	  /*	    since this may be EBCDIC codepage.		      */
	  /*	    (EBCDIC MBCS codepage uses SI/SO special chars to */
	  /*	     switch Single Byte Chars and Double Byte Chars,  */
	  /*	     contrary to JIS/ASCII MBCS which uses range of   */
	  /*	     Double Byte Chars' leading byte.  Since SI/SO    */
	  /*	     method is not supported in current OS/2, only    */
	  /*	     DBCS codepage can appear for EBCDIC.)	      */
	  /*----------------------------------------------------------*/
	  memcpy( pusGlyphIndexes, pchCodepoint, ulLength );
				       /* copy input string to dest   */
				       /* since next call replaces    */
				       /* input string with result    */

	  if (!eddj_MapCharGlyph( pFontDtl->usECodePage, ulLength,
				  pFontDtl->pFocaFont, pusGlyphIndexes ))
	    {			       /*			      */
	      return ERROR_NEG;        /* MUST NOT fail!	      */
	    }			       /* end of if:		      */
	}			       /* end of else:		      */

      /*--------------------------------------------------------------*/
      /* convert vector for DBCS CP				      */
      /*--------------------------------------------------------------*/
      if (plVector)		       /* if vector array is given    */
	{			       /*			      */
	  for (index = 1; index < ulLength/2; index++)
	    {			       /*			      */
	      plVector[index] = plVector[index*2];
				       /* discard vector for trailing */
				       /*   byte		      */
				       /* (need not copy 0th item)    */
	    }			       /* end of for:		      */
	}			       /* end of if:		      */

      /*--------------------------------------------------------------*/
      /* last byte handling for DBCS CP 			      */
      /*--------------------------------------------------------------*/
      if (!(ulLength % 2)
       || (NLSParseFlag & NLSCA_CONCAT))
	{			       /* if length is even or	      */
				       /* concat is req'd then        */
				       /* leave the last byte alone   */
	  *plResultCount = ulLength/2;
	  return EVEN(ulLength);       /* this number is processed    */
	}			       /* end of if:		      */
      else			       /* or if odd length & concat   */
	{			       /* is not req'd, translate     */
				       /* it to SBCS default char     */
	  *plResultCount = ulLength/2 + 1;
	  pusGlyphIndexes[ulLength/2] = usSBCSDefault;

	  if (plVector)
	    {
	      plVector[ulLength/2] = plVector[ulLength];
	    }			       /* end of if:		      */

	  return ulLength;	       /* all char is processed       */
	}			       /* end of else:		      */
    }				       /* end of if:		      */
  /*------------------------------------------------------------------*/
  /* MBCS codepage case:					      */
  /*------------------------------------------------------------------*/
  else				       /*			      */
    {				       /* MBCS case:		      */
      if (!(NLSParseFlag & NLSCA_MAP_DBCS))
	{			       /* no DBCS leading map? NOOOOO!*/
	  return ERROR_NEG;	       /* then we can do nothing      */
	}			       /* end of if:		      */

      pch = pchCodepoint;
      pus = pusGlyphIndexes;
      plS = plD = plVector;
      pchLast = pch + ulLength;        /* next of last codepoint      */
      while (pch != pchLast)	       /*			      */
	{			       /*			      */
	  if (pFontDtl->pDBCSMap[*pch])
	    {			       /* if DBCS leading byte	      */
	      /*------------------------------------------------------*/
	      /* DBCS leading byte in the last			      */
	      /*------------------------------------------------------*/
	      if (pch+1 == pchLast)    /* if it is the last byte      */
		{		       /*			      */
		  if (!(NLSParseFlag & NLSCA_CONCAT))
		    {		       /* do not leave it	      */
		      *(pus++) = usSBCSDefault;
		      pch++;	       /* need to advance them since  */
				       /*   will be used later	      */
		      if (plVector)    /*			      */
			{	       /*			      */
			  *plD = *plS; /* store vector for this byte  */
			}	       /* end of if:		      */
		    }		       /* end of if:		      */

		  break;	       /* end of scan anyway	      */
		}		       /* end of if:		      */

	      /*------------------------------------------------------*/
	      /* DBCS leading byte, not last			      */
	      /*------------------------------------------------------*/
	      if (NLSFontFlag & NLSCA_FONT_SBCS)
		{		       /*   but the font is SBCS...   */
		  *(pus++) = usSBCSDefault;
		  pch += 2;	       /* skip trailing byte	      */
		}		       /* end of if:		      */
	      else		       /*   O.K. font can do DBCS...  */
		{		       /*			      */
		  *(pus++)
		    = MAKEUSHORT( *(pch+1), *pch );
		  pch += 2;	       /* codepoint becomes glyph indx*/
		}		       /* end of else:		      */

	      if (plVector)	       /*			      */
		{		       /*			      */
		  *(plD++) = *plS;
		  plS += 2;	       /* skip vector for trailing    */
		}		       /* end of if:		      */
	    }			       /* end of if:		      */
	  else			       /* not DBCS leading->SBCS      */
	    {			       /*			      */
	      /*------------------------------------------------------*/
	      /* SBCS codepoint 				      */
	      /*------------------------------------------------------*/
	      if (NLSParseFlag & NLSCA_MAP_SBCS)
		{		       /*			      */
		  usGlyph = pFontDtl->pCodePageVector[*(pch++)];
		}		       /* end of if:		      */
	      else		       /*			      */
		{		       /*			      */
		  usGlyph = (USHORT)*(pch++);
		}		       /* end of else:		      */

	      *(pus++) = CHKRANGE( usGlyph, usSBCSFirst,
				   usSBCSLast, usSBCSDefault );
				       /* if out of range, use default*/
	      if (plVector)
		{
		  *(plD++) = *(plS++); /*			      */
		}		       /* end of if:		      */
	    }			       /* end of else:		      */
	}			       /* end of while: 	      */

      *plResultCount = pus - pusGlyphIndexes;
				       /* count of array to be ret'nd */
      return pch - pchCodepoint;       /* and this is processed byte  */
    }				       /* end of else:		      */
}				       /* end of func: eddj_GlyphIndex*/
#endif /*OMIT*/
/*===================== Exported Routine =============================*/
/*	eddj_GetCharWidth					      */
/*								      */
/* Accept a string and returns width of each character. 	      */
/*								      */
/* Entry      : 						      */
/*	      - Ptr to string					      */
/*		(May be U-DBCS, according to NLSCA_UNIFIED_DBCS)      */
/*	      - Number of characters in string			      */
/*	      - Ptr to current font's FONTDETAILS structure           */
/*	      - Ptr to buffer where width of each char is returned    */
/*								      */
/* Returns    : 						      */
/*	      - Width of each char is returned in given buffer	      */
/*		(For ABC font, total of A/B/C space is returned as    */
/*		 width) 					      */
/*	      - Returns sum of all chars' width                       */
/*								      */
/* Error Returns :	None					      */
/*								      */
/* Note       : 						      */
/*	      - When calculating total width, only width of each char */
/*		is counted.  charSpacing or BreakExtra are not	      */
/*		considered at all.				      */
/*								      */
/*	      - Since supplied width buffer is passed to 16-bit       */
/*		routine, it should not cross 64KB boundary.  In other */
/*		words, caller should make it static or allocate it    */
/*		with malloc or something.  Never make it auto var!    */
/*								      */
/*	      - Caller should guarantee that given string is not      */
/*		longer than limit.  (FM cache size & buffer size)     */
/*								      */
/* Calls      : 						      */
/*								      */
/*====================================================================*/
ULONG eddj_GetCharWidth( PCHAR pchCodePoints,
			 ULONG ulCharNum,
			 PFONTDETAILS pFontDtl,
			 PUSHORT pusWidth )
{				       /* top of func: eddj_GetCharWid*/
  StringToGlyph( pFontDtl, pchCodePoints, pusWidth, ulCharNum );
				       /* convert string to glyph-indx*/
  if ((pFontDtl->NLSParseFlag & NLSCA_CALL_DBCSFM) &&
      ((pFontDtl->NLSFontFlag & NLSCA_FONT_CACHED) ||
       (pFontDtl->usDbcWidth == 0)))
    {				       /* if chardef not accessible   */
      eddj_ValidateFontSeg( -((LONG)ulCharNum),
			    pFontDtl->pFocaFont,
			    pusWidth );
				       /* negative count -> no image  */
    }				       /* end of if:		      */

  return GlyphToWidth( pusWidth, ulCharNum, pFontDtl->pFocaFont );
				       /* convert to width of each chr*/
}				       /* end of func: eddj_GetCharWid*/

/*===================== Private  Routine =============================*/
/*	GlyphToWidth						      */
/*								      */
/* Convert glyph index array to width of each character 	      */
/*								      */
/* Entry      : 						      */
/*	      - glyph index array				      */
/*	      - number of glyphs				      */
/*	      - ptr to current font's FOCAFONT structure              */
/*								      */
/* Returns    : 						      */
/*	      - width of each char is put where glyph indexes are     */
/*		(if ABC font, total of A/B/C spaces are returned)     */
/*	      - Returns sum of all chars.			      */
/*								      */
/* Error Returns :	None					      */
/*								      */
/* Note       : 						      */
/*	      - For Font Manager font, caller should call CharStr     */
/*		before calling this, and should pass glyph index      */
/*		value returned by Font Manager. 		      */
/*	      - This function does no range check for supplied glyph  */
/*		index.						      */
/*								      */
/* Calls      : 						      */
/*								      */
/*====================================================================*/
ULONG GlyphToWidth( PUSHORT pusGlyphIndex,
		    ULONG ulGlyphCount,
		    PFOCAFONT pFont )
{				       /* top of func: GlyphToWidth   */
  PCHARDEFINITION pCharDef, pCharDefTop;
  ULONG ulWidth, ulTotal;
  const USHORT usFirstChar = pFont->fmMetrics.usFirstChar;

  pCharDefTop.pABC = (ABC_CHAR_DEFN *)(pFont + 1);
				       /* points first chardef struct */
  ulTotal = 0;			       /*			      */

  if (pFont->fdDefinitions.fsChardef == FONTDEFCHAR3)
    {				       /* if ABC space font	      */
      for ( ; ulGlyphCount > 0; ulGlyphCount --)
	{			       /*			      */
	  pCharDef.pABC = pCharDefTop.pABC
			     + (*pusGlyphIndex - usFirstChar);
				       /* ptr to the char's defn      */
	  ulWidth = (ULONG)pCharDef.pABC->usASpace +
		      pCharDef.pABC->usBSpace +
		      pCharDef.pABC->usCSpace;

	  *(pusGlyphIndex ++) = ulWidth;
	  ulTotal += ulWidth;
	}			       /* end of for:		      */
    }				       /* end of if:		      */
  else				       /*			      */
    {				       /*			      */
      for ( ; ulGlyphCount > 0; ulGlyphCount --)
	{			       /*			      */
	  pCharDef.pNonABC = pCharDefTop.pNonABC
				+ (*pusGlyphIndex - usFirstChar);
				       /* ptr to the char's defn      */
	  ulWidth = pCharDef.pNonABC->usCharWidth;
	  *(pusGlyphIndex ++) = ulWidth;
	  ulTotal += ulWidth;
	}			       /* end of for:		      */
    }				       /* end of else:		      */

  return ulTotal;
}				       /* end of func: GlyphToWidth   */

/*===================== Private  Routine =============================*/
/*	StringToGlyph						      */
/*								      */
/* Convert supplied string into glyph index array.  Similar to	      */
/* eddj_GlyphIndex, but different since this function can handle      */
/* Unified DBCS string when NLSCA_UNIFIED_DBCS bit is ON.	      */
/*								      */
/* Entry      : 						      */
/*	      - ptr to current font's FONTDETAILS structure           */
/*	      - ptr to source string				      */
/*	      - ptr to the buffer where glyph indexes are returned    */
/*	      - length of source string in chars (not bytes)	      */
/*								      */
/* Returns    : 	None					      */
/*								      */
/* Error Returns :	None					      */
/*								      */
/* Note       : 						      */
/*	      - caller must prepare at least ulLength*2 bytes of      */
/*		buffer, when current CP is SBCS.  (I.e. when passing  */
/*		byte-based string.)  This buffer also must not cross  */
/*		64KB boundary in linear address, since it may be      */
/*		passed to 16-bit routine.			      */
/*								      */
/* Calls      : 						      */
/*								      */
/*====================================================================*/
VOID StringToGlyph( PFONTDETAILS pFontDtl,
		    PCHAR pchCodepoint,
		    PUSHORT pusGlyphIndexes,
		    ULONG ulLength )
{				       /* top of func: StringToGlyph  */
#define NLSPARSEFLAG	(pFontDtl->NLSParseFlag)
#define NLSFONTFLAG	(pFontDtl->NLSFontFlag)
#define pusCodepoint	((PUSHORT)pchCodepoint)

  USHORT usFirstGlyph, usLastGlyph, usDefaultGlyph;

  usFirstGlyph = pFontDtl->pFocaFont->fmMetrics.usFirstChar;
  usLastGlyph = pFontDtl->pFocaFont->fmMetrics.usLastChar +
		  usFirstGlyph;
  usDefaultGlyph = pFontDtl->pFocaFont->fmMetrics.usDefaultChar +
		  usFirstGlyph;
				       /*			      */
  /*------------------------------------------------------------------*/
  /* byte-based (SBCS) string					      */
  /*------------------------------------------------------------------*/
  if (!(NLSPARSEFLAG & NLSCA_UNIFIED_DBCS))
    {				       /* if byte-based string given  */
      if (NLSFONTFLAG & NLSCA_FONT_DBCS)
	{			       /* if font has only DBCS...    */
				       /* Not required, as DBCS FM    */
				       /*   should do this.  But it   */
				       /*   will be faster...	      */
	  for ( ; ulLength; ulLength --)
	    {			       /*			      */
	      *(pusGlyphIndexes ++) = usDefaultGlyph;
				       /* this is DBCS default char   */
	    }			       /* end of for:		      */
	}			       /* end of if:		      */
      else			       /* or if font has SBCS part    */
	{
	  for ( ; ulLength; ulLength --)
	    {
	      *pusGlyphIndexes =
		    NLSPARSEFLAG & NLSCA_MAP_SBCS ?
		    pFontDtl->pCodePageVector[*(pchCodepoint ++)] :
		    (USHORT)*(pchCodepoint ++);

	      if ((*pusGlyphIndexes < usFirstGlyph) ||
		  (usLastGlyph < *pusGlyphIndexes))
		{		       /* if the glyph is out of range*/
		  *pusGlyphIndexes = usDefaultGlyph;
		}		       /* end of if:		      */

	      pusGlyphIndexes ++;      /*			      */
	    }			       /* end of for:		      */
	}			       /* end of else:		      */
    }				       /* end of if:		      */
  /*------------------------------------------------------------------*/
  /* word-based (MBCS or SBCS) string				      */
  /*		GPI routine does not construct U-DBCS string when CP  */
  /*		is SBCS, but others (i.e. AVIO) may do it...	      */
  /*------------------------------------------------------------------*/
  else if (!(NLSPARSEFLAG & NLSCA_DBCS))
    {				       /*			      */
      for ( ; ulLength; ulLength --)   /*			      */
	{			       /*			      */
	  if (HIBYTE(*pusCodepoint))   /* if >255, it is double byte  */
	    {			       /*			      */
	      *(pusGlyphIndexes ++) =
		NLSFONTFLAG & NLSCA_FONT_SBCS ?
		usDefaultGlyph :       /* if font has no DBCS char,   */
		*pusCodepoint;	       /*   convert to SBCS default   */
				       /* FORCED_SINGLEBYTE also      */
				       /*   should be handled here.   */
	      pusCodepoint ++;	       /*			      */
	    }			       /* end of if:		      */
	  else			       /* or if single byte char      */
	    {			       /*			      */
	      *pusGlyphIndexes =
		    NLSPARSEFLAG & NLSCA_MAP_SBCS ?
		    pFontDtl->pCodePageVector[*(pusCodepoint ++)] :
		    (USHORT)*(pusCodepoint ++);
				       /* we do not check font type   */
				       /*  here.  if it is DBCS font, */
				       /*  codepoint is used as glyph */
				       /*  index, then DBCS font mgr  */
				       /*  will convert it to DBCS    */
				       /*  default char later.	      */
				       /*  (Or maybe done by next     */
				       /*   range check?  don't know  */
				       /*   as we have no DBCS font   */
				       /*   available at present.)    */
	      if ((*pusGlyphIndexes < usFirstGlyph) ||
		  (usLastGlyph < *pusGlyphIndexes))
		{		       /* if the glyph is out of range*/
		  *pusGlyphIndexes = usDefaultGlyph;
		}		       /* end of if:		      */

	      pusGlyphIndexes ++;	 /*				*/
	    }			       /* end of else:		      */
	}			       /* end of for:		      */
    }				       /* end of if:		      */
  /*------------------------------------------------------------------*/
  /* word-based (DBCS) string					      */
  /*------------------------------------------------------------------*/
  else
    {				       /*			      */
      if (NLSFONTFLAG & NLSCA_FONT_SBCS)
	{			       /* if font is SBCS-only	      */
	  for ( ; ulLength; ulLength --)
	    {			       /*			      */
	      *(pusGlyphIndexes ++) = usDefaultGlyph;
	    }			       /* end of for:		      */
	}			       /* end of if:		      */
      else			       /*			      */
	{
	  ULONG index;		       /* U-DBCS to original format.  */
	  PCHAR pchSrc = pchCodepoint;
	  PUSHORT pusDest = pusGlyphIndexes;

	  for ( index = ulLength; index; index --)
	    {			       /* swap bytes		      */
	      *(pusDest ++) = MAKEUSHORT( *(pchSrc+1), *pchSrc );
	      pchSrc += 2;	       /*			      */
	    }			       /* end of for:		      */

	  eddj_MapCharGlyph( pFontDtl->usECodePage, ulLength * 2,
			     pFontDtl->pFocaFont, pusGlyphIndexes );
				       /* buffer contents is replaced */
				       /*   with glyph indexes	      */
				       /* Note: We need to request    */
				       /*   font manager since this   */
				       /*   CP may be EBCDIC...       */
				       /* Do not check result as it   */
				       /*   should not fail, and we   */
				       /*   can do nothing if fail!   */
	}			       /* end of else:		      */
				       /* now we need to rearrange    */
    }				       /* end of else:		      */
}				       /* end of func: StringToGlyph  */
#undef pusCodepoint
#undef NLSPARSEFLAG
#undef NLSFONTFLAG

/*===================== Exported Routine =============================*/
/*	eddj_CountChar						      */
/*								      */
/* Returns number of chars included in MBCS (or DBCS) string	      */
/*								      */
/* Entry      : 						      */
/*	      - Ptr to string (Not Unified DBCS)		      */
/*	      - Number of bytes in the string			      */
/*	      - Ptr to FONTDETAILS structure			      */
/*		(Parsing flag and DBCS vector map are used.)	      */
/*								      */
/* Returns    : 						      */
/*	      - Returns number of chars (either single byte or	      */
/*		double bytes)					      */
/*								      */
/* Error Returns :	None					      */
/*								      */
/* Note       : 						      */
/*	      - DBCS/SBCS can be handled correctly, but should not be */
/*		called in such cases.  (Caller can handle by himself!)*/
/*								      */
/*====================================================================*/
LONG eddj_CountChar( PCHAR  pchInput,
		     LONG lNumBytes,
		     PFONTDETAILS pFontDtl )
{				       /* top of func: eddj_CountChar */
  LONG lCount;			       /*			      */

  /*------------------------------------------------------------------*/
  /* SBCS/DBCS case, it is simple...				      */
  /*------------------------------------------------------------------*/
  if (pFontDtl->NLSParseFlag & NLSCA_DBCS)
    {				       /* if CP is DBCS 	      */
      return (lNumBytes+1) / 2;        /* when odd bytes, assume last */
				       /*   byte is another char      */
    }				       /* end of if:		      */

  if (pFontDtl->NLSParseFlag & NLSCA_SBCS)
    {				       /*			      */
      return lNumBytes; 	       /*			      */
    }				       /* end of if:		      */

  /*------------------------------------------------------------------*/
  /* MBCS case							      */
  /*------------------------------------------------------------------*/
  lCount = 0;			       /*			      */

  while (lNumBytes > 1) 	       /* will handle last byte       */
    {				       /*   separately		      */
      lCount ++;		       /* count this char	      */
      if (pFontDtl->pDBCSMap[*pchInput])
	{			       /* if it is DBCS leading byte  */
	  pchInput += 2;	       /* skip trailing byte	      */
	  lNumBytes -= 2;	       /*			      */
	}			       /* end of if:		      */
      else			       /* or if SBCS char	      */
	{			       /*			      */
	  pchInput ++;		       /*			      */
	  lNumBytes --; 	       /*			      */
	}			       /* end of else:		      */
    }				       /* end of while: 	      */

  lCount += lNumBytes;		       /* assume last byte is a char  */
  return lCount;		       /*			      */
}				       /* end of func: eddj_CountChar */

#ifdef OMIT
/*===================== Exported Routine =============================*/
/*	eddj_IsSbcsOnly 		<== Moved to EDDJASUB.ASM!    */
/*								      */
/* Set/Reset NLSCA_SBC_ONLY bit in NLSParseFlag by inspecting given   */
/*	string							      */
/*								      */
/* Entry      : 						      */
/*	      - Ptr to string					      */
/*	      - Number of bytes in the string			      */
/*	      - Ptr to FONTDETAILS structure			      */
/*		(Parsing flag and DBCS vector map are used.)	      */
/*								      */
/* Returns    : 						      */
/*	      - None.  NLSCA_SBC_ONLY bit in NLSParseFlag in given    */
/*		FONTDETAILS struct is changed.			      */
/*								      */
/* Error Returns :	None					      */
/*								      */
/* Note       : 						      */
/*	      - When searching DBCS leading byte, we will not check   */
/*		the last byte in string, since: 		      */
/*			if it is not DBCS leading, should be SBCS     */
/*			if it is DBCS leading and NLSCA_CONCAT is on, */
/*			  it should be left unprocessed 	      */
/*			if it is DBCS leading and NLSCA_CONCAT is off,*/
/*			  it should be considered as SBCS default.    */
/*								      */
/*	      - We do not check font type here.  Will check it later  */
/*		when deciding NLSCA_CALL_DBCSFM value.	(Should not   */
/*		use font type to decide NLSCA_UNIFIED_DBCS value)     */
/*								      */
/*====================================================================*/
VOID eddj_IsSbcsOnly( PCHAR pchString,
		      LONG lCount,
		      PFONTDETAILS pFontDtl )
{				       /* top of func: eddj_IsSbcsOnly*/
  if (pFontDtl->NLSParseFlag & NLSCA_SBCS)
    {
      pFontDtl->NLSParseFlag |= NLSCA_SBC_ONLY;
    }				       /* end of if:		      */
  else if (pFontDtl->NLSParseFlag & NLSCA_DBCS)
    {
      pFontDtl->NLSParseFlag &= ~NLSCA_SBC_ONLY;
    }				       /* end of if:		      */
  else				       /* if CP and font are both MBCS*/
    {				       /*   need to check string      */
      pFontDtl->NLSParseFlag |= NLSCA_SBC_ONLY;
      for ( ; lCount > 1; lCount --)   /* will not check last byte    */
	{			       /*			      */
	  if (pFontDtl->pDBCSMap[*(pchString ++)])
	    {			       /* if it is DBCS leading       */
	      pFontDtl->NLSParseFlag &= ~NLSCA_SBC_ONLY;
	      break;		       /* at least 1 DBCS found       */
	    }			       /* end of if:		      */
	}			       /* end of for:		      */
    }				       /* end of else:		      */
}				       /* end of func: eddj_IsSbcsOnly*/
#endif /*OMIT*/

/*===================== Exported Routine =============================*/
/*	eddj_IsCallDbcsFM					      */
/*								      */
/* Check if DBCS font manager need to be called before accessing      */
/*	font data						      */
/*								      */
/* Entry      : 						      */
/*	      - Ptr to FONTDETAILS structure			      */
/*								      */
/* Returns    : 						      */
/*	      - NLSCA_CALL_DBCSFM bit in NLSParseFlag is set/reset    */
/*								      */
/* Error Returns :	None					      */
/*								      */
/* Note       : 						      */
/*	      - Before calling this routine, NLSCA_SBC_ONLY bit must  */
/*		be set/reset (e.g. by calling eddj_IsSbcsOnly)	      */
/*								      */
/*	      - NLSCA_CALL_DBCSFM is set when:			      */
/*		(1) Given font is DBCS or MBCS font		      */
/*		and,						      */
/*		(2) Given font is not an engine font		      */
/*			(to exclude DBCS-IFI font case) 	      */
/*		and,						      */
/*		(3-a) SBCS chars are non-resident, or		      */
/*		(3-b) given string contains at least 1 double byte    */
/*			char					      */
/*								      */
/*====================================================================*/
VOID eddj_IsCallDbcsFM( PFONTDETAILS pFontDtl )
{				       /* top of func: eddj_IsCallDbcs*/
  if ((pFontDtl->NLSFontFlag & (NLSCA_FONT_DBCS | NLSCA_FONT_MBCS)) &&
      !(pFontDtl->pFocaFont->fmMetrics.fsDefn & FM_DEFN_GENERIC) &&
      ((pFontDtl->NLSFontFlag & NLSCA_FONT_CACHED) ||
	!(pFontDtl->NLSParseFlag & NLSCA_SBC_ONLY)))
    {				       /*			      */
      pFontDtl->NLSParseFlag |= NLSCA_CALL_DBCSFM;
    }				       /* end of if:		      */
  else				       /*			      */
    {				       /*			      */
      pFontDtl->NLSParseFlag &= ~NLSCA_CALL_DBCSFM;
    }				       /* end of else:		      */
}				       /* end of func: eddj_IsCallDbcs*/

/*===================== Exported Routine =============================*/
/*	eddj_CheckProcOptions					      */
/*								      */
/* Set/reset following bits in NLSParseFlag by inspecting given string*/
/*	and values in FONTDETAILS				      */
/*		NLSCA_SBC_ONLY					      */
/*		NLSCA_UNIFIED_DBCS				      */
/*		NLSCA_CALL_DBCSFM				      */
/*		NLSCA_MUST_CHOP 				      */
/*			(For the meaning of them, see EDDJSUB.H)      */
/*								      */
/* Entry      : 						      */
/*	      - Ptr to string					      */
/*	      - Number of bytes in the string			      */
/*	      - Ptr to FONTDETAILS structure			      */
/*								      */
/* Returns    : 	None					      */
/*								      */
/* Error Returns :	None					      */
/*								      */
/* Note       : 						      */
/*	      - When searching DBCS leading byte, we will not check   */
/*		the last byte in string, since: 		      */
/*			if it is not DBCS leading, should be SBCS     */
/*			if it is DBCS leading and NLSCA_CONCAT is on, */
/*			  it should be left unprocessed 	      */
/*			if it is DBCS leading and NLSCA_CONCAT is off,*/
/*			  it should be considered as SBCS default.    */
/*								      */
/*	      - NLSCA_UNIFIED_DBCS is set when: 		      */
/*		(1) given string contains at least 1 double byte char */
/*								      */
/*		NOTE: we will use unified-DBCS format when corrent CP */
/*		is DBCS too, to make charnum/vector handling easy.    */
/*		(I.e. if this bit is ON, charnum is always # of chars,*/
/*		and vectors for leading byte are removed.  If OFF,    */
/*		the string can be handled as pure SBCS string.)       */
/*								      */
/*	      - For the condition for NLSCA_CALL_DBCSFM, see comments */
/*		for eddj_IsCallDbcsFM.				      */
/*								      */
/*	      - NLSCA_MUST_CHOP is set when:			      */
/*		(1) NLSCA_CALL_DBCSFM is ON and given string is       */
/*		    longer than FM cache size for the font	      */
/*		or,						      */
/*		(2) given string is longer than common work buffer    */
/*		    size					      */
/*								      */
/*		NOTE: we will chop even if CALL_DBCSFM and UNIFIED_   */
/*		DBCS are both OFF, since this enables usage of common */
/*		work buffer and hence handling of string much easier. */
/*		(I believe it should cause little impact on driver's  */
/*		performance.  Being passed such a long string must be */
/*		rare case!)					      */
/*								      */
/*		When current CP is MBCS, we will not count the number */
/*		of characters here, but just assume the worst case.   */
/*								      */
/*====================================================================*/
VOID eddj_CheckProcOptions( PCHAR pchString,
			    LONG lCount,
			    PFONTDETAILS pFontDtl )
{				       /* top of func: eddj_CheckProcO*/
  LONG lCharCount;		       /* # of chars (wild guess)     */

  if (lCount == 0)		       /* quick check for PMCHART etc.*/
    {				       /*			      */
      pFontDtl->NLSParseFlag |= NLSCA_SBC_ONLY;
      pFontDtl->NLSParseFlag &=
	~(NLSCA_UNIFIED_DBCS | NLSCA_CALL_DBCSFM | NLSCA_MUST_CHOP);
      return;			       /* we can assume simplest case */
    }				       /* end of if:		      */

  /*------------------------------------------------------------------*/
  /* set/reset NLSCA_SBC_ONLY					      */
  /*------------------------------------------------------------------*/
  eddj_IsSbcsOnly( pchString, lCount, pFontDtl );

  /*------------------------------------------------------------------*/
  /* set/reset NLSCA_UNIFIED_DBCS				      */
  /*------------------------------------------------------------------*/
  if (!(pFontDtl->NLSParseFlag & NLSCA_SBC_ONLY))
    {				       /*			      */
      pFontDtl->NLSParseFlag |= NLSCA_UNIFIED_DBCS;
    }				       /* end of if:		      */
  else				       /*			      */
    {				       /*			      */
      pFontDtl->NLSParseFlag &= ~NLSCA_UNIFIED_DBCS;
    }				       /* end of else:		      */

  /*------------------------------------------------------------------*/
  /* set/reset NLSCA_CALL_DBCSFM				      */
  /*------------------------------------------------------------------*/
  eddj_IsCallDbcsFM( pFontDtl );       /*			      */

  /*------------------------------------------------------------------*/
  /* set/reset NLSCA_MUST_CHOP					      */
  /*------------------------------------------------------------------*/
  if ((pFontDtl->NLSParseFlag & NLSCA_DBCS) ||
      ((pFontDtl->NLSParseFlag & NLSCA_MBCS) &&
       !(pFontDtl->NLSParseFlag & NLSCA_SBC_ONLY)))
    {				       /*			      */
      lCharCount = lCount / 2;	       /* if MBCS and contains at     */
				       /*  least 1 DBC, assume worst  */
    }				       /* end of if:		      */
  else				       /*			      */
    {				       /*			      */
      lCharCount = lCount;	       /* if SBC only case...	      */
    }				       /* end of else:		      */

  if (lCharCount > STRINGLIMIT( pFontDtl ))
    {				       /*			      */
      pFontDtl->NLSParseFlag |= NLSCA_MUST_CHOP;
    }				       /* end of if:		      */
  else				       /*			      */
    {				       /*			      */
      pFontDtl->NLSParseFlag &= ~NLSCA_MUST_CHOP;
    }				       /* end of else:		      */
}				       /* end of func: eddj_CheckProcO*/

/*===================== Exported Routine =============================*/
/*	eddj_GetDefaultCodepoint				      */
/*								      */
/* Retrieves codepoint of default character for given CP/font	      */
/*								      */
/* Entry      : 						      */
/*	      - Ptr to FONTDETAILS structure			      */
/*								      */
/* Returns    : 						      */
/*	      - ulDefCodepoint field is set			      */
/*								      */
/* Error Returns :						      */
/*	      - If every effort fail, returns 0x20.		      */
/*								      */
/* Note       : 						      */
/*	      - Uses pFocaFont and pCodePageVector fields' value.     */
/*		So they must be set before calling this routine.      */
/*								      */
/*	      - This function can be used to retrieve only SBCS       */
/*		default char.					      */
/*								      */
/*	      - The value set here will be used in 2 cases:	      */
/*								      */
/*		1. DBCS codepoint using SBCS font		      */
/*			Default codepoint is set correctly. (I hope!) */
/*								      */
/*		2. SBCS codepoint using DBCS font		      */
/*			0 is set.  Then,			      */
/*			LocateInCache: handles it as SBCS, returns 0. */
/*			CodepointToGlyph, StringToGlyph:	      */
/*				if SBCS map does not exist, remains 0,*/
/*				otherwise changes to other SBCS char. */
/*			CacheCharacter, PutStringInCache:	      */
/*				As the font has no SBCS part, DBCS    */
/*				font manager should convert it to     */
/*				DBCS default char.		      */
/*								      */
/*====================================================================*/
VOID eddj_GetDefaultCodepoint( PFONTDETAILS pFontDtl )
{				       /* top of func: eddj_GetDefault*/
  USHORT usDefGlyph;		       /* default glyph index	      */
  ULONG ulIndex;		       /*			      */
				       /*			      */
  if (pFontDtl->NLSFontFlag & NLSCA_FONT_DBCS)
    {				       /*			      */
      pFontDtl->ulDefCodepoint = 0;    /*			      */
      return;			       /*			      */
    }				       /* end of if:		      */

  usDefGlyph = pFontDtl->pFocaFont->fmMetrics.usDefaultChar +
	       pFontDtl->pFocaFont->fmMetrics.usFirstChar;
				       /* get glyph index first       */
  if (!(pFontDtl->NLSParseFlag & NLSCA_MAP_SBCS) ||
      (pFontDtl->pCodePageVector[usDefGlyph] == usDefGlyph))
    {				       /* if no SBCS map or if it is  */
				       /*   mapped to itself	      */
      pFontDtl->ulDefCodepoint = (ULONG)usDefGlyph;
				       /* is also codepoint	      */
      return;			       /*			      */
    }				       /* end of if:		      */

  for (ulIndex = 0; ulIndex < 256; ulIndex ++)
    {				       /*			      */
      if (pFontDtl->pCodePageVector[ulIndex] == usDefGlyph)
	{			       /* found it!		      */
	  pFontDtl->ulDefCodepoint = ulIndex;
	  return;		       /*			      */
	}			       /* end of if:		      */
    }				       /* end of for:		      */

  pFontDtl->ulDefCodepoint = 0x20L;    /* wild guess!		      */
}				       /* end of func: eddj_GetDefault*/

/*===================== Exported Routine =============================*/
/*	xxx							      */
/*								      */
/* Description here........					      */
/*								      */
/* Entry      : 						      */
/*								      */
/* Returns    : 						      */
/*								      */
/* Error Returns :	None					      */
/*								      */
/* Note       : 						      */
/*								      */
/*====================================================================*/
/*===================== Private  Routine =============================*/
/*	 name							      */
/*								      */
/* some description here.					      */
/*								      */
/* Entry      : 						      */
/*								      */
/* Returns    : 						      */
/*								      */
/* Error Returns :						      */
/*								      */
/* Note       : 						      */
/*								      */
/* Calls      : 						      */
/*								      */
/*====================================================================*/
