From 9f0a771f52192acba6b64068be3ab151a66cbaac Mon Sep 17 00:00:00 2001 From: mike Date: Wed, 23 May 2012 20:17:12 +0000 Subject: [PATCH] Implement the IPP localization API (STR #3925) git-svn-id: svn+ssh://src.apple.com/svn/cups/cups.org/trunk@10506 7a7537e8-13f0-0310-91df-b6672ffda945 --- cups/dest-localization.c | 330 +++++++++++++++++++++++++++++++++++++-- cups/language-private.h | 1 + cups/language.c | 45 +++--- 3 files changed, 348 insertions(+), 28 deletions(-) diff --git a/cups/dest-localization.c b/cups/dest-localization.c index 3753869094..ad709ee82e 100644 --- a/cups/dest-localization.c +++ b/cups/dest-localization.c @@ -15,10 +15,14 @@ * * Contents: * - * cupsLocalizeDestOption() - Get the localized string for a destination - * option. - * cupsLocalizeDestValue() - Get the localized string for a destination - * option+value pair. + * cupsLocalizeDestOption() - Get the localized string for a destination + * option. + * cupsLocalizeDestValue() - Get the localized string for a destination + * option+value pair. + * cups_create_localizations() - Create the localizations array for a + * destination. + * cups_read_strings() - Read a pair of strings from a .strings file. + * cups_scan_strings() - Scan a quoted string. */ /* @@ -28,12 +32,22 @@ #include "cups-private.h" +/* + * Local functions... + */ + +static void cups_create_localizations(http_t *http, cups_dinfo_t *dinfo); +static int cups_read_strings(cups_file_t *fp, char *buffer, size_t bufsize, + char **id, char **str); +static char *cups_scan_strings(char *buffer); + + /* * 'cupsLocalizeDestOption()' - Get the localized string for a destination * option. * - * The returned string is stored in the localization array and will become - * invalid if the localization array is deleted. + * The returned string is stored in the destination information and will become + * invalid if the destination information is deleted. * * @since CUPS 1.6/OS X 10.8@ */ @@ -45,7 +59,25 @@ cupsLocalizeDestOption( cups_dinfo_t *dinfo, /* I - Destination information */ const char *option) /* I - Option to localize */ { - return (option); + _cups_message_t key, /* Search key */ + *match; /* Matching entry */ + + + if (!http || !dest || !dinfo) + return (option); + + if (!dinfo->localizations) + cups_create_localizations(http, dinfo); + + if (cupsArrayCount(dinfo->localizations) == 0) + return (option); + + key.id = (char *)option; + if ((match = (_cups_message_t *)cupsArrayFind(dinfo->localizations, + &key)) != NULL) + return (match->str); + else + return (option); } @@ -53,8 +85,8 @@ cupsLocalizeDestOption( * 'cupsLocalizeDestValue()' - Get the localized string for a destination * option+value pair. * - * The returned string is stored in the localization array and will become - * invalid if the localization array is deleted. + * The returned string is stored in the destination information and will become + * invalid if the destination information is deleted. * * @since CUPS 1.6/OS X 10.8@ */ @@ -67,10 +99,288 @@ cupsLocalizeDestValue( const char *option, /* I - Option to localize */ const char *value) /* I - Value to localize */ { - return (value); + _cups_message_t key, /* Search key */ + *match; /* Matching entry */ + char pair[256]; /* option.value pair */ + + + if (!http || !dest || !dinfo) + return (value); + + if (!dinfo->localizations) + cups_create_localizations(http, dinfo); + + if (cupsArrayCount(dinfo->localizations) == 0) + return (value); + + snprintf(pair, sizeof(pair), "%s.%s", option, value); + key.id = pair; + if ((match = (_cups_message_t *)cupsArrayFind(dinfo->localizations, + &key)) != NULL) + return (match->str); + else + return (value); +} + + +/* + * 'cups_create_localizations()' - Create the localizations array for a + * destination. + */ + +static void +cups_create_localizations( + http_t *http, /* I - Connection to destination */ + cups_dinfo_t *dinfo) /* I - Destination informations */ +{ + http_t *http2; /* Connection for strings file */ + http_status_t status; /* Request status */ + ipp_attribute_t *attr; /* "printer-strings-uri" attribute */ + char scheme[32], /* URI scheme */ + userpass[256], /* Username/password info */ + hostname[256], /* Hostname */ + resource[1024], /* Resource */ + http_hostname[256], + /* Hostname of connection */ + tempfile[1024]; /* Temporary filename */ + int port; /* Port number */ + http_encryption_t encryption; /* Encryption to use */ + cups_file_t *temp; /* Temporary file */ + + + /* + * Create an empty message catalog... + */ + + dinfo->localizations = _cupsMessageNew(NULL); + + /* + * See if there are any localizations... + */ + + if ((attr = ippFindAttribute(dinfo->attrs, "printer-strings-uri", + IPP_TAG_URI)) == NULL) + { + /* + * Nope... + */ + + DEBUG_puts("4cups_create_localizations: No printer-strings-uri (uri) " + "value."); + return; /* Nope */ + } + + /* + * Pull apart the URI and determine whether we need to try a different + * server... + */ + + if (httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[0].string.text, + scheme, sizeof(scheme), userpass, sizeof(userpass), + hostname, sizeof(hostname), &port, resource, + sizeof(resource)) < HTTP_URI_OK) + { + DEBUG_printf(("4cups_create_localizations: Bad printer-strings-uri value " + "\"%s\".", attr->values[0].string.text)); + return; + } + + httpGetHostname(http, http_hostname, sizeof(http_hostname)); + + if (!_cups_strcasecmp(http_hostname, hostname) && + port == _httpAddrPort(http->hostaddr)) + { + /* + * Use the same connection... + */ + + http2 = http; + } + else + { + /* + * Connect to the alternate host... + */ + + if (!strcmp(scheme, "https")) + encryption = HTTP_ENCRYPT_ALWAYS; + else + encryption = HTTP_ENCRYPT_IF_REQUESTED; + + if ((http2 = httpConnectEncrypt(hostname, port, encryption)) == NULL) + { + DEBUG_printf(("4cups_create_localizations: Unable to connect to " + "%s:%d: %s", hostname, port, cupsLastErrorString())); + return; + } + } + + /* + * Get a temporary file... + */ + + if ((temp = cupsTempFile2(tempfile, sizeof(tempfile))) == NULL) + { + DEBUG_printf(("4cups_create_localizations: Unable to create temporary " + "file: %s", cupsLastErrorString())); + if (http2 != http) + httpClose(http2); + return; + } + + status = cupsGetFd(http2, resource, cupsFileNumber(temp)); + + DEBUG_printf(("4cups_create_localizations: GET %s = %s", resource, + httpStatus(status))); + + if (status == HTTP_OK) + { + /* + * Got the file, read it... + */ + + char buffer[8192], /* Message buffer */ + *id, /* ID string */ + *str; /* Translated message */ + _cups_message_t *m; /* Current message */ + + lseek(cupsFileNumber(temp), 0, SEEK_SET); + + while (cups_read_strings(temp, buffer, sizeof(buffer), &id, &str)) + { + if ((m = malloc(sizeof(_cups_message_t))) == NULL) + break; + + m->id = strdup(id); + m->str = strdup(str); + + if (m->id && m->str) + cupsArrayAdd(dinfo->localizations, m); + else + { + if (m->id) + free(m->id); + + if (m->str) + free(m->str); + + free(m); + break; + } + } + } + + DEBUG_printf(("4cups_create_localizations: %d messages loaded.", + cupsArrayCount(dinfo->localizations))); + + /* + * Cleanup... + */ + + unlink(tempfile); + cupsFileClose(temp); + + if (http2 != http) + httpClose(http2); +} + + +/* + * 'cups_read_strings()' - Read a pair of strings from a .strings file. + */ + +static int /* O - 1 on success, 0 on failure */ +cups_read_strings(cups_file_t *strings, /* I - .strings file */ + char *buffer, /* I - Line buffer */ + size_t bufsize, /* I - Size of line buffer */ + char **id, /* O - Pointer to ID string */ + char **str) /* O - Pointer to translation string */ +{ + char *bufptr; /* Pointer into buffer */ + + + while (cupsFileGets(strings, buffer, bufsize)) + { + if (buffer[0] != '\"') + continue; + + *id = buffer + 1; + bufptr = cups_scan_strings(buffer); + + if (*bufptr != '\"') + continue; + + *bufptr++ = '\0'; + + while (*bufptr && *bufptr != '\"') + bufptr ++; + + if (!*bufptr) + continue; + + *str = bufptr + 1; + bufptr = cups_scan_strings(bufptr); + + if (*bufptr != '\"') + continue; + + *bufptr = '\0'; + + return (1); + } + + return (0); +} + + +/* + * 'cups_scan_strings()' - Scan a quoted string. + */ + +static char * /* O - End of string */ +cups_scan_strings(char *buffer) /* I - Start of string */ +{ + char *bufptr; /* Pointer into string */ + + + for (bufptr = buffer + 1; *bufptr && *bufptr != '\"'; bufptr ++) + { + if (*bufptr == '\\') + { + if (bufptr[1] >= '0' && bufptr[1] <= '3' && + bufptr[2] >= '0' && bufptr[2] <= '7' && + bufptr[3] >= '0' && bufptr[3] <= '7') + { + /* + * Decode \nnn octal escape... + */ + + *bufptr = ((((bufptr[1] - '0') << 3) | (bufptr[2] - '0')) << 3) | + (bufptr[3] - '0'); + _cups_strcpy(bufptr + 1, bufptr + 4); + } + else + { + /* + * Decode \C escape... + */ + + _cups_strcpy(bufptr, bufptr + 1); + if (*bufptr == 'n') + *bufptr = '\n'; + else if (*bufptr == 'r') + *bufptr = '\r'; + else if (*bufptr == 't') + *bufptr = '\t'; + } + } + } + + return (bufptr); } + /* * End of "$Id$". */ diff --git a/cups/language-private.h b/cups/language-private.h index 6a2a886b13..cf5b482b43 100644 --- a/cups/language-private.h +++ b/cups/language-private.h @@ -71,6 +71,7 @@ extern const char *_cupsLangString(cups_lang_t *lang, extern void _cupsMessageFree(cups_array_t *a); extern cups_array_t *_cupsMessageLoad(const char *filename, int unquote); extern const char *_cupsMessageLookup(cups_array_t *a, const char *m); +extern cups_array_t *_cupsMessageNew(void *context); extern void _cupsSetLocale(char *argv[]); diff --git a/cups/language.c b/cups/language.c index c536e5aa7d..58b31e082e 100644 --- a/cups/language.c +++ b/cups/language.c @@ -17,26 +17,27 @@ * Contents: * * _cupsAppleLanguage() - Get the Apple language identifier associated with - * a locale ID. + * a locale ID. * _cupsEncodingName() - Return the character encoding name string for the - * given encoding enumeration. - * cupsLangDefault() - Return the default language. - * cupsLangEncoding() - Return the character encoding (us-ascii, etc.) for - * the given language. - * cupsLangFlush() - Flush all language data out of the cache. - * cupsLangFree() - Free language data. - * cupsLangGet() - Get a language. - * _cupsLangString() - Get a message string. + * given encoding enumeration. + * cupsLangDefault() - Return the default language. + * cupsLangEncoding() - Return the character encoding (us-ascii, etc.) + * for the given language. + * cupsLangFlush() - Flush all language data out of the cache. + * cupsLangFree() - Free language data. + * cupsLangGet() - Get a language. + * _cupsLangString() - Get a message string. * _cupsMessageFree() - Free a messages array. * _cupsMessageLoad() - Load a .po file into a messages array. * _cupsMessageLookup() - Lookup a message string. + * _cupsMessageNew() - Make a new message catalog array. * appleLangDefault() - Get the default locale string. * appleMessageLoad() - Load a message catalog from a localizable bundle. * cups_cache_lookup() - Lookup a language in the cache... * cups_message_compare() - Compare two messages. * cups_message_free() - Free a message. * cups_message_load() - Load the message catalog for a language. - * cups_unquote() - Unquote characters in strings... + * cups_unquote() - Unquote characters in strings... */ /* @@ -854,10 +855,7 @@ _cupsMessageLoad(const char *filename, /* I - Message catalog to load */ * Create an array to hold the messages... */ - if ((a = cupsArrayNew3((cups_array_func_t)cups_message_compare, NULL, - (cups_ahash_func_t)NULL, 0, - (cups_acopy_func_t)NULL, - (cups_afree_func_t)cups_message_free)) == NULL) + if ((a = _cupsMessageNew(NULL)) == NULL) { DEBUG_puts("5_cupsMessageLoad: Unable to allocate array!"); return (NULL); @@ -1140,6 +1138,20 @@ _cupsMessageLookup(cups_array_t *a, /* I - Message array */ } +/* + * '_cupsMessageNew()' - Make a new message catalog array. + */ + +cups_array_t * /* O - Array */ +_cupsMessageNew(void *context) /* I - User data */ +{ + return (cupsArrayNew3((cups_array_func_t)cups_message_compare, context, + (cups_ahash_func_t)NULL, 0, + (cups_acopy_func_t)NULL, + (cups_afree_func_t)cups_message_free)); +} + + #ifdef __APPLE__ /* * 'appleLangDefault()' - Get the default locale string. @@ -1374,10 +1386,7 @@ appleMessageLoad(const char *locale) /* I - Locale ID */ * plist as the user data. */ - return (cupsArrayNew3((cups_array_func_t)cups_message_compare, (void *)plist, - (cups_ahash_func_t)NULL, 0, - (cups_acopy_func_t)NULL, - (cups_afree_func_t)cups_message_free)); + return (_cupsMessageNew((void *)plist)); } # endif /* CUPS_BUNDLEDIR */ #endif /* __APPLE__ */ -- 2.47.3