public StringBuilder toString(StringBuilder sb, String[] fs, long idx) { Vec vecs[] = vecs(); for (int c = 0; c < fs.length; c++) { Vec vec = vecs[c]; if (vec.isEnum()) { String s = "----------"; if (!vec.isNA(idx)) { int x = (int) vec.at8(idx); if (x >= 0 && x < vec._domain.length) s = vec._domain[x]; } sb.append(String.format(fs[c], s)); } else if (vec.isInt()) { if (vec.isNA(idx)) { Chunk C = vec.elem2BV(0); // 1st Chunk int len = C.pformat_len0(); // Printable width for (int i = 0; i < len; i++) sb.append('-'); } else { try { sb.append(String.format(fs[c], vec.at8(idx))); } catch (IllegalFormatException ife) { System.out.println("Format: " + fs[c] + " col=" + c + " not for ints"); ife.printStackTrace(); } } } else { sb.append(String.format(fs[c], vec.at(idx))); if (vec.isNA(idx)) sb.append(' '); } sb.append(' '); // Column seperator } sb.append('\n'); return sb; }
@Override public void unloadChunks() { for (Chunk chunk : this.chunks.values()) { this.unloadChunk(chunk.getX(), chunk.getZ(), false); } this.chunks = new HashMap<>(); }
@Override public void map(Chunk chks[], NewChunk nchks[]) { long rstart = chks[0]._start; int rlen = chks[0]._len; // Total row count int rx = 0; // Which row to in/ex-clude int rlo = 0; // Lo/Hi for this block of rows int rhi = rlen; while (true) { // Still got rows to include? if (_rows != null) { // Got a row selector? if (rx >= _rows.length) break; // All done with row selections long r = _rows[rx++] - 1; // Next row selector if (r < 0) { // Row exclusion if (rx > 0 && _rows[rx - 1] < _rows[rx]) throw H2O.unimpl(); long er = Math.abs(r) - 2; if (er < rstart) continue; // scoop up all of the rows before the first exclusion if (rx == 1 && ((int) (er + 1 - rstart)) > 0 && _ex) { rlo = (int) rstart; rhi = (int) (er - rstart); _ex = false; rx--; } else { rlo = (int) (er + 1 - rstart); // TODO: handle jumbled row indices ( e.g. -c(1,5,3) ) while (rx < _rows.length && (_rows[rx] + 1 == _rows[rx - 1] && rlo < rlen)) { if (rx < _rows.length - 1 && _rows[rx] < _rows[rx + 1]) throw H2O.unimpl(); rx++; rlo++; // Exclude consecutive rows } rhi = rx >= _rows.length ? rlen : (int) Math.abs(_rows[rx] - 1) - 2; if (rx < _rows.length - 1 && _rows[rx] < _rows[rx + 1]) throw H2O.unimpl(); } } else { // Positive row list? if (r < rstart) continue; rlo = (int) (r - rstart); rhi = rlo + 1; // Stop at the next row while (rx < _rows.length && (_rows[rx] - 1 - rstart) == rhi && rhi < rlen) { rx++; rhi++; // Grab sequential rows } } } // Process this next set of rows // For all cols in the new set for (int i = 0; i < _cols.length; i++) { Chunk oc = chks[_cols[i]]; NewChunk nc = nchks[i]; if (oc._vec.isInt()) { // Slice on integer columns for (int j = rlo; j < rhi; j++) if (oc.isNA0(j)) nc.addNA(); else nc.addNum(oc.at80(j), 0); } else { // Slice on double columns for (int j = rlo; j < rhi; j++) nc.addNum(oc.at0(j)); } } rlo = rhi; if (_rows == null) break; } }
@Override public void map(Chunk chks[], NewChunk nchks[]) { Chunk pred = chks[chks.length - 1]; for (int i = 0; i < pred._len; ++i) { if (pred.at0(i) != 0) for (int j = 0; j < chks.length - 1; ++j) nchks[j].addNum(chks[j].at0(i)); } }
/* * (non-Javadoc) * * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((original == null) ? 0 : original.hashCode()); result = prime * result + ((revised == null) ? 0 : revised.hashCode()); return result; }
/** Given a chunk, find a random position in it. */ protected static ChunkPosition getRandomSpawningPointInChunk( World par0World, int par1, int par2) { Chunk chunk = par0World.getChunkFromChunkCoords(par1, par2); int i = par1 * 16 + par0World.rand.nextInt(16); int j = par0World.rand.nextInt(chunk != null ? Math.max(128, chunk.getTopFilledSegment()) : 128); int k = par2 * 16 + par0World.rand.nextInt(16); return new ChunkPosition(i, j, k); }
/** Given a chunk, find a random position in it. */ protected static ChunkPosition getRandomSpawningPointInChunk( World par0World, int par1, int par2) { Chunk chunk = par0World.getChunkFromChunkCoords(par1, par2); int i = par1 * 16 + par0World.rand.nextInt(16); int j = par2 * 16 + par0World.rand.nextInt(16); int k = par0World.rand.nextInt( chunk != null ? (chunk.getTopFilledSegment() + 16) - 1 : par0World.getActualHeight()); return new ChunkPosition(i, k, j); }
@Override public boolean unloadChunk(int X, int Z, boolean safe) { String index = Level.chunkHash(X, Z); Chunk chunk = this.chunks.containsKey(index) ? this.chunks.get(index) : null; if (chunk != null && chunk.unload(false, safe)) { this.chunks.remove(index); return true; } return false; }
@Override public void setBlockMetadataAt(int metadata, BlockLocation blockLocation) { ChunkLocation location = new ChunkLocation(blockLocation); BlockLocation chunkBlockOffset = new BlockLocation(location); Chunk chunk = getChunkAt(location); if (chunk == null) return; chunk.setBlockMetadataAt( metadata, blockLocation.getX() - chunkBlockOffset.getX(), blockLocation.getY() - chunkBlockOffset.getY(), blockLocation.getZ() - chunkBlockOffset.getZ()); }
public Location getSurfaceAt(Location origin) { Chunk chunky = origin.getChunk(); int x = origin.getBlockX(), z = origin.getBlockZ(), surface = 0, envid = origin.getWorld().getEnvironment().getId(); Set dimmap = Sets.newHashSet(envid == 0 ? new int[] {1, 2, 3, 7, 15, 16} : envid == -1 ? 87 : 121); for (int y = 0; y != 256; y++) if (dimmap.contains(chunky.getBlock(x, y, z).getTypeId())) surface = y; return chunky.getBlock(x, surface, z).getLocation(); }
@Override public int getBlockMetadataAt(BlockLocation blockLocation) { ChunkLocation location = new ChunkLocation(blockLocation); BlockLocation chunkBlockOffset = new BlockLocation(location); Chunk chunk = getChunkAt(location); if (chunk == null) return 0; int metadata = chunk.getBlockMetadataAt( blockLocation.getX() - chunkBlockOffset.getX(), blockLocation.getY() - chunkBlockOffset.getY(), blockLocation.getZ() - chunkBlockOffset.getZ()); return metadata; }
@Override public Block getBlockAt(BlockLocation location) { ChunkLocation chunkLocation = new ChunkLocation(location); Chunk chunk = getChunkAt(chunkLocation); if (chunk == null) return null; BlockLocation chunkBlockOffset = new BlockLocation(chunkLocation); int chunkOffsetX = location.getX() - chunkBlockOffset.getX(); int chunkOffsetY = location.getY() - chunkBlockOffset.getY(); int chunkOffsetZ = location.getZ() - chunkBlockOffset.getZ(); int id = chunk.getBlockIdAt(chunkOffsetX, chunkOffsetY, chunkOffsetZ); int metadata = chunk.getBlockMetadataAt(chunkOffsetX, chunkOffsetY, chunkOffsetZ); return new Block(this, chunk, location, id, metadata); }
/* * (non-Javadoc) * * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Delta other = (Delta) obj; if (original == null) { if (other.original != null) return false; } else if (!original.equals(other.original)) return false; if (revised == null) { if (other.revised != null) return false; } else if (!revised.equals(other.revised)) return false; return true; }
// Print fixed-width row & fixed-width headers (more compressed print // format). Returns the column formats. public String[] toStringHdr(StringBuilder sb) { String[] fs = new String[numCols()]; for (int c = 0; c < fs.length; c++) { String n = (c < _names.length) ? _names[c] : ("C" + c); if (numRows() == 0) { sb.append(n).append(' '); continue; } int w = 0; if (_vecs[c].isEnum()) { String ss[] = _vecs[c]._domain; for (int i = 0; i < ss.length; i++) w = Math.max(w, ss[i].length()); w = Math.min(w, 10); fs[c] = "%" + w + "." + w + "s"; } else { Chunk C = _vecs[c].elem2BV(0); // 1st Chunk String f = fs[c] = C.pformat(); // Printable width for (int x = 0; x < f.length(); x++) // Get printable width from format if (Character.isDigit(f.charAt(x))) w = w * 10 + (f.charAt(x) - '0'); else if (w > 0) break; if (f.charAt(1) == ' ') w++; // Leading blank is not in print-width } int len = sb.length(); if (n.length() <= w) { // Short name, big digits sb.append(n); for (int i = n.length(); i < w; i++) sb.append(' '); } else if (w == 1) { // First char only sb.append(n.charAt(0)); } else if (w == 2) { // First 2 chars only sb.append(n.charAt(0)).append(n.charAt(1)); } else { // First char dot lastchars; e.g. Compress "Interval" to "I.val" sb.append(n.charAt(0)).append('.'); for (int i = n.length() - (w - 2); i < n.length(); i++) sb.append(n.charAt(i)); } assert len + w == sb.length(); sb.append(' '); // Column seperator } sb.append('\n'); return fs; }
@Override public void map(Chunk cs) { int idx = _chunkOffset + cs.cidx(); Key ckey = Vec.chunkKey(_v._key, idx); if (_cmap != null) { assert !cs.hasFloat() : "Input chunk (" + cs.getClass() + ") has float, but is expected to be categorical"; NewChunk nc = new NewChunk(_v, idx); // loop over rows and update ints for new domain mapping according to vecs[c].domain() for (int r = 0; r < cs._len; ++r) { if (cs.isNA(r)) nc.addNA(); else nc.addNum(_cmap[(int) cs.at8(r)], 0); } nc.close(_fs); } else { DKV.put(ckey, cs.deepCopy(), _fs, true); } }
@Override public boolean isChunkPopulated(int chunkX, int chunkZ) { Chunk chunk = this.getChunk(chunkX, chunkZ); return chunk != null && chunk.isPopulated(); }
// Constructor used when inflating a Chunk. public NewChunk(Chunk c) { this(c._vec, c.cidx()); _start = c._start; }
public Chunk getEmptyChunk(int chunkX, int chunkZ) { return Chunk.getEmptyChunk(chunkX, chunkZ, this); }
@Override public void saveChunks() { for (Chunk chunk : this.chunks.values()) { this.saveChunk(chunk.getX(), chunk.getZ()); } }
public void addStr(Chunk c, long row) { if (c.isNA_abs(row)) addNA(); else addStr(c.atStr_abs(new ValueString(), row)); }
/** * Greedy Mesher algorithm, made with <a * href="http://0fps.net/2012/06/30/meshing-in-a-minecraft-game/">This article</a> * * @param c Chunk to mesh * @param holder list of models to hold the quads */ public static Model Greedy(Chunk c) { // Position of the new quad's bottom left corner int[] position = new int[3]; // Allows us to select a new voxel to merge depending on the dimension // we're evaluating int[] offset = new int[3]; // Positioning offsets int[] xOffset = new int[3]; int[] yOffset = new int[3]; int u, v; List<float[]> floatdata = new LinkedList<float[]>(); List<int[]> indices = new LinkedList<int[]>(); int[] dimentions = new int[] {Chunk.CHUNK_SIZE, World.WORLD_HEIGHT, Chunk.CHUNK_SIZE}; Voxel[] mask; // the mask index int n; // Buffer variables Voxel tmp1, tmp2; // Quad size, used for tiling textures int width, height; boolean back = true, b = false; while (b != back) { // d = x or y or z for (int d = 0; d < 3; d++) { position[0] = position[1] = position[2] = 0; offset[0] = offset[1] = offset[2] = 0; offset[d] = 1; position[d] = -1; u = (d + 1) % 3; v = (d + 2) % 3; // we'll iterate once per direction (6 times) mask = new Voxel[dimentions[u] * dimentions[v]]; while (position[d] < dimentions[d]) { n = 0; for (position[v] = 0; position[v] < dimentions[v]; position[v]++) { for (position[u] = 0; position[u] < dimentions[u]; position[u]++) { tmp1 = (position[d] >= 0) ? c.getAt(position[0], position[1], position[2]) : null; tmp2 = (position[d] < dimentions[d] - 1) ? c.getAt( position[0] + offset[0], position[1] + offset[1], position[2] + offset[2]) : null; // if the two voxels can be merged, we add null to // the mesh mask otherwise we add the actual voxel. mask[n++] = (tmp1 != null && tmp2 != null && tmp1.canBeMerged(tmp2)) ? null : (back ? tmp1 : tmp2); } } // We increment the current voxel (face) to compute position[d]++; n = 0; for (int j = 0; j < dimentions[v]; j++) { int i = 0; while (i < dimentions[u]) { if (mask[n] != null) { for (width = 1; (i + width) < dimentions[u] && mask[n + width] != null && mask[n + width].canBeMerged(mask[n]); width++) { // No code, the point of this loop is to get // the right width value for the mesh } outerloop: for (height = 1; j + height < dimentions[v]; height++) { for (int k = 0; k < width; k++) { // calculate the right height value for // the given width if (mask[n + k + height * dimentions[u]] == null || !(mask[n + k + height * dimentions[u]].canBeMerged(mask[n]))) { break outerloop; } } } // if the voxel isn't visible we don't create a // mesh for it if (mask[n].isOpaque() && mask[n].isVisible()) { // Relative positions, will be multiplied to // make a voxel later position[u] = i; position[v] = j; xOffset[0] = xOffset[1] = xOffset[2] = 0; xOffset[u] = width; yOffset[0] = yOffset[1] = yOffset[2] = 0; yOffset[v] = height; CreateQuad( new Vector3f(position[0], position[1], position[2]), new Vector3f( position[0] + xOffset[0], position[1] + xOffset[1], position[2] + xOffset[2]), new Vector3f( position[0] + xOffset[0] + yOffset[0], position[1] + xOffset[1] + yOffset[1], position[2] + xOffset[2] + yOffset[2]), new Vector3f( position[0] + yOffset[0], position[1] + yOffset[1], position[2] + yOffset[2]), back, width, height, mask[n].getColor(), floatdata, indices); } // Reset mask and increase counters for (int l = 0; l < height; l++) { for (int k = 0; k < width; k++) { mask[n + k + l * dimentions[u]] = null; } } // go to the next "line" i += width; n += width; } else { // go to the next quad i++; n++; } } } } } back = back & b; b = !b; } float[] vertices = new float[floatdata.size() * 12 / 2]; float[] colors = new float[floatdata.size() * 12 / 2]; int[] finalIndices = new int[indices.size() * 6]; for (int k = 0; k < floatdata.size(); k++) { if (k % 2 == 0) { for (int i = 0; i < floatdata.get(k).length; i++) { vertices[k / 2 * 12 + i] = floatdata.get(k)[i]; } } else { for (int i = 0; i < floatdata.get(k).length; i++) { colors[k / 2 * 12 + i] = floatdata.get(k)[i]; } } } for (int j = 0; j < indices.size(); j++) { finalIndices[j * 6] = indices.get(j)[0]; finalIndices[j * 6 + 1] = indices.get(j)[1]; finalIndices[j * 6 + 2] = indices.get(j)[2]; finalIndices[j * 6 + 3] = indices.get(j)[3]; finalIndices[j * 6 + 4] = indices.get(j)[4]; finalIndices[j * 6 + 5] = indices.get(j)[5]; } return OGLUtil.createMeshVAO(vertices, vertices, colors, finalIndices); }
public void addStr(Chunk c, int row) { if (c.isNA(row)) addNA(); else addStr(c.atStr(new ValueString(), row)); }
public void addUUID(Chunk c, long row) { if (c.isNA_abs(row)) addUUID(C16Chunk._LO_NA, C16Chunk._HI_NA); else addUUID(c.at16l_abs(row), c.at16h_abs(row)); }
public void addUUID(Chunk c, int row) { if (c.isNA(row)) addUUID(C16Chunk._LO_NA, C16Chunk._HI_NA); else addUUID(c.at16l(row), c.at16h(row)); }
private boolean eventToNP( BasicChunk bs, Word tg, Word pr, Word pr2, List<Word> prep, Map<String, Rules> rules[], int ev_type, boolean evt1, boolean evt2, boolean add) { boolean prep1_pos, prep2_pos = false, prep_order = false, in_chunk = false; String prep1 = "", prep2 = "", ctype, pos_type; int count1, count2 = 0; // for theme2/cause int verb_type; boolean has_theme2 = false; String themeTrg = "", causeTrg = ""; bs.mergeNP(); if (bs.is_merged) { ctype = "CP"; } else { ctype = "NP"; } if (evt1) { // theme themeTrg = pr.word; } if (evt2) { // cause causeTrg = pr2.word; } pos_type = tg.pos_tag; prep1_pos = pr.pos > tg.pos ? true : false; // prep 1 position nppt++; // NP pattern if (pr2 == null) { // only theme if (bs.isSameChunk(tg, pr) && !evt1) { Counter ct = sameChunk.get(tg.word); if (ct == null) { ct = new Counter(1); sameChunk.put(tg.word, ct); } else { ct.inc(); } } count1 = bs.countChunks(tg, pr); if (prep1_pos) { // TG - PRO prep1 = getPrep(tg, pr, bs); if (ev_type <= 5) { Word sub_tg = findTrg(tg, pr.pos, bs); if (sub_tg != null) { // found sub-trg String key = tg.word + tg.pos_tag; Map<String, Counter> ct = subTG.get(key); if (ct == null) { ct = new HashMap<String, Counter>(); subTG.put(key, ct); } Counter c = ct.get(sub_tg.word + sub_tg.pos_tag); if (c == null) { c = new Counter(1); ct.put(sub_tg.word + sub_tg.pos_tag, c); } else { c.inc(); } } } } else { // PRO - TG if (!evt1 && bs.inChunk(tg, pr)) { in_chunk = true; count1 = 0; } else if (evt1 && tg.pos == pr.pos) { in_chunk = true; count1 = 0; } } if (in_chunk && !evt1) { Chunk tgc = bs.getChunk(tg.pos); if (tgc.is_inChunk(tg, tokens) && tgc.trigs.size() == 2) { // System.out.println("---->"+ tgc.getText()+"\n"+curr_pmid+" "+curr_sen_id); // bs.printChunk(); // System.out.println(""); } } } else { has_theme2 = true; // has cause/theme2 prep2_pos = pr2.pos > tg.pos ? true : false; count1 = bs.countChunks(tg, pr); count2 = bs.countChunks(tg, pr2); if (prep1_pos && prep2_pos) { // both are behind trig if (pr.pos > pr2.pos) { // reg only: TG - cause - theme prep1 = getPrep2(pr2, pr, bs); // theme prep2 = getPrep(tg, pr2, bs); // cause prep_order = true; // need to swich order } else { // binding & reg : TG- theme - cause/theme2 prep2 = getPrep2(pr, pr2, bs); // cause prep1 = getPrep(tg, pr, bs); // theme } } else if (prep1_pos && !prep2_pos) { // cause - tg - theme -> reg only prep1 = getPrep(tg, pr, bs); prep2 = getPrepFront(tg, pr2, bs); } else if (!prep1_pos && prep2_pos) { // theme - tg - cause | theme1 - tg - theme2 prep1 = getPrepFront(tg, pr, bs); prep2 = getPrep(tg, pr2, bs); } else { // both are in front of tg // binding & reg if (pr.pos > pr2.pos) { // cause/theme2 - theme -TG: should skip this prep1 = getPrepFront(tg, pr, bs); prep2 = getPrep2(pr2, pr, bs); prep_order = true; } else { // Reg only : theme - cause/theme2 - TG prep1 = getPrep2(pr, pr2, bs); prep2 = getPrepFront(tg, pr2, bs); } } if (ev_type == 5) { in_chunk = bs.inChunk(tg, pr); // count1 = 0; } else if (ev_type > 5 && !evt2 && !prep2_pos) { // cause must be pro in_chunk = bs.inChunk(tg, pr2); // count2 = 0; } } // pr2 condition verb_type = 0; Rules rl = rules[ev_type].get(tg.word); if (rl == null) { rl = new Rules(ev_type, tg.word); rules[ev_type].put(tg.word, rl); } if (ev_type < 5) { rl.addPattern(verb_type, pos_type, ctype, prep1_pos, prep1, in_chunk, count1, themeTrg, add); } else if (ev_type == 5) { rl.addPattern( verb_type, pos_type, ctype, prep1_pos, prep2_pos, prep_order, prep1, prep2, has_theme2, in_chunk, count1, count2, themeTrg, add); } else { // regulatory events rl.addPattern( verb_type, pos_type, ctype, prep1_pos, prep2_pos, prep_order, prep1, prep2, has_theme2, in_chunk, count1, count2, evt1, evt2, themeTrg, causeTrg, add); } return true; }
/** Reads a WAVE Chunk. */ protected boolean readChunk(RepInfo info) throws IOException { Chunk chunk = null; ChunkHeader chunkh = new ChunkHeader(this, info); if (!chunkh.readHeader(_dstream)) { return false; } int chunkSize = (int) chunkh.getSize(); bytesRemaining -= chunkSize + 8; if (bytesRemaining < 0) { info.setMessage(new ErrorMessage("Invalid chunk size", _nByte)); return false; } String id = chunkh.getID(); if ("fmt ".equals(id)) { if (formatChunkSeen) { dupChunkError(info, "Format"); } chunk = new FormatChunk(this, chunkh, _dstream); formatChunkSeen = true; } else if ("data".equals(id)) { if (dataChunkSeen) { dupChunkError(info, "Data"); } chunk = new DataChunk(this, chunkh, _dstream); dataChunkSeen = true; } else if ("fact".equals(id)) { chunk = new FactChunk(this, chunkh, _dstream); factChunkSeen = true; // Are multiple 'fact' chunks allowed? } else if ("note".equals(id)) { chunk = new NoteChunk(this, chunkh, _dstream); // Multiple note chunks are allowed } else if ("labl".equals(id)) { chunk = new LabelChunk(this, chunkh, _dstream); // Multiple label chunks are allowed } else if ("list".equals(id)) { chunk = new AssocDataListChunk(this, chunkh, _dstream, info); // Are multiple chunks allowed? Who knows? } else if ("LIST".equals(id)) { chunk = new ListInfoChunk(this, chunkh, _dstream, info); // Multiple list chunks must be OK, since there can // be different types, e.g., an INFO list and an exif list. } else if ("smpl".equals(id)) { chunk = new SampleChunk(this, chunkh, _dstream); // Multiple sample chunks are allowed -- I think } else if ("inst".equals(id)) { if (instrumentChunkSeen) { dupChunkError(info, "Instrument"); } chunk = new InstrumentChunk(this, chunkh, _dstream); // Only one instrument chunk is allowed instrumentChunkSeen = true; } else if ("mext".equals(id)) { if (mpegChunkSeen) { dupChunkError(info, "MPEG"); } chunk = new MpegChunk(this, chunkh, _dstream); // I think only one MPEG chunk is allowed mpegChunkSeen = true; } else if ("cart".equals(id)) { if (cartChunkSeen) { dupChunkError(info, "Cart"); } chunk = new CartChunk(this, chunkh, _dstream); cartChunkSeen = true; } else if ("bext".equals(id)) { if (broadcastExtChunkSeen) { dupChunkError(info, "Broadcast Audio Extension"); } chunk = new BroadcastExtChunk(this, chunkh, _dstream); broadcastExtChunkSeen = true; } else if ("levl".equals(id)) { if (peakChunkSeen) { dupChunkError(info, "Peak Envelope"); } chunk = new PeakEnvelopeChunk(this, chunkh, _dstream); peakChunkSeen = true; } else if ("link".equals(id)) { if (linkChunkSeen) { dupChunkError(info, "Link"); } chunk = new LinkChunk(this, chunkh, _dstream); linkChunkSeen = true; } else if ("cue ".equals(id)) { if (cueChunkSeen) { dupChunkError(info, "Cue"); } chunk = new CueChunk(this, chunkh, _dstream); cueChunkSeen = true; } else { info.setMessage(new InfoMessage("Chunk type '" + id + "' ignored", _nByte)); } if (chunk != null) { if (!chunk.readChunk(info)) { return false; } } else { // Other chunk types are legal, just skip over them skipBytes(_dstream, chunkSize, this); } if ((chunkSize & 1) != 0) { // Must come out to an even byte boundary skipBytes(_dstream, 1, this); --bytesRemaining; } return true; }