private CommonHFSExtentDescriptor getExtent(int extIndex, long startBlock) { long curStartBlock = startBlock; while (extIndex >= extentDescriptors.size()) { /* Need to read the next overflow extent into * extentDescriptors. */ if (overflowExtentsStore == null) { throw new RuntimeIOException( "No overflow extents store to " + "query for overflow extents."); } CommonHFSExtentLeafRecord extentRecord; if (all_extents_mapped) { extentRecord = null; } else { extentRecord = overflowExtentsStore.getExtentRecord(curStartBlock); } final CommonHFSExtentDescriptor[] descriptors = extentRecord.getRecordData(); for (int i = 0; i < descriptors.length; ++i) { final CommonHFSExtentDescriptor curDescriptor = descriptors[i]; final long blockCount = curDescriptor.getBlockCount(); if (blockCount == 0) { /* End-of-fork at first occurrence of block count 0. */ all_extents_mapped = true; break; } extentDescriptors.add(curDescriptor); curStartBlock += blockCount; } } return extentDescriptors.get(extIndex); }
/* @Override */ public int read(byte[] data, int pos, int len) { // System.err.println("ForkFilter.read(" + data + ", " + pos + ", " + len); long offset = Long.MAX_VALUE; // MAX_VALUE as a sentinel for seek long bytesToSkip = logicalPosition; long curLogicalBlock = 0; int extIndex; long currentExtentLength; if (extentDescriptors.size() < 1 || logicalPosition > forkLength) { return -1; // EOF } // Skip all extents whose range is located before the requested position (logicalPosition) // System.out.println("ForkFilter.read: skipping extents (bytesToSkip=" + // bytesToSkip + ")..."); for (extIndex = 0; ; ++extIndex) { CommonHFSExtentDescriptor cur = getExtent(extIndex, curLogicalBlock); if (cur == null) { /* No such extent available. */ return -1; } long currentBlockCount = cur.getBlockCount(); currentExtentLength = currentBlockCount * allocationBlockSize; if (bytesToSkip >= currentExtentLength) { bytesToSkip -= currentExtentLength; curLogicalBlock += currentBlockCount; } else { offset = fsOffset + firstBlockByteOffset + (cur.getStartBlock() * allocationBlockSize) + bytesToSkip; break; } } // System.out.println("done. skipped " + extIndex + " extents."); if (logicalPosition != lastLogicalPos) { // System.out.print("ForkFilter.read: (1)seeking to " + offset + "..."); sourceFile.seek(offset); // Seek to the correct position // System.out.println("done."); } else if (sourceFile.getFilePointer() != lastPhysicalPos) { // System.out.print("ForkFilter.read: (2)seeking to " + offset + "..."); sourceFile.seek(lastPhysicalPos); // System.out.println("done."); } long bytesLeftInStream = forkLength - logicalPosition; // System.err.println("bytesLeftInStream: " + bytesLeftInStream + " len: " + len); int totalBytesToRead = bytesLeftInStream < len ? (int) bytesLeftInStream : len; int bytesLeftToRead = totalBytesToRead; // System.err.println("bytesLeftToRead: " + bytesLeftToRead); // Start reading. Extent by extent if needed. for (; ; ++extIndex) { // System.out.println("ForkFilter.read: reading extent " + extIndex + "."); CommonHFSExtentDescriptor cur; try { cur = getExtent(extIndex, curLogicalBlock); } catch (RuntimeException e) { if (bytesLeftToRead == totalBytesToRead) { throw e; } else { break; } } sourceFile.seek( fsOffset + firstBlockByteOffset + (cur.getStartBlock() * allocationBlockSize) + bytesToSkip); long blockCount = cur.getBlockCount(); long bytesInExtent = blockCount * allocationBlockSize - bytesToSkip; int bytesToReadFromExtent = (bytesInExtent < bytesLeftToRead) ? (int) bytesInExtent : bytesLeftToRead; int bytesReadFromExtent = 0; while (bytesReadFromExtent < bytesToReadFromExtent) { int bytesToRead = bytesToReadFromExtent - bytesReadFromExtent; int positionInArray = pos + (totalBytesToRead - bytesLeftToRead) + bytesReadFromExtent; int bytesRead = sourceFile.read(data, positionInArray, bytesToRead); if (bytesRead > 0) bytesReadFromExtent += bytesRead; else { // Update tracker variables before returning lastPhysicalPos = sourceFile.getFilePointer(); int totalBytesRead = positionInArray - pos; logicalPosition += totalBytesRead; return totalBytesRead; } } bytesLeftToRead -= bytesReadFromExtent; bytesToSkip = 0; curLogicalBlock += blockCount; if (bytesLeftToRead == 0) break; } // Update tracker variables before returning lastPhysicalPos = sourceFile.getFilePointer(); logicalPosition += totalBytesToRead - bytesLeftToRead; if (bytesLeftToRead < totalBytesToRead) { int bytesRead = totalBytesToRead - bytesLeftToRead; // System.err.println("final bytesRead: " + bytesRead); return bytesRead; } else return -1; }