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