//C- -*- C++ -*- //C- ------------------------------------------------------------------- //C- DjVuLibre-3.5 //C- Copyright (c) 2002 Leon Bottou and Yann Le Cun. //C- Copyright (c) 2001 AT&T //C- //C- This software is subject to, and may be distributed under, the //C- GNU General Public License, Version 2. The license should have //C- accompanied the software or you may obtain a copy of the license //C- from the Free Software Foundation at http://www.fsf.org . //C- //C- This program is distributed in the hope that it will be useful, //C- but WITHOUT ANY WARRANTY; without even the implied warranty of //C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //C- GNU General Public License for more details. //C- //C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library //C- distributed by Lizardtech Software. On July 19th 2002, Lizardtech //C- Software authorized us to replace the original DjVu(r) Reference //C- Library notice by the following text (see doc/lizard2002.djvu): //C- //C- ------------------------------------------------------------------ //C- | DjVu (r) Reference Library (v. 3.5) //C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved. //C- | The DjVu Reference Library is protected by U.S. Pat. No. //C- | 6,058,214 and patents pending. //C- | //C- | This software is subject to, and may be distributed under, the //C- | GNU General Public License, Version 2. The license should have //C- | accompanied the software or you may obtain a copy of the license //C- | from the Free Software Foundation at http://www.fsf.org . //C- | //C- | The computer code originally released by LizardTech under this //C- | license and unmodified by other parties is deemed "the LIZARDTECH //C- | ORIGINAL CODE." Subject to any third party intellectual property //C- | claims, LizardTech grants recipient a worldwide, royalty-free, //C- | non-exclusive license to make, use, sell, or otherwise dispose of //C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the //C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU //C- | General Public License. This grant only confers the right to //C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to //C- | the extent such infringement is reasonably necessary to enable //C- | recipient to make, have made, practice, sell, or otherwise dispose //C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to //C- | any greater extent that may be necessary to utilize further //C- | modifications or combinations. //C- | //C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY //C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED //C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF //C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. //C- +------------------------------------------------------------------ // // $Id: DjVuMessageLite.cpp,v 1.13 2005/04/27 16:34:13 leonb Exp $ // $Name: release_3_5_15 $ #ifdef HAVE_CONFIG_H # include "config.h" #endif #if NEED_GNUG_PRAGMAS # pragma implementation #endif // From: Leon Bottou, 1/31/2002 // All these I18N XML messages are Lizardtech innovations. // For DjvuLibre, I changed the path extraction logic // and added support for non I18N messages. #include "DjVuMessageLite.h" #include "GOS.h" #include "XMLTags.h" #include "ByteStream.h" #include "GURL.h" #include "debug.h" #include #include #include // #include #ifdef WIN32 #include #include #include #include #endif #ifdef UNIX #include #include #include #endif #include #ifdef HAVE_NAMESPACES namespace DJVU { # ifdef NOT_DEFINED // Just to fool emacs c++ mode } #endif #endif const DjVuMessageLite& (*DjVuMessageLite::create)(void) = DjVuMessageLite::create_lite; static const char *failed_to_parse_XML= ERR_MSG("DjVuMessage.failed_to_parse_XML"); static const char *unrecognized= ERR_MSG("DjVuMessage.Unrecognized"); static const char *uparameter= ERR_MSG("DjVuMessage.Parameter"); #ifdef LIZARDTECH_1_800_NUMBER static const char unrecognized_default[] = "** Unrecognized DjVu Message: [Contact LizardTech at " LIZARDTECH_1_800_NUMBER " \n" "\t** Message name: %1!s!"; #else static const char unrecognized_default[] = "** Unrecognized DjVu Message:\n" "\t** Message name: %1!s!"; #endif static const char uparameter_default[] = "\t Parameter: %1!s!"; static const char failed_to_parse_XML_default[]= "Failed to parse XML message file: '%1!s!'."; static const char namestring[]="name"; static const char valuestring[]="value"; static const char numberstring[]="number"; static const char bodystring[]="BODY"; static const char messagestring[]="MESSAGE"; GPList & DjVuMessageLite::getByteStream(void) { static GPList gbs; return gbs; } GP & DjVuMessageLite::getDjVuMessageLite(void) { static GP message; return message; } void DjVuMessageLite::AddByteStreamLater(const GP &bs) { getByteStream().append(bs); } // There is only object of class DjVuMessage in a program, and here it is: //DjVuMessage DjVuMsg; const DjVuMessageLite & DjVuMessageLite::create_lite(void) { GP &static_message=getDjVuMessageLite(); if(!static_message) { static_message=new DjVuMessageLite; } DjVuMessageLite &m=*static_message; GPList &bs = getByteStream(); for(GPosition pos;(pos=bs);bs.del(pos)) { m.AddByteStream(bs[pos]); } return m; } // Constructor DjVuMessageLite::DjVuMessageLite( void ) {} // Destructor DjVuMessageLite::~DjVuMessageLite( ) {} void DjVuMessageLite::perror( const GUTF8String & MessageList ) { DjVuPrintErrorUTF8("%s\n",(const char *)DjVuMessageLite::LookUpUTF8(MessageList)); } // Expands message lists by looking up the message IDs and inserting // arguments into the retrieved messages. // N.B. The resulting string may be encoded in UTF-8 format (ISO 10646-1 Annex R) // and SHOULD NOT BE ASSUMED TO BE ASCII. GUTF8String DjVuMessageLite::LookUp( const GUTF8String & MessageList ) const { // DEBUG_MSG( "========== DjVuMessageLite::LookUp ==========\n" << // MessageList << // "\n========== DjVuMessageLite::LookUp ==========\n" ); GUTF8String result; // Result string; begins empty if(errors.length()) { const GUTF8String err1(errors); (const_cast(errors)).empty(); result=LookUp(err1)+"\n"; } int start = 0; // Beginning of next message int end = MessageList.length(); // End of the message string // Isolate single messages and process them while( start < end ) { if( MessageList[start] == '\n' ) { result += MessageList[start++]; // move the newline to the result // and advance to the next message } else { // Find the end of the next message and process it int next_ending = MessageList.search((unsigned long)'\n', start); if( next_ending < 0 ) next_ending = end; result += LookUpSingle( MessageList.substr(start, next_ending-start) ); // Advance to the next message start = next_ending; } } // All done return result; } // Expands a single message and inserts the arguments. Single_Message // contains no separators (newlines), but includes all the parameters // separated by tabs. GUTF8String DjVuMessageLite::LookUpSingle( const GUTF8String &Single_Message ) const { #if HAS_CTRL_C_IN_ERR_MSG if (Single_Message[0] != '\003') return Single_Message; #endif // Isolate the message ID and get the corresponding message text int ending_posn = Single_Message.contains("\t\v"); if( ending_posn < 0 ) ending_posn = Single_Message.length(); GUTF8String msg_text; GUTF8String msg_number; const GUTF8String message=Single_Message.substr(0,ending_posn); LookUpID( message, msg_text, msg_number ); // Check whether we found anything if( !msg_text.length()) { if(message == unrecognized) { msg_text = unrecognized_default; }else if(message == uparameter) { msg_text = uparameter_default; }else if(message == failed_to_parse_XML) { msg_text = failed_to_parse_XML_default; }else { return LookUpSingle(unrecognized + ("\t" + Single_Message)); } } // Insert the parameters (if any) unsigned int param_num = 0; while( (unsigned int)ending_posn < Single_Message.length() ) { GUTF8String arg; const int start_posn = ending_posn+1; if(Single_Message[ending_posn] == '\v') { ending_posn=Single_Message.length(); arg=LookUpSingle(Single_Message.substr(start_posn,ending_posn)); }else { ending_posn = Single_Message.contains("\v\t",start_posn); if( ending_posn < 0 ) ending_posn = Single_Message.length(); arg=Single_Message.substr(start_posn, ending_posn-start_posn); } InsertArg( msg_text, ++param_num, arg); } // Insert the message number InsertArg( msg_text, 0, msg_number ); return msg_text; } // Looks up the msgID in the file of messages and returns a pointer to // the beginning of the translated message, if found; and an empty string // otherwise. void DjVuMessageLite::LookUpID( const GUTF8String &xmsgID, GUTF8String &message_text, GUTF8String &message_number ) const { if(!Map.isempty()) { GUTF8String msgID = xmsgID; #if HAS_CTRL_C_IN_ERR_MSG int start = 0; while (msgID[start] == '\003') start ++; if (start > 0) msgID = msgID.substr(start, msgID.length() - start); #endif GPosition pos=Map.contains(msgID); if(pos) { const GP tag=Map[pos]; GPosition valuepos=tag->get_args().contains(valuestring); if(valuepos) { message_text=tag->get_args()[valuepos]; }else { const GUTF8String raw(tag->get_raw()); const int start_line=raw.search((unsigned long)'\n',0); const int start_text=raw.nextNonSpace(0); const int end_text=raw.firstEndSpace(0); if(start_line<0 || start_text<0 || start_text < start_line) { message_text=raw.substr(0,end_text).fromEscaped(); }else { message_text=raw.substr(start_line+1,end_text-start_line-1).fromEscaped(); } } GPosition numberpos=tag->get_args().contains(numberstring); if(numberpos) { message_number=tag->get_args()[numberpos]; } } } } // Insert a string into the message text. Will insert into any field // description. Except for an ArgId of zero (message number), if the ArgId // is not found, the routine adds a line with the parameter so information // will not be lost. void DjVuMessageLite::InsertArg( GUTF8String &message, const int ArgId, const GUTF8String &arg ) const { // argument target string const GUTF8String target= "%"+GUTF8String(ArgId)+"!"; // location of target string int format_start = message.search( (const char *)target ); if( format_start >= 0 ) { do { const int n=format_start+target.length()+1; const int format_end=message.search((unsigned long)'!',n); if(format_end > format_start) { const int len=1+format_end-n; if(len && isascii(message[n-1])) { GUTF8String narg; GUTF8String format="%"+message.substr(n-1,len); switch(format[len]) { case 'd': case 'i': narg.format((const char *)format,arg.toInt()); break; case 'u': case 'o': case 'x': case 'X': narg.format((const char *)format,(unsigned int)arg.toInt()); break; case 'f': { int endpos; narg.format((const char *)format, arg.toDouble(0,endpos)); if( endpos < 0 ) narg = arg; } break; default: narg.format((const char *)format,(const char *)arg); break; } message = message.substr( 0, format_start )+narg +message.substr( format_end+1, -1 ); }else { message = message.substr( 0, format_start )+arg +message.substr( format_end+1, -1 ); } } format_start=message.search((const char*)target, format_start+arg.length()); } while(format_start >= 0); } else { // Not found, fake it if( ArgId != 0 ) { message += "\n"+LookUpSingle(uparameter+("\t"+arg)); } } } // A C function to perform a message lookup. Arguments are a buffer to received the // translated message, a buffer size (bytes), and a message_list. The translated // result is returned in msg_buffer encoded in UTF-8. In case of error, msg_buffer is // empty (i.e., msg_buffer[0] == '\0'). void DjVuMessageLite_LookUp( char *msg_buffer, const unsigned int buffer_size, const char *message ) { GUTF8String converted = DjVuMessageLite::LookUpUTF8( message ); if( converted.length() >= buffer_size ) msg_buffer[0] = '\0'; else strcpy( msg_buffer, converted ); } void DjVuMessageLite::AddByteStream(const GP &bs) { const GP gtags(lt_XMLTags::create(bs)); lt_XMLTags &tags=*gtags; GPList Bodies=tags.get_Tags(bodystring); if(! Bodies.isempty()) { lt_XMLTags::get_Maps(messagestring,namestring,Bodies,Map); } } #ifdef HAVE_NAMESPACES } # ifndef NOT_USING_DJVU_NAMESPACE using namespace DJVU; # endif #endif void DjVuWriteError( const char *message ) { G_TRY { GP errout = ByteStream::get_stderr(); if (errout) { const GUTF8String external = DjVuMessageLite::LookUpUTF8( message ); errout->writestring(external+"\n"); } // Need to catch all exceptions because these might be // called from an outer exception handler (with prejudice) } G_CATCH_ALL { } G_ENDCATCH; } void DjVuWriteMessage( const char *message ) { G_TRY { GP strout = ByteStream::get_stdout(); if (strout) { const GUTF8String external = DjVuMessageLite::LookUpUTF8( message ); strout->writestring(external+"\n"); } // Need to catch all exceptions because these might be // called from an outer exception handler (with prejudice) } G_CATCH_ALL { } G_ENDCATCH; }