001/*
002 * $RCSfile: HeaderDecoder.java,v $
003 * $Revision: 1.2 $
004 * $Date: 2006/09/28 00:55:20 $
005 * $State: Exp $
006 *
007 * Class:                   HeaderDecoder
008 *
009 * Description:             Reads main and tile-part headers.
010 *
011 *
012 *
013 * COPYRIGHT:
014 *
015 * This software module was originally developed by Raphaël Grosbois and
016 * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
017 * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
018 * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
019 * Centre France S.A) in the course of development of the JPEG2000
020 * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
021 * software module is an implementation of a part of the JPEG 2000
022 * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
023 * Systems AB and Canon Research Centre France S.A (collectively JJ2000
024 * Partners) agree not to assert against ISO/IEC and users of the JPEG
025 * 2000 Standard (Users) any of their rights under the copyright, not
026 * including other intellectual property rights, for this software module
027 * with respect to the usage by ISO/IEC and Users of this software module
028 * or modifications thereof for use in hardware or software products
029 * claiming conformance to the JPEG 2000 Standard. Those intending to use
030 * this software module in hardware or software products are advised that
031 * their use may infringe existing patents. The original developers of
032 * this software module, JJ2000 Partners and ISO/IEC assume no liability
033 * for use of this software module or modifications thereof. No license
034 * or right to this software module is granted for non JPEG 2000 Standard
035 * conforming products. JJ2000 Partners have full right to use this
036 * software module for his/her own purpose, assign or donate this
037 * software module to any third party and to inhibit third parties from
038 * using this software module for non JPEG 2000 Standard conforming
039 * products. This copyright notice must be included in all copies or
040 * derivative works of this software module.
041 *
042 * Copyright (c) 1999/2000 JJ2000 Partners.
043 * */
044package jj2000.j2k.codestream.reader;
045import java.awt.Point;
046import java.io.ByteArrayInputStream;
047import java.io.ByteArrayOutputStream;
048import java.io.DataInputStream;
049import java.io.EOFException;
050import java.io.IOException;
051import java.util.Hashtable;
052import java.util.Vector;
053
054import jj2000.j2k.ModuleSpec;
055import jj2000.j2k.NotImplementedError;
056import jj2000.j2k.codestream.CorruptedCodestreamException;
057import jj2000.j2k.codestream.HeaderInfo;
058import jj2000.j2k.codestream.Markers;
059import jj2000.j2k.codestream.ProgressionType;
060import jj2000.j2k.decoder.DecoderSpecs;
061import jj2000.j2k.entropy.StdEntropyCoderOptions;
062import jj2000.j2k.entropy.decoder.CodedCBlkDataSrcDec;
063import jj2000.j2k.entropy.decoder.EntropyDecoder;
064import jj2000.j2k.entropy.decoder.StdEntropyDecoder;
065import jj2000.j2k.io.RandomAccessIO;
066import jj2000.j2k.quantization.dequantizer.CBlkQuantDataSrcDec;
067import jj2000.j2k.quantization.dequantizer.Dequantizer;
068import jj2000.j2k.quantization.dequantizer.StdDequantizer;
069import jj2000.j2k.quantization.dequantizer.StdDequantizerParams;
070import jj2000.j2k.roi.MaxShiftSpec;
071import jj2000.j2k.roi.ROIDeScaler;
072import jj2000.j2k.util.FacilityManager;
073import jj2000.j2k.util.MsgLogger;
074import jj2000.j2k.wavelet.FilterTypes;
075import jj2000.j2k.wavelet.synthesis.SynWTFilter;
076import jj2000.j2k.wavelet.synthesis.SynWTFilterFloatLift9x7;
077import jj2000.j2k.wavelet.synthesis.SynWTFilterIntLift5x3;
078
079import com.github.jaiimageio.jpeg2000.impl.J2KImageReadParamJava;
080
081/**
082 * This class reads Main and Tile-part headers from the codestream. It is
083 * created by the run() method of the Decoder instance.
084 *
085 * <p>A marker segment includes a marker and eventually marker segment
086 * parameters. It is designed by the three letters code of the marker
087 * associated with the marker segment. JPEG 2000 part 1 defines 6 types of
088 * markers:
089 *
090 * <ul>
091 * <li> Delimiting : SOC,SOT (read in FileBitstreamReaderAgent),SOD,EOC
092 * (read in FileBitstreamReaderAgent).</li> <li> Fixed information: SIZ.</li>
093 *
094 * <li> Functional: COD,COC,RGN,QCD,QCC,POC.</li> <li> In bit-stream:
095 * SOP,EPH.</li>
096 *
097 * <li> Pointer: TLM,PLM,PLT,PPM,PPT.</li>
098 *
099 * <li> Informational: CRG,COM.</li>
100 * </ul>
101 *
102 * <p>The main header is read when the constructor is called whereas tile-part
103 * headers are read when the FileBitstreamReaderAgent instance is created. The
104 * reading is done in 2 passes:
105 *
106 * <ul>
107 * <li>All marker segments are buffered and their corresponding flag is
108 * activated (extractMainMarkSeg and extractTilePartMarkSeg methods).</li>
109 *
110 * <li>Buffered marker segment are analyzed in a logical way and
111 * specifications are stored in appropriate member of DecoderSpecs instance
112 * (readFoundMainMarkSeg and readFoundTilePartMarkSeg methods).</li>
113 * </ul>
114 *
115 * <p>Whenever a marker segment is not recognized a warning message is
116 * displayed and its length parameter is used to skip it.
117 *
118 * @see DecoderSpecs
119 * @see Decoder
120 * @see FileBitstreamReaderAgent
121 * */
122public class HeaderDecoder implements ProgressionType, Markers,
123                                      StdEntropyCoderOptions {
124
125    /** The prefix for header decoder options: 'H' */
126    public final static char OPT_PREFIX = 'H';
127
128    /** The list of parameters that is accepted for quantization. Options
129     * for quantization start with 'Q'. */
130    private final static String [][] pinfo = null;
131
132    /** The reference to the HeaderInfo instance holding the information found
133     * in headers */
134    private HeaderInfo hi;
135
136    /** Current header information in a string */
137    private String hdStr = "";
138
139    /** The J2KImageReadParamJava instance of the decoder */
140    private J2KImageReadParamJava j2krparam;
141
142    /** The number of tiles within the image */
143    private int nTiles;
144
145    /** The number of tile parts per tile */
146    public int[] nTileParts;
147
148    /** Used to store which markers have been already read, by using flag
149     * bits. The different markers are marked with XXX_FOUND flags, such as
150     * SIZ_FOUND */
151    private int nfMarkSeg = 0;
152
153    /** Counts number of COC markers found in the header */
154    private int nCOCMarkSeg = 0;
155
156    /** Counts number of QCC markers found in the header */
157    private int nQCCMarkSeg = 0;
158
159    /** Counts number of COM markers found in the header */
160    private int nCOMMarkSeg = 0;
161
162    /** Counts number of RGN markers found in the header */
163    private int nRGNMarkSeg = 0;
164
165    /** Counts number of PPM markers found in the header */
166    private int nPPMMarkSeg = 0;
167
168    /** Counts number of PPT markers found in the header */
169    private int[][] nPPTMarkSeg = null;
170
171    /** Flag bit for SIZ marker segment found */
172    private static final int SIZ_FOUND = 1;
173
174    /** Flag bit for COD marker segment found */
175    private static final int COD_FOUND = 1<<1;
176
177    /** Flag bit for COC marker segment found */
178    private static final int COC_FOUND = 1<<2;
179
180    /** Flag bit for QCD marker segment found */
181    private static final int QCD_FOUND = 1<<3;
182
183    /** Flag bit for TLM marker segment found */
184    private static final int TLM_FOUND = 1<<4;
185
186    /** Flag bit for PLM marker segment found */
187    private static final int PLM_FOUND = 1<<5;
188
189    /** Flag bit for SOT marker segment found */
190    private static final int SOT_FOUND = 1<<6;
191
192    /** Flag bit for PLT marker segment found */
193    private static final int PLT_FOUND = 1<<7;
194
195    /** Flag bit for QCC marker segment found */
196    private static final int QCC_FOUND = 1<<8;
197
198    /** Flag bit for RGN marker segment found */
199    private static final int RGN_FOUND = 1<<9;
200
201    /** Flag bit for POC marker segment found */
202    private static final int POC_FOUND = 1<<10;
203
204    /** Flag bit for COM marker segment found */
205    private static final int COM_FOUND = 1<<11;
206
207    /** Flag bit for SOD marker segment found */
208    public static final int SOD_FOUND = 1<<13;
209
210    /** Flag bit for SOD marker segment found */
211    public static final int PPM_FOUND = 1<<14;
212
213    /** Flag bit for SOD marker segment found */
214    public static final int PPT_FOUND = 1<<15;
215
216    /** Flag bit for CRG marker segment found */
217    public static final int CRG_FOUND = 1<<16;
218
219    /** The reset mask for new tiles */
220    private static final int TILE_RESET = ~(PLM_FOUND|SIZ_FOUND|RGN_FOUND);
221
222    /** HashTable used to store marker segment byte buffers */
223    private Hashtable ht = null;
224
225    /** The number of components in the image */
226    private int nComp;
227
228    /** The horizontal code-block partition origin */
229    private int cb0x = -1;
230
231    /** The vertical code-block partition origin */
232    private int cb0y = -1;
233
234    /** The decoder specifications */
235    private DecoderSpecs decSpec;
236
237    /** Is the precinct partition used */
238    boolean precinctPartitionIsUsed;
239
240    /** The offset of the main header in the input stream */
241    public int mainHeadOff;
242
243    /** Vector containing info as to which tile each tilepart belong */
244    public Vector tileOfTileParts;
245
246    /** Array containing the Nppm and Ippm fields of the PPM marker segments*/
247    private byte[][] pPMMarkerData;
248
249    /** Array containing the Ippm fields of the PPT marker segments */
250    private byte[][][][] tilePartPkdPktHeaders;
251
252    /** The packed packet headers if the PPM or PPT markers are used */
253    private ByteArrayOutputStream[] pkdPktHeaders;
254
255    /** 
256     * Return the maximum height among all components 
257     *
258     * @return Maximum component height
259     * */
260    public int getMaxCompImgHeight() { return hi.siz.getMaxCompHeight(); }
261
262    /** 
263     * Return the maximum width among all components 
264     *
265     * @return Maximum component width
266     * */
267    public int getMaxCompImgWidth() { return hi.siz.getMaxCompWidth(); }
268
269    /**
270     * Returns the image width in the reference grid.
271     *
272     * @return The image width in the reference grid
273     * */
274    public final int getImgWidth() { return hi.siz.xsiz-hi.siz.x0siz; }
275
276    /**
277     * Returns the image height in the reference grid.
278     *
279     * @return The image height in the reference grid
280     * */
281    public final int getImgHeight() { return hi.siz.ysiz-hi.siz.y0siz; }
282
283    /**
284     * Return the horizontal upper-left coordinate of the image in the
285     * reference grid.
286     *
287     * @return The horizontal coordinate of the image origin.
288     * */
289    public final int getImgULX() { return hi.siz.x0siz; }
290
291    /**
292     * Return the vertical upper-left coordinate of the image in the reference
293     * grid.
294     *
295     * @return The vertical coordinate of the image origin.
296     * */
297    public final int getImgULY() { return hi.siz.y0siz; }
298
299    /**
300     * Returns the nominal width of the tiles in the reference grid.
301     *
302     * @return The nominal tile width, in the reference grid.
303     * */
304    public final int getNomTileWidth() { return hi.siz.xtsiz; }
305
306    /**
307     * Returns the nominal width of the tiles in the reference grid.
308     *
309     * @return The nominal tile width, in the reference grid.
310     * */
311    public final int getNomTileHeight() { return hi.siz.ytsiz; }
312
313    /**
314     * Returns the tiling origin, referred to as '(Px,Py)' in the 'ImgData'
315     * interface.
316     *
317     * @param co If not null this object is used to return the information. If
318     * null a new one is created and returned.
319     *
320     * @return The coordinate of the tiling origin, in the canvas system, on
321     * the reference grid.
322     *
323     * @see jj2000.j2k.image.ImgData
324     * */
325    public final Point getTilingOrigin(Point co) {
326        if (co != null) {
327            co.x = hi.siz.xt0siz;
328            co.y = hi.siz.yt0siz;
329            return co;
330        }
331        else {
332            return new Point(hi.siz.xt0siz,hi.siz.yt0siz);
333        }
334    }
335
336    /**
337     * Returns true if the original data of the specified component was
338     * signed. If the data was not signed a level shift has to be applied at
339     * the end of the decompression chain.
340     *
341     * @param c The index of the component
342     *
343     * @return True if the original image component was signed.
344     * */
345    public final boolean isOriginalSigned(int c) {
346        return hi.siz.isOrigSigned(c);
347    }
348
349    /**
350     * Returns the original bitdepth of the specified component.
351     *
352     * @param c The index of the component
353     *
354     * @return The bitdepth of the component
355     * */
356    public final int getOriginalBitDepth(int c) {
357        return hi.siz.getOrigBitDepth(c);
358    }
359
360    /**
361     * Returns the number of components in the image.
362     *
363     * @return The number of components in the image.
364     * */
365    public final int getNumComps() {
366        return nComp;
367    }
368
369    /**
370     * Returns the component sub-sampling factor, with respect to the
371     * reference grid, along the horizontal direction for the specified
372     * component.
373     *
374     * @param c The index of the component
375     *
376     * @return The component sub-sampling factor X-wise.
377     * */
378    public final int getCompSubsX(int c) { return hi.siz.xrsiz[c]; }
379
380    /**
381     * Returns the component sub-sampling factor, with respect to the
382     * reference grid, along the vertical direction for the specified
383     * component.
384     *
385     * @param c The index of the component
386     *
387     * @return The component sub-sampling factor Y-wise.
388     * */
389    public final int getCompSubsY(int c) { return hi.siz.yrsiz[c]; }
390
391    /**
392     * Returns the dequantizer parameters. Dequantizer parameters normally are
393     * the quantization step sizes, see DequantizerParams.
394     *
395     * @param src The source of data for the dequantizer.
396     *
397     * @param rb The number of range bits for each component. Must be
398     * the number of range bits of the mixed components.
399     *
400     * @param decSpec2 The DecoderSpecs instance after any image manipulation.
401     *
402     * @return The dequantizer
403     * */
404    public final Dequantizer createDequantizer(CBlkQuantDataSrcDec src,
405                                               int rb[],
406                                               DecoderSpecs decSpec2) {
407        return new StdDequantizer(src,rb,decSpec2);
408    }
409
410    /**
411     * Returns the horizontal code-block partition origin.Allowable values are
412     * 0 and 1, nothing else.
413     * */
414    public final int getCbULX() {
415        return cb0x;
416    }
417
418    /**
419     * Returns the vertical code-block partition origin. Allowable values are
420     * 0 and 1, nothing else.
421     * */
422    public final int getCbULY() {
423        return cb0y;
424    }
425
426    /**
427     * Returns the precinct partition width for the specified tile-component
428     * and resolution level.
429     *
430     * @param c the component index
431     *
432     * @param t the tile index
433     *
434     * @param rl the resolution level
435     *
436     * @return The precinct partition width for the specified tile-component
437     * and resolution level
438     * */
439    public final int getPPX(int t,int c,int rl) {
440        return decSpec.pss.getPPX(t,c,rl);
441    }
442
443    /**
444     * Returns the precinct partition height for the specified component, tile
445     * and resolution level.
446     *
447     * @param c the component
448     *
449     * @param t the tile index
450     *
451     * @param rl the resolution level
452     *
453     * @return The precinct partition height for the specified component,
454     * tile and resolution level
455     * */
456    public final int getPPY(int t, int c, int rl) {
457        return decSpec.pss.getPPY(t, c, rl);
458    }
459
460    /**
461     * Returns the boolean used to know if the precinct partition is used
462     **/
463    public final boolean precinctPartitionUsed() {
464        return precinctPartitionIsUsed;
465    }
466
467    /**
468     * Reads a wavelet filter from the codestream and returns the filter
469     * object that implements it.
470     *
471     * @param ehs The encoded header stream from where to read the info
472     *
473     * @param filtIdx Int array of one element to return the type of the
474     * wavelet filter.
475     * */
476    private SynWTFilter readFilter(DataInputStream ehs,int[] filtIdx)
477        throws IOException {
478        int kid; // the filter id
479
480        kid = filtIdx[0] = ehs.readUnsignedByte();
481        if (kid >= (1<<7)) {
482            throw new NotImplementedError("Custom filters not supported");
483        }
484        // Return filter based on ID
485        switch (kid) {
486        case FilterTypes.W9X7:
487            return new SynWTFilterFloatLift9x7();
488        case FilterTypes.W5X3:
489            return new SynWTFilterIntLift5x3();
490        default:
491            throw new CorruptedCodestreamException("Specified wavelet filter "+
492                                                  "not"+
493                                                  " JPEG 2000 part I "+
494                                                  "compliant");
495        }
496    }
497
498    /**
499     * Checks that the marker segment length is correct. 
500     *
501     * @param ehs The encoded header stream
502     *
503     * @param str The string identifying the marker, such as "SIZ marker"
504     *
505     * @exception IOException If an I/O error occurs
506     * */
507    public void checkMarkerLength(DataInputStream ehs, String str)
508        throws IOException {
509        if (ehs.available()!=0) {
510            FacilityManager.getMsgLogger().
511                printmsg(MsgLogger.WARNING,
512                         str+" length was short, attempting to resync.");
513        }
514    }
515
516    /**
517     * Reads the SIZ marker segment and realigns the codestream at the point
518     * where the next marker segment should be found. 
519     *
520     * <p>SIZ is a fixed information marker segment containing informations
521     * about image and tile sizes. It is required in the main header
522     * immediately after SOC.</p>
523     *
524     * @param ehs The encoded header stream
525     *
526     * @exception IOException If an I/O error occurs while reading from the
527     * encoded header stream
528     * */
529    private void readSIZ (DataInputStream ehs) throws IOException {
530        HeaderInfo.SIZ ms = hi.getNewSIZ();
531        hi.siz = ms;
532
533        // Read the length of SIZ marker segment (Lsiz)
534        ms.lsiz = ehs.readUnsignedShort();
535
536        // Read the capability of the codestream (Rsiz)
537        ms.rsiz = ehs.readUnsignedShort();
538        if (ms.rsiz > 2) {
539            throw new Error("Codestream capabiities not JPEG 2000 - Part I"+
540                            " compliant");
541        }
542
543        // Read image size
544        ms.xsiz = ehs.readInt();
545        ms.ysiz = ehs.readInt();
546        if ( ms.xsiz<=0 || ms.ysiz<=0 ) {
547            throw new IOException("JJ2000 does not support images whose "+
548                                  "width and/or height not in the "+
549                                  "range: 1 -- (2^31)-1");
550        }
551
552        // Read image offset
553        ms.x0siz = ehs.readInt();
554        ms.y0siz = ehs.readInt();
555        if ( ms.x0siz<0 || ms.y0siz<0 ) {
556            throw new IOException("JJ2000 does not support images offset "+
557                                  "not in the range: 0 -- (2^31)-1");
558        }
559
560        // Read size of tile
561        ms.xtsiz = ehs.readInt();
562        ms.ytsiz = ehs.readInt();
563        if ( ms.xtsiz<=0 || ms.ytsiz<=0 ) {
564            throw new IOException("JJ2000 does not support tiles whose "+
565                                  "width and/or height are not in  "+
566                                  "the range: 1 -- (2^31)-1");
567        }
568
569        // Read upper-left tile offset
570        ms.xt0siz = ehs.readInt();
571        ms.yt0siz = ehs.readInt();
572        if ( ms.xt0siz<0 || ms.yt0siz<0 ){
573            throw new IOException("JJ2000 does not support tiles whose "+
574                                  "offset is not in  "+
575                                  "the range: 0 -- (2^31)-1");
576        }
577
578        // Read number of components and initialize related arrays
579        nComp = ms.csiz = ehs.readUnsignedShort();
580        if (nComp<1 || nComp>16384) {
581            throw new IllegalArgumentException("Number of component out of "+
582                                               "range 1--16384: "+nComp);
583        }
584
585        ms.ssiz = new int[nComp];
586        ms.xrsiz = new int[nComp];
587        ms.yrsiz = new int[nComp];
588
589        // Read bit-depth and down-sampling factors of each component
590        for(int i = 0; i<nComp; i++) {
591            ms.ssiz[i] = ehs.readUnsignedByte();
592            ms.xrsiz[i] = ehs.readUnsignedByte();
593            ms.yrsiz[i] = ehs.readUnsignedByte();
594        }
595
596        // Check marker length
597        checkMarkerLength(ehs,"SIZ marker");
598
599        // Create needed ModuleSpec
600        nTiles = ms.getNumTiles();
601
602        // Finish initialization of decSpec
603        decSpec = new DecoderSpecs(nTiles,nComp);
604    }
605
606    /** 
607     * Reads a CRG marker segment and checks its length. CRG is an
608     * informational marker segment that allows specific registration of
609     * components with respect to each other.
610     *
611     * @param ehs The encoded header stream
612     * */
613    private void readCRG (DataInputStream ehs) throws IOException {
614        HeaderInfo.CRG ms = hi.getNewCRG();
615        hi.crg = ms;
616
617        ms.lcrg = ehs.readUnsignedShort();
618        ms.xcrg = new int[nComp];
619        ms.ycrg = new int[nComp];
620
621        FacilityManager.getMsgLogger().
622            printmsg(MsgLogger.WARNING,"Information in CRG marker segment "+
623                     "not taken into account. This may affect the display "+
624                     "of the decoded image.");
625        for(int c=0; c<nComp; c++) {
626            ms.xcrg[c] = ehs.readUnsignedShort();
627            ms.ycrg[c] = ehs.readUnsignedShort();
628        }
629
630        // Check marker length
631        checkMarkerLength(ehs,"CRG marker");
632    }
633
634
635    /**
636     * Reads a COM marker segments and realigns the bit stream at the point
637     * where the next marker segment should be found. COM is an informational
638     * marker segment that allows to include unstructured data in the main and
639     * tile-part headers.
640     *
641     * @param ehs The encoded header stream
642     *
643     * @param mainh Flag indicating whether or not this marker segment is read
644     * from the main header.
645     *
646     * @param tileIdx The index of the current tile
647     *
648     * @param comIdx Occurence of this COM marker in eith main or tile-part
649     * header 
650     * 
651     * @exception IOException If an I/O error occurs while reading from the
652     * encoded header stream
653     * */
654    private void readCOM (DataInputStream ehs, boolean mainh, int tileIdx,
655                          int comIdx) throws IOException {
656        HeaderInfo.COM ms = hi.getNewCOM();
657
658        // Read length of COM field
659        ms.lcom = ehs.readUnsignedShort();
660
661        // Read the registration value of the COM marker segment
662        ms.rcom = ehs.readUnsignedShort();
663        switch(ms.rcom) {
664        case RCOM_GEN_USE:
665            ms.ccom = new byte[ms.lcom-4];
666            for(int i=0; i<ms.lcom-4; i++) {
667                ms.ccom[i] = ehs.readByte();
668            }
669            break;
670        default:
671            // --- Unknown or unsupported markers ---
672            // (skip them and see if we can get way with it)
673            FacilityManager.getMsgLogger().
674                printmsg(MsgLogger.WARNING,
675                         "COM marker registered as 0x"+Integer.
676                         toHexString(ms.rcom)+
677                         " unknown, ignoring (this might crash the "+
678                         "decoder or decode a quality degraded or even "+
679                         "useless image)");
680            ehs.skipBytes(ms.lcom-4); //Ignore this field for the moment
681            break;
682        }
683
684        if (mainh) {
685            hi.com.put("main_"+comIdx,ms);
686        } else {
687            hi.com.put("t"+tileIdx+"_"+comIdx,ms);
688        }
689
690        // Check marker length
691        checkMarkerLength(ehs,"COM marker");
692    }
693
694    /**
695     * Reads a QCD marker segment and realigns the codestream at the point
696     * where the next marker should be found. QCD is a functional marker
697     * segment that describes the quantization default.
698     * 
699     * @param ehs The encoded stream.
700     *
701     * @param mainh Flag indicating whether or not this marker segment is read
702     * from the main header.
703     *
704     * @param tileIdx The index of the current tile
705     *
706     * @param tpIdx Tile-part index
707     *
708     * @exception IOException If an I/O error occurs while reading from the
709     * encoded header stream.
710     * */
711    private void readQCD (DataInputStream ehs, boolean mainh, int tileIdx,
712                          int tpIdx) throws IOException {
713        StdDequantizerParams qParms;
714        int guardBits;
715        int[][] exp;
716        float[][] nStep = null;
717        HeaderInfo.QCD ms = hi.getNewQCD();
718
719        // Lqcd (length of QCD field)
720        ms.lqcd = ehs.readUnsignedShort();
721
722        // Sqcd (quantization style)
723        ms.sqcd = ehs.readUnsignedByte();
724
725        guardBits = ms.getNumGuardBits();
726        int qType = ms.getQuantType();
727
728        if(mainh){
729            hi.qcd.put("main",ms);
730            // If the main header is being read set default value of
731            // dequantization spec
732            switch (qType) {
733            case SQCX_NO_QUANTIZATION:
734                decSpec.qts.setDefault("reversible");
735                break;
736            case SQCX_SCALAR_DERIVED:
737                decSpec.qts.setDefault("derived");
738                break;
739            case SQCX_SCALAR_EXPOUNDED:
740                decSpec.qts.setDefault("expounded");
741                break;
742            default:
743                throw new CorruptedCodestreamException("Unknown or "+
744                                                       "unsupported "+
745                                                       "quantization style "+
746                                                       "in Sqcd field, QCD "+
747                                                       "marker main header");
748            }
749        } else {
750            hi.qcd.put("t"+tileIdx,ms);
751            // If the tile header is being read set default value of
752            // dequantization spec for tile
753            switch (qType) {
754            case SQCX_NO_QUANTIZATION:
755                decSpec.qts.setTileDef(tileIdx, "reversible");
756                break;
757            case SQCX_SCALAR_DERIVED:
758                decSpec.qts.setTileDef(tileIdx, "derived");
759                break;
760            case SQCX_SCALAR_EXPOUNDED:
761                decSpec.qts.setTileDef(tileIdx, "expounded");
762                break;
763            default:
764                throw new CorruptedCodestreamException("Unknown or "+
765                                                       "unsupported "+
766                                                       "quantization style "+
767                                                       "in Sqcd field, QCD "+
768                                                       "marker, tile header");
769            }
770        }
771
772        qParms = new StdDequantizerParams();
773
774        if(qType == SQCX_NO_QUANTIZATION) {
775            int maxrl =
776                ( mainh ?
777                  ((Integer)decSpec.dls.getDefault()).intValue() :
778                  ((Integer)decSpec.dls.getTileDef(tileIdx)).intValue());
779            int i,j,rl;
780            int minb,maxb,hpd;
781            int tmp;
782
783            exp = qParms.exp = new int[maxrl+1][];
784            ms.spqcd = new int[maxrl+1][4];
785
786            for (rl=0; rl <= maxrl; rl++) { // Loop on resolution levels
787                // Find the number of subbands in the resolution level
788                if (rl == 0) { // Only the LL subband
789                    minb = 0;
790                    maxb = 1;
791                } else {
792                    // Dyadic decomposition
793                    hpd = 1;
794
795                    // Adapt hpd to resolution level
796                    if (hpd > maxrl-rl) {
797                        hpd -= maxrl-rl;
798                    }
799                    else {
800                        hpd = 1;
801                    }
802                    // Determine max and min subband index
803                    minb = 1<<((hpd-1)<<1); // minb = 4^(hpd-1)
804                    maxb = 1<<(hpd<<1); // maxb = 4^hpd
805                }
806                // Allocate array for subbands in resolution level
807                exp[rl] = new int[maxb];
808
809                for(j=minb; j<maxb; j++) {
810                    tmp = ms.spqcd[rl][j] = ehs.readUnsignedByte();
811                    exp[rl][j] = (tmp>>SQCX_EXP_SHIFT)&SQCX_EXP_MASK;
812                }
813            }// end for rl
814        } else {
815            int maxrl = (qType == SQCX_SCALAR_DERIVED) ? 0 :
816                ( mainh ?
817                 ((Integer)decSpec.dls.getDefault()).intValue() :
818                 ((Integer)decSpec.dls.getTileDef(tileIdx)).intValue());
819            int i,j,rl;
820            int minb,maxb,hpd;
821            int tmp;
822
823            exp = qParms.exp = new int[maxrl+1][];
824            nStep = qParms.nStep = new float[maxrl+1][];
825            ms.spqcd = new int[maxrl+1][4];
826
827            for (rl=0; rl <= maxrl; rl++) { // Loop on resolution levels
828                // Find the number of subbands in the resolution level
829                if (rl == 0) { // Only the LL subband
830                    minb = 0;
831                    maxb = 1;
832                } else {
833                    // Dyadic decomposition
834                    hpd = 1;
835
836                    // Adapt hpd to resolution level
837                    if (hpd > maxrl-rl) {
838                        hpd -= maxrl-rl;
839                    } else {
840                        hpd = 1;
841                    }
842                    // Determine max and min subband index
843                    minb = 1<<((hpd-1)<<1); // minb = 4^(hpd-1)
844                    maxb = 1<<(hpd<<1); // maxb = 4^hpd
845                }
846                // Allocate array for subbands in resolution level
847                exp[rl] = new int[maxb];
848                nStep[rl] = new float[maxb];
849
850                for(j=minb; j<maxb; j++) {
851                    tmp = ms.spqcd[rl][j] = ehs.readUnsignedShort();
852                    exp[rl][j] = (tmp>>11) & 0x1f;
853                    // NOTE: the formula below does not support more than 5
854                    // bits for the exponent, otherwise (-1<<exp) might
855                    // overflow (the - is used to be able to represent 2**31)
856                    nStep[rl][j] =
857                        (-1f-((float)(tmp & 0x07ff))/(1<<11))/
858                        (-1<<exp[rl][j]);
859                }
860            }// end for rl
861        } // end if (qType != SQCX_NO_QUANTIZATION)
862
863        // Fill qsss, gbs
864        if(mainh){
865            decSpec.qsss.setDefault(qParms);
866            decSpec.gbs.setDefault(new Integer(guardBits));
867        }
868        else{
869            decSpec.qsss.setTileDef(tileIdx,qParms);
870            decSpec.gbs.setTileDef(tileIdx,new Integer(guardBits));
871        }
872
873        // Check marker length
874        checkMarkerLength(ehs,"QCD marker");
875    }
876
877    /**
878     * Reads a QCC marker segment and realigns the codestream at the point
879     * where the next marker should be found. QCC is a functional marker
880     * segment that describes the quantization of one component.
881     * 
882     * @param ehs The encoded stream.
883     *
884     * @param mainh Flag indicating whether or not this marker segment is read
885     * from the main header.
886     *
887     * @param tileIdx The index of the current tile
888     *
889     * @param tpIdx Tile-part index
890     *
891     * @exception IOException If an I/O error occurs while reading from the
892     * encoded header stream.
893     * */
894    private void readQCC (DataInputStream ehs, boolean mainh, int tileIdx,
895                          int tpIdx) throws IOException {
896        int cComp;          // current component
897        int tmp;
898        StdDequantizerParams qParms;
899        int[][] expC;
900        float[][] nStepC = null;
901        HeaderInfo.QCC ms = hi.getNewQCC();
902
903        // Lqcc (length of QCC field)
904        ms.lqcc = ehs.readUnsignedShort();
905
906        // Cqcc
907        if (nComp < 257) {
908            cComp = ms.cqcc = ehs.readUnsignedByte();
909        } else {
910            cComp = ms.cqcc = ehs.readUnsignedShort();
911        }
912        if (cComp >= nComp) {
913            throw new CorruptedCodestreamException("Invalid component "+
914                                                   "index in QCC marker");
915        }
916
917        // Sqcc (quantization style)
918        ms.sqcc = ehs.readUnsignedByte();
919        int guardBits = ms.getNumGuardBits();
920        int qType = ms.getQuantType();
921
922        if(mainh) {
923            hi.qcc.put("main_c"+cComp,ms);
924            // If main header is being read, set default for component in all
925            // tiles
926            switch (qType) {
927            case SQCX_NO_QUANTIZATION:
928                decSpec.qts.setCompDef(cComp,"reversible");
929                break;
930            case SQCX_SCALAR_DERIVED:
931                decSpec.qts.setCompDef(cComp,"derived");
932                break;
933            case SQCX_SCALAR_EXPOUNDED:
934                decSpec.qts.setCompDef(cComp,"expounded");
935                break;
936            default:
937                throw new CorruptedCodestreamException("Unknown or "+
938                                                       "unsupported "+
939                                                       "quantization style "+
940                                                       "in Sqcd field, QCD "+
941                                                       "marker, main header");
942            }
943        } else {
944            hi.qcc.put("t"+tileIdx+"_c"+cComp,ms);
945            // If tile header is being read, set value for component in
946            // this tiles
947            switch (qType) {
948            case SQCX_NO_QUANTIZATION:
949                decSpec.qts.setTileCompVal(tileIdx, cComp,"reversible");
950                break;
951            case SQCX_SCALAR_DERIVED:
952                decSpec.qts.setTileCompVal(tileIdx, cComp,"derived");
953                break;
954            case SQCX_SCALAR_EXPOUNDED:
955                decSpec.qts.setTileCompVal(tileIdx, cComp,"expounded");
956                break;
957            default:
958                throw new CorruptedCodestreamException("Unknown or "+
959                                                       "unsupported "+
960                                                       "quantization style "+
961                                                       "in Sqcd field, QCD "+
962                                                       "marker, main header");
963            }
964        }
965
966        // Decode all dequantizer params
967        qParms = new StdDequantizerParams();
968
969        if (qType == SQCX_NO_QUANTIZATION) {
970            int maxrl = ( mainh ?
971                          ((Integer)decSpec.dls.getCompDef(cComp)).intValue() :
972                          ((Integer)decSpec.dls.getTileCompVal(tileIdx,cComp)).
973                          intValue());
974            int i,j,rl;
975            int minb,maxb,hpd;
976
977            expC = qParms.exp = new int[maxrl+1][];
978            ms.spqcc = new int[maxrl+1][4];
979
980            for (rl=0; rl <= maxrl; rl++) { // Loop on resolution levels
981                // Find the number of subbands in the resolution level
982                if (rl == 0) { // Only the LL subband
983                    minb = 0;
984                    maxb = 1;
985                } else {
986                    // Dyadic decomposition
987                    hpd = 1;
988
989                    // Adapt hpd to resolution level
990                    if (hpd > maxrl-rl) {
991                        hpd -= maxrl-rl;
992                    } else {
993                        hpd = 1;
994                    }
995                    // Determine max and min subband index
996                    minb = 1<<((hpd-1)<<1); // minb = 4^(hpd-1)
997                    maxb = 1<<(hpd<<1); // maxb = 4^hpd
998                }
999                // Allocate array for subbands in resolution level
1000                expC[rl] = new int[maxb];
1001
1002                for(j=minb; j<maxb; j++) {
1003                    tmp = ms.spqcc[rl][j] = ehs.readUnsignedByte();
1004                    expC[rl][j] = (tmp>>SQCX_EXP_SHIFT)&SQCX_EXP_MASK;
1005                }
1006            }// end for rl
1007        } else {
1008            int maxrl = (qType == SQCX_SCALAR_DERIVED) ? 0 :
1009                ( mainh ?
1010                 ((Integer)decSpec.dls.getCompDef(cComp)).intValue() :
1011                 ((Integer)decSpec.dls.getTileCompVal(tileIdx,cComp)).
1012                  intValue());
1013            int i,j,rl;
1014            int minb,maxb,hpd;
1015
1016            nStepC = qParms.nStep = new float[maxrl+1][];
1017            expC =  qParms.exp = new int[maxrl+1][];
1018            ms.spqcc = new int[maxrl+1][4];
1019
1020            for (rl=0; rl <= maxrl; rl++) { // Loop on resolution levels
1021                // Find the number of subbands in the resolution level
1022                if (rl == 0) { // Only the LL subband
1023                    minb = 0;
1024                    maxb = 1;
1025                } else {
1026                    // Dyadic decomposition
1027                    hpd = 1;
1028
1029                    // Adapt hpd to resolution level
1030                    if (hpd > maxrl-rl) {
1031                        hpd -= maxrl-rl;
1032                    } else {
1033                        hpd = 1;
1034                    }
1035                    // Determine max and min subband index
1036                    minb = 1<<((hpd-1)<<1); // minb = 4^(hpd-1)
1037                    maxb = 1<<(hpd<<1); // maxb = 4^hpd
1038                }
1039                // Allocate array for subbands in resolution level
1040                expC[rl] = new int[maxb];
1041                nStepC[rl] = new float[maxb];
1042
1043                for(j=minb; j<maxb; j++) {
1044                    tmp = ms.spqcc[rl][j] = ehs.readUnsignedShort();
1045                    expC[rl][j] = (tmp>>11) & 0x1f;
1046                    // NOTE: the formula below does not support more than 5
1047                    // bits for the exponent, otherwise (-1<<exp) might
1048                    // overflow (the - is used to be able to represent 2**31)
1049                    nStepC[rl][j] =
1050                        (-1f-((float)(tmp & 0x07ff))/(1<<11))/
1051                        (-1<<expC[rl][j]);
1052                }
1053            }// end for rl
1054        } // end if (qType != SQCX_NO_QUANTIZATION)
1055
1056        // Fill qsss, gbs
1057        if(mainh){
1058            decSpec.qsss.setCompDef(cComp,qParms);
1059            decSpec.gbs.setCompDef(cComp,new Integer(guardBits));
1060        }
1061        else{
1062            decSpec.qsss.setTileCompVal(tileIdx,cComp,qParms);
1063            decSpec.gbs.setTileCompVal(tileIdx,cComp,new Integer(guardBits));
1064        }
1065
1066        // Check marker length
1067        checkMarkerLength(ehs,"QCC marker");
1068    }
1069
1070    /**
1071     * Reads a COD marker segment and realigns the codestream where the next
1072     * marker should be found. 
1073     *
1074     * @param ehs The encoder header stream.
1075     *
1076     * @param mainh Flag indicating whether or not this marker segment is read
1077     * from the main header.
1078     *
1079     * @param tileIdx The index of the current tile
1080     *
1081     * @param tpIdx Tile-part index
1082     *
1083     * @exception IOException If an I/O error occurs while reading from the
1084     * encoder header stream
1085     * */
1086    private void readCOD (DataInputStream ehs, boolean mainh, int tileIdx,
1087                          int tpIdx) throws IOException {
1088        int cstyle;         // The block style
1089        SynWTFilter hfilters[],vfilters[];
1090        int l;
1091        Integer cblk[];
1092        String errMsg;
1093        boolean sopUsed = false;
1094        boolean ephUsed = false;
1095        HeaderInfo.COD ms = hi.getNewCOD();
1096
1097        // Lcod (marker length)
1098        ms.lcod = ehs.readUnsignedShort();
1099
1100        // Scod (block style)
1101        // We only support wavelet transformed data
1102        cstyle = ms.scod = ehs.readUnsignedByte();
1103
1104        if( (cstyle&SCOX_PRECINCT_PARTITION) != 0 ){
1105            precinctPartitionIsUsed = true;
1106            // Remove flag
1107            cstyle &= ~(SCOX_PRECINCT_PARTITION);
1108        } else {
1109            precinctPartitionIsUsed = false;
1110        }
1111
1112        // SOP markers
1113        if (mainh) {
1114            hi.cod.put("main",ms);
1115
1116            if( (cstyle&SCOX_USE_SOP) != 0 ){
1117                // SOP markers are used
1118                decSpec.sops.setDefault(new Boolean("true"));
1119                sopUsed = true;
1120                // Remove flag
1121                cstyle &= ~(SCOX_USE_SOP);
1122            } else {
1123                // SOP markers are not used
1124                decSpec.sops.setDefault(new Boolean("false"));
1125            }
1126        } else {
1127            hi.cod.put("t"+tileIdx,ms);
1128
1129            if( (cstyle&SCOX_USE_SOP) != 0 ){
1130                // SOP markers are used
1131                decSpec.sops.setTileDef(tileIdx, new Boolean("true"));
1132                sopUsed = true;
1133                // Remove flag
1134                cstyle &= ~(SCOX_USE_SOP);
1135            }
1136            else {
1137                // SOP markers are not used
1138                decSpec.sops.setTileDef(tileIdx, new Boolean("false"));
1139            }
1140        }
1141
1142        // EPH markers
1143        if (mainh) {
1144            if( (cstyle&SCOX_USE_EPH) != 0 ){
1145                // EPH markers are used
1146                decSpec.ephs.setDefault(new Boolean("true"));
1147                ephUsed = true;
1148                // Remove flag
1149                cstyle &= ~(SCOX_USE_EPH);
1150            } else {
1151                // EPH markers are not used
1152                decSpec.ephs.setDefault(new Boolean("false"));
1153            }
1154        } else {
1155            if( (cstyle&SCOX_USE_EPH) != 0 ){
1156                // EPH markers are used
1157                decSpec.ephs.setTileDef(tileIdx, new Boolean("true"));
1158                ephUsed = true;
1159                // Remove flag
1160                cstyle &= ~(SCOX_USE_EPH);
1161            } else {
1162                // EPH markers are not used
1163                decSpec.ephs.setTileDef(tileIdx, new Boolean("false"));
1164            }
1165        }
1166
1167        // Code-block partition origin
1168        if( (cstyle&(SCOX_HOR_CB_PART|SCOX_VER_CB_PART)) != 0) {
1169            FacilityManager.getMsgLogger().
1170                printmsg(MsgLogger.WARNING,"Code-block partition origin "+
1171                         "different from (0,0). This is defined in JPEG 2000"+
1172                         " part 2 and may not be supported by all JPEG "+
1173                         "2000 decoders.");
1174        }
1175        if( (cstyle&SCOX_HOR_CB_PART)!= 0) {
1176            if(cb0x!=-1 && cb0x==0) {
1177                throw new IllegalArgumentException("Code-block partition "+
1178                                                   "origin redefined in new"+
1179                                                   " COD marker segment. Not"+
1180                                                   " supported by JJ2000");
1181            }
1182            cb0x = 1;
1183            cstyle &= ~(SCOX_HOR_CB_PART);
1184        } else {
1185            if(cb0x!=-1 && cb0x==1) {
1186                throw new IllegalArgumentException("Code-block partition "+
1187                                                   "origin redefined in new"+
1188                                                   " COD marker segment. Not"+
1189                                                   " supported by JJ2000");
1190            }
1191            cb0x = 0;
1192        }
1193        if( (cstyle&SCOX_VER_CB_PART)!= 0) {
1194            if(cb0y!=-1 && cb0y==0) {
1195                throw new IllegalArgumentException("Code-block partition "+
1196                                                   "origin redefined in new"+
1197                                                   " COD marker segment. Not"+
1198                                                   " supported by JJ2000");
1199            }
1200            cb0y = 1;
1201            cstyle &= ~(SCOX_VER_CB_PART);
1202        } else {
1203            if(cb0y!=-1 && cb0y==1) {
1204                throw new IllegalArgumentException("Code-block partition "+
1205                                                   "origin redefined in new"+
1206                                                   " COD marker segment. Not"+
1207                                                   " supported by JJ2000");
1208            }
1209            cb0y = 0;
1210        }
1211
1212        // SGcod
1213        // Read the progressive order
1214        ms.sgcod_po = ehs.readUnsignedByte();
1215
1216        // Read the number of layers
1217        ms.sgcod_nl = ehs.readUnsignedShort();
1218        if (ms.sgcod_nl<=0 || ms.sgcod_nl>65535 ) {
1219            throw new CorruptedCodestreamException("Number of layers out of "+
1220                                                   "range: 1--65535");
1221        }
1222
1223        // Multiple component transform
1224        ms.sgcod_mct = ehs.readUnsignedByte();
1225
1226        // SPcod
1227        // decomposition levels
1228        int mrl = ms.spcod_ndl = ehs.readUnsignedByte();
1229        if( mrl>32 ){
1230            throw new CorruptedCodestreamException("Number of decomposition "+
1231                                                   "levels out of range: "+
1232                                                   "0--32");
1233        }
1234
1235        // Read the code-blocks dimensions
1236        cblk = new Integer[2];
1237        ms.spcod_cw = ehs.readUnsignedByte();
1238        cblk[0] = new Integer(1<<(ms.spcod_cw+2));
1239        if ( cblk[0].intValue() < StdEntropyCoderOptions.MIN_CB_DIM ||
1240             cblk[0].intValue() > StdEntropyCoderOptions.MAX_CB_DIM  ) {
1241            errMsg = "Non-valid code-block width in SPcod field, "+
1242                "COD marker";
1243            throw new CorruptedCodestreamException(errMsg);
1244        }
1245        ms.spcod_ch = ehs.readUnsignedByte();
1246        cblk[1] = new Integer(1<<(ms.spcod_ch+2));
1247        if ( cblk[1].intValue() < StdEntropyCoderOptions.MIN_CB_DIM ||
1248             cblk[1].intValue() > StdEntropyCoderOptions.MAX_CB_DIM ) {
1249            errMsg = "Non-valid code-block height in SPcod field, "+
1250                "COD marker";
1251            throw new CorruptedCodestreamException(errMsg);
1252        }
1253        if ( (cblk[0].intValue()*cblk[1].intValue()) >
1254             StdEntropyCoderOptions.MAX_CB_AREA ) {
1255            errMsg = "Non-valid code-block area in SPcod field, "+
1256                "COD marker";
1257            throw new CorruptedCodestreamException(errMsg);
1258        }
1259        if ( mainh ) {
1260            decSpec.cblks.setDefault(cblk);
1261        }
1262        else {
1263            decSpec.cblks.setTileDef(tileIdx, cblk);
1264        }
1265
1266        // Style of the code-block coding passes
1267        int ecOptions = ms.spcod_cs = ehs.readUnsignedByte();
1268        if ((ecOptions &
1269             ~(OPT_BYPASS|OPT_RESET_MQ|OPT_TERM_PASS|
1270               OPT_VERT_STR_CAUSAL|OPT_PRED_TERM | OPT_SEG_SYMBOLS)) != 0){
1271            throw
1272                new CorruptedCodestreamException("Unknown \"code-block "+
1273                                                "style\" in SPcod field, "+
1274                                                "COD marker: 0x"+
1275                                                Integer.
1276                                                 toHexString(ecOptions));
1277        }
1278
1279        // Read wavelet filter for tile or image
1280        hfilters = new SynWTFilter[1];
1281        vfilters = new SynWTFilter[1];
1282        hfilters[0] = readFilter(ehs,ms.spcod_t);
1283        vfilters[0] = hfilters[0];
1284
1285        // Fill the filter spec
1286        // If this is the main header, set the default value, if it is the
1287        // tile header, set default for this tile 
1288        SynWTFilter[][] hvfilters = new SynWTFilter[2][];
1289        hvfilters[0]=hfilters;
1290        hvfilters[1]=vfilters;
1291
1292        // Get precinct partition sizes
1293        Vector v[] = new Vector[2];
1294        v[0] = new Vector();
1295        v[1] = new Vector();
1296        int val = PRECINCT_PARTITION_DEF_SIZE;
1297        if ( !precinctPartitionIsUsed ) {
1298            Integer w, h;
1299            w = new Integer(1<<(val & 0x000F));
1300            v[0].addElement(w);
1301            h = new Integer(1<<(((val & 0x00F0)>>4)));
1302            v[1].addElement(h);
1303        } else {
1304            ms.spcod_ps = new int[mrl+1];
1305            for (int rl=mrl ;rl>=0 ;rl--) {
1306                Integer w, h;
1307                val = ms.spcod_ps[mrl-rl] = ehs.readUnsignedByte();
1308                w = new Integer(1<<(val & 0x000F));
1309                v[0].insertElementAt(w,0);
1310                h = new Integer(1<<(((val & 0x00F0)>>4)));
1311                v[1].insertElementAt(h,0);
1312            }
1313        }
1314        if (mainh) {
1315            decSpec.pss.setDefault(v);
1316        } else {
1317            decSpec.pss.setTileDef(tileIdx, v);
1318        }
1319        precinctPartitionIsUsed = true;
1320
1321        // Check marker length
1322        checkMarkerLength(ehs,"COD marker");
1323
1324        // Store specifications in decSpec
1325        if(mainh){
1326            decSpec.wfs.setDefault(hvfilters);
1327            decSpec.dls.setDefault(new Integer(mrl));
1328            decSpec.ecopts.setDefault(new Integer(ecOptions));
1329            decSpec.cts.setDefault(new Integer(ms.sgcod_mct));
1330            decSpec.nls.setDefault(new Integer(ms.sgcod_nl));
1331            decSpec.pos.setDefault(new Integer(ms.sgcod_po));
1332        }
1333        else{
1334            decSpec.wfs.setTileDef(tileIdx, hvfilters);
1335            decSpec.dls.setTileDef(tileIdx,new Integer(mrl));
1336            decSpec.ecopts.setTileDef(tileIdx,new Integer(ecOptions));
1337            decSpec.cts.setTileDef(tileIdx,new Integer(ms.sgcod_mct));
1338            decSpec.nls.setTileDef(tileIdx,new Integer(ms.sgcod_nl));
1339            decSpec.pos.setTileDef(tileIdx,new Integer(ms.sgcod_po));
1340        }
1341    }
1342
1343    /**
1344     * Reads the COC marker segment and realigns the codestream where the next
1345     * marker should be found.
1346     *
1347     * @param ehs The encoder header stream.
1348     *
1349     * @param mainh Flag indicating whether or not this marker segment is read
1350     * from the main header.
1351     *
1352     * @param tileIdx The index of the current tile
1353     *
1354     * @param tpIdx Tile-part index
1355     *
1356     * @exception IOException If an I/O error occurs while reading from the
1357     * encoder header stream
1358     * */
1359    private void readCOC (DataInputStream ehs, boolean mainh, int tileIdx,
1360                          int tpIdx) throws IOException {
1361        int cComp;         // current component
1362        SynWTFilter hfilters[],vfilters[];
1363        int tmp,l;
1364        int ecOptions;
1365        Integer cblk[];
1366        String errMsg;
1367        HeaderInfo.COC ms = hi.getNewCOC();
1368
1369        // Lcoc (marker length)
1370        ms.lcoc = ehs.readUnsignedShort();
1371
1372        // Ccoc
1373        if (nComp < 257) {
1374            cComp = ms.ccoc = ehs.readUnsignedByte();
1375        } else {
1376            cComp = ms.ccoc = ehs.readUnsignedShort();
1377        }
1378        if (cComp >= nComp) {
1379            throw new CorruptedCodestreamException("Invalid component index "+
1380                                                   "in QCC marker");
1381        }
1382
1383        // Scoc (block style)
1384        int cstyle = ms.scoc = ehs.readUnsignedByte();
1385        if( (cstyle&SCOX_PRECINCT_PARTITION) != 0 ){
1386            precinctPartitionIsUsed = true;
1387            // Remove flag
1388            cstyle &= ~(SCOX_PRECINCT_PARTITION);
1389        } else {
1390            precinctPartitionIsUsed = false;
1391        }
1392
1393        // SPcoc
1394
1395        // decomposition levels
1396        int mrl = ms.spcoc_ndl = ehs.readUnsignedByte();
1397
1398        // Read the code-blocks dimensions
1399        cblk = new Integer[2];
1400        ms.spcoc_cw = ehs.readUnsignedByte();
1401        cblk[0] = new Integer(1<<(ms.spcoc_cw+2));
1402        if ( cblk[0].intValue() < StdEntropyCoderOptions.MIN_CB_DIM ||
1403             cblk[0].intValue() > StdEntropyCoderOptions.MAX_CB_DIM  ) {
1404            errMsg = "Non-valid code-block width in SPcod field, "+
1405                "COC marker";
1406            throw new CorruptedCodestreamException(errMsg);
1407        }
1408        ms.spcoc_ch = ehs.readUnsignedByte();
1409        cblk[1] = new Integer(1<<(ms.spcoc_ch+2));
1410        if ( cblk[1].intValue() < StdEntropyCoderOptions.MIN_CB_DIM ||
1411             cblk[1].intValue() > StdEntropyCoderOptions.MAX_CB_DIM ) {
1412            errMsg = "Non-valid code-block height in SPcod field, "+
1413                "COC marker";
1414            throw new CorruptedCodestreamException(errMsg);
1415        }
1416        if ( (cblk[0].intValue()*cblk[1].intValue()) >
1417             StdEntropyCoderOptions.MAX_CB_AREA ) {
1418            errMsg = "Non-valid code-block area in SPcod field, "+
1419                "COC marker";
1420            throw new CorruptedCodestreamException(errMsg);
1421        }
1422        if ( mainh ) {
1423            decSpec.cblks.setCompDef(cComp,cblk);
1424        } else {
1425            decSpec.cblks.setTileCompVal(tileIdx,cComp,cblk);
1426        }
1427
1428        // Read entropy block mode options
1429        // NOTE: currently OPT_SEG_SYMBOLS is not included here
1430        ecOptions = ms.spcoc_cs = ehs.readUnsignedByte();
1431        if ((ecOptions &
1432             ~(OPT_BYPASS|OPT_RESET_MQ|OPT_TERM_PASS|
1433               OPT_VERT_STR_CAUSAL|OPT_PRED_TERM|OPT_SEG_SYMBOLS)) != 0){
1434            throw
1435                new CorruptedCodestreamException("Unknown \"code-block "+
1436                                                 "context\" in SPcoc field, "+
1437                                                 "COC marker: 0x"+
1438                                                 Integer.
1439                                                 toHexString(ecOptions));
1440        }
1441
1442        // Read wavelet filter for tile or image
1443        hfilters = new SynWTFilter[1];
1444        vfilters = new SynWTFilter[1];
1445        hfilters[0] = readFilter(ehs,ms.spcoc_t);
1446        vfilters[0] = hfilters[0];
1447
1448        // Fill the filter spec
1449        // If this is the main header, set the default value, if it is the
1450        // tile header, set default for this tile 
1451        SynWTFilter[][] hvfilters = new SynWTFilter[2][];
1452        hvfilters[0]=hfilters;
1453        hvfilters[1]=vfilters;
1454
1455        // Get precinct partition sizes
1456        Vector v[] = new Vector[2];
1457        v[0] = new Vector();
1458        v[1] = new Vector();
1459        int val = PRECINCT_PARTITION_DEF_SIZE;
1460        if ( !precinctPartitionIsUsed ) {
1461            Integer w, h;
1462            w = new Integer(1<<(val & 0x000F));
1463            v[0].addElement(w);
1464            h = new Integer(1<<(((val & 0x00F0)>>4)));
1465            v[1].addElement(h);
1466        } else {
1467            ms.spcoc_ps = new int[mrl+1];
1468            for ( int rl=mrl ; rl>=0 ; rl-- ) {
1469                Integer w, h;
1470                val = ms.spcoc_ps[rl] = ehs.readUnsignedByte();
1471                w = new Integer(1<<(val & 0x000F));
1472                v[0].insertElementAt(w,0);
1473                h = new Integer(1<<(((val & 0x00F0)>>4)));
1474                v[1].insertElementAt(h,0);
1475            }
1476        }
1477        if (mainh) {
1478            decSpec.pss.setCompDef(cComp,v);
1479        } else {
1480            decSpec.pss.setTileCompVal(tileIdx,cComp,v);
1481        }
1482        precinctPartitionIsUsed = true;
1483
1484        // Check marker length
1485        checkMarkerLength(ehs,"COD marker");
1486
1487        if(mainh){
1488            hi.coc.put("main_c"+cComp,ms);
1489            decSpec.wfs.setCompDef(cComp,hvfilters);
1490            decSpec.dls.setCompDef(cComp,new Integer(mrl));
1491            decSpec.ecopts.setCompDef(cComp,new Integer(ecOptions));
1492        } else {
1493            hi.coc.put("t"+tileIdx+"_c"+cComp,ms);
1494            decSpec.wfs.setTileCompVal(tileIdx,cComp,hvfilters);
1495            decSpec.dls.setTileCompVal(tileIdx,cComp,new Integer(mrl));
1496            decSpec.ecopts.setTileCompVal(tileIdx,cComp,
1497                                          new Integer(ecOptions));
1498        }
1499    }
1500
1501    /** 
1502     * Reads the POC marker segment and realigns the codestream where the next
1503     * marker should be found.
1504     *
1505     * @param ehs The encoder header stream.
1506     *
1507     * @param mainh Flag indicating whether or not this marker segment is read
1508     * from the main header.
1509     *
1510     * @param t The index of the current tile
1511     *
1512     * @param tpIdx Tile-part index
1513     *
1514     * @exception IOException If an I/O error occurs while reading from the
1515     * encoder header stream
1516     * */
1517    private void readPOC(DataInputStream ehs,boolean mainh,int t,int tpIdx)
1518        throws IOException {
1519
1520        boolean useShort = (nComp>=256) ? true : false;
1521        int tmp;
1522        int nOldChg = 0;
1523        HeaderInfo.POC ms;
1524        if(mainh || hi.poc.get("t"+t)==null) {
1525            ms = hi.getNewPOC();
1526        } else {
1527            ms = (HeaderInfo.POC)hi.poc.get("t"+t);
1528            nOldChg = ms.rspoc.length;
1529        }
1530
1531        // Lpoc
1532        ms.lpoc = ehs.readUnsignedShort();
1533
1534        // Compute the number of new progression changes
1535        // newChg = (lpoc - Lpoc(2)) / (RSpoc(1) + CSpoc(2) +
1536        //  LYEpoc(2) + REpoc(1) + CEpoc(2) + Ppoc (1) )
1537        int newChg = (ms.lpoc-2)/(5+ (useShort?4:2));
1538        int ntotChg = nOldChg+newChg;
1539
1540        int[][] change;
1541        if(nOldChg!=0) {
1542            // Creates new arrays
1543            change = new int[ntotChg][6];
1544            int[] tmprspoc = new int[ntotChg];
1545            int[] tmpcspoc = new int[ntotChg];
1546            int[] tmplyepoc = new int[ntotChg];
1547            int[] tmprepoc = new int[ntotChg];
1548            int[] tmpcepoc = new int[ntotChg];
1549            int[] tmpppoc = new int[ntotChg];
1550
1551            // Copy old values
1552            int[][] prevChg = (int[][])decSpec.pcs.getTileDef(t);
1553            for(int chg=0; chg<nOldChg; chg++) {
1554                change[chg] = prevChg[chg];
1555                tmprspoc[chg] = ms.rspoc[chg];
1556                tmpcspoc[chg] = ms.cspoc[chg];
1557                tmplyepoc[chg] = ms.lyepoc[chg];
1558                tmprepoc[chg] = ms.repoc[chg];
1559                tmpcepoc[chg] = ms.cepoc[chg];
1560                tmpppoc[chg] = ms.ppoc[chg];
1561            }
1562            ms.rspoc = tmprspoc;
1563            ms.cspoc = tmpcspoc;
1564            ms.lyepoc = tmplyepoc;
1565            ms.repoc = tmprepoc;
1566            ms.cepoc = tmpcepoc;
1567            ms.ppoc = tmpppoc;
1568        } else {
1569            change = new int[newChg][6];
1570            ms.rspoc = new int[newChg];
1571            ms.cspoc = new int[newChg];
1572            ms.lyepoc = new int[newChg];
1573            ms.repoc = new int[newChg];
1574            ms.cepoc = new int[newChg];
1575            ms.ppoc = new int[newChg];
1576        }
1577
1578        for(int chg=nOldChg; chg<ntotChg; chg++) {
1579            // RSpoc
1580            change[chg][0] = ms.rspoc[chg] = ehs.readUnsignedByte();
1581
1582            // CSpoc
1583            if(useShort) {
1584                change[chg][1] = ms.cspoc[chg] = ehs.readUnsignedShort();
1585            } else {
1586                change[chg][1] = ms.cspoc[chg] = ehs.readUnsignedByte();
1587            }
1588
1589            // LYEpoc
1590            change[chg][2] = ms.lyepoc[chg] = ehs.readUnsignedShort();
1591            if(change[chg][2]<1) {
1592                throw new CorruptedCodestreamException
1593                    ("LYEpoc value must be greater than 1 in POC marker "+
1594                     "segment of tile "+t+", tile-part "+tpIdx);
1595            }
1596
1597            // REpoc
1598            change[chg][3] = ms.repoc[chg] = ehs.readUnsignedByte();
1599            if(change[chg][3]<=change[chg][0]) {
1600                throw new CorruptedCodestreamException
1601                    ("REpoc value must be greater than RSpoc in POC marker "+
1602                     "segment of tile "+t+", tile-part "+tpIdx);
1603            }
1604
1605            // CEpoc
1606            if(useShort) {
1607                change[chg][4] = ms.cepoc[chg] = ehs.readUnsignedShort();
1608            } else {
1609                tmp = ms.cepoc[chg] = ehs.readUnsignedByte();
1610                if(tmp==0) {
1611                    change[chg][4] = 0;
1612                } else {
1613                    change[chg][4] = tmp;
1614                }
1615            }
1616            if(change[chg][4]<=change[chg][1]) {
1617                throw new CorruptedCodestreamException
1618                    ("CEpoc value must be greater than CSpoc in POC marker "+
1619                     "segment of tile "+t+", tile-part "+tpIdx);
1620            }
1621
1622            // Ppoc
1623            change[chg][5] = ms.ppoc[chg] = ehs.readUnsignedByte();
1624        }
1625
1626        // Check marker length
1627        checkMarkerLength(ehs,"POC marker");
1628
1629        // Register specifications
1630        if(mainh) {
1631            hi.poc.put("main",ms);
1632            decSpec.pcs.setDefault(change);
1633        } else {
1634            hi.poc.put("t"+t,ms);
1635            decSpec.pcs.setTileDef(t,change);
1636        }
1637    }
1638
1639    /**
1640     * Reads TLM marker segment and realigns the codestream where the next
1641     * marker should be found. Informations stored in these fields are
1642     * currently NOT taken into account.
1643     *
1644     * @param ehs The encoder header stream.
1645     *
1646     * @exception IOException If an I/O error occurs while reading from the
1647     * encoder header stream
1648     * */
1649    private void readTLM(DataInputStream ehs) throws IOException {
1650        int length;
1651
1652        length = ehs.readUnsignedShort();
1653        //Ignore all informations contained
1654        ehs.skipBytes(length-2);
1655
1656        FacilityManager.getMsgLogger().
1657            printmsg(MsgLogger.INFO,"Skipping unsupported TLM marker");
1658    }
1659
1660    /**
1661     * Reads PLM marker segment and realigns the codestream where the next
1662     * marker should be found. Informations stored in these fields are
1663     * currently not taken into account.
1664     *
1665     * @param ehs The encoder header stream.
1666     *
1667     * @exception IOException If an I/O error occurs while reading from the
1668     * encoder header stream
1669     * */
1670    private void readPLM(DataInputStream ehs) throws IOException{
1671        int length;
1672
1673        length = ehs.readUnsignedShort();
1674        //Ignore all informations contained
1675        ehs.skipBytes(length-2);
1676
1677        FacilityManager.getMsgLogger().
1678            printmsg(MsgLogger.INFO,"Skipping unsupported PLM marker");
1679    }
1680
1681    /**
1682     * Reads the PLT fields and realigns the codestream where the next marker
1683     * should be found. Informations stored in these fields are currently NOT
1684     * taken into account.
1685     *
1686     * @param ehs The encoder header stream.
1687     *
1688     * @exception IOException If an I/O error occurs while reading from the
1689     * encoder header stream
1690     * */
1691    private void readPLTFields(DataInputStream ehs) throws IOException{
1692        int length;
1693
1694        length = ehs.readUnsignedShort();
1695        //Ignore all informations contained
1696        ehs.skipBytes(length-2);
1697
1698        FacilityManager.getMsgLogger().
1699            printmsg(MsgLogger.INFO,"Skipping unsupported PLT marker");
1700    }
1701
1702    /**
1703     * Reads the RGN marker segment of the codestream header.
1704     *
1705     * <p>May be used in tile or main header. If used in main header, it
1706     * refers to the maxshift value of a component in all tiles. When used in
1707     * tile header, only the particular tile-component is affected.</p>
1708     *
1709     * @param ehs The encoder header stream.
1710     *
1711     * @param mainh Flag indicating whether or not this marker segment is read
1712     * from the main header.
1713     *
1714     * @param tileIdx The index of the current tile
1715     *
1716     * @param tpIdx Tile-part index
1717     *
1718     * @exception IOException If an I/O error occurs while reading from the
1719     * encoder header stream
1720     * */
1721    private void readRGN(DataInputStream ehs, boolean mainh, int tileIdx,
1722                         int tpIdx) throws IOException {
1723        int comp;           // ROI component
1724        int i;              // loop variable
1725        int tempComp;       // Component for
1726        HeaderInfo.RGN ms = hi.getNewRGN();
1727
1728        // Lrgn (marker length)
1729        ms.lrgn = ehs.readUnsignedShort();
1730
1731        // Read component
1732        ms.crgn = comp = (nComp < 257) ? ehs.readUnsignedByte():
1733            ehs.readUnsignedShort();
1734        if (comp >= nComp) {
1735            throw new CorruptedCodestreamException("Invalid component "+
1736                                                  "index in RGN marker"+
1737                                                  comp);
1738        }
1739
1740        // Read type of RGN.(Srgn) 
1741        ms.srgn = ehs.readUnsignedByte();
1742
1743        // Check that we can handle it.
1744        if(ms.srgn != SRGN_IMPLICIT)
1745            throw new CorruptedCodestreamException("Unknown or unsupported "+
1746                                                  "Srgn parameter in ROI "+
1747                                                  "marker");
1748
1749        if(decSpec.rois==null) { // No maxshift spec defined
1750            // Create needed ModuleSpec
1751            decSpec.rois=new MaxShiftSpec(nTiles,nComp,
1752                                          ModuleSpec.SPEC_TYPE_TILE_COMP, "null");
1753        }
1754
1755        // SPrgn
1756        ms.sprgn = ehs.readUnsignedByte();
1757
1758        if(mainh) {
1759            hi.rgn.put("main_c"+comp,ms);
1760            decSpec.rois.setCompDef(comp, new Integer(ms.sprgn));
1761        } else {
1762            hi.rgn.put("t"+tileIdx+"_c"+comp,ms);
1763            decSpec.rois.setTileCompVal(tileIdx,comp,new Integer(ms.sprgn));
1764        }
1765
1766        // Check marker length
1767        checkMarkerLength(ehs,"RGN marker");
1768    }
1769
1770    /**
1771     * Reads the PPM marker segment of the main header.
1772     *
1773     * @param ehs The encoder header stream.
1774     *
1775     * @exception IOException If an I/O error occurs while reading from the
1776     * encoder header stream
1777     * */
1778    private void readPPM(DataInputStream ehs) throws IOException {
1779        int curMarkSegLen;
1780        int i,indx,len,off;
1781        int remSegLen;
1782        byte[] b;
1783
1784        // If first time readPPM method is called allocate arrays for packed
1785        // packet data
1786        if(pPMMarkerData==null) {
1787            pPMMarkerData = new byte[nPPMMarkSeg][];
1788            tileOfTileParts = new Vector();
1789            decSpec.pphs.setDefault(new Boolean(true));
1790        }
1791
1792        // Lppm (marker length)
1793        curMarkSegLen = ehs.readUnsignedShort();
1794        remSegLen = curMarkSegLen - 3;
1795
1796        // Zppm (index of PPM marker)
1797        indx = ehs.readUnsignedByte();
1798
1799        // Read Nppm and Ippm data 
1800        pPMMarkerData[indx] = new byte[remSegLen];
1801        ehs.read(pPMMarkerData[indx],0,remSegLen);
1802
1803        // Check marker length
1804        checkMarkerLength(ehs,"PPM marker");
1805    }
1806
1807    /**
1808     * Teads the PPT marker segment of the main header.
1809     *
1810     * @param ehs The encoder header stream.
1811     *
1812     * @param tile The tile to which the current tile part belongs
1813     *
1814     * @param tpIdx Tile-part index
1815     *
1816     * @exception IOException If an I/O error occurs while reading from the
1817     * encoder header stream
1818     * */
1819    private void readPPT(DataInputStream ehs,int tile,int tpIdx)
1820        throws IOException {
1821        int curMarkSegLen;
1822        int indx,len=0;
1823        byte[] temp;
1824
1825        if(tilePartPkdPktHeaders == null){
1826            tilePartPkdPktHeaders = new byte[nTiles][][][];
1827        }
1828
1829        if(tilePartPkdPktHeaders[tile] == null){
1830            tilePartPkdPktHeaders[tile] = new byte[nTileParts[tile]][][];
1831        }
1832
1833        if(tilePartPkdPktHeaders[tile][tpIdx] == null){
1834            tilePartPkdPktHeaders[tile][tpIdx] =
1835                new byte[nPPTMarkSeg[tile][tpIdx]][];
1836        }
1837
1838        // Lppt (marker length)
1839        curMarkSegLen = ehs.readUnsignedShort();
1840
1841        // Zppt (index of PPT marker)
1842        indx = ehs.readUnsignedByte();
1843
1844        // Ippt (packed packet headers)
1845        temp = new byte[curMarkSegLen-3];
1846        ehs.read(temp);
1847        tilePartPkdPktHeaders[tile][tpIdx][indx]=temp;
1848
1849        // Check marker length
1850        checkMarkerLength(ehs,"PPT marker");
1851
1852        decSpec.pphs.setTileDef(tile, new Boolean(true));
1853    }
1854
1855    /** 
1856     * This method extract a marker segment from the main header and stores it
1857     * into a byte buffer for the second pass. The marker segment is first
1858     * identified. Then its flag is activated. Finally, its content is
1859     * buffered into a byte array stored in an hashTable.
1860     *
1861     * <p>If the marker is not recognized, it prints a warning and skips it
1862     * according to its length.</p>
1863     *
1864     * <p>SIZ marker segment shall be the first encountered marker segment.</p>
1865     *
1866     * @param marker The marker segment to process
1867     *
1868     * @param ehs The encoded header stream
1869     * */
1870    private void extractMainMarkSeg(short marker,RandomAccessIO ehs)
1871        throws IOException {
1872        if(nfMarkSeg == 0) { // First non-delimiting marker of the header
1873            // JPEG 2000 part 1 specify that it must be SIZ
1874            if(marker != SIZ) {
1875                throw new CorruptedCodestreamException("First marker after "+
1876                                                       "SOC "+
1877                                                       "must be SIZ "+
1878                                                       Integer.
1879                                                       toHexString(marker));
1880            }
1881        }
1882
1883        String htKey=""; // Name used as a key for the hash-table
1884        if(ht==null) {
1885            ht = new Hashtable();
1886        }
1887
1888        switch(marker){
1889        case SIZ:
1890            if ((nfMarkSeg & SIZ_FOUND) != 0) {
1891                throw
1892                  new CorruptedCodestreamException("More than one SIZ marker "+
1893                                                   "segment found in main "+
1894                                                   "header");
1895            }
1896            nfMarkSeg |= SIZ_FOUND;
1897            htKey = "SIZ";
1898            break;
1899        case SOD:
1900            throw new CorruptedCodestreamException("SOD found in main header");
1901        case EOC:
1902            throw new CorruptedCodestreamException("EOC found in main header");
1903        case SOT:
1904            if ((nfMarkSeg & SOT_FOUND) != 0) {
1905                throw new CorruptedCodestreamException("More than one SOT "+
1906                                                       "marker "+
1907                                                       "found right after "+
1908                                                       "main "+
1909                                                       "or tile header");
1910            }
1911            nfMarkSeg |= SOT_FOUND;
1912            return;
1913        case COD:
1914            if((nfMarkSeg & COD_FOUND) != 0) {
1915                throw new CorruptedCodestreamException("More than one COD "+
1916                                                      "marker "+
1917                                                      "found in main header");
1918            }
1919            nfMarkSeg |= COD_FOUND;
1920            htKey = "COD";
1921            break;
1922        case COC:
1923            nfMarkSeg |= COC_FOUND;
1924            htKey = "COC"+(nCOCMarkSeg++);
1925            break;
1926        case QCD:
1927            if((nfMarkSeg & QCD_FOUND) != 0) {
1928                throw new CorruptedCodestreamException("More than one QCD "+
1929                                                      "marker "+
1930                                                      "found in main header");
1931            }
1932            nfMarkSeg |= QCD_FOUND;
1933            htKey = "QCD";
1934            break;
1935        case QCC:
1936            nfMarkSeg |= QCC_FOUND;
1937            htKey = "QCC"+(nQCCMarkSeg++);
1938            break;
1939        case RGN:
1940            nfMarkSeg |= RGN_FOUND;
1941            htKey = "RGN"+(nRGNMarkSeg++);
1942            break;
1943        case COM:
1944            nfMarkSeg |= COM_FOUND;
1945            htKey = "COM"+(nCOMMarkSeg++);
1946            break;
1947        case CRG:
1948            if((nfMarkSeg & CRG_FOUND) != 0) {
1949                throw new CorruptedCodestreamException("More than one CRG "+
1950                                                      "marker "+
1951                                                      "found in main header");
1952            }
1953            nfMarkSeg |= CRG_FOUND;
1954            htKey = "CRG";
1955            break;
1956        case PPM:
1957            nfMarkSeg |= PPM_FOUND;
1958            htKey = "PPM"+(nPPMMarkSeg++);
1959            break;
1960        case TLM:
1961            if((nfMarkSeg & TLM_FOUND) != 0) {
1962                FacilityManager.getMsgLogger().
1963                    printmsg(MsgLogger.INFO,
1964                             "More than one TLM "+
1965                             "marker "+
1966                             "found in main header");
1967                /** XXX It is legal to have multiple TLM segments.
1968                throw new CorruptedCodestreamException("More than one TLM "+
1969                                                      "marker "+
1970                                                      "found in main header");
1971                */
1972            }
1973            nfMarkSeg |= TLM_FOUND;
1974            break;
1975        case PLM:
1976            if((nfMarkSeg & PLM_FOUND) != 0) {
1977                throw new CorruptedCodestreamException("More than one PLM "+
1978                                                      "marker "+
1979                                                      "found in main header");
1980            }
1981            FacilityManager.getMsgLogger().
1982                printmsg(MsgLogger.WARNING,"PLM marker segment found but "+
1983                         "not used by by JJ2000 decoder.");
1984            nfMarkSeg |= PLM_FOUND;
1985            htKey = "PLM";
1986            break;
1987        case POC:
1988            if( (nfMarkSeg&POC_FOUND)!=0) {
1989                throw new CorruptedCodestreamException("More than one POC "+
1990                                                       "marker segment found "+
1991                                                       "in main header");
1992            }
1993            nfMarkSeg |= POC_FOUND;
1994            htKey = "POC";
1995            break;
1996        case PLT:
1997            throw new CorruptedCodestreamException("PLT found in main header");
1998        case PPT:
1999            throw new CorruptedCodestreamException("PPT found in main header");
2000        default:
2001            htKey = "UNKNOWN";
2002            FacilityManager.getMsgLogger().
2003                printmsg(MsgLogger.WARNING,"Non recognized marker segment (0x"+
2004                         Integer.toHexString(marker)+") in main header!");
2005            break;
2006        }
2007
2008        if(marker < 0xffffff30 || marker > 0xffffff3f){
2009            // Read marker segment length and create corresponding byte buffer
2010            int markSegLen = ehs.readUnsignedShort();
2011            byte[] buf = new byte[markSegLen];
2012
2013            // Copy data (after re-insertion of the marker segment length);
2014            buf[0]= (byte)((markSegLen>>8) & 0xFF);
2015            buf[1]= (byte)(markSegLen & 0xFF);
2016            ehs.readFully(buf,2,markSegLen-2);
2017
2018            if(!htKey.equals("UNKNOWN")) {
2019                // Store array in hashTable
2020                ht.put(htKey,buf);
2021            }
2022        }
2023    }
2024
2025    /**     
2026     * This method extracts a marker segment in a tile-part header and stores
2027     * it into a byte buffer for the second pass. The marker is first
2028     * recognized, then its flag is activated and, finally, its content is
2029     * buffered in an element of byte arrays accessible thanks to a hashTable.
2030     * If a marker segment is not recognized, it prints a warning and skip it
2031     * according to its length.
2032     *  
2033     * @param marker The marker to process
2034     *  
2035     * @param ehs The encoded header stream
2036     *                                            
2037     * @param tileIdx The index of the current tile
2038     *
2039     * @param tilePartIdx The index of the current tile part
2040     * */   
2041    public void extractTilePartMarkSeg(short marker, RandomAccessIO ehs,
2042                                       int tileIdx, int tilePartIdx)
2043        throws IOException {
2044
2045        String htKey=""; // Name used as a hash-table key
2046        if(ht==null) {
2047            ht = new Hashtable();
2048        }
2049
2050        switch(marker) {
2051        case SOT:
2052            throw new CorruptedCodestreamException("Second SOT marker "+
2053                                                   "segment found in tile-"+
2054                                                   "part header");
2055        case SIZ:
2056            throw new CorruptedCodestreamException("SIZ found in tile-part"+
2057                                                   " header");
2058        case EOC:
2059            throw new CorruptedCodestreamException("EOC found in tile-part"+
2060                                                   " header");
2061        case TLM:                                      
2062            throw new CorruptedCodestreamException("TLM found in tile-part"+
2063                                                   " header");
2064        case PPM:
2065            throw new CorruptedCodestreamException("PPM found in tile-part"+
2066                                                   " header");
2067        case COD:
2068            if((nfMarkSeg & COD_FOUND) != 0) {
2069                throw new CorruptedCodestreamException("More than one COD "+
2070                                                       "marker "+
2071                                                       "found in tile-part"+
2072                                                       " header");
2073            }
2074            nfMarkSeg |= COD_FOUND;
2075            htKey = "COD";
2076            break;
2077        case COC:
2078            nfMarkSeg |= COC_FOUND;
2079            htKey = "COC"+(nCOCMarkSeg++);
2080            break;
2081        case QCD:
2082            if((nfMarkSeg & QCD_FOUND) != 0) {
2083                throw new CorruptedCodestreamException("More than one QCD "+
2084                                                       "marker "+
2085                                                       "found in tile-part"+
2086                                                       " header");
2087            }
2088            nfMarkSeg |= QCD_FOUND;
2089            htKey = "QCD";
2090            break;
2091        case QCC:
2092            nfMarkSeg |= QCC_FOUND;
2093            htKey = "QCC"+(nQCCMarkSeg++);
2094            break;
2095        case RGN:
2096            nfMarkSeg |= RGN_FOUND;
2097            htKey = "RGN"+(nRGNMarkSeg++);
2098            break;
2099        case COM:
2100            nfMarkSeg |= COM_FOUND;
2101            htKey = "COM"+(nCOMMarkSeg++);
2102            break;
2103        case CRG:
2104            throw new CorruptedCodestreamException("CRG marker found in "+
2105                                                   "tile-part header");
2106        case PPT:
2107            nfMarkSeg |= PPT_FOUND;
2108            if(nPPTMarkSeg == null){
2109                nPPTMarkSeg = new int[nTiles][];
2110            }
2111            if(nPPTMarkSeg[tileIdx] == null){
2112                nPPTMarkSeg[tileIdx] = new int[nTileParts[tileIdx]];
2113            }
2114            htKey = "PPT"+(nPPTMarkSeg[tileIdx][tilePartIdx]++);
2115            break;
2116        case SOD:
2117            nfMarkSeg |= SOD_FOUND;
2118            return;
2119        case POC:
2120            if( (nfMarkSeg&POC_FOUND) != 0)
2121                throw new CorruptedCodestreamException("More than one POC "+
2122                                                       "marker segment found "+
2123                                                       "in tile-part"+
2124                                                       " header");
2125            nfMarkSeg |= POC_FOUND;
2126            htKey = "POC";
2127            break;
2128        case PLT:
2129            if((nfMarkSeg & PLM_FOUND) != 0) {
2130                throw new CorruptedCodestreamException("PLT marker found even"+
2131                                                       "though PLM marker "+
2132                                                       "found in main header");
2133            }
2134            FacilityManager.getMsgLogger().
2135                printmsg(MsgLogger.WARNING,"PLT marker segment found but "+
2136                         "not used by JJ2000 decoder.");
2137            htKey = "UNKNOWN";
2138            break;
2139        default:
2140            htKey = "UNKNOWN";
2141            FacilityManager.getMsgLogger().
2142                printmsg(MsgLogger.WARNING,"Non recognized marker segment (0x"+
2143                         Integer.toHexString(marker)+") in tile-part header"+
2144                         " of tile "+tileIdx+" !");
2145            break;
2146        }
2147
2148        // Read marker segment length and create corresponding byte buffer
2149        int markSegLen = ehs.readUnsignedShort();
2150        byte[] buf = new byte[markSegLen];
2151
2152        // Copy data (after re-insertion of marker segment length);
2153        buf[0]= (byte)((markSegLen>>8) & 0xFF);
2154        buf[1]= (byte)(markSegLen & 0xFF);
2155        ehs.readFully(buf,2,markSegLen-2);
2156
2157        if(!htKey.equals("UNKNOWN")) {
2158            // Store array in hashTable
2159            ht.put(htKey,buf);
2160        }
2161    }
2162
2163
2164
2165    /** 
2166     * Retrieves and reads all marker segments found in the main header during
2167     * the first pass.
2168     * */
2169    private void readFoundMainMarkSeg() throws IOException {
2170        DataInputStream dis;
2171        ByteArrayInputStream bais;
2172
2173        // SIZ marker segment
2174        if((nfMarkSeg&SIZ_FOUND) != 0) {
2175            bais = new ByteArrayInputStream( (byte[])(ht.get("SIZ")));
2176            readSIZ(new DataInputStream(bais));
2177        }
2178
2179        // COM marker segments
2180        if((nfMarkSeg&COM_FOUND) != 0) {
2181            for(int i=0; i<nCOMMarkSeg; i++) {
2182                bais = new ByteArrayInputStream( (byte[])(ht.get("COM"+i)));
2183                readCOM(new DataInputStream(bais),true,0,i);
2184            }
2185        }
2186
2187        // CRG marker segment
2188        if((nfMarkSeg&CRG_FOUND) != 0) {
2189            bais = new ByteArrayInputStream( (byte[])(ht.get("CRG")));
2190            readCRG(new DataInputStream(bais));
2191        }
2192
2193        // COD marker segment
2194        if((nfMarkSeg&COD_FOUND) != 0) {
2195            bais = new ByteArrayInputStream( (byte[])(ht.get("COD")));
2196            readCOD(new DataInputStream(bais),true,0,0);
2197        }
2198
2199        // COC marker segments
2200        if((nfMarkSeg&COC_FOUND) != 0) {
2201            for(int i=0; i<nCOCMarkSeg; i++) {
2202                bais = new ByteArrayInputStream( (byte[])(ht.get("COC"+i)));
2203                readCOC(new DataInputStream(bais),true,0,0);
2204            }
2205        }
2206
2207        // RGN marker segment
2208        if((nfMarkSeg&RGN_FOUND) != 0) {
2209            for(int i=0; i<nRGNMarkSeg; i++) {
2210                bais = new ByteArrayInputStream( (byte[])(ht.get("RGN"+i)));
2211                readRGN(new DataInputStream(bais),true,0,0);
2212            }
2213        }
2214
2215        // QCD marker segment
2216        if((nfMarkSeg&QCD_FOUND) != 0) {
2217            bais = new ByteArrayInputStream( (byte[])(ht.get("QCD")));
2218            readQCD(new DataInputStream(bais),true,0,0);
2219        }
2220
2221        // QCC marker segments
2222        if((nfMarkSeg&QCC_FOUND) != 0) {
2223            for(int i=0;i<nQCCMarkSeg; i++) {
2224                bais = new ByteArrayInputStream( (byte[])(ht.get("QCC"+i)));
2225                readQCC(new DataInputStream(bais),true,0,0);
2226            }
2227        }
2228
2229        // POC marker segment
2230        if( (nfMarkSeg&POC_FOUND) != 0) {
2231            bais = new ByteArrayInputStream( (byte[])(ht.get("POC")));
2232            readPOC(new DataInputStream(bais),true,0,0);
2233        }
2234
2235        // PPM marker segments
2236        if((nfMarkSeg&PPM_FOUND) != 0) {
2237            for(int i=0;i<nPPMMarkSeg; i++) {
2238                bais = new ByteArrayInputStream( (byte[])(ht.get("PPM"+i)));
2239                readPPM(new DataInputStream(bais));
2240            }
2241        }
2242
2243        // Reset the hashtable
2244        ht = null;
2245    }
2246
2247
2248    /**
2249     * Return the DecoderSpecs instance filled when reading the headers
2250     *
2251     * @retrieves and reads all marker segments previously found in the
2252     * tile-part header.
2253     *
2254     * @param tileIdx The index of the current tile
2255     * 
2256     * @param tpIdx Index of the current tile-part
2257     * */
2258    public void readFoundTilePartMarkSeg(int tileIdx,int tpIdx)
2259        throws IOException {
2260
2261        DataInputStream dis;
2262        ByteArrayInputStream bais;
2263
2264        // COD marker segment
2265        if((nfMarkSeg&COD_FOUND) != 0) {
2266            bais = new ByteArrayInputStream( (byte[])(ht.get("COD")) );
2267            readCOD(new DataInputStream(bais),false,tileIdx,tpIdx);
2268        }
2269
2270        // COC marker segments
2271        if((nfMarkSeg&COC_FOUND) != 0) {
2272            for(int i=0; i<nCOCMarkSeg; i++) {
2273                bais = new ByteArrayInputStream( (byte[])(ht.get("COC"+i)) );
2274                readCOC(new DataInputStream(bais),false,tileIdx,tpIdx);
2275            }
2276        }
2277
2278        // RGN marker segment
2279        if((nfMarkSeg&RGN_FOUND) != 0) {
2280            for(int i=0; i<nRGNMarkSeg; i++) {
2281                bais = new ByteArrayInputStream( (byte[])(ht.get("RGN"+i)) );
2282                readRGN(new DataInputStream(bais),false,tileIdx,tpIdx);
2283            }
2284        }
2285
2286        // QCD marker segment
2287        if((nfMarkSeg&QCD_FOUND) != 0) {
2288            bais = new ByteArrayInputStream( (byte[])(ht.get("QCD")) );
2289            readQCD(new DataInputStream(bais),false,tileIdx,tpIdx);
2290        }
2291
2292        // QCC marker segments
2293        if((nfMarkSeg&QCC_FOUND) != 0) {
2294            for(int i=0;i<nQCCMarkSeg; i++) {
2295                bais = new ByteArrayInputStream( (byte[])(ht.get("QCC"+i)) );
2296                readQCC(new DataInputStream(bais),false,tileIdx,tpIdx);
2297            }
2298        }
2299        // POC marker segment
2300        if( (nfMarkSeg&POC_FOUND) != 0) {
2301            bais = new ByteArrayInputStream( (byte[])(ht.get("POC")));
2302            readPOC(new DataInputStream(bais),false,tileIdx,tpIdx);
2303        }
2304
2305        // COM marker segments
2306        if((nfMarkSeg&COM_FOUND) != 0) {
2307            for(int i=0; i<nCOMMarkSeg; i++) {
2308                bais = new ByteArrayInputStream( (byte[])(ht.get("COM"+i)) );
2309                readCOM(new DataInputStream(bais),false,tileIdx,i);
2310            }
2311        }
2312
2313        // PPT marker segments
2314        if((nfMarkSeg&PPT_FOUND) != 0) {
2315            for(int i=0;i<nPPTMarkSeg[tileIdx][tpIdx]; i++) {
2316                bais = new ByteArrayInputStream( (byte[])(ht.get("PPT"+i)) );
2317                readPPT(new DataInputStream(bais),tileIdx,tpIdx);
2318            }
2319        }
2320
2321        // Reset ht
2322        ht = null;
2323    }
2324
2325
2326    /** 
2327     * Return the DecoderSpecs instance filled when reading the headers
2328     * 
2329     * @return The DecoderSpecs of the decoder
2330     * */
2331    public DecoderSpecs getDecoderSpecs(){
2332        return decSpec;
2333    }
2334
2335    /**
2336     * Creates a HeaderDecoder instance and read in two passes the main header
2337     * of the codestream. The first and last marker segments shall be
2338     * respectively SOC and SOT.
2339     *
2340     * @param ehs The encoded header stream where marker segment are
2341     * extracted.
2342     *
2343     * @param j2krparam The parameter list of the decoder
2344     *
2345     * @param hi The HeaderInfo holding information found in marker segments
2346     *
2347     * @exception IOException If an I/O error occurs while reading from the
2348     * encoded header stream.
2349     *
2350     * @exception EOFException If the end of the encoded header stream is
2351     * reached before getting all the data.
2352     *
2353     * @exception CorruptedCodestreamException If invalid data is found in the
2354     * codestream main header.
2355     * */
2356    public HeaderDecoder(RandomAccessIO ehs, 
2357                         J2KImageReadParamJava j2krparam,
2358                         HeaderInfo hi)
2359        throws IOException {
2360
2361        this.hi = hi;
2362        this.j2krparam = j2krparam;
2363        mainHeadOff = ehs.getPos();
2364        if( ((short)ehs.readShort()) != Markers.SOC ) {
2365            throw new CorruptedCodestreamException("SOC marker segment not "+
2366                                                   " found at the "+
2367                                                   "beginning of the "+
2368                                                   "codestream.");
2369        }
2370
2371        // First Pass: Decode and store main header information until the SOT
2372        // marker segment is found
2373        nfMarkSeg = 0;
2374        do {
2375            extractMainMarkSeg(ehs.readShort(),ehs);
2376        } while ((nfMarkSeg & SOT_FOUND)==0); //Stop when SOT is found
2377        ehs.seek(ehs.getPos()-2); // Realign codestream on SOT marker
2378
2379        // Second pass: Read each marker segment previously found
2380        readFoundMainMarkSeg();
2381    }
2382
2383    /**
2384     * Creates and returns the entropy decoder corresponding to the
2385     * information read from the codestream header and with the special
2386     * additional parameters from the parameter list.
2387     *
2388     * @param src The bit stream reader agent where to get code-block data
2389     * from.
2390     *
2391     * @param j2krparam The parameter list containing parameters applicable to the
2392     * entropy decoder (other parameters can also be present).
2393     *
2394     * @return The entropy decoder
2395     * */
2396    public EntropyDecoder createEntropyDecoder(CodedCBlkDataSrcDec src,
2397                                               J2KImageReadParamJava j2krparam) {
2398        // Get error detection option
2399        // boolean doer = j2krparam.getCer();;
2400        boolean doer = true;
2401        // Get verbose error detection option
2402        //boolean verber = j2krparam.getVerbose();
2403        boolean verber = false;
2404
2405        // Get maximum number of bit planes from m quit condition
2406//        int mMax = j2krparam.getMQuit();
2407        int mMax = -1;
2408        return new StdEntropyDecoder(src,decSpec,doer,verber,mMax);
2409    }
2410
2411
2412    /**
2413     * Creates and returns the EnumeratedColorSpaceMapper
2414     * corresponding to the information read from the JP2 image file
2415     * via the ColorSpace parameter.
2416     *
2417     * @param src The bit stream reader agent where to get code-block
2418     * data from.
2419     * @param csMap provides color space information from the image file
2420     *
2421     * @return The color space mapping object
2422     * @exception IOException image access exception
2423     * @exception ICCProfileException if image contains a bad icc profile
2424     * @exception ColorSpaceException if image contains a bad colorspace box
2425     **/
2426/*
2427    public BlkImgDataSrc createColorSpaceMapper(BlkImgDataSrc src,
2428                                                ColorSpace csMap)
2429        throws IOException, ICCProfileException, ColorSpaceException {
2430        return ColorSpaceMapper.createInstance(src,csMap);
2431    }
2432*/
2433     /**
2434      * Creates and returns the ChannelDefinitonMapper which maps the
2435      * input channels to the channel definition for the appropriate
2436      * colorspace.
2437      *
2438      * @param src The bit stream reader agent where to get code-block
2439      * data from.
2440      * @param csMap provides color space information from the image file
2441      *
2442      * @return The channel definition mapping object
2443      * @exception IOException image access exception
2444      * @exception ColorSpaceException if image contains a bad colorspace box
2445      **/
2446/*
2447     public BlkImgDataSrc createChannelDefinitionMapper(BlkImgDataSrc src,
2448                                                        ColorSpace csMap)
2449         throws IOException, ColorSpaceException {
2450         return ChannelDefinitionMapper.createInstance(src,csMap);
2451     }
2452*/
2453    /**
2454     * Creates and returns the PalettizedColorSpaceMapper which uses
2455     * the input samples as indicies into a sample palette to
2456     * construct the output.
2457     *
2458     * @param src The bit stream reader agent where to get code-block
2459     * data from.
2460     * @param csMap provides color space information from the image file
2461     *
2462     * @return a  PalettizedColorSpaceMapper instance
2463     * @exception IOException image access exception
2464     * @exception ColorSpaceException if image contains a bad colorspace box
2465     **/
2466/*
2467    public BlkImgDataSrc createPalettizedColorSpaceMapper(BlkImgDataSrc src,
2468                                                          ColorSpace csMap)
2469        throws IOException, ColorSpaceException {
2470        return PalettizedColorSpaceMapper.createInstance(src, csMap); }
2471*/
2472    /**
2473     * Creates and returns the Resampler which converts the input
2474     * source to one in which all channels have the same number of
2475     * samples.  This is required for colorspace conversions.
2476     *
2477     * @param src The bit stream reader agent where to get code-block
2478     * data from.
2479     * @param csMap provides color space information from the image file
2480     *
2481     * @return The resampled BlkImgDataSrc
2482     * @exception IOException image access exception
2483     * @exception ColorSpaceException if image contains a bad colorspace box
2484     **/
2485/*
2486    public BlkImgDataSrc createResampler(BlkImgDataSrc src,
2487                                         ColorSpace csMap)
2488        throws IOException, ColorSpaceException {
2489        return Resampler.createInstance(src, csMap); }
2490*/
2491    /**
2492     * Creates and returns the ROIDeScaler corresponding to the information
2493     * read from the codestream header and with the special additional
2494     * parameters from the parameter list.
2495     *
2496     * @param src The bit stream reader agent where to get code-block data
2497     * from.
2498     *
2499     * @param pl The parameter list containing parameters applicable to the
2500     * entropy decoder (other parameters can also be present).
2501     *
2502     * @return The ROI descaler
2503     * */
2504    public ROIDeScaler createROIDeScaler(CBlkQuantDataSrcDec src,
2505                                         J2KImageReadParamJava j2krparam,
2506                                         DecoderSpecs decSpec2){
2507        return ROIDeScaler.createInstance(src, j2krparam, decSpec2);
2508    }
2509
2510    /** 
2511     * Method that resets members indicating which markers have already been
2512     * found
2513     * */
2514    public void resetHeaderMarkers() {
2515        // The found status of PLM remains since only PLM OR PLT allowed
2516        // Same goes for PPM and PPT
2517        nfMarkSeg = nfMarkSeg & (PLM_FOUND | PPM_FOUND);
2518        nCOCMarkSeg = 0;
2519        nQCCMarkSeg = 0;
2520        nCOMMarkSeg = 0;
2521        nRGNMarkSeg = 0;
2522    }
2523
2524
2525    /**
2526     * Print information about the current header.
2527     *
2528     * @return Information in a String
2529     * */
2530    public String toString(){
2531        return hdStr;
2532    }
2533
2534    /**
2535     * Returns the parameters that are used in this class. It returns a 2D
2536     * String array. Each of the 1D arrays is for a different option, and they
2537     * have 3 elements. The first element is the option name, the second one
2538     * is the synopsis and the third one is a long description of what the
2539     * parameter is. The synopsis or description may be 'null', in which case
2540     * it is assumed that there is no synopsis or description of the option,
2541     * respectively.
2542     *
2543     * @return the options name, their synopsis and their explanation.
2544     * */
2545    public static String[][] getParameterInfo() {
2546        return pinfo;
2547    }
2548
2549    /**
2550     * Return the number of tiles in the image
2551     *
2552     * @return The number of tiles
2553     * */
2554    public int getNumTiles(){
2555        return nTiles;
2556    }
2557
2558    /**
2559     * Return the packed packet headers for a given tile.
2560     *
2561     * @return An input stream containing the packed packet headers for a
2562     * particular tile
2563     *
2564     * @exception IOException If an I/O error occurs while reading from the
2565     * encoder header stream
2566     * */
2567     public ByteArrayInputStream getPackedPktHead(int tile)
2568         throws IOException {
2569
2570        if(pkdPktHeaders==null) {
2571            int i,t;
2572            pkdPktHeaders = new ByteArrayOutputStream[nTiles];
2573            for(i=nTiles-1; i>=0; i--) {
2574                pkdPktHeaders[i] = new ByteArrayOutputStream();
2575            }
2576            if(nPPMMarkSeg!=0) {
2577                // If this is first time packed packet headers are requested,
2578                // create packed packet headers from Nppm and Ippm fields
2579                int nppm;
2580                int nTileParts = tileOfTileParts.size();
2581                byte[] temp;
2582                ByteArrayInputStream pph;
2583                ByteArrayOutputStream allNppmIppm =
2584                    new ByteArrayOutputStream();
2585
2586                // Concatenate all Nppm and Ippm fields
2587                for(i=0 ; i<nPPMMarkSeg ; i++) {
2588                    allNppmIppm.write(pPMMarkerData[i]);
2589                }
2590                pph = new ByteArrayInputStream(allNppmIppm.toByteArray());
2591
2592                // Read all packed packet headers and concatenate for each
2593                // tile part
2594                for(i=0; i<nTileParts ; i++) {
2595                    t = ((Integer)tileOfTileParts.elementAt(i)).intValue();
2596                    // get Nppm value
2597                    nppm = (pph.read()<<24)|(pph.read()<<16)|
2598                        (pph.read()<<8)|(pph.read());
2599
2600                    temp = new byte[nppm];
2601                    // get ippm field
2602                    pph.read(temp);
2603                    pkdPktHeaders[t].write(temp);
2604                }
2605            } else {
2606                int tp;
2607                // Write all packed packet headers to pkdPktHeaders
2608                for(t=nTiles-1; t>=0; t--) {
2609                    for(tp=0; tp<nTileParts[t]; tp++){
2610                        for(i=0 ; i<nPPTMarkSeg[t][tp] ; i++) {
2611                           pkdPktHeaders[t].
2612                                write(tilePartPkdPktHeaders[t][tp][i]);
2613                        }
2614                    }
2615                }
2616            }
2617        }
2618
2619        return new ByteArrayInputStream(pkdPktHeaders[tile].toByteArray());
2620    }
2621
2622    /**
2623     * Sets the tile of each tile part in order. This information is needed
2624     * for identifying which packet header belongs to which tile when using
2625     * the PPM marker.
2626     *
2627     * @param tile The tile number that the present tile part belongs to.
2628     * */
2629    public void setTileOfTileParts(int tile) {
2630        if(nPPMMarkSeg!=0) {
2631            tileOfTileParts.addElement(new Integer(tile));
2632        }
2633    }
2634
2635    /**
2636     * Returns the number of found marker segments in the current header.
2637     *
2638     * @return The number of marker segments found in the current header.
2639     * */
2640    public int getNumFoundMarkSeg() {
2641        return nfMarkSeg;
2642    }
2643
2644}