ContentStoreDirUtf8 extends ContentStoreDirAbstract { @Override public synchronized String[] retrieveParts(int contentId, int[] start, int[] end) { try { TocEntry e = toc.get(contentId); if (e == null || e.deleted) return null; int n = start.length; if (n != end.length) throw new IllegalArgumentException("start and end must be of equal length"); String[] result = new String[n]; try (FileInputStream fileInputStream = new FileInputStream(getContentFile(e.fileId))) { try (FileChannel fileChannel = fileInputStream.getChannel()) { for (int i = 0; i < n; i++) { int a = start[i]; int b = end[i]; if (a == -1) a = 0; if (b == -1) b = e.entryLengthCharacters; if (a < 0 || b < 0) { throw new IllegalArgumentException("Illegal values, start = " + a + ", end = " + b); } if (a > e.entryLengthCharacters || b > e.entryLengthCharacters) { throw new IllegalArgumentException("Value(s) out of range, start = " + a + ", end = " + b + ", content length = " + e.entryLengthCharacters); } if (b <= a) { throw new IllegalArgumentException( "Tried to read empty or negative length snippet (from " + a + " to " + b + ")"); } int firstBlock = a / e.blockSizeCharacters; int lastBlock = (b - 1) / e.blockSizeCharacters; StringBuilder decoded = new StringBuilder(); for (int j = firstBlock; j <= lastBlock; j++) { long readStartOffset = e.getBlockStartOffset(j); int bytesToRead = (int) (e.getBlockEndOffset(j) - readStartOffset); ByteBuffer buffer = ByteBuffer.allocate(bytesToRead); int bytesRead = fileChannel.read(buffer, readStartOffset); if (bytesRead < bytesToRead) { throw new BlackLabRuntimeException("Not enough bytes read, " + bytesRead + " < " + bytesToRead); } decoded.append(decodeBlock(buffer.array(), 0, bytesRead)); } int firstChar = a % e.blockSizeCharacters; String decodedStr = decoded.toString(); try { result[i] = decodedStr.substring(firstChar, firstChar + b - a); } catch (StringIndexOutOfBoundsException e1) { System.err.println("ERROR!\ndecodedStr.length() = " + decodedStr.length() + "\n" + "firstChar = " + firstChar + "\na = " + a + "\nb = " + b + "\nfirstBlock = " + firstBlock + "\nlastBlock = " + lastBlock); System.err.flush(); throw e1; } } } } return result; } catch (IOException e) { throw BlackLabRuntimeException.wrap(e); } } ContentStoreDirUtf8(File dir);  ContentStoreDirUtf8(File dir, boolean create); void setWriteMapReserve(int writeMapReserve); void setBlockSizeCharacters(int size); @Override void clear(); @Override void close(); void setDataFileSizeHint(long dataFileSizeHint); void addToBlock(String contentPart); void writeCurrentBlock(OutputStream os); @Override synchronized void storePart(String content); @Override synchronized int store(String content); @Override String retrieve(int id); @Override synchronized String[] retrieveParts(int contentId, int[] start, int[] end); @Override synchronized void delete(int id); @Override boolean isDeleted(int id); @Override int docLength(int id); @Override Set<Integer> idSet(); @Override void initialize();  }
@Test public void testRetrievePart() { String[] parts = store.retrieveParts(2, new int[] { 5, 15 }, new int[] { 7, 18 }); Assert.assertEquals(str[1].substring(5, 7), parts[0]); Assert.assertEquals(str[1].substring(15, 18), parts[1]); }