/* @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; }