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 #ifdef HAVE_CONFIG_H
57 # include "config.h"
58 #endif
59 #if NEED_GNUG_PRAGMAS
60 # pragma implementation
61 #endif
62 
63 #include "DjVuDumpHelper.h"
64 #include "DataPool.h"
65 #include "DjVmDir.h"
66 #include "DjVuInfo.h"
67 #include "IFFByteStream.h"
68 
69 
70 #ifdef HAVE_NAMESPACES
71 namespace DJVU {
72 # ifdef NOT_DEFINED // Just to fool emacs c++ mode
73 }
74 #endif
75 #endif
76 
77 
78 #ifdef putchar
79 #undef putchar
80 #endif
81 
82 struct DjVmInfo
83 {
84   GP<DjVmDir> dir;
85   GPMap<int,DjVmDir::File> map;
86 };
87 
88 inline static void
putchar(ByteStream & str,char ch)89 putchar(ByteStream & str, char ch)
90 {
91    str.write(&ch, 1);
92 }
93 
94 // ---------- ROUTINES FOR SUMMARIZING CHUNK DATA
95 
96 static void
display_djvu_info(ByteStream & out_str,IFFByteStream & iff,GUTF8String,size_t size,DjVmInfo &,int)97 display_djvu_info(ByteStream & out_str, IFFByteStream &iff,
98 		  GUTF8String, size_t size, DjVmInfo&, int)
99 {
100   GP<DjVuInfo> ginfo=DjVuInfo::create();
101   DjVuInfo &info=*ginfo;
102   info.decode(*iff.get_bytestream());
103   if (size >= 4)
104     out_str.format( "DjVu %dx%d", info.width, info.height);
105   if (size >= 5)
106     out_str.format( ", v%d", info.version);
107   if (size >= 8)
108     out_str.format( ", %d dpi", info.dpi);
109   if (size >= 9)
110     out_str.format( ", gamma=%3.1f", info.gamma);
111 }
112 
113 static void
display_djbz(ByteStream & out_str,IFFByteStream & iff,GUTF8String,size_t,DjVmInfo &,int)114 display_djbz(ByteStream & out_str, IFFByteStream &iff,
115 	     GUTF8String, size_t, DjVmInfo&, int)
116 {
117   out_str.format( "JB2 shared dictionary");
118 }
119 
120 static void
display_fgbz(ByteStream & out_str,IFFByteStream & iff,GUTF8String,size_t,DjVmInfo &,int)121 display_fgbz(ByteStream & out_str, IFFByteStream &iff,
122 	     GUTF8String, size_t, DjVmInfo&, int)
123 {
124   GP<ByteStream> gbs = iff.get_bytestream();
125   int version = gbs->read8();
126   int size = gbs->read16();
127   out_str.format( "JB2 colors data, v%d, %d colors",
128                   version & 0x7f, size);
129 }
130 
131 static void
display_sjbz(ByteStream & out_str,IFFByteStream & iff,GUTF8String,size_t,DjVmInfo &,int)132 display_sjbz(ByteStream & out_str, IFFByteStream &iff,
133 	     GUTF8String, size_t, DjVmInfo&, int)
134 {
135   out_str.format( "JB2 bilevel data");
136 }
137 
138 static void
display_smmr(ByteStream & out_str,IFFByteStream & iff,GUTF8String,size_t,DjVmInfo &,int)139 display_smmr(ByteStream & out_str, IFFByteStream &iff,
140 	     GUTF8String, size_t, DjVmInfo&, int)
141 {
142   out_str.format( "G4/MMR stencil data");
143 }
144 
145 static void
display_iw4(ByteStream & out_str,IFFByteStream & iff,GUTF8String,size_t,DjVmInfo &,int)146 display_iw4(ByteStream & out_str, IFFByteStream &iff,
147 	    GUTF8String, size_t, DjVmInfo&, int)
148 {
149   GP<ByteStream> gbs = iff.get_bytestream();
150   unsigned char serial = gbs->read8();
151   unsigned char slices = gbs->read8();
152   out_str.format( "IW4 data #%d, %d slices", serial+1, slices);
153   if (serial == 0)
154     {
155       unsigned char major = gbs->read8();
156       unsigned char minor = gbs->read8();
157       unsigned char xhi = gbs->read8();
158       unsigned char xlo = gbs->read8();
159       unsigned char yhi = gbs->read8();
160       unsigned char ylo = gbs->read8();
161       out_str.format( ", v%d.%d (%s), %dx%d", major & 0x7f, minor,
162                       (major & 0x80 ? "b&w" : "color"),
163                       (xhi<<8)+xlo, (yhi<<8)+ylo );
164     }
165 }
166 
167 static void
display_djvm_dirm(ByteStream & out_str,IFFByteStream & iff,GUTF8String head,size_t,DjVmInfo & djvminfo,int)168 display_djvm_dirm(ByteStream & out_str, IFFByteStream & iff,
169 		  GUTF8String head, size_t, DjVmInfo& djvminfo, int)
170 {
171   GP<DjVmDir> dir = DjVmDir::create();
172   dir->decode(iff.get_bytestream());
173   GPList<DjVmDir::File> list = dir->get_files_list();
174   if (dir->is_indirect())
175   {
176     out_str.format( "Document directory (indirect, %d files %d pages)",
177 	                  dir->get_files_num(), dir->get_pages_num());
178     for (GPosition p=list; p; ++p)
179       out_str.format( "\n%s%s -> %s", (const char*)head,
180                       (const char*)list[p]->get_load_name(), (const char*)list[p]->get_save_name() );
181   }
182   else
183   {
184     out_str.format( "Document directory (bundled, %d files %d pages)",
185 	                  dir->get_files_num(), dir->get_pages_num());
186     djvminfo.dir = dir;
187     djvminfo.map.empty();
188     for (GPosition p=list; p; ++p)
189       djvminfo.map[list[p]->offset] = list[p];
190   }
191 }
192 
193 static void
display_th44(ByteStream & out_str,IFFByteStream & iff,GUTF8String,size_t,DjVmInfo & djvminfo,int counter)194 display_th44(ByteStream & out_str, IFFByteStream & iff,
195 	     GUTF8String, size_t, DjVmInfo & djvminfo, int counter)
196 {
197    int start_page=-1;
198    if (djvminfo.dir)
199    {
200       GPList<DjVmDir::File> files_list=djvminfo.dir->get_files_list();
201       for(GPosition pos=files_list;pos;++pos)
202       {
203 	 GP<DjVmDir::File> frec=files_list[pos];
204 	 if (iff.tell()>=frec->offset &&
205 	     iff.tell()<frec->offset+frec->size)
206 	 {
207 	    while(pos && !files_list[pos]->is_page())
208 	       ++pos;
209 	    if (pos)
210 	       start_page=files_list[pos]->get_page_num();
211 	    break;
212 	 }
213       }
214    }
215    if (start_page>=0)
216       out_str.format( "Thumbnail icon for page %d", start_page+counter+1);
217    else
218       out_str.format( "Thumbnail icon");
219 }
220 
221 static void
display_incl(ByteStream & out_str,IFFByteStream & iff,GUTF8String,size_t,DjVmInfo &,int)222 display_incl(ByteStream & out_str, IFFByteStream & iff,
223 	     GUTF8String, size_t, DjVmInfo&, int)
224 {
225    GUTF8String name;
226    char ch;
227    while(iff.read(&ch, 1) && ch!='\n')
228      name += ch;
229    out_str.format( "Indirection chunk --> {%s}", (const char *) name);
230 }
231 
232 static void
display_anno(ByteStream & out_str,IFFByteStream & iff,GUTF8String,size_t,DjVmInfo &,int)233 display_anno(ByteStream & out_str, IFFByteStream &iff,
234 	     GUTF8String, size_t, DjVmInfo&, int)
235 {
236    out_str.format( "Page annotation");
237    GUTF8String id;
238    iff.short_id(id);
239    out_str.format( " (hyperlinks, etc.)");
240 }
241 
242 static void
display_text(ByteStream & out_str,IFFByteStream & iff,GUTF8String,size_t,DjVmInfo &,int)243 display_text(ByteStream & out_str, IFFByteStream &iff,
244 	     GUTF8String, size_t, DjVmInfo&, int)
245 {
246    out_str.format( "Hidden text");
247    GUTF8String id;
248    iff.short_id(id);
249    out_str.format( " (text, etc.)");
250 }
251 
252 struct displaysubr
253 {
254   const char *id;
255   void (*subr)(ByteStream &, IFFByteStream &, GUTF8String,
256 	       size_t, DjVmInfo&, int counter);
257 };
258 
259 static displaysubr disproutines[] =
260 {
261   { "DJVU.INFO", display_djvu_info },
262   { "DJVU.Smmr", display_smmr },
263   { "DJVU.Sjbz", display_sjbz },
264   { "DJVU.Djbz", display_djbz },
265   { "DJVU.FG44", display_iw4 },
266   { "DJVU.BG44", display_iw4 },
267   { "DJVU.FGbz", display_fgbz },
268   { "DJVI.Sjbz", display_sjbz },
269   { "DJVI.Djbz", display_djbz },
270   { "DJVI.FGbz", display_fgbz },
271   { "DJVI.FG44", display_iw4 },
272   { "DJVI.BG44", display_iw4 },
273   { "BM44.BM44", display_iw4 },
274   { "PM44.PM44", display_iw4 },
275   { "DJVM.DIRM", display_djvm_dirm },
276   { "THUM.TH44", display_th44 },
277   { "INCL", display_incl },
278   { "ANTa", display_anno },
279   { "ANTz", display_anno },
280   { "TXTa", display_text },
281   { "TXTz", display_text },
282   { 0, 0 },
283 };
284 
285 // ---------- ROUTINES FOR DISPLAYING CHUNK STRUCTURE
286 
287 static void
display_chunks(ByteStream & out_str,IFFByteStream & iff,const GUTF8String & head,DjVmInfo djvminfo)288 display_chunks(ByteStream & out_str, IFFByteStream &iff,
289 	       const GUTF8String &head, DjVmInfo djvminfo)
290 {
291   size_t size;
292   GUTF8String id, fullid;
293   GUTF8String head2 = head + "  ";
294   GPMap<int,DjVmDir::File> djvmmap;
295   int rawoffset;
296   GMap<GUTF8String, int> counters;
297 
298   while ((size = iff.get_chunk(id, &rawoffset)))
299   {
300     if (!counters.contains(id)) counters[id]=0;
301     else counters[id]++;
302 
303     GUTF8String msg;
304     msg.format("%s%s [%d] ", (const char *)head, (const char *)id, size);
305     out_str.format( "%s", (const char *)msg);
306     // Display DJVM is when adequate
307     if (djvminfo.dir)
308     {
309       GP<DjVmDir::File> rec = djvminfo.map[rawoffset];
310       if (rec)
311         {
312           GUTF8String id = rec->get_load_name();
313           GUTF8String title = rec->get_title();
314           out_str.format( "{%s}", (const char*) id);
315           if (rec->is_include())
316             out_str.format(" [I]");
317           if (rec->is_thumbnails())
318             out_str.format(" [T]");
319           if (rec->is_shared_anno())
320             out_str.format(" [S]");
321           if (rec->is_page())
322             out_str.format(" [P%d]", rec->get_page_num()+1);
323           if (id != title)
324             out_str.format(" (%s)", (const char*)title);
325         }
326     }
327     // Test chunk type
328     iff.full_id(fullid);
329     for (int i=0; disproutines[i].id; i++)
330       if (fullid == disproutines[i].id || id == disproutines[i].id)
331       {
332         int n = msg.length();
333         while (n++ < 14+(int) head.length()) putchar(out_str, ' ');
334         if (!iff.composite()) out_str.format( "    ");
335         (*disproutines[i].subr)(out_str, iff, head2,
336                                 size, djvminfo, counters[id]);
337         break;
338       }
339     // Default display of composite chunk
340     out_str.format( "\n");
341     if (iff.composite())
342       display_chunks(out_str, iff, head2, djvminfo);
343     // Terminate
344     iff.close_chunk();
345   }
346 }
347 
348 GP<ByteStream>
dump(const GP<DataPool> & pool)349 DjVuDumpHelper::dump(const GP<DataPool> & pool)
350 {
351    return dump(pool->get_stream());
352 }
353 
354 GP<ByteStream>
dump(GP<ByteStream> gstr)355 DjVuDumpHelper::dump(GP<ByteStream> gstr)
356 {
357    GP<ByteStream> out_str=ByteStream::create();
358    GUTF8String head="  ";
359    GP<IFFByteStream> iff=IFFByteStream::create(gstr);
360    DjVmInfo djvminfo;
361    display_chunks(*out_str, *iff, head, djvminfo);
362    return out_str;
363 }
364 
365 
366 #ifdef HAVE_NAMESPACES
367 }
368 # ifndef NOT_USING_DJVU_NAMESPACE
369 using namespace DJVU;
370 # endif
371 #endif
372