PR_Free(buf);
nsMemory::Free(buf);
GetGlyphIndices(HDC              aDC,                nsCharacterMap** aCMAP,                const PRUnichar* aString,                 PRUint32         aLength,                PRUint16*        aBuffer,                 PRUint32         aBufferLength){    NS_ASSERTION(aString && aBuffer, "null arg");  if (!aString || !aBuffer)    return nsnull;  PRUint8* buf = nsnull;  DWORD len = -1;    // --------------  // Dig for the Unicode subtable if this is the first call.  if (!aCMAP || // the caller doesn't cache the CMAP, or      !*aCMAP || (*aCMAP)->mLength < 0  // the CMAP is not yet initialized     )   {    // Initialize as a 0-length CMAP, so that if there is an    // error with this CMAP, it will never be tried again.    if (aCMAP && *aCMAP) (*aCMAP)->mLength = 0;     len = GetFontData(aDC, CMAP, 0, nsnull, 0);    if ((len == GDI_ERROR) || (!len)) {      return nsnull;    }    buf = (PRUint8*) PR_Malloc(len);    if (!buf) {      return nsnull;    }    DWORD newLen = GetFontData(aDC, CMAP, 0, buf, len);    if (newLen != len) {      PR_Free(buf);      return nsnull;    }    PRUint8* p = buf + 2;    PRUint16 n = GET_SHORT(p);    p += 2;    PRUint16 i;    PRUint32 offset;    for (i = 0; i < n; ++i) {      PRUint16 platformID = GET_SHORT(p);      p += 2;      PRUint16 encodingID = GET_SHORT(p);      p += 2;      offset = GET_LONG(p);      p += 4;      if (platformID == 3 && encodingID == 1) // Unicode        break;    }    if (i == n) {      NS_WARNING("nsFontMetricsWin::GetGlyphIndices() called for a non-unicode font!");      PR_Free(buf);      return nsnull;    }    p = buf + offset;    PRUint16 format = GET_SHORT(p);    if (format != 4) {      PR_Free(buf);      return nsnull;    }    PRUint8* end = buf + len;    // XXX byte swapping only required for little endian (ifdef?)    while (p < end) {      PRUint8 tmp = p[0];      p[0] = p[1];      p[1] = tmp;      p += 2;    }#ifdef MOZ_MATHML    // cache these for later re-use    if (aCMAP) {      nsAutoString name;      nsFontInfo* info;      if (GetNAME(aDC, &name) == eGetName_OK) {        info = (nsFontInfo*)PL_HashTableLookup(nsFontMetricsWin::gFontMaps, &name);        if (info) {          info->mCMAP.mData = buf;          info->mCMAP.mLength = len;          *aCMAP = &(info->mCMAP);        }      }    }#endif  }  // --------------  // get glyph indices  if (aCMAP && *aCMAP) { // recover cached CMAP if we have skipped the previous step    buf = (*aCMAP)->mData;    len = (*aCMAP)->mLength;  }  if (buf && len > 0) {    // get the offset       PRUint8* p = buf + 2;    PRUint16 n = GET_SHORT(p);    p += 2;    PRUint16 i;    PRUint32 offset;    for (i = 0; i < n; ++i) {      PRUint16 platformID = GET_SHORT(p);      p += 2;      PRUint16 encodingID = GET_SHORT(p);      p += 2;      offset = GET_LONG(p);      p += 4;      if (platformID == 3 && encodingID == 1) // Unicode        break;    }    PRUint8* end = buf + len;    PRUint16* s = (PRUint16*) (buf + offset);    PRUint16 segCount = s[3] / 2;    PRUint16* endCode = &s[7];    PRUint16* startCode = endCode + segCount + 1;    PRUint16* idDelta = startCode + segCount;    PRUint16* idRangeOffset = idDelta + segCount;    // if output buffer too small, allocate a bigger array -- the caller should free    PRUint16* result = aBuffer;    if (aLength > aBufferLength) {      result = new PRUint16[aLength];      if (!result) return nsnull;    }    for (i = 0; i < aLength; ++i) {      result[i] = GetGlyphIndex(segCount, endCode, startCode,                                idRangeOffset, idDelta, end,                                 aString[i]);    }    if (!aCMAP) { // free work-space if the CMAP is not to be cached      PR_Free(buf);    }    return result;  }  return nsnull;}