source: trunk/libdjvu/DjVuMessageLite.cpp @ 17

Last change on this file since 17 was 17, checked in by Eugene Romanenko, 15 years ago

update makefiles, remove absolute paths, update djvulibre to version 3.5.17

File size: 14.9 KB
Line 
1//C-  -*- C++ -*-
2//C- -------------------------------------------------------------------
3//C- DjVuLibre-3.5
4//C- Copyright (c) 2002  Leon Bottou and Yann Le Cun.
5//C- Copyright (c) 2001  AT&T
6//C-
7//C- This software is subject to, and may be distributed under, the
8//C- GNU General Public License, Version 2. The license should have
9//C- accompanied the software or you may obtain a copy of the license
10//C- from the Free Software Foundation at http://www.fsf.org .
11//C-
12//C- This program is distributed in the hope that it will be useful,
13//C- but WITHOUT ANY WARRANTY; without even the implied warranty of
14//C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15//C- GNU General Public License for more details.
16//C-
17//C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library
18//C- distributed by Lizardtech Software.  On July 19th 2002, Lizardtech
19//C- Software authorized us to replace the original DjVu(r) Reference
20//C- Library notice by the following text (see doc/lizard2002.djvu):
21//C-
22//C-  ------------------------------------------------------------------
23//C- | DjVu (r) Reference Library (v. 3.5)
24//C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved.
25//C- | The DjVu Reference Library is protected by U.S. Pat. No.
26//C- | 6,058,214 and patents pending.
27//C- |
28//C- | This software is subject to, and may be distributed under, the
29//C- | GNU General Public License, Version 2. The license should have
30//C- | accompanied the software or you may obtain a copy of the license
31//C- | from the Free Software Foundation at http://www.fsf.org .
32//C- |
33//C- | The computer code originally released by LizardTech under this
34//C- | license and unmodified by other parties is deemed "the LIZARDTECH
35//C- | ORIGINAL CODE."  Subject to any third party intellectual property
36//C- | claims, LizardTech grants recipient a worldwide, royalty-free,
37//C- | non-exclusive license to make, use, sell, or otherwise dispose of
38//C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the
39//C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU
40//C- | General Public License.   This grant only confers the right to
41//C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to
42//C- | the extent such infringement is reasonably necessary to enable
43//C- | recipient to make, have made, practice, sell, or otherwise dispose
44//C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to
45//C- | any greater extent that may be necessary to utilize further
46//C- | modifications or combinations.
47//C- |
48//C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY
49//C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
50//C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF
51//C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
52//C- +------------------------------------------------------------------
53//
54// $Id: DjVuMessageLite.cpp,v 1.13 2005/04/27 16:34:13 leonb Exp $
55// $Name:  $
56
57#ifdef HAVE_CONFIG_H
58# include "config.h"
59#endif
60#if NEED_GNUG_PRAGMAS
61# pragma implementation
62#endif
63
64// From: Leon Bottou, 1/31/2002
65// All these I18N XML messages are Lizardtech innovations.
66// For DjvuLibre, I changed the path extraction logic
67// and added support for non I18N messages.
68
69#include "DjVuMessageLite.h"
70#include "GOS.h"
71#include "XMLTags.h"
72#include "ByteStream.h"
73#include "GURL.h"
74#include "debug.h"
75#include <ctype.h>
76#include <string.h>
77#include <stdlib.h>
78// #include <stdio.h>
79#ifdef WIN32
80#include <tchar.h>
81#include <atlbase.h>
82#include <windows.h>
83#include <winreg.h>
84#endif
85#ifdef UNIX
86#include <unistd.h>
87#include <pwd.h>
88#include <sys/types.h>
89#endif
90#include <locale.h>
91
92
93#ifdef HAVE_NAMESPACES
94namespace DJVU {
95# ifdef NOT_DEFINED // Just to fool emacs c++ mode
96}
97#endif
98#endif
99
100
101const DjVuMessageLite& (*DjVuMessageLite::create)(void) = 
102  DjVuMessageLite::create_lite; 
103
104static const char *failed_to_parse_XML=
105  ERR_MSG("DjVuMessage.failed_to_parse_XML");
106static const char *unrecognized=
107  ERR_MSG("DjVuMessage.Unrecognized");
108static const char *uparameter=
109  ERR_MSG("DjVuMessage.Parameter");
110#ifdef LIZARDTECH_1_800_NUMBER
111static const char unrecognized_default[] =
112  "** Unrecognized DjVu Message: [Contact LizardTech at " 
113  LIZARDTECH_1_800_NUMBER " \n"
114  "\t** Message name:  %1!s!";
115#else
116static const char unrecognized_default[] =
117  "** Unrecognized DjVu Message:\n"
118  "\t** Message name:  %1!s!";
119#endif
120static const char uparameter_default[] = 
121  "\t   Parameter: %1!s!";
122static const char failed_to_parse_XML_default[]=
123  "Failed to parse XML message file:&#10;&#09;&apos;%1!s!&apos;.";
124
125static const char namestring[]="name";
126static const char valuestring[]="value";
127static const char numberstring[]="number";
128static const char bodystring[]="BODY";
129static const char messagestring[]="MESSAGE";
130
131GPList<ByteStream> &
132DjVuMessageLite::getByteStream(void)
133{
134  static GPList<ByteStream> gbs;
135  return gbs;
136}
137
138GP<DjVuMessageLite> &
139DjVuMessageLite::getDjVuMessageLite(void)
140{
141  static GP<DjVuMessageLite> message;
142  return message;
143}
144
145void
146DjVuMessageLite::AddByteStreamLater(const GP<ByteStream> &bs)
147{
148  getByteStream().append(bs);
149}
150
151//  There is only object of class DjVuMessage in a program, and here it is:
152//DjVuMessage  DjVuMsg;
153const DjVuMessageLite &
154DjVuMessageLite::create_lite(void)
155{
156  GP<DjVuMessageLite> &static_message=getDjVuMessageLite();
157  if(!static_message)
158  {
159    static_message=new DjVuMessageLite;
160  }
161  DjVuMessageLite &m=*static_message;
162  GPList<ByteStream> &bs = getByteStream();
163  for(GPosition pos;(pos=bs);bs.del(pos))
164  {
165    m.AddByteStream(bs[pos]);
166  }
167  return m;
168}
169
170// Constructor
171DjVuMessageLite::DjVuMessageLite( void ) {}
172
173// Destructor
174DjVuMessageLite::~DjVuMessageLite( ) {}
175
176
177void
178DjVuMessageLite::perror( const GUTF8String & MessageList )
179{
180  DjVuPrintErrorUTF8("%s\n",(const char *)DjVuMessageLite::LookUpUTF8(MessageList));
181}
182
183
184//  Expands message lists by looking up the message IDs and inserting
185//  arguments into the retrieved messages.
186//  N.B. The resulting string may be encoded in UTF-8 format (ISO 10646-1 Annex R)
187//       and SHOULD NOT BE ASSUMED TO BE ASCII.
188GUTF8String
189DjVuMessageLite::LookUp( const GUTF8String & MessageList ) const
190{
191//  DEBUG_MSG( "========== DjVuMessageLite::LookUp ==========\n" <<
192//             MessageList <<
193//             "\n========== DjVuMessageLite::LookUp ==========\n" );
194  GUTF8String result;                       // Result string; begins empty
195  if(errors.length())
196  {
197    const GUTF8String err1(errors);
198    (const_cast<GUTF8String &>(errors)).empty();
199    result=LookUp(err1)+"\n";
200  }
201
202  int start = 0;                            // Beginning of next message
203  int end = MessageList.length();           // End of the message string
204
205  //  Isolate single messages and process them
206  while( start < end )
207  {
208    if( MessageList[start] == '\n' )
209    {
210      result += MessageList[start++];       // move the newline to the result
211                                            // and advance to the next message
212    }
213    else
214    {
215      //  Find the end of the next message and process it
216      int next_ending = MessageList.search((unsigned long)'\n', start);
217      if( next_ending < 0 )
218        next_ending = end;
219      result += LookUpSingle( MessageList.substr(start, next_ending-start) );
220      //  Advance to the next message
221      start = next_ending;
222    }
223  }
224
225  //  All done
226  return result;
227}
228
229
230// Expands a single message and inserts the arguments. Single_Message
231// contains no separators (newlines), but includes all the parameters
232// separated by tabs.
233GUTF8String
234DjVuMessageLite::LookUpSingle( const GUTF8String &Single_Message ) const
235{
236#if HAS_CTRL_C_IN_ERR_MSG
237  if (Single_Message[0] != '\003')
238    return Single_Message;
239#endif
240  //  Isolate the message ID and get the corresponding message text
241  int ending_posn = Single_Message.contains("\t\v");
242  if( ending_posn < 0 )
243    ending_posn = Single_Message.length();
244  GUTF8String msg_text;
245  GUTF8String msg_number;
246  const GUTF8String message=Single_Message.substr(0,ending_posn);
247  LookUpID( message, msg_text, msg_number );
248
249  //  Check whether we found anything
250  if( !msg_text.length())
251  {
252    if(message == unrecognized)
253    {
254      msg_text = unrecognized_default;
255    }else if(message == uparameter)
256    {
257      msg_text = uparameter_default;
258    }else if(message == failed_to_parse_XML)
259    {
260      msg_text = failed_to_parse_XML_default;
261    }else
262    {
263      return LookUpSingle(unrecognized + ("\t" + Single_Message));
264    }
265  }
266   
267  //  Insert the parameters (if any)
268  unsigned int param_num = 0;
269  while( (unsigned int)ending_posn < Single_Message.length() )
270  {
271    GUTF8String arg;
272    const int start_posn = ending_posn+1;
273    if(Single_Message[ending_posn] == '\v')
274    {
275      ending_posn=Single_Message.length();
276      arg=LookUpSingle(Single_Message.substr(start_posn,ending_posn));
277    }else
278    {
279      ending_posn = Single_Message.contains("\v\t",start_posn);
280      if( ending_posn < 0 )
281        ending_posn = Single_Message.length();
282      arg=Single_Message.substr(start_posn, ending_posn-start_posn);
283    }
284    InsertArg( msg_text, ++param_num, arg);
285  }
286  //  Insert the message number
287  InsertArg( msg_text, 0, msg_number );
288
289  return msg_text;
290}
291
292
293// Looks up the msgID in the file of messages and returns a pointer to
294// the beginning of the translated message, if found; and an empty string
295// otherwise.
296void
297DjVuMessageLite::LookUpID( const GUTF8String &xmsgID,
298                       GUTF8String &message_text,
299                       GUTF8String &message_number ) const
300{
301  if(!Map.isempty())
302  {
303    GUTF8String msgID = xmsgID;
304#if HAS_CTRL_C_IN_ERR_MSG
305    int start = 0;
306    while (msgID[start] == '\003') 
307      start ++;
308    if (start > 0)
309      msgID = msgID.substr(start, msgID.length() - start);
310#endif
311    GPosition pos=Map.contains(msgID);
312    if(pos)
313    {
314      const GP<lt_XMLTags> tag=Map[pos];
315      GPosition valuepos=tag->get_args().contains(valuestring);
316      if(valuepos)
317      {
318        message_text=tag->get_args()[valuepos];
319      }else
320      {
321        const GUTF8String raw(tag->get_raw());
322        const int start_line=raw.search((unsigned long)'\n',0);
323     
324        const int start_text=raw.nextNonSpace(0);
325        const int end_text=raw.firstEndSpace(0);
326        if(start_line<0 || start_text<0 || start_text < start_line)
327        {
328          message_text=raw.substr(0,end_text).fromEscaped();
329        }else
330        {
331          message_text=raw.substr(start_line+1,end_text-start_line-1).fromEscaped();
332        }
333      }
334      GPosition numberpos=tag->get_args().contains(numberstring);
335      if(numberpos)
336      {
337        message_number=tag->get_args()[numberpos];
338      }
339    }
340  }
341}
342
343
344// Insert a string into the message text. Will insert into any field
345// description.  Except for an ArgId of zero (message number), if the ArgId
346// is not found, the routine adds a line with the parameter so information
347// will not be lost.
348void
349DjVuMessageLite::InsertArg( GUTF8String &message,
350  const int ArgId, const GUTF8String &arg ) const
351{
352    // argument target string
353  const GUTF8String target= "%"+GUTF8String(ArgId)+"!";
354    // location of target string
355  int format_start = message.search( (const char *)target );
356  if( format_start >= 0 )
357  {
358    do
359    {
360      const int n=format_start+target.length()+1;
361      const int format_end=message.search((unsigned long)'!',n);
362      if(format_end > format_start)
363      { 
364        const int len=1+format_end-n;
365        if(len && isascii(message[n-1]))
366        {
367          GUTF8String narg;
368          GUTF8String format="%"+message.substr(n-1,len);
369          switch(format[len])
370          {
371            case 'd':
372            case 'i':
373              narg.format((const char *)format,arg.toInt());
374              break;
375            case 'u':
376            case 'o':
377            case 'x':
378            case 'X':
379              narg.format((const char *)format,(unsigned int)arg.toInt());
380              break;
381            case 'f':
382              {
383                int endpos;
384                narg.format((const char *)format, arg.toDouble(0,endpos));
385                if( endpos < 0 )
386                  narg = arg;
387              }
388              break;
389            default:
390              narg.format((const char *)format,(const char *)arg);
391              break;
392          }
393          message = message.substr( 0, format_start )+narg
394            +message.substr( format_end+1, -1 );
395        }else
396        {
397          message = message.substr( 0, format_start )+arg
398            +message.substr( format_end+1, -1 );
399        }
400      }
401      format_start=message.search((const char*)target, format_start+arg.length());
402    } while(format_start >= 0);
403  }
404  else
405  {
406    //  Not found, fake it
407    if( ArgId != 0 )
408    {
409      message += "\n"+LookUpSingle(uparameter+("\t"+arg));
410    }
411  }
412}
413
414
415//  A C function to perform a message lookup. Arguments are a buffer to received the
416//  translated message, a buffer size (bytes), and a message_list. The translated
417//  result is returned in msg_buffer encoded in UTF-8. In case of error, msg_buffer is
418//  empty (i.e., msg_buffer[0] == '\0').
419void 
420DjVuMessageLite_LookUp( char *msg_buffer, const unsigned int buffer_size, const char *message )
421{
422  GUTF8String converted = DjVuMessageLite::LookUpUTF8( message );
423  if( converted.length() >= buffer_size )
424    msg_buffer[0] = '\0';
425  else
426    strcpy( msg_buffer, converted );
427}
428
429void
430DjVuMessageLite::AddByteStream(const GP<ByteStream> &bs)
431{
432  const GP<lt_XMLTags> gtags(lt_XMLTags::create(bs));
433  lt_XMLTags &tags=*gtags;
434  GPList<lt_XMLTags> Bodies=tags.get_Tags(bodystring);
435  if(! Bodies.isempty())
436  {
437    lt_XMLTags::get_Maps(messagestring,namestring,Bodies,Map);
438  }
439}
440
441
442
443#ifdef HAVE_NAMESPACES
444}
445# ifndef NOT_USING_DJVU_NAMESPACE
446using namespace DJVU;
447# endif
448#endif
449
450void
451DjVuWriteError( const char *message )
452{
453  G_TRY {
454    GP<ByteStream> errout = ByteStream::get_stderr();
455    if (errout)
456      {
457        const GUTF8String external = DjVuMessageLite::LookUpUTF8( message );
458        errout->writestring(external+"\n");
459      }
460    // Need to catch all exceptions because these might be
461    // called from an outer exception handler (with prejudice)
462  } G_CATCH_ALL { } G_ENDCATCH;
463}
464
465void
466DjVuWriteMessage( const char *message )
467{
468  G_TRY {
469    GP<ByteStream> strout = ByteStream::get_stdout();
470    if (strout)
471      {
472        const GUTF8String external = DjVuMessageLite::LookUpUTF8( message );
473        strout->writestring(external+"\n");
474      }
475    // Need to catch all exceptions because these might be
476    // called from an outer exception handler (with prejudice)
477  } G_CATCH_ALL { } G_ENDCATCH;
478}
Note: See TracBrowser for help on using the repository browser.