зеркало из https://github.com/mozilla/pjs.git
543 строки
10 KiB
C++
543 строки
10 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (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.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is mozilla.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Netscape Communications Corporation.
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
/*
|
|
*
|
|
* All function that are of general use in libfont/ are implemented here.
|
|
*
|
|
* dp Suresh <dp@netscape.com>
|
|
*/
|
|
|
|
|
|
#include "libfont.h"
|
|
#include "nf.h"
|
|
#include "wfMisc.h"
|
|
#include "Mnffmi.h"
|
|
|
|
#ifdef XP_MAC
|
|
#include "probslet.h"
|
|
#else
|
|
#include "obsolete/probslet.h"
|
|
#endif
|
|
|
|
|
|
// The logic we are using to merge these is brute force.
|
|
// For each size in newSizes list, if it is already in the oldSizes,
|
|
// then we wont add it. If not we will add it in.
|
|
// We should make sure the we are using the public memory allocator
|
|
// here because this memory is expected to be freed by the caller.
|
|
#define INTS_AT_A_TIME 128
|
|
void
|
|
MergeSizes(jdouble * &oldSizes, int &oldLenMax, jdouble *newSizes)
|
|
{
|
|
int newlen = 0;
|
|
|
|
if (!newSizes)
|
|
{
|
|
return;
|
|
}
|
|
|
|
while (newSizes[newlen] >= 0)
|
|
{
|
|
int i = 0;
|
|
int found = 0;
|
|
if (oldSizes == NULL)
|
|
{
|
|
oldSizes = (jdouble *) WF_ALLOC(sizeof(*oldSizes) * INTS_AT_A_TIME);
|
|
if (!oldSizes) return;
|
|
oldSizes[0] = -1;
|
|
oldLenMax = INTS_AT_A_TIME;
|
|
}
|
|
for (;oldSizes[i] >= 0; i++)
|
|
{
|
|
if (newSizes[newlen] == oldSizes[i])
|
|
{
|
|
found++;
|
|
break;
|
|
}
|
|
}
|
|
if (!found)
|
|
{
|
|
// Add newSizes[newlen] to oldSizes
|
|
if (i >= oldLenMax-1)
|
|
{
|
|
// Need more memory.
|
|
oldSizes = (jdouble *)
|
|
WF_REALLOC(oldSizes,
|
|
sizeof(*oldSizes) * (oldLenMax + INTS_AT_A_TIME));
|
|
if (!oldSizes) return;
|
|
oldLenMax += INTS_AT_A_TIME;
|
|
}
|
|
oldSizes[i++] = newSizes[newlen];
|
|
oldSizes[i++] = -1;
|
|
}
|
|
newlen++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// CopyString
|
|
//
|
|
// Make a copy of the input C-String and return a new C++ allocated
|
|
// C-String.
|
|
//
|
|
char *
|
|
CopyString(const char *str)
|
|
{
|
|
char *newStr = NULL;
|
|
int len = 0;
|
|
const char *tmp1;
|
|
char *tmp2;
|
|
|
|
if (str && *str)
|
|
{
|
|
for (tmp1=str; *tmp1; len++, tmp1++);
|
|
newStr = new char[len+1];
|
|
if (newStr)
|
|
{
|
|
for (tmp1=str, tmp2=newStr; *tmp1; *tmp2++ = *tmp1++);
|
|
*tmp2 = '\0';
|
|
}
|
|
}
|
|
return (newStr);
|
|
}
|
|
|
|
|
|
//
|
|
// Returns a newly allocated string that Escapes characters {:-*\}
|
|
// in the input str.
|
|
// For eg.
|
|
// input string : string-to*be-escaped\n
|
|
// return : string\-to\*be\-escaped\\n
|
|
//
|
|
// WARNING: Caller must delete the return string.
|
|
|
|
char *
|
|
EscapeString(const char *str, const char *escapeThese)
|
|
{
|
|
if (!str || !*str)
|
|
{
|
|
return NULL;
|
|
}
|
|
char *newstr = new char [2*strlen(str)+1];
|
|
if (!newstr)
|
|
{
|
|
// ERROR: No memory
|
|
return (NULL);
|
|
}
|
|
char* t = newstr;
|
|
while (*str)
|
|
{
|
|
if (strchr(escapeThese, *str))
|
|
*t++ = '\\';
|
|
*t++ = *str++;
|
|
}
|
|
*t = '\0';
|
|
return (newstr);
|
|
}
|
|
|
|
//
|
|
// ScanToken
|
|
// Scans a token delimited by 'stopChars' from 'str' and copies it out
|
|
// into 'buf'
|
|
// By default this compresses multiple spaces in the token to a single space.
|
|
// If 'noSpacesOnOutput' is set, all spaces, leading/trailing/intermediate
|
|
// spaces are stripped.
|
|
//
|
|
// Returns a pointer to the character after the token in 'str'
|
|
//
|
|
const char *
|
|
wf_scanToken(const char *str, char *buf, int len, char *stopChars,
|
|
int noSpacesOnOutput)
|
|
{
|
|
int pos = 0;
|
|
|
|
str = wf_skipSpaces(str);
|
|
|
|
while (*str != '\0')
|
|
{
|
|
while (*str != '\0' && ! isspace(*str) &&
|
|
(stopChars == NULL || strchr(stopChars, *str) == NULL))
|
|
{
|
|
buf[pos++] = *str++;
|
|
}
|
|
|
|
str = wf_skipSpaces(str);
|
|
if (*str == '\0' || stopChars == NULL ||
|
|
strchr(stopChars, *str) != NULL)
|
|
{
|
|
break;
|
|
}
|
|
if (! noSpacesOnOutput)
|
|
{
|
|
buf[pos++] = ' ';
|
|
}
|
|
}
|
|
buf[pos] = '\0';
|
|
return str;
|
|
}
|
|
|
|
//
|
|
// wf_scanVariableAndValue
|
|
// Modifies buf such that variable and value point to the the LHS and RHS of
|
|
// a buf of the format " variable = value "
|
|
// Leading and trailing spaces for both variable and value are trimmed.
|
|
//
|
|
int
|
|
wf_scanVariableAndValue(char *buf, int buflen, char *&variable, char *&value)
|
|
{
|
|
variable = buf;
|
|
value = NULL;
|
|
while (*buf && *buf != '=')
|
|
{
|
|
buf ++;
|
|
}
|
|
if ('=' == *buf)
|
|
{
|
|
*buf = '\0';
|
|
buf++;
|
|
value = buf;
|
|
}
|
|
variable = wf_trimSpaces(variable);
|
|
value = wf_trimSpaces(value);
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* wf_StringEndsWith
|
|
*
|
|
* returns nonzero if string 's' ends with string 'endstr'
|
|
* else returns zero
|
|
*/
|
|
int
|
|
wf_stringEndsWith(const char *s, const char *endstr)
|
|
{
|
|
int l, lend;
|
|
int retval = 0;
|
|
|
|
if (!endstr)
|
|
{
|
|
/* All strings ends in NULL */
|
|
retval = 1;
|
|
}
|
|
else if (!s)
|
|
{
|
|
/* NULL strings will never have endstr at its end */
|
|
retval = 0;
|
|
}
|
|
else
|
|
{
|
|
lend = strlen(endstr);
|
|
l = strlen(s);
|
|
#ifdef XP_WIN
|
|
if (l >= lend && !stricmp(s+l-lend, endstr)) /* ignore case for windows */
|
|
#else
|
|
if (l >= lend && !strcmp(s+l-lend, endstr))
|
|
#endif
|
|
{
|
|
retval = 1;
|
|
}
|
|
}
|
|
return (retval);
|
|
}
|
|
|
|
|
|
//
|
|
// wf_skipSpaces
|
|
// Returns a pointer to the first non-space character in 'str'
|
|
//
|
|
const char *
|
|
wf_skipSpaces(const char *str)
|
|
{
|
|
while (*str != '\0' && isspace(*str))
|
|
{
|
|
str++;
|
|
}
|
|
return str;
|
|
}
|
|
|
|
|
|
//
|
|
// wf_trimSpaces
|
|
// Trims initial and trailing spaces from the input string.
|
|
//
|
|
char *
|
|
wf_trimSpaces(char *inputString)
|
|
{
|
|
char *str = inputString;
|
|
|
|
if (!str || !*str)
|
|
{
|
|
return (str);
|
|
}
|
|
|
|
// Fix trailing spaces
|
|
int nstr = strlen(str);
|
|
int len = nstr;
|
|
while (len && isspace(str[len-1]))
|
|
{
|
|
--len;
|
|
}
|
|
if (len < nstr)
|
|
{
|
|
str[len] = '\0';
|
|
nstr = len+1;
|
|
}
|
|
|
|
// Fix leading spaces
|
|
while (*str && isspace(*str))
|
|
{
|
|
str++;
|
|
nstr--;
|
|
}
|
|
if (str != inputString)
|
|
{
|
|
memmove(inputString, str, nstr+1);
|
|
}
|
|
|
|
return (inputString);
|
|
}
|
|
|
|
//
|
|
// Returns
|
|
// 0 : if both strings are the same on a case insensitive compare
|
|
// -1 : if any of the string were NULL
|
|
// 1 : if string 'two' is a case insensitive substring of string 'one'
|
|
// 2 : if string 'one' is a case insensitive substring of string 'two'
|
|
// 3 : if case insensitive compare failed
|
|
//
|
|
int
|
|
wf_strcasecmp(const char *one, const char *two)
|
|
{
|
|
if (!one || !two)
|
|
{
|
|
return (-1);
|
|
}
|
|
|
|
for(; *one && *two; one++, two++)
|
|
{
|
|
if ((*one != *two) && (tolower(*one) != tolower(*two)))
|
|
return (3);
|
|
}
|
|
if (*one)
|
|
return (1);
|
|
if (*two)
|
|
return (2);
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// return 0 if the 2 strings are same on case insensitive compare upto
|
|
// atmost n bytes
|
|
// else -1
|
|
//
|
|
int
|
|
wf_strncasecmp(const char *one, const char *two, int n)
|
|
{
|
|
if (!one || !two)
|
|
{
|
|
return (-1);
|
|
}
|
|
|
|
for(; *one && *two && n-- > 0; one++, two++)
|
|
{
|
|
if ((*one != *two) && (tolower(*one) != tolower(*two)))
|
|
return (-1);
|
|
}
|
|
|
|
if (n <= 0 || (*one == '\0' && *two == '\0'))
|
|
return (0);
|
|
else
|
|
return (-1);
|
|
}
|
|
|
|
|
|
// returns a pointer to the extension part of the input string
|
|
const char *wf_getExtension(const char *fullname)
|
|
{
|
|
const char *ext = NULL;
|
|
if (!fullname || !*fullname)
|
|
{
|
|
return (ext);
|
|
}
|
|
|
|
while (*fullname)
|
|
{
|
|
if (*fullname == '.')
|
|
{
|
|
ext = fullname+1;
|
|
}
|
|
fullname++;
|
|
}
|
|
return(ext);
|
|
}
|
|
|
|
int wf_addToString(char **str, int *len, int *maxlen, const char *s)
|
|
{
|
|
if (!s || !*s)
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
if (!maxlen || !str)
|
|
{
|
|
// Invalid params.
|
|
return (-1);
|
|
}
|
|
|
|
int slen = strlen(s);
|
|
int curlen = 0;
|
|
if (!len)
|
|
{
|
|
curlen = strlen(*str);
|
|
}
|
|
else
|
|
{
|
|
curlen = *len;
|
|
}
|
|
|
|
if (curlen + slen + 1 > *maxlen)
|
|
{
|
|
int newlen = WF_ROUND_INT(curlen+slen+1, WF_STRING_ALLOCATION_STEP);
|
|
*str = (char *)WF_REALLOC(*str, sizeof(char)*newlen);
|
|
if (!*str)
|
|
{
|
|
// No memory
|
|
return (-1);
|
|
}
|
|
*maxlen = newlen;
|
|
}
|
|
memcpy((*str)+curlen, s, slen+1);
|
|
|
|
if (len)
|
|
{
|
|
*len += slen;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
//
|
|
// Webfont related miscellaneous routines
|
|
//
|
|
|
|
int
|
|
wf_releaseFmis(struct nffmi **fmis)
|
|
{
|
|
if (!fmis)
|
|
{
|
|
return (-1);
|
|
}
|
|
while (*fmis)
|
|
{
|
|
nffmi_release(*fmis, NULL);
|
|
fmis++;
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
|
|
//-----------------
|
|
// File operations
|
|
//-----------------
|
|
|
|
int wf_isFileReadable(const char *filename)
|
|
{
|
|
if (!filename || !*filename)
|
|
return (-1);
|
|
|
|
FILE *fp = fopen(filename, "r");
|
|
int readable = (fp != NULL);
|
|
fclose(fp);
|
|
|
|
return (readable);
|
|
}
|
|
|
|
int wf_isFileDirectory(const char *filename)
|
|
{
|
|
if (!filename || !*filename)
|
|
return (0);
|
|
|
|
PRFileInfo finfo;
|
|
|
|
if (PR_GetFileInfo(filename, &finfo) == PR_FAILURE)
|
|
return (0);
|
|
|
|
return (finfo.type == PR_FILE_DIRECTORY);
|
|
}
|
|
|
|
|
|
//
|
|
// expandFileName:
|
|
//
|
|
// expands the following in the filename
|
|
// beginning ~ : HOME
|
|
//
|
|
// Returns the no: of expansions done. If none was done, returns 0.
|
|
// Returns -ve if there was no space to do the expansion.
|
|
//
|
|
extern int wf_expandFilename(char *filename, int maxlen)
|
|
{
|
|
int ret = 0;
|
|
|
|
// Expand initial ~ to HOME
|
|
if (*filename == '~')
|
|
{
|
|
const char *home = getenv("HOME");
|
|
if (home && *home)
|
|
{
|
|
// Insert home into filename
|
|
int homelen = strlen(home);
|
|
int len = strlen(filename);
|
|
|
|
if (len+homelen <= maxlen)
|
|
{
|
|
// Shift all characters in filename by homelen bytes
|
|
memmove(filename+homelen, filename+1, len);
|
|
// Copy home into filename
|
|
memcpy(filename, home, homelen);
|
|
ret ++;
|
|
}
|
|
else
|
|
{
|
|
ret = -1;
|
|
}
|
|
}
|
|
}
|
|
return (ret);
|
|
}
|