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