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