001/*
002 * $RCSfile: HeaderInfo.java,v $
003 * $Revision: 1.1 $
004 * $Date: 2005/02/11 05:02:00 $
005 * $State: Exp $
006 *
007 * Class:                   HeaderInfo
008 *
009 * Description:             Holds information found in main and tile-part
010 *                          headers 
011 *
012 *
013 *
014 * COPYRIGHT:
015 * 
016 * This software module was originally developed by Raphaël Grosbois and
017 * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
018 * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
019 * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
020 * Centre France S.A) in the course of development of the JPEG2000
021 * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
022 * software module is an implementation of a part of the JPEG 2000
023 * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
024 * Systems AB and Canon Research Centre France S.A (collectively JJ2000
025 * Partners) agree not to assert against ISO/IEC and users of the JPEG
026 * 2000 Standard (Users) any of their rights under the copyright, not
027 * including other intellectual property rights, for this software module
028 * with respect to the usage by ISO/IEC and Users of this software module
029 * or modifications thereof for use in hardware or software products
030 * claiming conformance to the JPEG 2000 Standard. Those intending to use
031 * this software module in hardware or software products are advised that
032 * their use may infringe existing patents. The original developers of
033 * this software module, JJ2000 Partners and ISO/IEC assume no liability
034 * for use of this software module or modifications thereof. No license
035 * or right to this software module is granted for non JPEG 2000 Standard
036 * conforming products. JJ2000 Partners have full right to use this
037 * software module for his/her own purpose, assign or donate this
038 * software module to any third party and to inhibit third parties from
039 * using this software module for non JPEG 2000 Standard conforming
040 * products. This copyright notice must be included in all copies or
041 * derivative works of this software module.
042 * 
043 * Copyright (c) 1999/2000 JJ2000 Partners.
044 * */
045package jj2000.j2k.codestream;
046
047import jj2000.j2k.wavelet.*;
048
049import java.util.*;
050
051/**
052 * Classe that holds information found in the marker segments of the main and
053 * tile-part headers. There is one inner-class per marker segment type found
054 * in these headers.
055 * */
056public class HeaderInfo implements Markers,ProgressionType,FilterTypes,
057                                   Cloneable {
058
059    /** Internal class holding information found in the SIZ marker segment */
060    public class SIZ implements Cloneable {
061        public int lsiz;
062        public int rsiz;
063        public int xsiz;
064        public int ysiz;
065        public int x0siz;
066        public int y0siz;
067        public int xtsiz;
068        public int ytsiz;
069        public int xt0siz;
070        public int yt0siz;
071        public int csiz;
072        public int[] ssiz;
073        public int[] xrsiz;
074        public int[] yrsiz;
075
076        /** Component widths */
077        private int[] compWidth = null;
078        /** Maximum width among all components */
079        private int maxCompWidth = -1;
080        /** Component heights */
081        private int[] compHeight = null;
082        /** Maximum height among all components */
083        private int maxCompHeight = -1;
084        /** 
085         * Width of the specified tile-component
086         *
087         * @param t Tile index
088         *
089         * @param c Component index
090         * */
091        public int getCompImgWidth(int c) {
092            if (compWidth==null) {
093                compWidth = new int[csiz];
094                for(int cc=0; cc<csiz; cc++) {
095                    compWidth[cc] = 
096                        (int)(Math.ceil((xsiz)/(double)xrsiz[cc])
097                              - Math.ceil(x0siz/(double)xrsiz[cc]));
098                }
099            } 
100            return compWidth[c];
101        }
102        public int getMaxCompWidth() {
103            if (compWidth==null) {
104                compWidth = new int[csiz];
105                for(int cc=0; cc<csiz; cc++) {
106                    compWidth[cc] = 
107                        (int)(Math.ceil((xsiz)/(double)xrsiz[cc])
108                              - Math.ceil(x0siz/(double)xrsiz[cc]));
109                }
110            } 
111            if (maxCompWidth==-1) {
112                for(int c=0; c<csiz; c++) {
113                    if(compWidth[c]>maxCompWidth) {
114                        maxCompWidth = compWidth[c];
115                    }
116                }
117            }
118            return maxCompWidth;
119        }
120        public int getCompImgHeight(int c) {
121            if (compHeight==null) {
122                compHeight = new int[csiz];
123                for(int cc=0; cc<csiz; cc++) {
124                    compHeight[cc] = 
125                        (int)(Math.ceil((ysiz)/(double)yrsiz[cc])
126                              - Math.ceil(y0siz/(double)yrsiz[cc]));
127                }
128            } 
129            return compHeight[c];
130        }
131        public int getMaxCompHeight() {
132            if (compHeight==null) {
133                compHeight = new int[csiz];
134                for(int cc=0; cc<csiz; cc++) {
135                    compHeight[cc] = 
136                        (int)(Math.ceil((ysiz)/(double)yrsiz[cc])
137                              - Math.ceil(y0siz/(double)yrsiz[cc]));
138                }
139            } 
140            if (maxCompHeight==-1) {
141                for(int c=0; c<csiz; c++) {
142                    if(compHeight[c]!=maxCompHeight) {
143                        maxCompHeight = compHeight[c];
144                    }
145                }
146            }
147            return maxCompHeight;
148        }
149        private int numTiles = -1;
150        public int getNumTiles() {
151            if(numTiles==-1) {
152                numTiles = ((xsiz-xt0siz+xtsiz-1) / xtsiz) * 
153                    ((ysiz-yt0siz+ytsiz-1) / ytsiz);
154            }
155            return numTiles;
156        }
157        private boolean[] origSigned = null;
158        public boolean isOrigSigned(int c) {
159            if(origSigned==null) {
160                origSigned = new boolean[csiz];
161                for(int cc=0; cc<csiz; cc++) {
162                    origSigned[cc] = ((ssiz[cc]>>>SSIZ_DEPTH_BITS)==1);
163                }
164            }
165            return origSigned[c];
166        }
167        private int[] origBitDepth = null;
168        public int getOrigBitDepth(int c) {
169            if(origBitDepth==null) {
170                origBitDepth = new int[csiz];
171                for (int cc=0; cc<csiz; cc++) {
172                    origBitDepth[cc] = (ssiz[cc] & ((1<<SSIZ_DEPTH_BITS)-1))+1;
173                }
174            }
175            return origBitDepth[c];
176        }
177        public SIZ getCopy() { 
178            SIZ ms = null;
179            try {
180                ms = (SIZ)this.clone(); 
181            } catch (CloneNotSupportedException e) {
182                throw new Error("Cannot clone SIZ marker segment");
183            }
184            return ms;
185        }
186
187        /** Display information found in SIZ marker segment */
188        public String toString() {
189            String str = "\n --- SIZ ("+lsiz+" bytes) ---\n";
190            str += " Capabilities : "+rsiz+"\n";
191            str += " Image dim.   : "+(xsiz-x0siz)+"x"+(ysiz-y0siz)+", (off="+
192                x0siz+","+y0siz+")\n";
193            str += " Tile dim.    : "+xtsiz+"x"+ytsiz+", (off="+xt0siz+","+
194                yt0siz+")\n";
195            str += " Component(s) : "+csiz+"\n";
196            str += " Orig. depth  : ";
197            for (int i=0; i<csiz; i++) { str += getOrigBitDepth(i)+" "; }
198            str += "\n";
199            str += " Orig. signed : ";
200            for (int i=0; i<csiz; i++) { str += isOrigSigned(i)+" "; }
201            str += "\n";
202            str += " Subs. factor : ";
203            for (int i=0; i<csiz; i++) { str += xrsiz[i]+","+yrsiz[i]+" "; }
204            str += "\n";
205            return str;
206        }
207    }
208    /** Returns a new instance of SIZ */
209    public SIZ getNewSIZ() { return new SIZ(); }
210
211    /** Internal class holding information found in the SOt marker segments */
212    public class SOT {
213        public int lsot;
214        public int isot;
215        public int psot;
216        public int tpsot;
217        public int tnsot;
218
219        /** Display information found in this SOT marker segment */
220        public String toString() {
221            String str = "\n --- SOT ("+lsot+" bytes) ---\n";
222            str += "Tile index         : "+isot+"\n";
223            str += "Tile-part length   : "+psot+" bytes\n";
224            str += "Tile-part index    : "+tpsot+"\n";
225            str += "Num. of tile-parts : "+tnsot+"\n";
226            str += "\n";
227            return str;
228        }
229    }
230    /** Returns a new instance of SOT */
231    public SOT getNewSOT() { return new SOT(); }
232
233    /** Internal class holding information found in the COD marker segments */
234    public class COD implements Cloneable {
235        public int lcod;
236        public int scod;
237        public int sgcod_po; // Progression order
238        public int sgcod_nl; // Number of layers
239        public int sgcod_mct; // Multiple component transformation
240        public int spcod_ndl; // Number of decomposition levels
241        public int spcod_cw; // Code-blocks width
242        public int spcod_ch; // Code-blocks height
243        public int spcod_cs; // Code-blocks style
244        public int[] spcod_t = new int[1]; // Transformation
245        public int[] spcod_ps; // Precinct size
246
247        public COD getCopy() { 
248            COD ms = null;
249            try {
250                ms = (COD)this.clone(); 
251            } catch (CloneNotSupportedException e) {
252                throw new Error("Cannot clone SIZ marker segment");
253            }
254            return ms;
255        }
256        /** Display information found in this COD marker segment */
257        public String toString() {
258            String str = "\n --- COD ("+lcod+" bytes) ---\n";
259            str += " Coding style   : ";
260            if(scod==0) {
261                str += "Default";
262            } else {
263                if((scod&SCOX_PRECINCT_PARTITION)!=0) str += "Precints ";
264                if((scod&SCOX_USE_SOP)!=0) str += "SOP ";
265                if((scod&SCOX_USE_EPH)!=0) str += "EPH ";
266                int cb0x = ((scod&SCOX_HOR_CB_PART)!=0) ? 1 : 0;
267                int cb0y = ((scod&SCOX_VER_CB_PART)!=0) ? 1 : 0;
268                if (cb0x!=0 || cb0y!=0) {
269                    str += "Code-blocks offset";
270                    str += "\n Cblk partition : "+cb0x+","+cb0y;
271                }
272            }
273            str += "\n";
274            str += " Cblk style     : ";
275            if(spcod_cs==0) {
276                str += "Default";
277            } else {
278                if((spcod_cs&0x1)!=0) str += "Bypass ";
279                if((spcod_cs&0x2)!=0) str += "Reset ";
280                if((spcod_cs&0x4)!=0) str += "Terminate ";
281                if((spcod_cs&0x8)!=0) str += "Vert_causal ";
282                if((spcod_cs&0x10)!=0) str += "Predict ";
283                if((spcod_cs&0x20)!=0) str += "Seg_symb ";
284            }
285            str += "\n";
286            str += " Num. of levels : "+spcod_ndl+"\n";
287            switch(sgcod_po) {
288            case LY_RES_COMP_POS_PROG:
289                str += " Progress. type : LY_RES_COMP_POS_PROG\n";
290                break;
291            case RES_LY_COMP_POS_PROG:
292                str += " Progress. type : RES_LY_COMP_POS_PROG\n";
293                break;
294            case RES_POS_COMP_LY_PROG:
295                str += " Progress. type : RES_POS_COMP_LY_PROG\n";
296                break;
297            case POS_COMP_RES_LY_PROG:
298                str += " Progress. type : POS_COMP_RES_LY_PROG\n";
299                break;
300            case COMP_POS_RES_LY_PROG:
301                str += " Progress. type : COMP_POS_RES_LY_PROG\n";
302                break;
303            }
304            str += " Num. of layers : "+sgcod_nl+"\n";
305            str += " Cblk dimension : "+(1<<(spcod_cw+2))+"x"+
306                (1<<(spcod_ch+2))+"\n";
307            switch (spcod_t[0]) {
308            case W9X7:
309                str += " Filter         : 9-7 irreversible\n";
310                break;
311            case W5X3:
312                str += " Filter         : 5-3 reversible\n";
313                break;
314            }
315            str += " Multi comp tr. : "+(sgcod_mct==1)+"\n";  
316            if(spcod_ps!=null) {
317                str += " Precincts      : ";
318                for(int i=0; i<spcod_ps.length; i++) {
319                    str += (1<<(spcod_ps[i] & 0x000F))+"x"+
320                        (1<<(((spcod_ps[i] & 0x00F0)>>4)))+" ";
321                }
322            }
323            str += "\n";
324            return str;
325        }
326    }
327    /** Returns a new instance of COD */
328    public COD getNewCOD() { return new COD(); }
329
330    /** Internal class holding information found in the COC marker segments */
331    public class COC {
332        public int lcoc;
333        public int ccoc;
334        public int scoc;
335        public int spcoc_ndl; // Number of decomposition levels
336        public int spcoc_cw;
337        public int spcoc_ch;
338        public int spcoc_cs;
339        public int[] spcoc_t = new int[1];
340        public int[] spcoc_ps;
341        /** Display information found in this COC marker segment */
342        public String toString() {
343            String str = "\n --- COC ("+lcoc+" bytes) ---\n";
344            str += " Component      : "+ccoc+"\n";
345            str += " Coding style   : ";
346            if(scoc==0) {
347                str += "Default";
348            } else {
349                if((scoc&0x1)!=0) str += "Precints ";
350                if((scoc&0x2)!=0) str += "SOP ";
351                if((scoc&0x4)!=0) str += "EPH ";
352            }
353            str += "\n";
354            str += " Cblk style     : ";
355            if(spcoc_cs==0) {
356                str += "Default";
357            } else {
358                if((spcoc_cs&0x1)!=0) str += "Bypass ";
359                if((spcoc_cs&0x2)!=0) str += "Reset ";
360                if((spcoc_cs&0x4)!=0) str += "Terminate ";
361                if((spcoc_cs&0x8)!=0) str += "Vert_causal ";
362                if((spcoc_cs&0x10)!=0) str += "Predict ";
363                if((spcoc_cs&0x20)!=0) str += "Seg_symb ";
364            }
365            str += "\n";
366            str += " Num. of levels : "+spcoc_ndl+"\n";
367            str += " Cblk dimension : "+(1<<(spcoc_cw+2))+"x"+
368                (1<<(spcoc_ch+2))+"\n";
369            switch (spcoc_t[0]) {
370            case W9X7:
371                str += " Filter         : 9-7 irreversible\n";
372                break;
373            case W5X3:
374                str += " Filter         : 5-3 reversible\n";
375                break;
376            }
377            if(spcoc_ps!=null) {
378                str += " Precincts      : ";
379                for(int i=0; i<spcoc_ps.length; i++) {
380                    str += (1<<(spcoc_ps[i] & 0x000F))+"x"+
381                        (1<<(((spcoc_ps[i] & 0x00F0)>>4)))+" ";
382                }
383            }
384            str += "\n";
385            return str;
386        }
387    }
388    /** Returns a new instance of COC */
389    public COC getNewCOC() { return new COC(); }
390
391    /** Internal class holding information found in the RGN marker segments */
392    public class RGN {
393        public int lrgn;
394        public int crgn;
395        public int srgn;
396        public int sprgn;
397        /** Display information found in this RGN marker segment */
398        public String toString() {
399            String str = "\n --- RGN ("+lrgn+" bytes) ---\n";
400            str += " Component : "+crgn+"\n";
401            if(srgn==0) {
402                str += " ROI style : Implicit\n";
403            } else {
404                str += " ROI style : Unsupported\n";
405            }
406            str += " ROI shift : "+sprgn+"\n";
407            str += "\n";
408            return str;
409        }
410    }
411    /** Returns a new instance of RGN */
412    public RGN getNewRGN() { return new RGN(); }
413    
414    /** Internal class holding information found in the QCD marker segments */
415    public class QCD {
416        public int lqcd;
417        public int sqcd;
418        public int[][] spqcd;
419
420        private int qType = -1;
421        public int getQuantType() {
422            if(qType==-1) {
423                qType = sqcd & ~(SQCX_GB_MSK<<SQCX_GB_SHIFT);
424            }
425            return qType;
426        }
427        private int gb = -1;
428        public int getNumGuardBits() {
429            if(gb==-1) {
430                gb = (sqcd>>SQCX_GB_SHIFT)&SQCX_GB_MSK;
431            }
432            return gb;
433        }
434
435        /** Display information found in this QCD marker segment */
436        public String toString() {
437            String str = "\n --- QCD ("+lqcd+" bytes) ---\n";
438            str += " Quant. type    : ";
439            int qt = getQuantType();
440            if(qt==SQCX_NO_QUANTIZATION) str += "No quantization \n";
441            else if(qt==SQCX_SCALAR_DERIVED) str += "Scalar derived\n";
442            else if(qt==SQCX_SCALAR_EXPOUNDED) str += "Scalar expounded\n";
443            str += " Guard bits     : "+getNumGuardBits()+"\n";
444            if(qt==SQCX_NO_QUANTIZATION) {
445                str += " Exponents   :\n";
446                int exp;
447                for (int i=0; i<spqcd.length; i++) {
448                    for(int j=0; j<spqcd[i].length; j++) {
449                        if (i==0 && j==0) {
450                            exp = (spqcd[0][0]>>SQCX_EXP_SHIFT)&SQCX_EXP_MASK;
451                            str += "\tr=0 : "+exp+"\n";
452                        } else if (i!=0 && j>0) {
453                            exp = (spqcd[i][j]>>SQCX_EXP_SHIFT)&SQCX_EXP_MASK;
454                            str += "\tr="+i+",s="+j+" : "+exp+"\n";
455                        }
456                    }
457                }
458            } else {
459                str += " Exp / Mantissa : \n"; 
460                int exp;
461                double mantissa;
462                for (int i=0; i<spqcd.length; i++) {
463                    for(int j=0; j<spqcd[i].length; j++) {
464                        if (i==0 && j==0) {
465                            exp = (spqcd[0][0]>>11)&0x1f;
466                            mantissa = (-1f-((float)(spqcd[0][0]&0x07ff))/
467                                        (1<<11))/(-1<<exp);
468                            str += "\tr=0 : "+exp+" / "+mantissa+"\n";
469                        } else if (i!=0 && j>0) {
470                            exp = (spqcd[i][j]>>11)&0x1f;
471                            mantissa = (-1f-((float)(spqcd[i][j]&0x07ff))/
472                                        (1<<11))/(-1<<exp);
473                            str += "\tr="+i+",s="+j+" : "+exp+" / "+
474                                mantissa+"\n";
475                        }
476                    }
477                }
478            }
479            str += "\n";
480            return str;
481        }
482    }
483    /** Returns a new instance of QCD */
484    public QCD getNewQCD() { return new QCD(); }
485
486    /** Internal class holding information found in the QCC marker segments */
487    public class QCC {
488        public int lqcc;
489        public int cqcc;
490        public int sqcc;
491        public int[][] spqcc;
492
493        private int qType = -1;
494        public int getQuantType() {
495            if(qType==-1) {
496                qType = sqcc & ~(SQCX_GB_MSK<<SQCX_GB_SHIFT);
497            }
498            return qType;
499        }
500        private int gb = -1;
501        public int getNumGuardBits() {
502            if(gb==-1) {
503                gb = (sqcc>>SQCX_GB_SHIFT)&SQCX_GB_MSK;
504            }
505            return gb;
506        }
507
508       /** Display information found in this QCC marker segment */
509        public String toString() {
510            String str = "\n --- QCC ("+lqcc+" bytes) ---\n";
511            str += " Component      : "+cqcc+"\n";
512            str += " Quant. type    : ";
513            int qt = getQuantType();
514            if(qt==SQCX_NO_QUANTIZATION) str += "No quantization \n";
515            else if(qt==SQCX_SCALAR_DERIVED) str += "Scalar derived\n";
516            else if(qt==SQCX_SCALAR_EXPOUNDED) str += "Scalar expounded\n";
517            str += " Guard bits     : "+getNumGuardBits()+"\n";
518            if(qt==SQCX_NO_QUANTIZATION) {
519                str += " Exponents   :\n";
520                int exp;
521                for (int i=0; i<spqcc.length; i++) {
522                    for(int j=0; j<spqcc[i].length; j++) {
523                        if (i==0 && j==0) {
524                            exp = (spqcc[0][0]>>SQCX_EXP_SHIFT)&SQCX_EXP_MASK;
525                            str += "\tr=0 : "+exp+"\n";
526                        } else if (i!=0 && j>0) {
527                            exp = (spqcc[i][j]>>SQCX_EXP_SHIFT)&SQCX_EXP_MASK;
528                            str += "\tr="+i+",s="+j+" : "+exp+"\n";
529                        }
530                    }
531                }
532            } else {
533                str += " Exp / Mantissa : \n"; 
534                int exp;
535                double mantissa;
536                for (int i=0; i<spqcc.length; i++) {
537                    for(int j=0; j<spqcc[i].length; j++) {
538                        if (i==0 && j==0) {
539                            exp = (spqcc[0][0]>>11)&0x1f;
540                            mantissa = (-1f-((float)(spqcc[0][0]&0x07ff))/
541                                        (1<<11))/(-1<<exp);
542                            str += "\tr=0 : "+exp+" / "+mantissa+"\n";
543                        } else if (i!=0 && j>0) {
544                            exp = (spqcc[i][j]>>11)&0x1f;
545                            mantissa = (-1f-((float)(spqcc[i][j]&0x07ff))/
546                                        (1<<11))/(-1<<exp);
547                            str += "\tr="+i+",s="+j+" : "+exp+" / "+
548                                mantissa+"\n";
549                        }
550                    }
551                }
552            }
553            str += "\n";
554            return str;
555        }
556    }
557    /** Returns a new instance of QCC */
558    public QCC getNewQCC() { return new QCC(); }
559
560    /** Internal class holding information found in the POC marker segments */
561    public class POC {
562        public int lpoc;
563        public int[] rspoc;
564        public int[] cspoc;
565        public int[] lyepoc;
566        public int[] repoc;
567        public int[] cepoc;
568        public int[] ppoc;
569        /** Display information found in this POC marker segment */
570        public String toString() {
571            String str = "\n --- POC ("+lpoc+" bytes) ---\n";
572            str += " Chg_idx RSpoc CSpoc LYEpoc REpoc CEpoc Ppoc\n";
573            for(int chg=0;chg<rspoc.length;chg++) {
574                str += "   "+chg
575                    +"      "+rspoc[chg]
576                    +"     "+cspoc[chg]
577                    +"     "+lyepoc[chg]
578                    +"      "+repoc[chg]
579                    +"     "+cepoc[chg];
580                switch(ppoc[chg]) {
581                case ProgressionType.LY_RES_COMP_POS_PROG:
582                    str += "  LY_RES_COMP_POS_PROG\n";
583                    break;
584                case ProgressionType.RES_LY_COMP_POS_PROG:
585                    str += "  RES_LY_COMP_POS_PROG\n";
586                    break;
587                case ProgressionType.RES_POS_COMP_LY_PROG:
588                    str += "  RES_POS_COMP_LY_PROG\n";
589                    break;
590                case ProgressionType.POS_COMP_RES_LY_PROG:
591                    str += "  POS_COMP_RES_LY_PROG\n";
592                    break;
593                case ProgressionType.COMP_POS_RES_LY_PROG:
594                    str += "  COMP_POS_RES_LY_PROG\n";
595                    break;
596                }
597            }
598            str += "\n";
599            return str;
600        }
601    }
602    /** Returns a new instance of POC */
603    public POC getNewPOC() { return new POC(); }
604
605    /** Internal class holding information found in the CRG marker segment */
606    public class CRG {
607        public int lcrg;
608        public int[] xcrg;
609        public int[] ycrg;
610        /** Display information found in the CRG marker segment */
611        public String toString() {
612            String str = "\n --- CRG ("+lcrg+" bytes) ---\n";
613            for(int c=0; c<xcrg.length; c++) {
614                str += " Component "+c+" offset : "+xcrg[c]+","+ycrg[c]+"\n";
615            }
616            str += "\n";
617            return str;
618        }
619    }
620    /** Returns a new instance of CRG */
621    public CRG getNewCRG() { return new CRG(); }
622
623    /** Internal class holding information found in the COM marker segments */
624    public class COM {
625        public int lcom;
626        public int rcom;
627        public byte[] ccom;
628        /** Display information found in the COM marker segment */
629        public String toString() {
630            String str = "\n --- COM ("+lcom+" bytes) ---\n";
631            if (rcom==0) {
632                str += " Registration : General use (binary values)\n";
633            } else if (rcom==1) {
634                str += " Registration : General use (IS 8859-15:1999 "+
635                    "(Latin) values)\n";
636                str += " Text         : "+(new String(ccom))+"\n";
637            } else {
638                str += " Registration : Unknown\n";
639            }
640            str += "\n";
641            return str;
642        }
643    }
644    /** Returns a new instance of COM */
645    public COM getNewCOM() { ncom++; return new COM(); }
646
647    /** Returns the number of found COM marker segments */
648    public int getNumCOM() { return ncom; }
649
650    /** Reference to the SIZ marker segment found in main header */
651    public SIZ siz;
652
653    /** Reference to the SOT marker segments found in tile-part headers. The
654     * kwy is given by "t"+tileIdx"_tp"+tilepartIndex. */
655    public Hashtable sot = new Hashtable();
656
657    /** Reference to the COD marker segments found in main and first tile-part
658     * header. The key is either "main" or "t"+tileIdx.*/
659    public Hashtable cod = new Hashtable();
660
661    /** Reference to the COC marker segments found in main and first tile-part
662     * header. The key is either "main_c"+componentIndex or
663     * "t"+tileIdx+"_c"+component_index. */
664    public Hashtable coc = new Hashtable();
665
666    /** Reference to the RGN marker segments found in main and first tile-part
667     * header. The key is either "main_c"+componentIndex or
668     * "t"+tileIdx+"_c"+component_index. */
669    public Hashtable rgn = new Hashtable();
670
671    /** Reference to the QCD marker segments found in main and first tile-part
672     * header. The key is either "main" or "t"+tileIdx. */
673    public Hashtable qcd = new Hashtable();
674
675    /** Reference to the QCC marker segments found in main and first tile-part
676     * header. They key is either "main_c"+componentIndex or
677     * "t"+tileIdx+"_c"+component_index. */
678    public Hashtable qcc = new Hashtable();
679
680    /** Reference to the POC marker segments found in main and first tile-part
681     * header. They key is either "main" or "t"+tileIdx. */
682    public Hashtable poc = new Hashtable();
683
684    /** Reference to the CRG marker segment found in main header */
685    public CRG crg;
686
687    /** Reference to the COM marker segments found in main and tile-part
688     * headers. The key is either "main_"+comIdx or "t"+tileIdx+"_"+comIdx. */
689    public Hashtable com = new Hashtable();
690
691    /** Number of found COM marker segment */
692    private int ncom = 0;
693
694    /** Display information found in the different marker segments of the main
695     * header */
696    public String toStringMainHeader() {
697        int nc = siz.csiz;
698        // SIZ
699        String str = ""+siz;
700        // COD
701        if(cod.get("main")!=null) {
702            str += ""+(COD)cod.get("main");
703        }
704        // COCs
705        for(int c=0; c<nc; c++) {
706            if(coc.get("main_c"+c)!=null) {
707                str += ""+(COC)coc.get("main_c"+c);
708            }
709        }
710        // QCD
711        if(qcd.get("main")!=null) {
712            str += ""+(QCD)qcd.get("main");
713        }
714        // QCCs
715        for(int c=0; c<nc; c++) {
716            if(qcc.get("main_c"+c)!=null) {
717                str += ""+(QCC)qcc.get("main_c"+c);
718            }
719        }
720        // RGN
721        for(int c=0; c<nc; c++) {
722            if(rgn.get("main_c"+c)!=null) {
723                str += ""+(RGN)rgn.get("main_c"+c);
724            }
725        }
726        // POC
727        if(poc.get("main")!=null) {
728            str += ""+(POC)poc.get("main");
729        }
730        // CRG
731        if(crg!=null) {
732            str += ""+crg;
733        }
734        // COM
735        for(int i=0; i<ncom; i++) {
736            if(com.get("main_"+i)!=null) {
737                str += ""+(COM)com.get("main_"+i);
738            }
739        }
740        return str;
741    }
742
743    /** 
744     * Returns information found in the tile-part headers of a given tile.
745     *
746     * @param t index of the tile
747     *
748     * @param tp Number of tile-parts
749     * */
750    public String toStringTileHeader(int t, int ntp) {
751        int nc = siz.csiz;
752        String str = "";
753        // SOT
754        for(int i=0; i<ntp; i++) {
755            str += "Tile-part "+i+", tile "+t+":\n";
756            str += ""+(SOT)sot.get("t"+t+"_tp"+i);
757        }
758        // COD
759        if(cod.get("t"+t)!=null) {
760            str += ""+(COD)cod.get("t"+t);
761        }
762        // COCs
763        for(int c=0; c<nc; c++) {
764            if(coc.get("t"+t+"_c"+c)!=null) {
765                str += ""+(COC)coc.get("t"+t+"_c"+c);
766            }
767        }
768        // QCD
769        if(qcd.get("t"+t)!=null) {
770            str += ""+(QCD)qcd.get("t"+t);
771        }
772        // QCCs
773        for(int c=0; c<nc; c++) {
774            if(qcc.get("t"+t+"_c"+c)!=null) {
775                str += ""+(QCC)qcc.get("t"+t+"_c"+c);
776            }
777        }
778        // RGN
779        for(int c=0; c<nc; c++) {
780            if(rgn.get("t"+t+"_c"+c)!=null) {
781                str += ""+(RGN)rgn.get("t"+t+"_c"+c);
782            }
783        }
784        // POC
785        if(poc.get("t"+t)!=null) {
786            str += ""+(POC)poc.get("t"+t);
787        }
788        return str;
789    }
790
791    /** 
792     * Returns information found in the tile-part headers of a given tile
793     * exception the SOT marker segment.
794     *
795     * @param t index of the tile
796     *
797     * @param tp Number of tile-parts
798     * */
799    public String toStringThNoSOT(int t, int ntp) {
800        int nc = siz.csiz;
801        String str = "";
802        // COD
803        if(cod.get("t"+t)!=null) {
804            str += ""+(COD)cod.get("t"+t);
805        }
806        // COCs
807        for(int c=0; c<nc; c++) {
808            if(coc.get("t"+t+"_c"+c)!=null) {
809                str += ""+(COC)coc.get("t"+t+"_c"+c);
810            }
811        }
812        // QCD
813        if(qcd.get("t"+t)!=null) {
814            str += ""+(QCD)qcd.get("t"+t);
815        }
816        // QCCs
817        for(int c=0; c<nc; c++) {
818            if(qcc.get("t"+t+"_c"+c)!=null) {
819                str += ""+(QCC)qcc.get("t"+t+"_c"+c);
820            }
821        }
822        // RGN
823        for(int c=0; c<nc; c++) {
824            if(rgn.get("t"+t+"_c"+c)!=null) {
825                str += ""+(RGN)rgn.get("t"+t+"_c"+c);
826            }
827        }
828        // POC
829        if(poc.get("t"+t)!=null) {
830            str += ""+(POC)poc.get("t"+t);
831        }
832        return str;
833    }
834
835    /** Returns a copy of this object */
836    public HeaderInfo getCopy(int nt) {
837        HeaderInfo nhi = null;
838        // SIZ
839        try {
840            nhi = (HeaderInfo)clone();
841        } catch (CloneNotSupportedException e) {
842            throw new Error("Cannot clone HeaderInfo instance");
843        }
844        nhi.siz = siz.getCopy();
845        // COD
846        if(cod.get("main")!=null) {
847            COD ms = (COD)cod.get("main");
848            nhi.cod.put("main",ms.getCopy());
849        }
850        for (int t=0; t<nt; t++) {
851            if(cod.get("t"+t)!=null) {
852                COD ms = (COD)cod.get("t"+t);
853                nhi.cod.put("t"+t,ms.getCopy());
854            }
855        }
856        return nhi;
857    }
858}