source: trunk/libdjvu/DjVuMessageLite.cpp @ 280

Last change on this file since 280 was 280, checked in by rbri, 11 years ago

DJVU plugin: djvulibre updated to version 3.5.22

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