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 #ifndef _GIFFMANAGER_H
57 #define _GIFFMANAGER_H
58 #ifdef HAVE_CONFIG_H
59 #include "config.h"
60 #endif
61 #if NEED_GNUG_PRAGMAS
62 # pragma interface
63 #endif
64 
65 
66 #include "IFFByteStream.h"
67 #include "GContainer.h"
68 #include "Arrays.h"
69 #include "GSmartPointer.h"
70 #include "GString.h"
71 
72 #ifdef HAVE_NAMESPACES
73 namespace DJVU {
74 # ifdef NOT_DEFINED // Just to fool emacs c++ mode
75 }
76 #endif
77 #endif
78 
79 
80 /** @name GIFFManager.h
81 
82     Files #"GIFFManager.h"# and #"GIFFManager.cpp"# define more convenient
83     interface to IFF files. You may want to use the {\Ref GIFFManager} class
84     instead of coping with {\Ref IFFByteStream} especially when you have to
85     insert or move chunks, which is a kind of tricky with sequential access
86     provided by {\Ref IFFByteStream}.
87 
88     You will mostly deal with {\Ref GIFFManager} class, but sometimes you may
89     want to use {\Ref GIFFChunk}s as well thus bypassing {\Ref GIFFManager}'s
90     interface and working with the chunks hierarchy yourself.
91 
92     Interface to IFF files.
93     @author
94     Andrei Erofeev <eaf@geocities.com> -- Initial implementation.
95 */
96 
97 /** #GIFFChunk# is the base class for other IFF chunks understood by
98     {\Ref GIFFManager}. It provides some basic interface, and is not supposed
99     to be used on its own. */
100 
101 class GIFFChunk : public GPEnabled
102 {
103 protected:
104    GIFFChunk(void);
105    GIFFChunk(const GUTF8String &name);
106    GIFFChunk(const GUTF8String &name, const TArray<char> & data);
107 public:
108       /// Default creator.
create(void)109    static GP<GIFFChunk> create(void) {return new GIFFChunk();}
110 
111       /** Creates the chunk with the given name. The {\em name} may not
112 	  contain dots colons or brackets */
create(const GUTF8String & name)113    static GP<GIFFChunk> create(const GUTF8String &name)
114    {return new GIFFChunk(name);}
115 
116       /** Creates the {\em plain chunk} containing raw data */
create(const GUTF8String & name,const TArray<char> & data)117    static GP<GIFFChunk> create(const GUTF8String &name, const TArray<char> & data)
118    { return new GIFFChunk(name,data); }
119 
120       /// Destructor
121    virtual ~GIFFChunk(void);
122 
123       /// Returns the name of the chunk (without possible #FORM:# or similar prefixes)
124    GUTF8String	get_name(void) const;
125       /// Returns full chunk name, with possible container specification
126    GUTF8String	get_full_name(void) const;
127       /// Returns the chunk type, like #CAT# for chunk #CAT:DJVU#
128    GUTF8String	get_type(void) const;
129       /// Returns TRUE if the chunk may contain other chunks or FALSE otherwise
130    bool		is_container(void) const;
131       /** Sets the chunk name. The {\em name} may not contain dots or brackets,
132 	  but {\bf may} contain colons. */
133    void		set_name(GUTF8String name);
134       /** Parses the {\em name} probably containing colon and compares it
135 	  with its own name returning TRUE if they are the same */
136    bool		check_name(GUTF8String name);
137 
138       /** Adds the {\em chunk} to the chunks list at position {\em order}.
139 	  Set {\em order} to #-1# to append the chunk to the list.
140           {\bf Note!} By adding chunk #PROP# you will convert this chunk
141           to type #LIST# {\em automatically}. */
142    void		add_chunk(const GP<GIFFChunk> & chunk, int order=-1);
143       /** Removes the chunk with given {\em name}. The {\em name} may not
144 	  contain dots, but MAY contain colons and brackets (the latter -
145 	  for specifying the chunk number) */
146    void		del_chunk(const GUTF8String &name);
147       /** Returns the chunk with given {\em name}. The {\em name} may not
148 	  contain dots, but MAY contain colons and brackets (the latter -
149 	  for specifying the chunk number). If {\em position} is not zero
150 	  then the chunk position in its parent will be put into #*position# */
151    GP<GIFFChunk>get_chunk(const GUTF8String &name, int * position=0);
152       /** Returns the number of chunks with given {\em name}. The {\em name}
153 	  may not contain dots and brackets. If {\em name} is ZERO, the
154 	  total number of chunks will be returned. */
155    int		get_chunks_number(const GUTF8String &name);
156    int		get_chunks_number(void);
157       /** Returns the data array for plain chunks */
158    TArray<char>	get_data(void) const;
159 
160       /** Saves the chunk into the {\Ref IFFByteStream}.
161 	  Set {\em use_trick} to #1# if this is a top-level chunk */
162    void		save(IFFByteStream & istr, bool use_trick=0);
163 private:
164    char			name[5];
165    GUTF8String		type;
166    GPList<GIFFChunk>	chunks;
167    TArray<char>		data;
168    static GUTF8String decode_name(const GUTF8String &name, int &number);
169 };
170 
171 inline GUTF8String
get_name(void)172 GIFFChunk::get_name(void) const { return GUTF8String(name, 4); }
173 
174 inline GUTF8String
get_type(void)175 GIFFChunk::get_type(void) const { return type; };
176 
177 inline GUTF8String
get_full_name(void)178 GIFFChunk::get_full_name(void) const { return get_type()+":"+get_name(); };
179 
180 inline bool
is_container(void)181 GIFFChunk::is_container(void) const { return type.length()!=0; };
182 
183 inline TArray<char>
get_data(void)184 GIFFChunk::get_data(void) const { return data; };
185 
186 inline
GIFFChunk(void)187 GIFFChunk::GIFFChunk(void) { name[0]=0; }
188 
189 inline
GIFFChunk(const GUTF8String & name)190 GIFFChunk::GIFFChunk(const GUTF8String &name) { set_name(name); }
191 
192 inline
GIFFChunk(const GUTF8String & name,const TArray<char> & data_in)193 GIFFChunk::GIFFChunk(const GUTF8String &name, const TArray<char> & data_in) :
194       data(data_in)
195 {
196    set_name(name);
197 }
198 
199 //************************************************************************
200 
201 /** Intuitive interface to IFF files.
202 
203     It's too terrible to keep reading/writing IFF files chunk after chunk
204     using {\Ref IFFByteStream}s. This class allows you to operate with chunks
205     as with structures or arrays without even caring about the byte streams.
206 
207     Some of the examples are below:
208     \begin{verbatim}
209        GP<GIFFChunk> chunk;
210        chunk=manager1.get_chunk("BG44[2]");
211        manager2.add_chunk(".FORM:DJVU.BG44[-1]", chunk);
212     \end{verbatim}
213 
214     {\bf Chunk name}
215     \begin{itemize}
216        \item Every chunk name may contain optional prefix #FORM:#, #LIST:#,
217              #PROP:# or #CAT:#. If the prefix is omitted and the chunk happens
218 	     to contain other chunks, #FORM:# will be assumed.
219        \item Every chunk name may be {\em short} or {\em complete}.
220              {\em short} chunk names may not contain dots as they're a
221 	     subchunks names with respect to a given chunk.
222 	     {\em complete} chunk names may contain dots. But there may be
223 	     or may not be the {\em leading dot} in the name. If the
224 	     {\em leading dot} is present, then the name is assumed to contain
225 	     the name of the top-level chunk as well. Otherwise it's treated
226 	     {\em with respect} to the top-level chunk. You may want to use
227 	     the leading dot only when you add a chunk to an empty document,
228 	     since a command like #manager.addChunk(".FORM:DJVU.BG44", chunk)#
229 	     will create the top level chunk of the requested type (#FORM:DJVU#)
230 	     and will add chunk #BG44# to it {\em automatically}.
231        \item You may use {\em brackets} in the name to specify the chunk's
232              position. The meaning of the number inside the brackets depends
233 	     on the function you call. In most of the cases this is the number
234 	     of the chunk with the given name in the parent chunk. But sometimes
235 	     (as in #addChunk(name, buffer, length)#) the brackets at the
236 	     end of the #name# actually specify the {\em position} of the
237 	     chunk in the parent. For example, to insert #INCL# chunk into
238 	     #DJVU# form at position #1# (make it the second) you may want to
239 	     use #manager.addChunk(".DJVU.INCL[1]", data, size)#. At the same
240 	     time, to get 2-nd chunk with name #BG44# from form #DJVU# you
241 	     should do smth like #chunk=manager.getChunk("BG44[1]")#. Note, that
242 	     here the manager will search for chunk #BG44# in form #DJVU# and
243 	     will take the second {\em found} one.
244     \end{itemize} */
245 
246 class GIFFManager : public GPEnabled
247 {
248 protected:
249    GIFFManager(void);
250    void init(void);
251    void init(const GUTF8String &name);
252 public:
253       /// Default creator.
254    static GP<GIFFManager> create(void);
255 
256       /** Creates the {\Ref GIFFManager} and assigns name {\em name} to
257 	  the top-level chunk. you may use chunk type names (before colon)
258 	  to set the top-level chunk type, or omit it to work with #FORM# */
259    static GP<GIFFManager> create(const GUTF8String &name);
260 
261       /// Virtual destructor.
262    virtual ~GIFFManager(void);
263 
264       /// Sets the name of the top level chunk to {\em name}
265    void		set_name(const GUTF8String &name);
266       /** Adds the chunk {\em chunk} to chunk with name {\em parent_name} at
267 	  position {\em pos}. {\em parent_name} may contain dots, brackets
268 	  and colons. All missing chunks in the chain will be created.
269 
270 	  {\bf Examples:}
271 	  \begin{verbatim}
272 	     ;; To set the top-level chunk to 'ch'
273 	     m.addChunk(".", ch);
274 	     ;; To add 'ch' to the top-level chunk "DJVU" creating it if necessary
275 	     m.addChunk(".DJVU", ch);
276 	     ;; Same as above regardless of top-level chunk name
277 	     m.addChunk("", ch);
278 	     ;; To add 'ch' to 2nd FORM DJVU in top-level form DJVM
279 	     m.addChunk(".FORM:DJVM.FORM:DJVU[1]", ch);
280 	     ;; Same thing regardless of the top-level chunk name
281 	     m.addChunk("FORM:DJVU[1]", ch);
282 	  \end{verbatim} */
283    void		add_chunk(GUTF8String parent_name, const GP<GIFFChunk> & chunk, int pos=-1);
284       /** If {\em name}={\em name1}.{\em name2} where {\em name2} doesn't
285 	  contain dots, then #addChunk()# will create plain chunk with
286 	  name {\em name2} with data {\em buffer} of size {\em length} and
287 	  will add it to chunk {\em name1} in the same way as
288 	  #addChunk(name, chunk, pos)# function would do it. The #pos# in
289 	  this case is either #-1# (append) or is extracted from between
290           brackets if the {\em name} ends with them.
291 
292           {\bf Examples:}
293           \begin{verbatim}
294              ;; To insert INCL chunk at position 2 (make it 3rd)
295              m.addChunk("INCL[2]", data, length);
296              ;; To append chunk BG44 to 2nd DjVu file inside DjVm archive:
297              m.addChunk(".DJVM.DJVU[1].BG44", data, length);
298           \end{verbatim} */
299    void		add_chunk(GUTF8String name, const TArray<char> & data);
300       /** Will remove chunk with name {\em name}. You may use dots, colons
301 	  and brackets to specify the chunk uniquely.
302 
303 	  {\bf Examples:}
304 	  \begin{verbatim}
305 	     ;; To remove 2nd DjVu document from DjVm archive use
306 	     m.delChunk(".DJVM.DJVU[1]");
307 	     ;; Same thing without top-level chunk name specification
308 	     m.delChunk("DJVU[1]");
309 	     ;; Same thing for the first DJVU chunk
310 	     m.delChunk("DJVU");
311 	  \end{verbatim}
312       */
313    void		del_chunk(GUTF8String name);
314    void		del_chunk(void);
315       /** Will return the number of chunks with given name. The {\em name} may
316 	  not end with brackets, but may contain them inside. It may also
317 	  contain dots and colons. If {\em name} is ZERO, the total number
318 	  of chunks will be returned.
319 
320 	  {\bf Examples:}
321 	  \begin{verbatim}
322 	     ;; To get the number of DJVU forms inside DjVm document
323 	     m.getChunksNumber(".DJVM.DJVU");
324 	     ;; Same thing without top-level chunk name specification
325 	     m.getChunksNumber("DJVU");
326 	  \end{verbatim}
327       */
328    int		get_chunks_number(const GUTF8String &name);
329    int		get_chunks_number(void);
330 
331       /** Returns the chunk with name {\em name}. The {\em name} may contain dots
332 	  colons and slashes. If {\em position} is not zero, #*position# will
333 	  be assigned the position of the found chunk in the parent chunk.
334 
335 	  {\bf Examples:}
336 	  \begin{verbatim}
337 	     ;; To get the directory chunk of DjVm document
338 	     m.getChunk(".DJVM.DIR0");
339 	     ;; To get chunk corresponding to 2nd DJVU form
340 	     m.getChunk(".DJVU[1]");
341 	  \end{verbatim} */
342    GP<GIFFChunk>get_chunk(GUTF8String name, int * position=0);
343 
344       /** Loads the composite {\em chunk}'s contents from stream {\em istr}. */
345    void		load_chunk(IFFByteStream & istr, GP<GIFFChunk> chunk);
346       /** Loads the file contents from stream {\em str} */
347    void		load_file(GP<ByteStream> str);
348       /** Loads the file contents from the data array {\em data} */
349    void		load_file(const TArray<char> & data);
350       /** Saves all the chunks into stream {\em str} */
351    void		save_file(GP<ByteStream> str);
352       /** Saves all the chunks into the data array {\em data} */
353    void		save_file(TArray<char> & data);
354 
355 private:
356    GP<GIFFChunk>	top_level;
357 
358    static const char *	check_leading_dot(const GUTF8String &name);
359 private: //dummy methods
360    static void save_file(ByteStream *);
361    static void load_file(ByteStream *);
362 };
363 
364 inline void
set_name(const GUTF8String & name)365 GIFFManager::set_name(const GUTF8String &name)
366 {
367    top_level->set_name(name);
368 }
369 
370 inline
GIFFManager(void)371 GIFFManager::GIFFManager(void) {}
372 
373 inline  void
init(void)374 GIFFManager::init(void)
375 {
376   top_level=GIFFChunk::create();
377 }
378 
379 inline  void
init(const GUTF8String & name)380 GIFFManager::init(const GUTF8String &name)
381 {
382   top_level=GIFFChunk::create(name);
383 }
384 
385 
386 #ifdef HAVE_NAMESPACES
387 }
388 # ifndef NOT_USING_DJVU_NAMESPACE
389 using namespace DJVU;
390 # endif
391 #endif
392 #endif
393