001/*
002 * $RCSfile: FileBitstreamReaderAgent.java,v $
003 * $Revision: 1.4 $
004 * $Date: 2006/10/05 01:10:31 $
005 * $State: Exp $
006 *
007 * Class:                   FileBitstreamReaderAgent
008 *
009 * Description:             Retrieve code-blocks codewords in the bit stream
010 *
011 *
012 *
013 * COPYRIGHT:
014 *
015 * This software module was originally developed by Raphaël Grosbois and
016 * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
017 * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
018 * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
019 * Centre France S.A) in the course of development of the JPEG2000
020 * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
021 * software module is an implementation of a part of the JPEG 2000
022 * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
023 * Systems AB and Canon Research Centre France S.A (collectively JJ2000
024 * Partners) agree not to assert against ISO/IEC and users of the JPEG
025 * 2000 Standard (Users) any of their rights under the copyright, not
026 * including other intellectual property rights, for this software module
027 * with respect to the usage by ISO/IEC and Users of this software module
028 * or modifications thereof for use in hardware or software products
029 * claiming conformance to the JPEG 2000 Standard. Those intending to use
030 * this software module in hardware or software products are advised that
031 * their use may infringe existing patents. The original developers of
032 * this software module, JJ2000 Partners and ISO/IEC assume no liability
033 * for use of this software module or modifications thereof. No license
034 * or right to this software module is granted for non JPEG 2000 Standard
035 * conforming products. JJ2000 Partners have full right to use this
036 * software module for his/her own purpose, assign or donate this
037 * software module to any third party and to inhibit third parties from
038 * using this software module for non JPEG 2000 Standard conforming
039 * products. This copyright notice must be included in all copies or
040 * derivative works of this software module.
041 *
042 * Copyright (c) 1999/2000 JJ2000 Partners.
043 * */
044package jj2000.j2k.codestream.reader;
045import java.awt.Point;
046import java.io.ByteArrayInputStream;
047import java.io.EOFException;
048import java.io.IOException;
049import java.util.ArrayList;
050import java.util.Vector;
051
052import javax.imageio.stream.ImageInputStream;
053import javax.imageio.stream.MemoryCacheImageInputStream;
054
055import jj2000.j2k.JJ2KExceptionHandler;
056import jj2000.j2k.NoNextElementException;
057import jj2000.j2k.NotImplementedError;
058import jj2000.j2k.codestream.CorruptedCodestreamException;
059import jj2000.j2k.codestream.HeaderInfo;
060import jj2000.j2k.codestream.Markers;
061import jj2000.j2k.codestream.PrecInfo;
062import jj2000.j2k.codestream.ProgressionType;
063import jj2000.j2k.decoder.DecoderSpecs;
064import jj2000.j2k.entropy.StdEntropyCoderOptions;
065import jj2000.j2k.entropy.decoder.DecLyrdCBlk;
066import jj2000.j2k.io.RandomAccessIO;
067import jj2000.j2k.quantization.dequantizer.StdDequantizerParams;
068import jj2000.j2k.util.ArrayUtil;
069import jj2000.j2k.util.FacilityManager;
070import jj2000.j2k.util.MathUtil;
071import jj2000.j2k.util.MsgLogger;
072import jj2000.j2k.wavelet.synthesis.SubbandSyn;
073
074import com.github.jaiimageio.jpeg2000.impl.J2KImageReadParamJava;
075
076/**
077 * This class reads the bit stream (with the help of HeaderDecoder for tile
078 * headers and PktDecoder for packets header and body) and retrives location
079 * of all code-block's codewords.
080 *
081 * <P>Note: All tile-parts headers are read by the constructor whereas packets
082 * are processed when decoding related tile (when setTile method is called).
083 *
084 * <P>In parsing mode, the reader simulates a virtual layer-resolution
085 * progressive bit stream with the same truncation points in each code-block,
086 * whereas in truncation mode, only the first bytes are taken into account (it
087 * behaves like if it is a real truncated codestream).
088 *
089 * @see HeaderDecoder
090 * @see PktDecoder
091 * */
092public class FileBitstreamReaderAgent extends BitstreamReaderAgent
093    implements Markers, ProgressionType, StdEntropyCoderOptions{
094
095    /** Whether or not the last read Psot value was zero. Only the Psot in the
096     * last tile-part in the codestream can have such a value. */
097    private boolean isPsotEqualsZero = true;
098
099    /** Reference to the PktDecoder instance */
100    public PktDecoder pktDec;
101
102    /** Reference to the J2KImageReadParamJava instance */
103    private J2KImageReadParamJava j2krparam;
104
105    /** The RandomAccessIO where to get data from */
106    private RandomAccessIO in;
107
108    /** The number of tiles in the image */
109    private int nt;
110
111    /** Offset of the first packet in each tile-part in each tile */
112    private int[][] firstPackOff;
113
114    /**
115     * Returns the number of tile-part found for a given tile
116     *
117     * @param t Tile index
118     *
119     * */
120    public int getNumTileParts(int t) {
121        if(firstPackOff==null || firstPackOff[t]==null) {
122            throw new Error("Tile "+t+" not found in input codestream.");
123        }
124        return firstPackOff[t].length;
125    }
126
127    /** Number of bytes allocated to each tile. In parsing mode, this number
128     * is related to the tile length in the codestream whereas in truncation
129     * mode all the rate is affected to the first tiles. */
130    private int[] nBytes;
131
132    /** Whether or not to print information found in codestream */
133    private boolean printInfo = false;
134
135    /**
136     * Backup of the number of bytes allocated to each tile. This array is
137     * used to restore the number of bytes to read in each tile when the
138     * codestream is read several times (for instance when decoding an R,G,B
139     * image to three output files)
140     * */
141    private int[] baknBytes;
142
143    /** Length of each tile-part (written in Psot) */
144    private int[][] tilePartLen;
145
146    /** Total length of each tile */
147    private int[] totTileLen;
148
149    /** Total length of tiles' header */
150    private int[] totTileHeadLen;
151
152    /** First tile part header length*/
153    private int firstTilePartHeadLen;
154
155    /** Total length of all tile parts in all tiles */
156    private double totAllTileLen;
157
158    /** Length of main header */
159    private int mainHeadLen;
160
161    /** Length of main and tile-parts headers */
162    private int headLen = 0;
163
164    /** Length of all tile-part headers */
165    private int[][] tilePartHeadLen;
166
167    /** Length of each packet head found in the tile */
168    private Vector pktHL;
169
170    /** True if truncation mode is used. False if parsing mode */
171    private boolean isTruncMode;
172
173    /** The number of tile-parts that remain to read */
174    private int remainingTileParts;
175
176    /** The number of tile-parts read so far for each tile */
177    private int[] tilePartsRead;
178
179    /** Thetotal  number of tile-parts read so far */
180    private int totTilePartsRead=0;
181
182    /** The number of tile-parts in each tile */
183    private int[] tileParts;
184
185    /** The total number of tile-parts in each tile */
186    private int[] totTileParts;
187
188    /** The current tile part being used */
189    private int curTilePart;
190
191    /** The number of the tile-part in the codestream */
192    private int[][] tilePartNum;
193
194    /** Whether or not a EOC marker has been found instead of a SOT */
195    private boolean isEOCFound = false;
196
197    /** Reference to the HeaderInfo instance (used when reading SOT marker
198     * segments) */
199    private HeaderInfo hi;
200
201    /** Array containing info. for all the code-blocks:<br>
202     * - 1st dim: component index.<br>
203     * - 2nd dim: resolution level index.<br>
204     * - 3rd dim: subband index.<br>
205     * - 4th/5th dim: code-block index (vert. and horiz.).<br>
206     */
207    private CBlkInfo[][][][][] cbI;
208
209    /** Gets the reference to the CBlkInfo array */
210    public CBlkInfo[][][][][] getCBlkInfo() {
211        return cbI;
212    }
213
214    /** The maximum number of layers to decode for any code-block */
215    private int lQuit;
216
217    /** Whether or not to use only first progression order */
218    private boolean usePOCQuit = false;
219
220    /**
221     * Reads all tiles headers and keep offset of their first
222     * packet. Finally it calls the rate allocation method.
223     *
224     * @param hd HeaderDecoder of the codestream.
225     *
226     * @param ehs The input stream where to read bit-stream.
227     *
228     * @param decSpec The decoder specifications
229     *
230     * @param j2krparam The J2KImageReadParam instance created from the
231     * command-line arguments.
232     *
233     * @param cdstrInfo Whether or not to print information found in
234     * codestream.
235     *
236     * @see #allocateRate
237     * */
238    public FileBitstreamReaderAgent(HeaderDecoder hd,RandomAccessIO ehs,
239                                    DecoderSpecs decSpec,
240                                    J2KImageReadParamJava j2krparam,
241                                    boolean cdstrInfo,HeaderInfo hi)
242        throws IOException {
243        super(hd,decSpec);
244
245        this.j2krparam = j2krparam;
246        this.printInfo = cdstrInfo;
247        this.hi = hi;
248
249        String strInfo = printInfo ?
250            "Codestream elements information in bytes "+
251            "(offset, total length, header length):\n\n" : null;
252
253        // Check whether quit conditiosn used
254        //usePOCQuit = j2krparam.getPOCQuit();
255
256        // Get decoding rate
257        if (j2krparam.getDecodingRate() == Double.MAX_VALUE)
258            tnbytes = Integer.MAX_VALUE;
259        else
260            tnbytes = (int)(j2krparam.getDecodingRate() * hd.getMaxCompImgWidth() *
261                        hd.getMaxCompImgHeight()) / 8;
262        //isTruncMode = !j2krparam.getParsing();
263        isTruncMode = true;
264
265        // Check if quit conditions are being used
266        //int ncbQuit = j2krparam.getNCBQuit();
267        int ncbQuit = -1;
268        if(ncbQuit != -1 && !isTruncMode){
269            throw new Error("Cannot use -parsing and -ncb_quit condition at "+
270                            "the same time.");
271        }
272
273//        lQuit = j2krparam.getLQuit();
274        lQuit = -1;
275
276        // initializations
277        nt = ntX * ntY;
278        in = ehs;
279        pktDec = new PktDecoder(decSpec,hd,ehs,this,isTruncMode, ncbQuit);
280
281        tileParts = new int[nt];
282        totTileParts = new int[nt];
283        totTileLen = new int[nt];
284        tilePartLen = new int[nt][];
285        tilePartNum = new int[nt][];
286        firstPackOff = new int[nt][];
287        tilePartsRead = new int[nt];
288        totTileHeadLen = new int[nt];
289        tilePartHeadLen = new int[nt][];
290        nBytes = new int[nt];
291        baknBytes = new int[nt];
292        hd.nTileParts = new int[nt];
293
294
295        this.isTruncMode = isTruncMode;
296
297        // Keeps main header's length, takes file format overhead into account
298        cdstreamStart = hd.mainHeadOff; // Codestream offset in the file
299        mainHeadLen = in.getPos() - cdstreamStart;
300        headLen = mainHeadLen;
301
302        // If ncb and lbody quit conditions are used, headers are not counted
303        if(ncbQuit == -1) {
304            anbytes = mainHeadLen;
305        } else {
306            anbytes = 0;
307        }
308
309        if(printInfo)
310            strInfo += "Main header length    : "+cdstreamStart+", "+mainHeadLen+
311                ", "+mainHeadLen+"\n";
312
313        // If cannot even read the first tile-part
314        if(anbytes>tnbytes) {
315            throw new Error("Requested bitrate is too small.");
316        }
317
318        // Initialize variables used when reading tile-part headers.
319        totAllTileLen = 0;
320        remainingTileParts = nt; // at least as many tile-parts as tiles
321        maxPos = lastPos = in.getPos();
322
323        // Update 'res' value according to the parameter and the main header.
324        if(j2krparam.getResolution()== -1) {
325            targetRes = decSpec.dls.getMin();
326        } else {
327                targetRes = j2krparam.getResolution();
328                if(targetRes<0) {
329                    throw new
330                        IllegalArgumentException("Specified negative "+
331                                                 "resolution level index: "+
332                                                 targetRes);
333                }
334        }
335
336        // Verify reduction in resolution level
337        int mdl = decSpec.dls.getMin();
338        if(targetRes>mdl) {
339            FacilityManager.getMsgLogger().
340                printmsg(MsgLogger.WARNING,
341                         "Specified resolution level ("+targetRes+
342                         ") is larger"+
343                         " than the maximum possible. Setting it to "+
344                         mdl +" (maximum possible)");
345            targetRes = mdl;
346        }
347
348        // Initialize tile part positions from TLM marker segment.
349        initTLM();
350    }
351
352    // An array of the positions of tile parts:
353    // - length of tilePartPositions is nt.
354    // - length of tilePartPositions[i] is totTileParts[i].
355    long[][] tilePartPositions = null;
356
357    //
358    // Initialize the tilePartPositions positions array if a TLM marker
359    // segment is present in the main header. If no such marker segment
360    // is present the array will remain null. This method rewinds to the
361    // start of the codestream and scans until the first SOT marker is
362    // encountered. Before return the stream is returned to its position
363    // when the method was invoked.
364    //
365    private void initTLM() throws IOException {
366        // Save the position to return to at the end of this method.
367        int savePos = in.getPos();
368
369        // Array to store contents of TLM segments. The first index is
370        // Ztlm. The contents of tlmSegments[i] is the bytes in the TLM
371        // segment with Ztlm == i after the Ztlm byte.
372        byte[][] tlmSegments = null;
373
374        // Number of TLM segments. The first numTLM elements of tlmSegments
375        // should be non-null if the segments are correct.
376        int numTLM = 0;
377
378        try {
379            // Rewind to the start of the main header.
380            in.seek(cdstreamStart + 2); // skip SOC
381
382            // Loop over marker segments.
383            short marker;
384            while((marker = in.readShort()) != SOT) {
385                // Get the length (which includes the 2-byte length parameter).
386                int markerLength = in.readUnsignedShort();
387
388                // Process TLM segments.
389                if(marker == TLM) {
390                    numTLM++;
391
392                    if(tlmSegments == null) {
393                        tlmSegments = new byte[256][]; // 0 <= Ztlm <= 255
394                    }
395
396                    // Save contents after Ztlm in array.
397                    int Ztlm = in.read();
398                    tlmSegments[Ztlm] = new byte[markerLength - 3];
399                    in.readFully(tlmSegments[Ztlm], 0, markerLength - 3);
400                } else {
401                    in.skipBytes(markerLength - 2);
402                }
403            }
404        } catch(IOException e) {
405            // Reset so that the TLM segments are not processed further.
406            tlmSegments = null;
407        }
408
409        if(tlmSegments != null) {
410            ArrayList[] tlmOffsets = null;
411
412            // Tiles start after the main header.
413            long tilePos = cdstreamStart + mainHeadLen;
414
415            // Tile counter for when tile indexes are not included.
416            int tileCounter = 0;
417
418            for(int itlm = 0; itlm < numTLM; itlm++) {
419                if(tlmSegments[itlm] == null) {
420                    // Null segment among first numTLM entries: error.
421                    tlmOffsets = null;
422                    break;
423                } else if(tlmOffsets == null) {
424                    tlmOffsets = new ArrayList[nt];
425                }
426
427                // Create a stream.
428                ByteArrayInputStream bais =
429                    new ByteArrayInputStream(tlmSegments[itlm]);
430                ImageInputStream iis = new MemoryCacheImageInputStream(bais);
431
432                try {
433                    int Stlm = iis.read();
434                    int ST = (Stlm >> 4) & 0x3;
435                    int SP = (Stlm >> 6) & 0x1;
436
437                    int tlmLength = tlmSegments[itlm].length;
438                    while(iis.getStreamPosition() < tlmLength) {
439                        int tileIndex = tileCounter;
440                        switch(ST) {
441                        case 1:
442                            tileIndex = iis.read();
443                            break;
444                        case 2:
445                            tileIndex = iis.readUnsignedShort();
446                        }
447
448                        if(tlmOffsets[tileIndex] == null) {
449                            tlmOffsets[tileIndex] = new ArrayList();
450                        }
451                        tlmOffsets[tileIndex].add(new Long(tilePos));
452
453                        long tileLength = 0L;
454                        switch(SP) {
455                        case 0:
456                            tileLength = iis.readUnsignedShort();
457                            break;
458                        case 1:
459                            tileLength = iis.readUnsignedInt();
460                            break;
461                        }
462
463                        tilePos += tileLength;
464
465                        if(ST == 0) tileCounter++;
466                    }
467                } catch(IOException e) {
468                    // XXX?
469                }
470            }
471
472            if(tlmOffsets != null) {
473                tilePartPositions = new long[nt][];
474                for(int i = 0; i < nt; i++) {
475                    if(tlmOffsets[i] == null) {
476                        tilePartPositions = null;
477                        break;
478                    } else {
479                        ArrayList list = tlmOffsets[i];
480                        int count = list.size();
481                        tilePartPositions[i] = new long[count];
482                        long[] tpPos = tilePartPositions[i];
483                        for(int j = 0; j < count; j++) {
484                            tpPos[j] = ((Long)list.get(j)).longValue();
485                        }
486                    }
487                }
488            }
489        }
490
491        in.seek(savePos);
492    }
493
494    int cdstreamStart = 0;
495    int t=0, pos=-1, tp=0, tptot=0;
496    int tilePartStart = 0;
497    boolean rateReached = false;
498    int numtp = 0;
499    int maxTP = nt; // If maximum 1 tile part per tile specified
500    int lastPos = 0, maxPos = 0;
501
502    /**
503     * Read all tile-part headers of the requested tile. All tile-part
504     * headers prior to the last tile-part header of the current tile will
505     * also be read.
506     *
507     * @param tileNum The index of the tile for which to read tile-part
508     * headers.
509     */
510    private void initTile(int tileNum) throws IOException {
511        if(tilePartPositions == null) in.seek(lastPos);
512        String strInfo = "";
513        int ncbQuit = -1;
514        boolean isTilePartRead = false;
515        boolean isEOFEncountered = false;
516        try {
517            int tpNum = 0;
518            while(remainingTileParts!=0 &&
519                  (totTileParts[tileNum] == 0 ||
520                   tilePartsRead[tileNum] < totTileParts[tileNum])) {
521                isTilePartRead = true;
522
523                if(tilePartPositions != null) {
524                    in.seek((int)tilePartPositions[tileNum][tpNum++]);
525                }
526                tilePartStart = in.getPos();
527
528                // Read tile-part header
529                try {
530                    t = readTilePartHeader();
531                    if(isEOCFound) { // Some tiles are missing but the
532                        // codestream is OK
533                        break;
534                    }
535                    tp = tilePartsRead[t];
536                    if(isPsotEqualsZero) { // Psot may equals zero for the
537                        // last tile-part: it is assumed that this tile-part
538                        // contain all data until EOC
539                        tilePartLen[t][tp] = in.length()-2-tilePartStart;
540                    }
541                } catch(EOFException e) {
542                    firstPackOff[t][tp] = in.length();
543                    throw e;
544                }
545
546                pos = in.getPos();
547
548                // In truncation mode, if target decoding rate is reached in
549                // tile-part header, skips the tile-part and stop reading
550                // unless the ncb and lbody quit condition is in use
551                if(isTruncMode && ncbQuit == -1) {
552                    if((pos-cdstreamStart)>tnbytes) {
553                        firstPackOff[t][tp] = in.length();
554                        rateReached = true;
555                        break;
556                    }
557                }
558
559                // Set tile part position and header length
560                firstPackOff[t][tp] = pos;
561                tilePartHeadLen[t][tp] = (pos-tilePartStart);
562
563                if(printInfo)
564                    strInfo += "Tile-part "+tp+" of tile "+t+" : "+tilePartStart
565                        +", "+tilePartLen[t][tp]+", "+tilePartHeadLen[t][tp]+"\n";
566
567                // Update length counters
568                totTileLen[t] += tilePartLen[t][tp];
569                totTileHeadLen[t] += tilePartHeadLen[t][tp];
570                totAllTileLen += tilePartLen[t][tp];
571                if(isTruncMode) {
572                    if(anbytes+tilePartLen[t][tp]>tnbytes) {
573                        anbytes += tilePartHeadLen[t][tp];
574                        headLen += tilePartHeadLen[t][tp];
575                        rateReached = true;
576                        nBytes[t] += (tnbytes-anbytes);
577                        break;
578                    } else {
579                        anbytes += tilePartHeadLen[t][tp];
580                        headLen += tilePartHeadLen[t][tp];
581                        nBytes[t] += (tilePartLen[t][tp]-
582                                      tilePartHeadLen[t][tp]);
583                    }
584                } else {
585                    if(anbytes+tilePartHeadLen[t][tp]>tnbytes) {
586                        break;
587                    } else {
588                        anbytes += tilePartHeadLen[t][tp];
589                        headLen += tilePartHeadLen[t][tp];
590                    }
591                }
592
593                // If this is first tile-part, remember header length
594                if(tptot==0)
595                    firstTilePartHeadLen = tilePartHeadLen[t][tp];
596
597                // Go to the beginning of next tile part
598                tilePartsRead[t]++;
599                int nextMarkerPos = tilePartStart+tilePartLen[t][tp];
600                if(tilePartPositions == null) {
601                    in.seek(nextMarkerPos);
602                }
603                if(nextMarkerPos > maxPos) {
604                    maxPos = nextMarkerPos;
605                }
606                remainingTileParts--;
607                maxTP--;
608                tptot++;
609                // If Psot of the current tile-part was equal to zero, it is
610                // assumed that it contains all data until the EOC marker
611                if(isPsotEqualsZero) {
612                    if(remainingTileParts!=0) {
613                        FacilityManager.getMsgLogger().printmsg
614                            (MsgLogger.WARNING,"Some tile-parts have not "+
615                             "been found. The codestream may be corrupted.");
616                    }
617                    break;
618                }
619            }
620        } catch(EOFException e) {
621            isEOFEncountered = true;
622
623            if(printInfo) {
624               FacilityManager.getMsgLogger().
625                   printmsg(MsgLogger.INFO,strInfo);
626            }
627            FacilityManager.getMsgLogger().
628                printmsg(MsgLogger.WARNING,"Codestream truncated in tile "+t);
629
630            // Set specified rate to end of file if valid
631            int fileLen = in.length();
632            if(fileLen<tnbytes) {
633                tnbytes = fileLen;
634                trate = tnbytes*8f/hd.getMaxCompImgWidth()/
635                    hd.getMaxCompImgHeight();
636            }
637        }
638
639        // If no tile-parts read then return.
640        if(!isTilePartRead) return;
641
642        /* XXX: BEGIN Updating the resolution here is logical when all tile-part
643           headers are read as was the case with the original version of this
644           class. With initTile() however the tiles could be read in random
645           order so modifying the resolution value could cause unexpected
646           results if a given tile-part has fewer levels than the main header
647           indicated.
648        // Update 'res' value once all tile-part headers are read
649        if(j2krparam.getResolution()== -1) {
650            targetRes = decSpec.dls.getMin();
651        } else {
652                targetRes = j2krparam.getResolution();
653                if(targetRes<0) {
654                    throw new
655                        IllegalArgumentException("Specified negative "+
656                                                 "resolution level index: "+
657                                                 targetRes);
658                }
659        }
660
661        // Verify reduction in resolution level
662        int mdl = decSpec.dls.getMin();
663        if(targetRes>mdl) {
664            FacilityManager.getMsgLogger().
665                printmsg(MsgLogger.WARNING,
666                         "Specified resolution level ("+targetRes+
667                         ") is larger"+
668                         " than the maximum possible. Setting it to "+
669                         mdl +" (maximum possible)");
670            targetRes = mdl;
671        }
672        XXX: END */
673
674        if(!isEOFEncountered) {
675            if(printInfo) {
676                FacilityManager.getMsgLogger().printmsg(MsgLogger.INFO,strInfo);
677            }
678
679            if(remainingTileParts == 0) {
680                // Check presence of EOC marker is decoding rate not reached or
681                // if this marker has not been found yet
682                if(!isEOCFound && !isPsotEqualsZero && !rateReached) {
683                    try {
684                        int savePos = in.getPos();
685                        in.seek(maxPos);
686                        if(in.readShort()!=EOC) {
687                            FacilityManager.getMsgLogger().
688                                printmsg(MsgLogger.WARNING,"EOC marker not found. "+
689                                         "Codestream is corrupted.");
690                        }
691                        in.seek(savePos);
692                    } catch(EOFException e) {
693                        FacilityManager.getMsgLogger().
694                            printmsg(MsgLogger.WARNING,"EOC marker is missing");
695                    }
696                }
697            }
698        }
699
700        // Bit-rate allocation
701        if(!isTruncMode) {
702            allocateRate();
703        } else if(remainingTileParts == 0 && !isEOFEncountered) {
704            // Take EOC into account if rate is not reached
705            if(in.getPos()>=tnbytes)
706                anbytes += 2;
707        }
708
709        if(tilePartPositions == null) lastPos = in.getPos();
710
711        // Backup nBytes
712        for (int tIdx=0; tIdx<nt; tIdx++) {
713            baknBytes[tIdx] = nBytes[tIdx];
714            if(printInfo) {
715                FacilityManager.getMsgLogger().
716                    println(""+hi.toStringTileHeader(tIdx,tilePartLen[tIdx].
717                                                     length),2,2);
718            }
719        }
720    }
721
722    /**
723     * Allocates output bit-rate for each tile in parsing mode: The allocator
724     * simulates the truncation of a virtual layer-resolution progressive
725     * codestream.
726     * */
727    private void allocateRate() throws IOException {
728        int stopOff = tnbytes;
729
730        // In parsing mode, the bitrate is allocated related to each tile's
731        // length in the bit stream
732
733        // EOC marker's length
734        if(remainingTileParts == 0) anbytes += 2;
735
736        // If there are too few bytes to read the tile part headers throw an
737        // error
738        if(anbytes > stopOff){
739            throw new Error("Requested bitrate is too small for parsing");
740        }
741
742        // Calculate bitrate for each tile
743        int rem = stopOff-anbytes;
744        int totnByte = rem;
745        for(int t=nt-1; t>0; t--){
746            rem -= nBytes[t]=(int)(totnByte*(totTileLen[t]/totAllTileLen));
747        }
748        nBytes[0] = rem;
749    }
750
751    /**
752     * Reads SOT marker segment of the tile-part header and calls related
753     * methods of the HeaderDecoder to read other markers segments. The
754     * tile-part header is entirely read when a SOD marker is encountered.
755     *
756     * @return The tile number of the tile part that was read
757     * */
758    private int readTilePartHeader() throws IOException{
759        HeaderInfo.SOT ms = hi.getNewSOT();
760
761        // SOT marker
762        short marker = in.readShort();
763        if(marker!=SOT) {
764            if(marker==EOC) {
765                isEOCFound = true;
766                return -1;
767            } else {
768                throw new CorruptedCodestreamException("SOT tag not found "+
769                                                       "in tile-part start");
770            }
771        }
772        isEOCFound = false;
773
774        // Lsot (shall equals 10)
775        int lsot = in.readUnsignedShort();
776        ms.lsot = lsot;
777        if(lsot!=10)
778            throw new CorruptedCodestreamException("Wrong length for "+
779                                                   "SOT marker segment: "+
780                                                   lsot);
781
782        // Isot
783        int tile = in.readUnsignedShort();
784        ms.isot = tile;
785        if(tile>65534){
786            throw new CorruptedCodestreamException("Tile index too high in "+
787                                                   "tile-part.");
788        }
789
790        // Psot
791        int psot = in.readInt();
792        ms.psot = psot;
793        isPsotEqualsZero = (psot!=0) ? false : true;
794        if(psot<0) {
795            throw new NotImplementedError("Tile length larger "+
796                                          "than maximum supported");
797        }
798        // TPsot
799        int tilePart = in.read();
800        ms.tpsot = tilePart;
801        if( tilePart!=tilePartsRead[tile] || tilePart<0 || tilePart>254 ) {
802            throw new CorruptedCodestreamException("Out of order tile-part");
803        }
804        // TNsot
805        int nrOfTileParts = in.read();
806        ms.tnsot = nrOfTileParts;
807        hi.sot.put("t"+tile+"_tp"+tilePart,ms);
808        if(nrOfTileParts==0) { // The number of tile-part is not specified in
809            // this tile-part header.
810
811            // Assumes that there will be another tile-part in the codestream
812            // that will indicate the number of tile-parts for this tile)
813            int nExtraTp;
814            if(tileParts[tile]==0 || tileParts[tile]==tilePartLen.length ) {
815                // Then there are two tile-parts (one is the current and the
816                // other will indicate the number of tile-part for this tile)
817                nExtraTp = 2;
818                remainingTileParts += 1;
819            } else {
820                // There is already one scheduled extra tile-part. In this
821                // case just add place for the current one
822                nExtraTp = 1;
823            }
824
825            tileParts[tile] += nExtraTp;
826            nrOfTileParts = tileParts[tile];
827            FacilityManager.getMsgLogger().
828                printmsg(MsgLogger.WARNING,"Header of tile-part "+tilePart+
829                         " of tile "+tile+", does not indicate the total"+
830                         " number of tile-parts. Assuming that there are "+
831                         nrOfTileParts+" tile-parts for this tile.");
832
833            // Increase and re-copy tilePartLen array
834            int[] tmpA = tilePartLen[tile];
835            tilePartLen[tile] = new int[nrOfTileParts];
836            for(int i=0; i<nrOfTileParts-nExtraTp; i++) {
837                tilePartLen[tile][i] = tmpA[i];
838            }
839            // Increase and re-copy tilePartNum array
840            tmpA = tilePartNum[tile];
841            tilePartNum[tile] = new int[nrOfTileParts];
842            for(int i=0; i<nrOfTileParts-nExtraTp; i++) {
843                tilePartNum[tile][i] = tmpA[i];
844            }
845
846            // Increase and re-copy firsPackOff array
847            tmpA = firstPackOff[tile];
848            firstPackOff[tile] = new int[nrOfTileParts];
849            for(int i=0; i<nrOfTileParts-nExtraTp; i++) {
850                firstPackOff[tile][i] = tmpA[i];
851            }
852
853            // Increase and re-copy tilePartHeadLen array
854            tmpA = tilePartHeadLen[tile];
855            tilePartHeadLen[tile] = new int[nrOfTileParts];
856            for(int i=0; i<nrOfTileParts-nExtraTp; i++) {
857                tilePartHeadLen[tile][i] = tmpA[i];
858            }
859        } else { // The number of tile-parts is specified in the tile-part
860            // header
861            totTileParts[tile] = nrOfTileParts;
862
863            // Check if it is consistant with what was found in previous
864            // tile-part headers
865
866            if(tileParts[tile]==0) { // First tile-part: OK
867                remainingTileParts += nrOfTileParts- 1;
868                tileParts[tile] = nrOfTileParts;
869                tilePartLen[tile] = new int[nrOfTileParts];
870                tilePartNum[tile] = new int[nrOfTileParts];
871                firstPackOff[tile] = new int[nrOfTileParts];
872                tilePartHeadLen[tile] = new int[nrOfTileParts];
873            } else if(tileParts[tile] > nrOfTileParts ) {
874                // Already found more tile-parts than signaled here
875                throw new CorruptedCodestreamException("Invalid number "+
876                                                       "of tile-parts in"+
877                                                       " tile "+tile+": "+
878                                                       nrOfTileParts);
879            } else { // Signaled number of tile-part fits with number of
880                // previously found tile-parts
881                remainingTileParts += nrOfTileParts-tileParts[tile];
882
883                if(tileParts[tile]!=nrOfTileParts) {
884
885                    // Increase and re-copy tilePartLen array
886                    int[] tmpA = tilePartLen[tile];
887                    tilePartLen[tile] = new int[nrOfTileParts];
888                    for(int i=0; i<tileParts[tile]-1; i++) {
889                        tilePartLen[tile][i] = tmpA[i];
890                    }
891
892                    // Increase and re-copy tilePartNum array
893                    tmpA = tilePartNum[tile];
894                    tilePartNum[tile] = new int[nrOfTileParts];
895                    for(int i=0; i<tileParts[tile]-1; i++) {
896                        tilePartNum[tile][i] = tmpA[i];
897                    }
898
899                    // Increase and re-copy firstPackOff array
900                    tmpA = firstPackOff[tile];
901                    firstPackOff[tile] = new int[nrOfTileParts];
902                    for(int i=0; i<tileParts[tile]-1; i++) {
903                        firstPackOff[tile][i] = tmpA[i];
904                    }
905
906                    // Increase and re-copy tilePartHeadLen array
907                    tmpA = tilePartHeadLen[tile];
908                    tilePartHeadLen[tile] = new int[nrOfTileParts];
909                    for(int i=0; i<tileParts[tile]-1; i++) {
910                        tilePartHeadLen[tile][i] = tmpA[i];
911                    }
912                }
913            }
914        }
915
916        // Other markers
917        hd.resetHeaderMarkers();
918        hd.nTileParts[tile] = nrOfTileParts;
919        // Decode and store the tile-part header (i.e. until a SOD marker is
920        // found)
921        do {
922            hd.extractTilePartMarkSeg(in.readShort(),in,tile,tilePart);
923        } while ((hd.getNumFoundMarkSeg() & hd.SOD_FOUND)==0);
924
925        // Read each marker segment previously found
926        hd.readFoundTilePartMarkSeg(tile,tilePart);
927
928        tilePartLen[tile][tilePart] = psot;
929
930        tilePartNum[tile][tilePart] = totTilePartsRead;
931        totTilePartsRead++;
932
933        // Add to list of which tile each successive tile-part belongs.
934        // This list is needed if there are PPM markers used
935        hd.setTileOfTileParts(tile);
936
937        return tile;
938
939    }
940
941    /**
942     * Reads packets of the current tile according to the
943     * layer-resolution-component-position progressiveness.
944     *
945     * @param lys Index of the first layer for each component and resolution.
946     *
947     * @param lye Index of the last layer.
948     *
949     * @param ress Index of the first resolution level.
950     *
951     * @param rese Index of the last resolution level.
952     *
953     * @param comps Index of the first component.
954     *
955     * @param compe Index of the last component.
956     *
957     * @return True if rate has been reached.
958     * */
959    private boolean readLyResCompPos(int[][] lys,int lye,int ress,int rese,
960                                     int comps,int compe)
961        throws IOException {
962
963        int minlys = 10000;
964        for(int c=comps; c<compe; c++) { //loop on components
965            // Check if this component exists
966            if(c>=mdl.length) continue;
967
968            for(int r=ress; r<rese; r++) {//loop on resolution levels
969                if(lys[c]!=null && r<lys[c].length && lys[c][r]<minlys) {
970                    minlys = lys[c][r];
971                }
972            }
973        }
974
975        int t = getTileIdx();
976        int start;
977        boolean status = false;
978        int lastByte = firstPackOff[t][curTilePart]+
979            tilePartLen[t][curTilePart]-1-
980            tilePartHeadLen[t][curTilePart];
981        int numLayers = ((Integer)decSpec.nls.getTileDef(t)).intValue();
982        int nPrec = 1;
983        int hlen,plen;
984        String strInfo = printInfo ?
985            "Tile "+getTileIdx()+" (tile-part:"+curTilePart+
986            "): offset, length, header length\n" : null;
987        boolean pph = false;
988        if(((Boolean)decSpec.pphs.getTileDef(t)).booleanValue()) {
989            pph = true;
990        }
991        for(int l=minlys; l<lye; l++) { // loop on layers
992            for(int r=ress; r<rese; r++) { // loop on resolution levels
993                for(int c=comps; c<compe; c++) { // loop on components
994                    // Checks if component exists
995                    if(c>=mdl.length) continue;
996                    // Checks if resolution level exists
997                    if(r>=lys[c].length) continue;
998                    if(r>mdl[c]) continue;
999                    // Checks if layer exists
1000                    if(l<lys[c][r] || l>=numLayers) continue;
1001
1002                    nPrec = pktDec.getNumPrecinct(c,r);
1003                    for(int p=0; p<nPrec; p++) { // loop on precincts
1004                        start = in.getPos();
1005
1006                        // If packed packet headers are used, there is no need
1007                        // to check that there are bytes enough to read header
1008                        if(pph) {
1009                            pktDec.readPktHead(l,r,c,p,cbI[c][r],nBytes);
1010                        }
1011
1012                        // If we are about to read outside of tile-part,
1013                        // skip to next tile-part
1014                        if(start>lastByte &&
1015                           curTilePart<firstPackOff[t].length-1) {
1016                            curTilePart++;
1017                            in.seek(firstPackOff[t][curTilePart]);
1018                            lastByte = in.getPos()+
1019                                tilePartLen[t][curTilePart]-1-
1020                                tilePartHeadLen[t][curTilePart];
1021                        }
1022
1023                        // Read SOP marker segment if necessary
1024                        status = pktDec.readSOPMarker(nBytes,p,c,r);
1025
1026                        if(status) {
1027                            if(printInfo) {
1028                                FacilityManager.getMsgLogger().
1029                                    printmsg(MsgLogger.INFO,strInfo);
1030                            }
1031                            return true;
1032                        }
1033
1034                        if(!pph) {
1035                            status =
1036                                pktDec.readPktHead(l,r,c,p,cbI[c][r],nBytes);
1037                        }
1038
1039                        if(status) {
1040                            if(printInfo) {
1041                                FacilityManager.getMsgLogger().
1042                                    printmsg(MsgLogger.INFO,strInfo);
1043                            }
1044                            return true;
1045                        }
1046
1047                        // Store packet's head length
1048                        hlen = in.getPos()-start;
1049                        pktHL.addElement(new Integer(hlen));
1050
1051                        // Reads packet's body
1052                        status = pktDec.readPktBody(l,r,c,p,cbI[c][r],nBytes);
1053                        plen = in.getPos()-start;
1054                        if(printInfo)
1055                            strInfo+= " Pkt l="+l+",r="+r+",c="+c+",p="+p+": "+
1056                                start+", "+plen+", "+hlen+"\n";
1057
1058                        if(status) {
1059                            if(printInfo) {
1060                                FacilityManager.getMsgLogger().
1061                                    printmsg(MsgLogger.INFO,strInfo);
1062                            }
1063                            return true;
1064                        }
1065
1066                    } // end loop on precincts
1067                } // end loop on components
1068            } // end loop on resolution levels
1069        } // end loop on layers
1070
1071        if(printInfo) {
1072            FacilityManager.getMsgLogger().printmsg(MsgLogger.INFO,strInfo);
1073        }
1074        return false; // Decoding rate was not reached
1075    }
1076
1077    /**
1078     * Reads packets of the current tile according to the
1079     * resolution-layer-component-position progressiveness.
1080     *
1081     * @param lys Index of the first layer for each component and resolution.
1082     *
1083     * @param lye Index of the last layer.
1084     *
1085     * @param ress Index of the first resolution level.
1086     *
1087     * @param rese Index of the last resolution level.
1088     *
1089     * @param comps Index of the first component.
1090     *
1091     * @param compe Index of the last component.
1092     *
1093     * @return True if rate has been reached.
1094     * */
1095    private boolean readResLyCompPos(int lys[][],int lye,int ress,int rese,
1096                                     int comps,int compe)
1097        throws IOException {
1098
1099        int t = getTileIdx(); // Current tile index
1100        boolean status=false; // True if decoding rate is reached when
1101        int lastByte = firstPackOff[t][curTilePart]+
1102            tilePartLen[t][curTilePart]-1-
1103            tilePartHeadLen[t][curTilePart];
1104        int minlys = 10000;
1105        for(int c=comps; c<compe; c++) { //loop on components
1106            // Check if this component exists
1107            if(c>=mdl.length) continue;
1108
1109            for(int r=ress; r<rese; r++) {//loop on resolution levels
1110                if(r>mdl[c]) continue;
1111                if(lys[c]!=null && r<lys[c].length && lys[c][r]<minlys) {
1112                    minlys = lys[c][r];
1113                }
1114            }
1115        }
1116
1117        String strInfo = printInfo ?
1118            "Tile "+getTileIdx()+" (tile-part:"+curTilePart+
1119            "): offset, length, header length\n" : null;
1120        int numLayers = ((Integer)decSpec.nls.getTileDef(t)).intValue();
1121        boolean pph = false;
1122        if(((Boolean)decSpec.pphs.getTileDef(t)).booleanValue()) {
1123            pph = true;
1124        }
1125        int nPrec = 1;
1126        int start;
1127        int hlen,plen;
1128        for(int r=ress; r<rese; r++) { // loop on resolution levels
1129            for(int l=minlys; l<lye; l++) { // loop on layers
1130                for(int c=comps; c<compe; c++) { // loop on components
1131                    // Checks if component exists
1132                    if(c>=mdl.length) continue;
1133                    // Checks if resolution level exists
1134                    if(r>mdl[c]) continue;
1135                    if(r>=lys[c].length) continue;
1136                    // Checks if layer exists
1137                    if(l<lys[c][r] || l>=numLayers) continue;
1138
1139                    nPrec = pktDec.getNumPrecinct(c,r);
1140
1141                    for(int p=0; p<nPrec; p++) { // loop on precincts
1142                        start = in.getPos();
1143
1144                        // If packed packet headers are used, there is no need
1145                        // to check that there are bytes enough to read header
1146                        if(pph) {
1147                            pktDec.readPktHead(l,r,c,p,cbI[c][r],nBytes);
1148                        }
1149
1150                        // If we are about to read outside of tile-part,
1151                        // skip to next tile-part
1152                        if(start>lastByte &&
1153                           curTilePart<firstPackOff[t].length-1) {
1154                            curTilePart++;
1155                            in.seek(firstPackOff[t][curTilePart]);
1156                            lastByte = in.getPos()+
1157                                tilePartLen[t][curTilePart]-1-
1158                                tilePartHeadLen[t][curTilePart];
1159                        }
1160
1161                        // Read SOP marker segment if necessary
1162                        status = pktDec.readSOPMarker(nBytes,p,c,r);
1163
1164                        if(status) {
1165                            if(printInfo) {
1166                                FacilityManager.getMsgLogger().
1167                                    printmsg(MsgLogger.INFO,strInfo);
1168                            }
1169                            return true;
1170                        }
1171
1172                        if(!pph) {
1173                            status = pktDec.
1174                                readPktHead(l,r,c,p,cbI[c][r],nBytes);
1175                        }
1176
1177                        if(status) {
1178                            if(printInfo) {
1179                                FacilityManager.getMsgLogger().
1180                                    printmsg(MsgLogger.INFO,strInfo);
1181                            }
1182                            // Output rate of EOF reached
1183                            return true;
1184                        }
1185
1186                        // Store packet's head length
1187                        hlen = in.getPos()-start;
1188                        pktHL.addElement(new Integer(hlen));
1189
1190                        // Reads packet's body
1191                        status = pktDec.readPktBody(l,r,c,p,cbI[c][r],nBytes);
1192                        plen = in.getPos()-start;
1193                        if(printInfo)
1194                            strInfo+= " Pkt l="+l+",r="+r+",c="+c+",p="+p+": "+
1195                                start+", "+plen+", "+hlen+"\n";
1196
1197                        if(status) {
1198                            if(printInfo) {
1199                                FacilityManager.getMsgLogger().
1200                                    printmsg(MsgLogger.INFO,strInfo);
1201                            }
1202                            // Output rate or EOF reached
1203                            return true;
1204                        }
1205
1206                    } // end loop on precincts
1207                } // end loop on components
1208            } // end loop on layers
1209        } // end loop on resolution levels
1210
1211        if(printInfo) {
1212            FacilityManager.getMsgLogger().printmsg(MsgLogger.INFO,strInfo);
1213        }
1214        return false; // Decoding rate was not reached
1215   }
1216
1217
1218    /**
1219     * Reads packets of the current tile according to the
1220     * resolution-position-component-layer progressiveness.
1221     *
1222     * @param lys Index of the first layer for each component and resolution.
1223     *
1224     * @param lye Index of the last layer.
1225     *
1226     * @param ress Index of the first resolution level.
1227     *
1228     * @param rese Index of the last resolution level.
1229     *
1230     * @param comps Index of the first component.
1231     *
1232     * @param compe Index of the last component.
1233     *
1234     * @return True if rate has been reached.
1235     * */
1236    private boolean readResPosCompLy(int[][] lys,int lye,int ress,int rese,
1237                                     int comps,int compe)
1238        throws IOException {
1239        // Computes current tile offset in the reference grid
1240
1241        Point nTiles = getNumTiles(null);
1242        Point tileI = getTile(null);
1243        int x0siz = hd.getImgULX();
1244        int y0siz = hd.getImgULY();
1245        int xsiz = x0siz + hd.getImgWidth();
1246        int ysiz = y0siz + hd.getImgHeight();
1247        int xt0siz = getTilePartULX();
1248        int yt0siz = getTilePartULY();
1249        int xtsiz = getNomTileWidth();
1250        int ytsiz = getNomTileHeight();
1251        int tx0 = (tileI.x==0) ? x0siz : xt0siz+tileI.x*xtsiz;
1252        int ty0 = (tileI.y==0) ? y0siz : yt0siz+tileI.y*ytsiz;
1253        int tx1 = (tileI.x!=nTiles.x-1) ? xt0siz+(tileI.x+1)*xtsiz : xsiz;
1254        int ty1 = (tileI.y!=nTiles.y-1) ? yt0siz+(tileI.y+1)*ytsiz : ysiz;
1255
1256        // Get precinct information (number,distance between two consecutive
1257        // precincts in the reference grid) in each component and resolution
1258        // level
1259        int t = getTileIdx(); // Current tile index
1260        PrecInfo prec; // temporary variable
1261        int p; // Current precinct index
1262        int gcd_x = 0; // Horiz. distance between 2 precincts in the ref. grid
1263        int gcd_y = 0; // Vert. distance between 2 precincts in the ref. grid
1264        int nPrec = 0; // Total number of found precincts
1265        int[][] nextPrec = new int [compe][]; // Next precinct index in each
1266        // component and resolution level
1267        int minlys = 100000; // minimum layer start index of each component
1268        int minx = tx1; // Horiz. offset of the second precinct in the
1269        // reference grid
1270        int miny = ty1; // Vert. offset of the second precinct in the
1271        // reference grid.
1272        int maxx = tx0; // Max. horiz. offset of precincts in the ref. grid
1273        int maxy = ty0; // Max. vert. offset of precincts in the ref. grid
1274        Point numPrec;
1275        for(int c=comps; c<compe; c++) { // components
1276            for(int r=ress; r<rese; r++) { // resolution levels
1277                if(c>=mdl.length) continue;
1278                if(r>mdl[c]) continue;
1279                nextPrec[c] = new int[mdl[c]+1];
1280                if (lys[c]!=null && r<lys[c].length && lys[c][r]<minlys) {
1281                    minlys = lys[c][r];
1282                }
1283                p = pktDec.getNumPrecinct(c,r)-1;
1284                for(; p>=0; p--) {
1285                    prec = pktDec.getPrecInfo(c,r,p);
1286                    if(prec.rgulx!=tx0) {
1287                        if(prec.rgulx<minx) minx = prec.rgulx;
1288                        if(prec.rgulx>maxx) maxx = prec.rgulx;
1289                    }
1290                    if(prec.rguly!=ty0) {
1291                        if(prec.rguly<miny) miny = prec.rguly;
1292                        if(prec.rguly>maxy) maxy = prec.rguly;
1293                    }
1294
1295                    if(nPrec==0) {
1296                        gcd_x = prec.rgw;
1297                        gcd_y = prec.rgh;
1298                    } else {
1299                        gcd_x = MathUtil.gcd(gcd_x,prec.rgw);
1300                        gcd_y = MathUtil.gcd(gcd_y,prec.rgh);
1301                    }
1302                    nPrec++;
1303                } // precincts
1304            } // resolution levels
1305        } // components
1306
1307        if(nPrec==0) {
1308            throw new Error("Image cannot have no precinct");
1309        }
1310
1311        int pyend = (maxy-miny)/gcd_y+1;
1312        int pxend = (maxx-minx)/gcd_x+1;
1313        int x,y;
1314        int hlen,plen;
1315        int start;
1316        boolean status = false;
1317        int lastByte = firstPackOff[t][curTilePart]+
1318            tilePartLen[t][curTilePart]-1-
1319            tilePartHeadLen[t][curTilePart];
1320        int numLayers = ((Integer)decSpec.nls.getTileDef(t)).intValue();
1321        String strInfo = printInfo ?
1322            "Tile "+getTileIdx()+" (tile-part:"+curTilePart+
1323            "): offset, length, header length\n" : null;
1324        boolean pph = false;
1325        if(((Boolean)decSpec.pphs.getTileDef(t)).booleanValue()) {
1326            pph = true;
1327        }
1328        for(int r=ress; r<rese; r++) { // loop on resolution levels
1329            y = ty0;
1330            x = tx0;
1331            for(int py=0; py<=pyend; py++) { // Vertical precincts
1332                for(int px=0; px<=pxend; px++) { // Horiz. precincts
1333                    for(int c=comps; c<compe; c++) { // Components
1334                        if(c>=mdl.length) continue;
1335                        if(r>mdl[c]) continue;
1336                        if(nextPrec[c][r]>=pktDec.getNumPrecinct(c,r)) {
1337                            continue;
1338                        }
1339                        prec = pktDec.getPrecInfo(c,r,nextPrec[c][r]);
1340                        if((prec.rgulx!=x) || (prec.rguly!=y)) {
1341                            continue;
1342                        }
1343                        for(int l=minlys; l<lye; l++) { // layers
1344                            if(r>=lys[c].length) continue;
1345                            if(l<lys[c][r] || l>=numLayers) continue;
1346
1347                            start = in.getPos();
1348
1349                            // If packed packet headers are used, there is no
1350                            // need to check that there are bytes enough to
1351                            // read header
1352                            if(pph) {
1353                                pktDec.readPktHead(l,r,c,nextPrec[c][r],
1354                                                   cbI[c][r],nBytes);
1355                            }
1356                            // If we are about to read outside of tile-part,
1357                            // skip to next tile-part
1358                            if(start>lastByte &&
1359                               curTilePart<firstPackOff[t].length-1) {
1360                                curTilePart++;
1361                                in.seek(firstPackOff[t][curTilePart]);
1362                                lastByte = in.getPos()+
1363                                    tilePartLen[t][curTilePart]-1-
1364                                    tilePartHeadLen[t][curTilePart];
1365                            }
1366
1367                            // Read SOP marker segment if necessary
1368                            status = pktDec.readSOPMarker(nBytes,
1369                                                          nextPrec[c][r],c,r);
1370
1371                            if(status) {
1372                                if(printInfo) {
1373                                    FacilityManager.getMsgLogger().
1374                                        printmsg(MsgLogger.INFO,strInfo);
1375                                }
1376                                return true;
1377                            }
1378
1379                            if(!pph) {
1380                                status =
1381                                    pktDec.readPktHead(l,r,c,
1382                                                       nextPrec[c][r],
1383                                                       cbI[c][r],nBytes);
1384                            }
1385
1386                            if(status) {
1387                                if(printInfo) {
1388                                    FacilityManager.getMsgLogger().
1389                                        printmsg(MsgLogger.INFO,strInfo);
1390                                }
1391                                return true;
1392                            }
1393
1394                            // Store packet's head length
1395                            hlen = in.getPos()-start;
1396                            pktHL.addElement(new Integer(hlen));
1397
1398
1399                            // Reads packet's body
1400                            status = pktDec.readPktBody(l,r,c,nextPrec[c][r],
1401                                                        cbI[c][r],nBytes);
1402                            plen = in.getPos()-start;
1403                            if(printInfo)
1404                                strInfo+= " Pkt l="+l+",r="+r+",c="+c+",p="+
1405                                    nextPrec[c][r]+": "+
1406                                    start+", "+plen+", "+hlen+"\n";
1407
1408                            if(status) {
1409                                if(printInfo) {
1410                                    FacilityManager.getMsgLogger().
1411                                        printmsg(MsgLogger.INFO,strInfo);
1412                                }
1413                                return true;
1414                            }
1415                        } // layers
1416                        nextPrec[c][r]++;
1417                    } // Components
1418                    if(px!=pxend) {
1419                        x = minx+px*gcd_x;
1420                    } else {
1421                        x = tx0;
1422                    }
1423                } // Horizontal precincts
1424                if(py!=pyend) {
1425                    y = miny+py*gcd_y;
1426                } else {
1427                    y = ty0;
1428                }
1429            } // Vertical precincts
1430        } // end loop on resolution levels
1431
1432       if(printInfo) {
1433            FacilityManager.getMsgLogger().printmsg(MsgLogger.INFO,strInfo);
1434        }
1435        return false; // Decoding rate was not reached
1436    }
1437
1438    /**
1439     * Reads packets of the current tile according to the
1440     * position-component-resolution-layer progressiveness.
1441     *
1442     * @param lys Index of the first layer for each component and resolution.
1443     *
1444     * @param lye Index of the last layer.
1445     *
1446     * @param ress Index of the first resolution level.
1447     *
1448     * @param rese Index of the last resolution level.
1449     *
1450     * @param comps Index of the first component.
1451     *
1452     * @param compe Index of the last component.
1453     *
1454     * @return True if rate has been reached.
1455     * */
1456    private boolean readPosCompResLy(int[][] lys,int lye,int ress,int rese,
1457                                     int comps,int compe)
1458        throws IOException {
1459        Point nTiles = getNumTiles(null);
1460        Point tileI = getTile(null);
1461        int x0siz = hd.getImgULX();
1462        int y0siz = hd.getImgULY();
1463        int xsiz = x0siz + hd.getImgWidth();
1464        int ysiz = y0siz + hd.getImgHeight();
1465        int xt0siz = getTilePartULX();
1466        int yt0siz = getTilePartULY();
1467        int xtsiz = getNomTileWidth();
1468        int ytsiz = getNomTileHeight();
1469        int tx0 = (tileI.x==0) ? x0siz : xt0siz+tileI.x*xtsiz;
1470        int ty0 = (tileI.y==0) ? y0siz : yt0siz+tileI.y*ytsiz;
1471        int tx1 = (tileI.x!=nTiles.x-1) ? xt0siz+(tileI.x+1)*xtsiz : xsiz;
1472        int ty1 = (tileI.y!=nTiles.y-1) ? yt0siz+(tileI.y+1)*ytsiz : ysiz;
1473
1474        // Get precinct information (number,distance between two consecutive
1475        // precincts in the reference grid) in each component and resolution
1476        // level
1477        int t = getTileIdx(); // Current tile index
1478        PrecInfo prec; // temporary variable
1479        int p; // Current precinct index
1480        int gcd_x = 0; // Horiz. distance between 2 precincts in the ref. grid
1481        int gcd_y = 0; // Vert. distance between 2 precincts in the ref. grid
1482        int nPrec = 0; // Total number of found precincts
1483        int[][] nextPrec = new int [compe][]; // Next precinct index in each
1484        // component and resolution level
1485        int minlys = 100000; // minimum layer start index of each component
1486        int minx = tx1; // Horiz. offset of the second precinct in the
1487        // reference grid
1488        int miny = ty1; // Vert. offset of the second precinct in the
1489        // reference grid.
1490        int maxx = tx0; // Max. horiz. offset of precincts in the ref. grid
1491        int maxy = ty0; // Max. vert. offset of precincts in the ref. grid
1492        Point numPrec;
1493        for(int c=comps; c<compe; c++) { // components
1494            for(int r=ress; r<rese; r++) { // resolution levels
1495                if(c>=mdl.length) continue;
1496                if(r>mdl[c]) continue;
1497                nextPrec[c] = new int[mdl[c]+1];
1498                if (lys[c]!=null && r<lys[c].length && lys[c][r]<minlys) {
1499                    minlys = lys[c][r];
1500                }
1501                p = pktDec.getNumPrecinct(c,r)-1;
1502                for(; p>=0; p--) {
1503                    prec = pktDec.getPrecInfo(c,r,p);
1504                    if(prec.rgulx!=tx0) {
1505                        if(prec.rgulx<minx) minx = prec.rgulx;
1506                        if(prec.rgulx>maxx) maxx = prec.rgulx;
1507                    }
1508                    if(prec.rguly!=ty0) {
1509                        if(prec.rguly<miny) miny = prec.rguly;
1510                        if(prec.rguly>maxy) maxy = prec.rguly;
1511                    }
1512
1513                    if(nPrec==0) {
1514                        gcd_x = prec.rgw;
1515                        gcd_y = prec.rgh;
1516                    } else {
1517                        gcd_x = MathUtil.gcd(gcd_x,prec.rgw);
1518                        gcd_y = MathUtil.gcd(gcd_y,prec.rgh);
1519                    }
1520                    nPrec++;
1521                } // precincts
1522            } // resolution levels
1523        } // components
1524
1525        if(nPrec==0) {
1526            throw new Error("Image cannot have no precinct");
1527        }
1528
1529        int pyend = (maxy-miny)/gcd_y+1;
1530        int pxend = (maxx-minx)/gcd_x+1;
1531        int hlen,plen;
1532        int start;
1533        boolean status = false;
1534        int lastByte = firstPackOff[t][curTilePart]+
1535            tilePartLen[t][curTilePart]-1-
1536            tilePartHeadLen[t][curTilePart];
1537        int numLayers = ((Integer)decSpec.nls.getTileDef(t)).intValue();
1538        String strInfo = printInfo ?
1539            "Tile "+getTileIdx()+" (tile-part:"+curTilePart+
1540            "): offset, length, header length\n" : null;
1541        boolean pph = false;
1542        if(((Boolean)decSpec.pphs.getTileDef(t)).booleanValue()) {
1543            pph = true;
1544        }
1545
1546        int y = ty0;
1547        int x = tx0;
1548        for(int py=0; py<=pyend; py++) { // Vertical precincts
1549            for(int px=0; px<=pxend; px++) { // Horiz. precincts
1550                for(int c=comps; c<compe; c++) { // Components
1551                    if(c>=mdl.length) continue;
1552                    for(int r=ress; r<rese; r++) { // Resolution levels
1553                        if(r>mdl[c]) continue;
1554                        if(nextPrec[c][r]>=pktDec.getNumPrecinct(c,r)) {
1555                            continue;
1556                        }
1557                        prec = pktDec.getPrecInfo(c,r,nextPrec[c][r]);
1558                        if((prec.rgulx!=x) || (prec.rguly!=y)) {
1559                            continue;
1560                        }
1561                        for(int l=minlys; l<lye; l++) { // Layers
1562                            if(r>=lys[c].length) continue;
1563                            if(l<lys[c][r] || l>=numLayers) continue;
1564
1565                            start = in.getPos();
1566
1567                            // If packed packet headers are used, there is no
1568                            // need to check that there are bytes enough to
1569                            // read header
1570                            if(pph) {
1571                                pktDec.readPktHead(l,r,c,nextPrec[c][r],
1572                                                   cbI[c][r],nBytes);
1573                            }
1574                            // Read SOP marker segment if necessary
1575                            status = pktDec.readSOPMarker(nBytes,
1576                                                          nextPrec[c][r],c,r);
1577
1578                            if(status) {
1579                                if(printInfo) {
1580                                    FacilityManager.getMsgLogger().
1581                                        printmsg(MsgLogger.INFO,strInfo);
1582                                }
1583                                return true;
1584                            }
1585
1586                            if(!pph) {
1587                                status =
1588                                    pktDec.readPktHead(l,r,c,
1589                                                       nextPrec[c][r],
1590                                                       cbI[c][r],nBytes);
1591                            }
1592
1593                            if(status) {
1594                                if(printInfo) {
1595                                    FacilityManager.getMsgLogger().
1596                                        printmsg(MsgLogger.INFO,strInfo);
1597                                }
1598                                return true;
1599                            }
1600
1601                            // Store packet's head length
1602                            hlen = in.getPos()-start;
1603                            pktHL.addElement(new Integer(hlen));
1604
1605                            // Reads packet's body
1606                            status = pktDec.readPktBody(l,r,c,nextPrec[c][r],
1607                                                        cbI[c][r],nBytes);
1608                            plen = in.getPos()-start;
1609                            if(printInfo)
1610                                strInfo+= " Pkt l="+l+",r="+r+",c="+c+",p="+
1611                                    nextPrec[c][r]+": "+
1612                                    start+", "+plen+", "+hlen+"\n";
1613
1614                            if(status) {
1615                                if(printInfo) {
1616                                    FacilityManager.getMsgLogger().
1617                                        printmsg(MsgLogger.INFO,strInfo);
1618                                }
1619                                return true;
1620                            }
1621
1622                        } // layers
1623                        nextPrec[c][r]++;
1624                    } // Resolution levels
1625                } // Components
1626                if(px!=pxend) {
1627                    x = minx+px*gcd_x;
1628                } else {
1629                    x = tx0;
1630                }
1631            } // Horizontal precincts
1632            if(py!=pyend) {
1633                y = miny+py*gcd_y;
1634            } else {
1635                y = ty0;
1636            }
1637        } // Vertical precincts
1638
1639        if(printInfo) {
1640            FacilityManager.getMsgLogger().printmsg(MsgLogger.INFO,strInfo);
1641        }
1642        return false; // Decoding rate was not reached
1643    }
1644
1645    /**
1646     * Reads packets of the current tile according to the
1647     * component-position-resolution-layer progressiveness.
1648     *
1649     * @param lys Index of the first layer for each component and resolution.
1650     *
1651     * @param lye Index of the last layer.
1652     *
1653     * @param ress Index of the first resolution level.
1654     *
1655     * @param rese Index of the last resolution level.
1656     *
1657     * @param comps Index of the first component.
1658     *
1659     * @param compe Index of the last component.
1660     *
1661     * @return True if rate has been reached.
1662     * */
1663    private boolean readCompPosResLy(int lys[][],int lye,int ress,int rese,
1664                                     int comps,int compe)
1665        throws IOException {
1666        Point nTiles = getNumTiles(null);
1667        Point tileI = getTile(null);
1668        int x0siz = hd.getImgULX();
1669        int y0siz = hd.getImgULY();
1670        int xsiz = x0siz + hd.getImgWidth();
1671        int ysiz = y0siz + hd.getImgHeight();
1672        int xt0siz = getTilePartULX();
1673        int yt0siz = getTilePartULY();
1674        int xtsiz = getNomTileWidth();
1675        int ytsiz = getNomTileHeight();
1676        int tx0 = (tileI.x==0) ? x0siz : xt0siz+tileI.x*xtsiz;
1677        int ty0 = (tileI.y==0) ? y0siz : yt0siz+tileI.y*ytsiz;
1678        int tx1 = (tileI.x!=nTiles.x-1) ? xt0siz+(tileI.x+1)*xtsiz : xsiz;
1679        int ty1 = (tileI.y!=nTiles.y-1) ? yt0siz+(tileI.y+1)*ytsiz : ysiz;
1680
1681        // Get precinct information (number,distance between two consecutive
1682        // precincts in the reference grid) in each component and resolution
1683        // level
1684        int t = getTileIdx(); // Current tile index
1685        PrecInfo prec; // temporary variable
1686        int p; // Current precinct index
1687        int gcd_x = 0; // Horiz. distance between 2 precincts in the ref. grid
1688        int gcd_y = 0; // Vert. distance between 2 precincts in the ref. grid
1689        int nPrec = 0; // Total number of found precincts
1690        int[][] nextPrec = new int [compe][]; // Next precinct index in each
1691        // component and resolution level
1692        int minlys = 100000; // minimum layer start index of each component
1693        int minx = tx1; // Horiz. offset of the second precinct in the
1694        // reference grid
1695        int miny = ty1; // Vert. offset of the second precinct in the
1696        // reference grid.
1697        int maxx = tx0; // Max. horiz. offset of precincts in the ref. grid
1698        int maxy = ty0; // Max. vert. offset of precincts in the ref. grid
1699        Point numPrec;
1700        for(int c=comps; c<compe; c++) { // components
1701            for(int r=ress; r<rese; r++) { // resolution levels
1702                if(c>=mdl.length) continue;
1703                if(r>mdl[c]) continue;
1704                nextPrec[c] = new int[mdl[c]+1];
1705                if (lys[c]!=null && r<lys[c].length && lys[c][r]<minlys) {
1706                    minlys = lys[c][r];
1707                }
1708                p = pktDec.getNumPrecinct(c,r)-1;
1709                for(; p>=0; p--) {
1710                    prec = pktDec.getPrecInfo(c,r,p);
1711                    if(prec.rgulx!=tx0) {
1712                        if(prec.rgulx<minx) minx = prec.rgulx;
1713                        if(prec.rgulx>maxx) maxx = prec.rgulx;
1714                    }
1715                    if(prec.rguly!=ty0) {
1716                        if(prec.rguly<miny) miny = prec.rguly;
1717                        if(prec.rguly>maxy) maxy = prec.rguly;
1718                    }
1719
1720                    if(nPrec==0) {
1721                        gcd_x = prec.rgw;
1722                        gcd_y = prec.rgh;
1723                    } else {
1724                        gcd_x = MathUtil.gcd(gcd_x,prec.rgw);
1725                        gcd_y = MathUtil.gcd(gcd_y,prec.rgh);
1726                    }
1727                    nPrec++;
1728                } // precincts
1729            } // resolution levels
1730        } // components
1731
1732        if(nPrec==0) {
1733            throw new Error("Image cannot have no precinct");
1734        }
1735
1736        int pyend = (maxy-miny)/gcd_y+1;
1737        int pxend = (maxx-minx)/gcd_x+1;
1738        int hlen,plen;
1739        int start;
1740        boolean status = false;
1741        int lastByte = firstPackOff[t][curTilePart]+
1742            tilePartLen[t][curTilePart]-1-
1743            tilePartHeadLen[t][curTilePart];
1744        int numLayers = ((Integer)decSpec.nls.getTileDef(t)).intValue();
1745        String strInfo = printInfo ?
1746            "Tile "+getTileIdx()+" (tile-part:"+curTilePart+
1747            "): offset, length, header length\n" : null;
1748        boolean pph = false;
1749        if(((Boolean)decSpec.pphs.getTileDef(t)).booleanValue()) {
1750            pph = true;
1751        }
1752
1753        int x,y;
1754        for(int c=comps; c<compe; c++) { // components
1755            if(c>=mdl.length) continue;
1756            y = ty0;
1757            x = tx0;
1758            for(int py=0; py<=pyend; py++) { // Vertical precincts
1759                for(int px=0; px<=pxend; px++) { // Horiz. precincts
1760                    for(int r=ress; r<rese; r++) { // Resolution levels
1761                        if(r>mdl[c]) continue;
1762                        if(nextPrec[c][r]>=pktDec.getNumPrecinct(c,r)) {
1763                            continue;
1764                        }
1765                        prec = pktDec.getPrecInfo(c,r,nextPrec[c][r]);
1766                        if((prec.rgulx!=x) || (prec.rguly!=y)) {
1767                            continue;
1768                        }
1769
1770                        for(int l=minlys; l<lye; l++) { // Layers
1771                            if(r>=lys[c].length) continue;
1772                            if(l<lys[c][r]) continue;
1773
1774                            start = in.getPos();
1775
1776                            // If packed packet headers are used, there is no
1777                            // need to check that there are bytes enough to
1778                            // read header
1779                            if(pph) {
1780                                pktDec.readPktHead(l,r,c,nextPrec[c][r],
1781                                                   cbI[c][r],nBytes);
1782                            }
1783                            // If we are about to read outside of tile-part,
1784                            // skip to next tile-part
1785                            if(start>lastByte &&
1786                               curTilePart<firstPackOff[t].length-1) {
1787                                curTilePart++;
1788                                in.seek(firstPackOff[t][curTilePart]);
1789                                lastByte = in.getPos()+
1790                                    tilePartLen[t][curTilePart]-1-
1791                                    tilePartHeadLen[t][curTilePart];
1792                            }
1793
1794                            // Read SOP marker segment if necessary
1795                            status = pktDec.readSOPMarker(nBytes,
1796                                                          nextPrec[c][r],c,r);
1797
1798                            if(status) {
1799                                if(printInfo) {
1800                                    FacilityManager.getMsgLogger().
1801                                        printmsg(MsgLogger.INFO,strInfo);
1802                                }
1803                                return true;
1804                            }
1805
1806                            if(!pph) {
1807                                status =
1808                                    pktDec.readPktHead(l,r,c,
1809                                                       nextPrec[c][r],
1810                                                       cbI[c][r],nBytes);
1811                            }
1812
1813                            if(status) {
1814                                if(printInfo) {
1815                                    FacilityManager.getMsgLogger().
1816                                        printmsg(MsgLogger.INFO,strInfo);
1817                                }
1818                                return true;
1819                            }
1820
1821                            // Store packet's head length
1822                            hlen = in.getPos()-start;
1823                            pktHL.addElement(new Integer(hlen));
1824
1825                            // Reads packet's body
1826                            status = pktDec.readPktBody(l,r,c,nextPrec[c][r],
1827                                                        cbI[c][r],nBytes);
1828                            plen = in.getPos()-start;
1829                            if(printInfo)
1830                                strInfo+= " Pkt l="+l+",r="+r+",c="+c+",p="+
1831                                    nextPrec[c][r]+": "+
1832                                    start+", "+plen+", "+hlen+"\n";
1833
1834                            if(status) {
1835                                if(printInfo) {
1836                                    FacilityManager.getMsgLogger().
1837                                        printmsg(MsgLogger.INFO,strInfo);
1838                                }
1839                                return true;
1840                            }
1841
1842                        } // layers
1843                        nextPrec[c][r]++;
1844                    } // Resolution levels
1845                    if(px!=pxend) {
1846                        x = minx+px*gcd_x;
1847                    } else {
1848                        x = tx0;
1849                    }
1850                } // Horizontal precincts
1851                if(py!=pyend) {
1852                    y = miny+py*gcd_y;
1853                } else {
1854                    y = ty0;
1855                }
1856            } // Vertical precincts
1857        } // components
1858
1859        if(printInfo) {
1860            FacilityManager.getMsgLogger().printmsg(MsgLogger.INFO,strInfo);
1861        }
1862        return false; // Decoding rate was not reached
1863    }
1864
1865    /**
1866     * Finish initialization of members for specified tile, reads packets head
1867     * of each tile and keeps location of each code-block's codewords. The
1868     * last 2 tasks are done by calling specific methods of PktDecoder.
1869     *
1870     * <p>Then, if a parsing output rate is defined, it keeps information of
1871     * first layers only. This operation simulates a creation of a
1872     * layer-resolution-component progressive bit-stream which will be next
1873     * truncated and decoded.</p>
1874     *
1875     * @param t Tile index
1876     *
1877     * @see PktDecoder
1878     * */
1879    private void readTilePkts(int t) throws IOException {
1880        pktHL = new Vector();
1881
1882        int oldNBytes = nBytes[t];
1883
1884        // Number of layers
1885        int nl = ((Integer)decSpec.nls.getTileDef(t)).intValue();
1886
1887        // If packed packet headers was used, get the packet headers for this
1888        // tile
1889        if(((Boolean)decSpec.pphs.getTileDef(t)).booleanValue()) {
1890            // Gets packed headers as separate input stream
1891            ByteArrayInputStream pphbais = hd.getPackedPktHead(t);
1892
1893            // Restarts PktDecoder instance
1894            cbI = pktDec.restart(nc,mdl,nl,cbI,true,pphbais);
1895        } else {
1896            // Restarts PktDecoder instance
1897            cbI = pktDec.restart(nc,mdl,nl,cbI,false,null);
1898        }
1899
1900        // Reads packets of the tile according to the progression order
1901        int[][] pocSpec = ((int[][])decSpec.pcs.getTileDef(t));
1902        int nChg = (pocSpec==null) ?  1 : pocSpec.length;
1903
1904        // Create an array containing information about changes (progression
1905        // order type, layers index start, layer index end, resolution level
1906        // start, resolution level end, component index start, component index
1907        // end). There is one row per progresion order
1908        int[][] change = new int[nChg][6];
1909        int idx = 0; // Index of the current progression order
1910
1911        change[0][1] = 0; // layer start
1912
1913        if(pocSpec==null) {
1914            change[idx][0] = ((Integer)decSpec.pos.getTileDef(t)).intValue();
1915            // Progression type found in COx marker segments
1916            change[idx][1] = nl; // Layer index end
1917            change[idx][2] = 0; // resolution level start
1918            change[idx][3] = decSpec.dls.getMaxInTile(t)+1; // res. level end
1919            change[idx][4] = 0; // Component index start
1920            change[idx][5] = nc; // Component index end
1921        } else {
1922            for(idx=0; idx<nChg; idx++){
1923                change[idx][0] = pocSpec[idx][5];
1924                change[idx][1] = pocSpec[idx][2]; // layer end
1925                change[idx][2] = pocSpec[idx][0]; // res. lev. start
1926                change[idx][3] = pocSpec[idx][3]; // res. lev. end
1927                change[idx][4] = pocSpec[idx][1]; // Comp. index start
1928                change[idx][5] = pocSpec[idx][4]; // Comp. index end
1929            }
1930        }
1931
1932        // Seeks to the first packet of the first tile-part
1933        try {
1934            // If in truncation mode, the first tile-part may be beyond the
1935            // target decoding rate. In this case, the offset of the first
1936            // packet is not defined.
1937            if(isTruncMode && firstPackOff==null || firstPackOff[t]==null) {
1938                return;
1939            }
1940            in.seek(firstPackOff[t][0]);
1941        } catch(EOFException e) {
1942            FacilityManager.getMsgLogger().
1943                printmsg(MsgLogger.WARNING,"Codestream truncated in tile "+t);
1944            return;
1945        }
1946
1947        curTilePart = 0;
1948
1949        // Start and end indexes for layers, resolution levels and components.
1950        int lye,ress,rese,comps,compe;
1951        boolean status = false;
1952        int nb = nBytes[t];
1953        int[][] lys = new int[nc][];
1954        for(int c=0; c<nc; c++) {
1955            lys[c] = new int[((Integer)decSpec.dls.getTileCompVal(t,c)).
1956                            intValue()+1];
1957        }
1958
1959
1960        try {
1961            for(int chg=0; chg<nChg; chg++) {
1962
1963                lye = change[chg][1];
1964                ress = change[chg][2];
1965                rese = change[chg][3];
1966                comps = change[chg][4];
1967                compe = change[chg][5];
1968
1969                switch(change[chg][0]) {
1970                case LY_RES_COMP_POS_PROG:
1971                    status = readLyResCompPos(lys,lye,ress,rese,comps,compe);
1972                    break;
1973                case RES_LY_COMP_POS_PROG:
1974                    status = readResLyCompPos(lys,lye,ress,rese,comps,compe);
1975                    break;
1976                case RES_POS_COMP_LY_PROG:
1977                    status = readResPosCompLy(lys,lye,ress,rese,comps,compe);
1978                    break;
1979                case POS_COMP_RES_LY_PROG:
1980                    status = readPosCompResLy(lys,lye,ress,rese,comps,compe);
1981                    break;
1982                case COMP_POS_RES_LY_PROG:
1983                    status = readCompPosResLy(lys,lye,ress,rese,comps,compe);
1984                    break;
1985                default:
1986                    throw new IllegalArgumentException("Not recognized "+
1987                                                       "progression type");
1988                }
1989
1990                // Update next first layer index
1991                for(int c=comps; c<compe; c++) {
1992                    if(c>=lys.length) continue;
1993                    for(int r=ress; r<rese; r++) {
1994                        if(r>=lys[c].length) continue;
1995                        lys[c][r] = lye;
1996                    }
1997                }
1998
1999                if(status || usePOCQuit) {
2000                    break;
2001                }
2002            }
2003        } catch(EOFException e) {
2004            // Should never happen. Truncated codestream are normally found by
2005            // the class constructor
2006            throw e;
2007        }
2008
2009        // In truncation mode, update the number of read bytes
2010        if(isTruncMode) {
2011            anbytes += nb-nBytes[t];
2012
2013            // If truncation rate is reached
2014            if(status) {
2015                nBytes[t] = 0;
2016            }
2017        } else if(nBytes[t]<(totTileLen[t]-totTileHeadLen[t])) {
2018        // In parsing mode, if there is not enough rate to entirely read the
2019        // tile. Then, parses the bit stream so as to create a virtual
2020        // layer-resolution-component progressive bit stream that will be
2021        // truncated and decoded afterwards.
2022            CBlkInfo cb;
2023
2024            // Systematicaly reject all remaining code-blocks if one
2025            // code-block, at least, is refused.
2026            boolean reject;
2027            // Stop reading any data from the bit stream
2028            boolean stopCount = false;
2029            // Length of each packet's head (in an array)
2030            int[] pktHeadLen = new int[pktHL.size()];
2031            for(int i=pktHL.size()-1;i>=0;i--) {
2032                pktHeadLen[i] = ((Integer)pktHL.elementAt(i)).intValue();
2033            }
2034
2035            // Parse each code-block, layer per layer until nBytes[t] is
2036            // reached
2037            reject = false;
2038            for(int l=0; l<nl; l++) { // layers
2039                if(cbI==null) continue;
2040                int nc = cbI.length;
2041
2042                int mres = 0;
2043                for(int c=0; c<nc; c++) {
2044                    if(cbI[c]!=null && cbI[c].length>mres)
2045                        mres = cbI[c].length;
2046                }
2047                for(int r=0; r<mres; r++) { // resolutions
2048
2049
2050                    int msub = 0;
2051                    for(int c=0; c<nc; c++) {
2052                        if(cbI[c]!=null && cbI[c][r]!=null
2053                           && cbI[c][r].length>msub)
2054                            msub = cbI[c][r].length;
2055                    }
2056                    for(int s=0; s<msub; s++) { // subbands
2057                        // Only LL subband resolution level 0
2058                        if(r==0 && s!=0) {
2059                            continue;
2060                        } else if(r!=0 && s==0) {
2061                            // No LL subband in resolution level > 0
2062                            continue;
2063                        }
2064
2065                        int mnby=0;
2066                        for(int c=0; c<nc; c++) {
2067                            if(cbI[c]!=null && cbI[c][r]!=null &&
2068                               cbI[c][r][s]!=null &&
2069                               cbI[c][r][s].length>mnby)
2070                                mnby = cbI[c][r][s].length;
2071                        }
2072                        for(int m=0; m<mnby; m++) {
2073
2074                            int mnbx = 0;
2075                            for(int c=0; c<nc; c++) {
2076                                if(cbI[c]!=null && cbI[c][r]!=null &&
2077                                   cbI[c][r][s]!=null && cbI[c][r][s][m]!=null
2078                                   && cbI[c][r][s][m].length>mnbx)
2079                                    mnbx = cbI[c][r][s][m].length;
2080                            }
2081                            for(int n=0; n<mnbx; n++) {
2082
2083                                for(int c=0; c<nc; c++) {
2084
2085                                    if(cbI[c]==null || cbI[c][r]==null ||
2086                                       cbI[c][r][s]==null ||
2087                                       cbI[c][r][s][m]==null ||
2088                                       cbI[c][r][s][m][n]==null ) {
2089                                        continue;
2090                                    }
2091                                    cb = cbI[c][r][s][m][n];
2092
2093                                    // If no code-block has been refused until
2094                                    // now
2095                                    if(!reject) {
2096                                        // Rate is to low to allow reading of
2097                                        // packet's head
2098                                        if(nBytes[t]<pktHeadLen[cb.pktIdx[l]]){
2099                                            // Stop parsing
2100                                            stopCount = true;
2101                                            // Reject all next
2102                                            // code-blocks
2103                                            reject=true;
2104                                        } else {
2105                                            // Rate is enough to read packet's
2106                                            // head
2107                                            if(!stopCount) {
2108                                                //If parsing was not stopped
2109                                                //Takes into account packet's
2110                                                //head length
2111                                                nBytes[t] -=
2112                                                    pktHeadLen[cb.pktIdx[l]];
2113                                                anbytes +=
2114                                                    pktHeadLen[cb.pktIdx[l]];
2115                                                // Set packet's head length to
2116                                                // 0, so that it won't be
2117                                                // taken into account next
2118                                                // time
2119                                                pktHeadLen[cb.pktIdx[l]]=0;
2120                                            }
2121                                        }
2122                                    }
2123                                    // Code-block has no data in this layer
2124                                    if(cb.len[l]==0) {
2125                                        continue;
2126                                    }
2127
2128                                    // Accepts code-block if length is enough,
2129                                    // if this code-block was not refused in a
2130                                    // previous layer and if no code-block was
2131                                    // refused in current component
2132                                    if(cb.len[l]<nBytes[t]
2133                                       && !reject){
2134                                        nBytes[t] -= cb.len[l];
2135                                        anbytes += cb.len[l];
2136                                    } else {
2137                                        // Refuses code-block
2138                                        // Forgets code-block's data
2139                                        cb.len[l]=cb.off[l]=cb.ntp[l]= 0;
2140                                        // Refuses all other code-block in
2141                                        // current and next component
2142                                        reject=true;
2143                                    }
2144
2145                                } // End loop on components
2146                            } // End loop on horiz. code-blocks
2147                        } // End loop on vert. code-blocks
2148                    } // End loop on subbands
2149                } // End loop on resolutions
2150            } // End loop on layers
2151        } else {
2152            // No parsing for this tile, adds tile's body to the total
2153            // number of read bytes.
2154            anbytes += totTileLen[t]-totTileHeadLen[t];
2155            if(t<getNumTiles()-1) {
2156                nBytes[t+1] += nBytes[t]-(totTileLen[t]-totTileHeadLen[t]);
2157            }
2158        }
2159
2160        // In this method nBytes[t] might be changed.  This change will affect
2161        // to decode this tile next time.  So cache the old nByte[t] and
2162        // recover it here.  -- Qinghuai Gao
2163        nBytes[t] = oldNBytes;
2164    }
2165
2166    /**
2167     * Changes the current tile, given the new indexes. An
2168     * IllegalArgumentException is thrown if the indexes do not correspond to
2169     * a valid tile.
2170     *
2171     * @param x The horizontal indexes the tile.
2172     *
2173     * @param y The vertical indexes of the new tile.
2174     * */
2175    public void setTile(int x,int y) {
2176
2177        int i;          // counter
2178        // Check validity of tile indexes
2179        if (x<0 || y<0 || x>=ntX || y>=ntY) {
2180            throw new IllegalArgumentException();
2181        }
2182        int t = (y*ntX+x);
2183        try {
2184            initTile(t);
2185        } catch(IOException ioe) {
2186            // XXX Do something!
2187        }
2188
2189        // Reset number of read bytes if needed
2190        if(t==0) {
2191            anbytes = headLen;
2192            if(!isTruncMode) {
2193                anbytes += 2;
2194            }
2195            // Restore values of nBytes
2196            for(int tIdx=0; tIdx<nt; tIdx++) {
2197                nBytes[tIdx] = baknBytes[tIdx];
2198            }
2199        }
2200
2201        // Set the new current tile
2202        ctX = x;
2203        ctY = y;
2204        // Calculate tile relative points
2205        int ctox = (x == 0) ? ax : px+x*ntW;
2206        int ctoy = (y == 0) ? ay : py+y*ntH;
2207        for (i=nc-1; i>=0; i--) {
2208            culx[i] = (ctox+hd.getCompSubsX(i)-1)/hd.getCompSubsX(i);
2209            culy[i] = (ctoy+hd.getCompSubsY(i)-1)/hd.getCompSubsY(i);
2210            offX[i] = (px+x*ntW+hd.getCompSubsX(i)-1)/hd.getCompSubsX(i);
2211            offY[i] = (py+y*ntH+hd.getCompSubsY(i)-1)/hd.getCompSubsY(i);
2212        }
2213
2214        // Initialize subband tree and number of resolution levels
2215        subbTrees = new SubbandSyn[nc];
2216        mdl = new int[nc];
2217        derived = new boolean[nc];
2218        params = new StdDequantizerParams[nc];
2219        gb = new int[nc];
2220
2221        for(int c=0; c<nc; c++){
2222            derived[c] = decSpec.qts.isDerived(t,c);
2223            params[c] =
2224                (StdDequantizerParams)decSpec.qsss.getTileCompVal(t,c);
2225            gb[c] = ((Integer)decSpec.gbs.getTileCompVal(t,c)).intValue();
2226            mdl[c] = ((Integer)decSpec.dls.getTileCompVal(t,c)).intValue();
2227
2228            subbTrees[c] =
2229                new SubbandSyn(getTileCompWidth(t,c,mdl[c]),
2230                               getTileCompHeight(t,c,mdl[c]),
2231                               getResULX(c,mdl[c]),getResULY(c,mdl[c]),mdl[c],
2232                               decSpec.wfs.getHFilters(t,c),
2233                               decSpec.wfs.getVFilters(t,c));
2234            initSubbandsFields(c,subbTrees[c]);
2235        }
2236
2237        // Read tile's packets
2238        try {
2239            readTilePkts(t);
2240        } catch(IOException e) {
2241            e.printStackTrace();
2242            throw new Error("IO Error when reading tile "+x+" x "+y);
2243        }
2244    }
2245
2246
2247    /**
2248     * Advances to the next tile, in standard scan-line order (by rows
2249     * then columns). An NoNextElementException is thrown if the
2250     * current tile is the last one (i.e. there is no next tile).
2251     * */
2252    public void nextTile(){
2253        if (ctX == ntX-1 && ctY == ntY-1) { // Already at last tile
2254            throw new NoNextElementException();
2255        }
2256        else if (ctX < ntX-1) { // If not at end of current tile line
2257            setTile(ctX+1,ctY);
2258        }
2259        else { // Go to first tile at next line
2260            setTile(0,ctY+1);
2261        }
2262    }
2263
2264    /**
2265     * Returns the specified coded code-block, for the specified component, in
2266     * the current tile. The first layer to return is indicated by 'fl'. The
2267     * number of layers that is returned depends on 'nl' and the amount of
2268     * available data.
2269     *
2270     * <p>The argument 'fl' is to be used by subsequent calls to this method
2271     * for the same code-block. In this way supplemental data can be retrieved
2272     * at a later time. The fact that data from more than one layer can be
2273     * returned means that several packets from the same code-block, of the
2274     * same component, and the same tile, have been concatenated.</p>
2275     *
2276     * <p>The returned compressed code-block can have its progressive
2277     * attribute set. If this attribute is set it means that more data can be
2278     * obtained by subsequent calls to this method (subject to transmission
2279     * delays, etc). If the progressive attribute is not set it means that the
2280     * returned data is all the data that can be obtained for the specified
2281     * code-block.</p>
2282     *
2283     * <p>The compressed code-block is uniquely specified by the current tile,
2284     * the component (identified by 'c'), the subband (indentified by 'sb')
2285     * and the code-block vertical and horizontal indexes 'n' and 'm'.</p>
2286     *
2287     * <p>The 'ulx' and 'uly' members of the returned 'DecLyrdCBlk' object
2288     * contain the coordinates of the top-left corner of the block, with
2289     * respect to the tile, not the subband.</p>
2290     *
2291     * @param c The index of the component, from 0 to N-1.
2292     *
2293     * @param m The vertical index of the code-block to return, in the
2294     * specified subband.
2295     *
2296     * @param n The horizontal index of the code-block to return, in the
2297     * specified subband.
2298     *
2299     * @param sb The subband in whic the requested code-block is.
2300     *
2301     * @param fl The first layer to return.
2302     *
2303     * @param nl The number of layers to return, if negative all available
2304     * layers are returned, starting at 'fl'.
2305     *
2306     * @param ccb If not null this object is used to return the compressed
2307     * code-block. If null a new object is created and returned. If the data
2308     * array in ccb is not null then it can be reused to return the compressed
2309     * data.
2310     * @return The compressed code-block, with a certain number of layers
2311     * determined by the available data and 'nl'.
2312     * */
2313    public DecLyrdCBlk getCodeBlock(int c,int m,int n,SubbandSyn sb,int fl,
2314                                    int nl,DecLyrdCBlk ccb) {
2315
2316        int t = getTileIdx();
2317        CBlkInfo rcb; // requested code-block
2318        int r = sb.resLvl;  // Resolution level
2319        int s = sb.sbandIdx; // Subband index
2320        int tpidx;
2321        int passtype;
2322
2323        // Number of layers
2324        int numLayers = ((Integer)decSpec.nls.getTileDef(t)).intValue();
2325        int options = ((Integer)decSpec.ecopts.getTileCompVal(t,c)).intValue();
2326        if(nl<0) {
2327            nl = numLayers-fl+1;
2328        }
2329
2330        // If the l quit condition is used, Make sure that no layer
2331        // after lquit is returned
2332        if(lQuit != -1 && fl+nl>lQuit){
2333          nl = lQuit - fl;
2334        }
2335
2336        // Check validity of resquested resolution level (according to the
2337        // "-res" option).
2338        int maxdl = getSynSubbandTree(t,c).resLvl;
2339        /* XXX Suppress error check for speed performance reasons.
2340        if(r>targetRes+maxdl-decSpec.dls.getMin()) {
2341            throw new Error("JJ2000 error: requesting a code-block "+
2342                            "disallowed by the '-res' option.");
2343        }
2344        */
2345
2346        // Check validity of all the arguments
2347        try {
2348            rcb = cbI[c][r][s][m][n];
2349
2350            if(fl<1 || fl>numLayers || fl+nl-1>numLayers) {
2351                throw new IllegalArgumentException();
2352            }
2353        } catch(ArrayIndexOutOfBoundsException e) {
2354            throw new IllegalArgumentException("Code-block (t:"+t+", c:"+
2355                                               c+", r:"+r+", s:"+s+", "+m+"x"+
2356                                               +n+") not found in codestream");
2357        } catch(NullPointerException e) {
2358            throw new IllegalArgumentException("Code-block (t:"+t+", c:"+
2359                                               c+", r:"+r+", s:"+s+", "+m+"x"
2360                                               +n+") not found in bit stream");
2361        }
2362
2363        // Create DecLyrdCBlk object if necessary
2364        if(ccb==null) {
2365            ccb = new DecLyrdCBlk();
2366        }
2367        ccb.m = m;
2368        ccb.n = n;
2369        ccb.nl = 0;
2370        ccb.dl = 0;
2371        ccb.nTrunc = 0;
2372
2373        if(rcb==null) {
2374            // This code-block was skipped when reading. Returns no data
2375            ccb.skipMSBP = 0;
2376            ccb.prog = false;
2377            ccb.w = ccb.h = ccb.ulx = ccb.uly = 0;
2378            return ccb;
2379        }
2380
2381        // ccb initialization
2382        ccb.skipMSBP = rcb.msbSkipped;
2383        ccb.ulx = rcb.ulx;
2384        ccb.uly = rcb.uly;
2385        ccb.w = rcb.w;
2386        ccb.h = rcb.h;
2387        ccb.ftpIdx = 0;
2388
2389        // Search for index of first truncation point (first layer where
2390        // length of data is not zero)
2391        int l=0;
2392        while( (l<rcb.len.length) && (rcb.len[l]==0)) {
2393            ccb.ftpIdx += rcb.ntp[l];
2394            l++;
2395        }
2396
2397        // Calculate total length, number of included layer and number of
2398        // truncation points
2399        for(l=fl-1; l<fl+nl-1; l++) {
2400            ccb.nl++;
2401            ccb.dl += rcb.len[l];
2402            ccb.nTrunc += rcb.ntp[l];
2403        }
2404
2405        // Calculate number of terminated segments
2406        int nts;
2407        if((options & OPT_TERM_PASS) != 0) {
2408            // Regular termination in use One segment per pass
2409            // (i.e. truncation point)
2410            nts = ccb.nTrunc-ccb.ftpIdx;
2411        } else if((options & OPT_BYPASS) != 0) {
2412            // Selective arithmetic coding bypass mode in use, but no regular
2413            // termination: 1 segment upto the end of the last pass of the 4th
2414            // most significant bit-plane, and, in each following bit-plane,
2415            // one segment upto the end of the 2nd pass and one upto the end
2416            // of the 3rd pass.
2417
2418            if(ccb.nTrunc <= FIRST_BYPASS_PASS_IDX) {
2419                nts = 1;
2420            } else {
2421                nts = 1;
2422                // Adds one for each terminated pass
2423                for (tpidx = ccb.ftpIdx; tpidx < ccb.nTrunc; tpidx++) {
2424                    if (tpidx >= FIRST_BYPASS_PASS_IDX-1) {
2425                        passtype =
2426                            (tpidx+NUM_EMPTY_PASSES_IN_MS_BP)%NUM_PASSES;
2427                        if (passtype == 1 || passtype == 2) {
2428                            // lazy pass just before MQ pass or MQ pass just
2429                            // before lazy pass => terminated
2430                            nts++;
2431                        }
2432                    }
2433                }
2434            }
2435        } else {
2436            // Nothing special in use, just one terminated segment
2437            nts = 1;
2438        }
2439
2440        // ccb.data creation
2441        if(ccb.data==null || ccb.data.length<ccb.dl) {
2442            ccb.data = new byte[ccb.dl];
2443        }
2444
2445        // ccb.tsLengths creation
2446        if (nts>1 && (ccb.tsLengths==null || ccb.tsLengths.length<nts)) {
2447            ccb.tsLengths = new int[nts];
2448        } else if (nts>1 &&
2449                   (options & (OPT_BYPASS|OPT_TERM_PASS)) == OPT_BYPASS) {
2450            ArrayUtil.intArraySet(ccb.tsLengths,0);
2451        }
2452
2453        // Fill ccb with compressed data
2454        int dataIdx = -1;
2455        tpidx = ccb.ftpIdx;
2456        int ctp = ccb.ftpIdx; // Cumulative number of truncation
2457        // point for the current layer layer
2458        int tsidx=0;
2459        int j;
2460
2461        for(l=fl-1; l<fl+nl-1; l++) {
2462            ctp += rcb.ntp[l];
2463            // No data in this layer
2464            if(rcb.len[l]==0) continue;
2465
2466            // Read data
2467            // NOTE: we should never get an EOFException here since all
2468            // data is checked to be within the file.
2469            try {
2470                in.seek(rcb.off[l]);
2471                in.readFully(ccb.data,dataIdx+1,rcb.len[l]);
2472                dataIdx += rcb.len[l];
2473            } catch (IOException e) {
2474                JJ2KExceptionHandler.handleException(e);
2475            }
2476
2477            // Get the terminated segment lengths, if any
2478            if(nts==1) continue;
2479            if((options & OPT_TERM_PASS) != 0) {
2480                // Regular termination => each pass is terminated
2481                for(j=0; tpidx<ctp; j++,tpidx++) {
2482                    if(rcb.segLen[l]!=null) {
2483                        ccb.tsLengths[tsidx++] = rcb.segLen[l][j];
2484                    } else { // Only one terminated segment in packet
2485                        ccb.tsLengths[tsidx++] = rcb.len[l];
2486                    }
2487                }
2488            } else {
2489                // Lazy coding without regular termination
2490                for(j=0; tpidx<ctp; tpidx++) {
2491                    if(tpidx>=FIRST_BYPASS_PASS_IDX-1) {
2492                        passtype =
2493                            (tpidx+NUM_EMPTY_PASSES_IN_MS_BP)%NUM_PASSES;
2494                        if(passtype!=0) {
2495                            // lazy pass just before MQ pass or MQ
2496                            // pass just before lazy pass =>
2497                            // terminated
2498                            if(rcb.segLen[l]!=null) {
2499                                ccb.tsLengths[tsidx++] += rcb.segLen[l][j++];
2500                                rcb.len[l] -= rcb.segLen[l][j-1];
2501                            } else { // Only one terminated segment in packet
2502                                ccb.tsLengths[tsidx++] += rcb.len[l];
2503                                rcb.len[l] = 0;
2504                            }
2505                        }
2506
2507                    }
2508                }
2509
2510                // Last length in packet always in (either terminated segment
2511                // or contribution to terminated segment)
2512                if(rcb.segLen[l]!=null && j<rcb.segLen[l].length) {
2513                    ccb.tsLengths[tsidx] += rcb.segLen[l][j];
2514                    rcb.len[l] -= rcb.segLen[l][j];
2515                } else { // Only one terminated segment in packet
2516                    if(tsidx<nts) {
2517                        ccb.tsLengths[tsidx] += rcb.len[l];
2518                        rcb.len[l] = 0;
2519                    }
2520                }
2521            }
2522        }
2523       if(nts==1 && ccb.tsLengths!=null) {
2524           ccb.tsLengths[0] = ccb.dl;
2525       }
2526
2527       // Set the progressive flag
2528       int lastlayer = fl+nl-1;
2529       if(lastlayer<numLayers-1){
2530           for(l=lastlayer+1; l<numLayers; l++){
2531               // It remains data for this code-block in the bit stream
2532               if(rcb.len[l]!=0){
2533                   ccb.prog = true;
2534               }
2535           }
2536       }
2537
2538       return ccb;
2539    }
2540
2541}