Blame libdjvu/DjVuMessageLite.cpp

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