/* write a chunk data to the region file at specified sector number */ private void write(int sectorNumber, byte[] data, int length) throws IOException { debugln(" " + sectorNumber); file.seek(sectorNumber * SECTOR_BYTES); file.writeInt(length + 1); // chunk length file.writeByte(VERSION_DEFLATE); // chunk version number file.write(data, 0, length); // chunk data }
/* * gets an (uncompressed) stream representing the chunk data returns null if * the chunk is not found or an error occurs */ public synchronized DataInputStream getChunkDataInputStream(int x, int z) { if (outOfBounds(x, z)) { debugln("READ", x, z, "out of bounds"); return null; } try { int offset = getOffset(x, z); if (offset == 0) { // debugln("READ", x, z, "miss"); return null; } int sectorNumber = offset >> 8; int numSectors = offset & 0xFF; if (sectorNumber + numSectors > sectorFree.size()) { debugln("READ", x, z, "invalid sector"); return null; } file.seek(sectorNumber * SECTOR_BYTES); int length = file.readInt(); if (length > SECTOR_BYTES * numSectors) { debugln("READ", x, z, "invalid length: " + length + " > 4096 * " + numSectors); return null; } byte version = file.readByte(); if (version == VERSION_GZIP) { byte[] data = new byte[length - 1]; file.read(data); DataInputStream ret = new DataInputStream( new BufferedInputStream(new GZIPInputStream(new ByteArrayInputStream(data)))); // debug("READ", x, z, " = found"); return ret; } else if (version == VERSION_DEFLATE) { byte[] data = new byte[length - 1]; file.read(data); DataInputStream ret = new DataInputStream( new BufferedInputStream(new InflaterInputStream(new ByteArrayInputStream(data)))); // debug("READ", x, z, " = found"); return ret; } debugln("READ", x, z, "unknown version " + version); return null; } catch (IOException e) { debugln("READ", x, z, "exception"); return null; } }
public static long checksumRandomAccessFile(Path filename) throws IOException { try (RandomAccessFile file = new RandomAccessFile(filename.toFile(), "r")) { long length = file.length(); CRC32 crc = new CRC32(); for (long p = 0; p < length; p++) { file.seek(p); int c = file.readByte(); crc.update(c); } return crc.getValue(); } }
/** * Read block from file. * * @param file - File to read. * @param off - Marker position in file to start read from if {@code -1} read last blockSz bytes. * @param blockSz - Maximum number of chars to read. * @param lastModified - File last modification time. * @return Read file block. * @throws IOException In case of error. */ public static VisorFileBlock readBlock(File file, long off, int blockSz, long lastModified) throws IOException { RandomAccessFile raf = null; try { long fSz = file.length(); long fLastModified = file.lastModified(); long pos = off >= 0 ? off : Math.max(fSz - blockSz, 0); // Try read more that file length. if (fLastModified == lastModified && fSz != 0 && pos >= fSz) throw new IOException( "Trying to read file block with wrong offset: " + pos + " while file size: " + fSz); if (fSz == 0) return new VisorFileBlock(file.getPath(), pos, fLastModified, 0, false, EMPTY_FILE_BUF); else { int toRead = Math.min(blockSz, (int) (fSz - pos)); byte[] buf = new byte[toRead]; raf = new RandomAccessFile(file, "r"); raf.seek(pos); int cntRead = raf.read(buf, 0, toRead); if (cntRead != toRead) throw new IOException( "Count of requested and actually read bytes does not match [cntRead=" + cntRead + ", toRead=" + toRead + ']'); boolean zipped = buf.length > 512; return new VisorFileBlock( file.getPath(), pos, fSz, fLastModified, zipped, zipped ? zipBytes(buf) : buf); } } finally { U.close(raf, null); } }
/** * Decode file charset. * * @param f File to process. * @return File charset. * @throws IOException in case of error. */ public static Charset decode(File f) throws IOException { SortedMap<String, Charset> charsets = Charset.availableCharsets(); String[] firstCharsets = { Charset.defaultCharset().name(), "US-ASCII", "UTF-8", "UTF-16BE", "UTF-16LE" }; Collection<Charset> orderedCharsets = U.newLinkedHashSet(charsets.size()); for (String c : firstCharsets) if (charsets.containsKey(c)) orderedCharsets.add(charsets.get(c)); orderedCharsets.addAll(charsets.values()); try (RandomAccessFile raf = new RandomAccessFile(f, "r")) { FileChannel ch = raf.getChannel(); ByteBuffer buf = ByteBuffer.allocate(4096); ch.read(buf); buf.flip(); for (Charset charset : orderedCharsets) { CharsetDecoder decoder = charset.newDecoder(); decoder.reset(); try { decoder.decode(buf); return charset; } catch (CharacterCodingException ignored) { } } } return Charset.defaultCharset(); }
public RegionFile(File path) { offsets = new int[SECTOR_INTS]; chunkTimestamps = new int[SECTOR_INTS]; fileName = path; debugln("REGION LOAD " + fileName); sizeDelta = 0; try { if (path.exists()) { lastModified = path.lastModified(); } file = new RandomAccessFile(path, "rw"); if (file.length() < SECTOR_BYTES) { /* we need to write the chunk offset table */ for (int i = 0; i < SECTOR_INTS; ++i) { file.writeInt(0); } // write another sector for the timestamp info for (int i = 0; i < SECTOR_INTS; ++i) { file.writeInt(0); } sizeDelta += SECTOR_BYTES * 2; } if ((file.length() & 0xfff) != 0) { /* the file size is not a multiple of 4KB, grow it */ for (int i = 0; i < (file.length() & 0xfff); ++i) { file.write((byte) 0); } } /* set up the available sector map */ int nSectors = (int) file.length() / SECTOR_BYTES; sectorFree = new ArrayList<Boolean>(nSectors); for (int i = 0; i < nSectors; ++i) { sectorFree.add(true); } sectorFree.set(0, false); // chunk offset table sectorFree.set(1, false); // for the last modified info file.seek(0); for (int i = 0; i < SECTOR_INTS; ++i) { int offset = file.readInt(); offsets[i] = offset; if (offset != 0 && (offset >> 8) + (offset & 0xFF) <= sectorFree.size()) { for (int sectorNum = 0; sectorNum < (offset & 0xFF); ++sectorNum) { sectorFree.set((offset >> 8) + sectorNum, false); } } } for (int i = 0; i < SECTOR_INTS; ++i) { int lastModValue = file.readInt(); chunkTimestamps[i] = lastModValue; } } catch (IOException e) { e.printStackTrace(); } }
public void close() throws IOException { file.close(); }
private void setTimestamp(int x, int z, int value) throws IOException { chunkTimestamps[x + z * 32] = value; file.seek(SECTOR_BYTES + (x + z * 32) * 4); file.writeInt(value); }
private void setOffset(int x, int z, int offset) throws IOException { offsets[x + z * 32] = offset; file.seek((x + z * 32) * 4); file.writeInt(offset); }
/* write a chunk at (x,z) with length bytes of data to disk */ protected synchronized void write(int x, int z, byte[] data, int length) { try { int offset = getOffset(x, z); int sectorNumber = offset >> 8; int sectorsAllocated = offset & 0xFF; int sectorsNeeded = (length + CHUNK_HEADER_SIZE) / SECTOR_BYTES + 1; // maximum chunk size is 1MB if (sectorsNeeded >= 256) { return; } if (sectorNumber != 0 && sectorsAllocated == sectorsNeeded) { /* we can simply overwrite the old sectors */ debug("SAVE", x, z, length, "rewrite"); write(sectorNumber, data, length); } else { /* we need to allocate new sectors */ /* mark the sectors previously used for this chunk as free */ for (int i = 0; i < sectorsAllocated; ++i) { sectorFree.set(sectorNumber + i, true); } /* scan for a free space large enough to store this chunk */ int runStart = sectorFree.indexOf(true); int runLength = 0; if (runStart != -1) { for (int i = runStart; i < sectorFree.size(); ++i) { if (runLength != 0) { if (sectorFree.get(i)) runLength++; else runLength = 0; } else if (sectorFree.get(i)) { runStart = i; runLength = 1; } if (runLength >= sectorsNeeded) { break; } } } if (runLength >= sectorsNeeded) { /* we found a free space large enough */ debug("SAVE", x, z, length, "reuse"); sectorNumber = runStart; setOffset(x, z, (sectorNumber << 8) | sectorsNeeded); for (int i = 0; i < sectorsNeeded; ++i) { sectorFree.set(sectorNumber + i, false); } write(sectorNumber, data, length); } else { /* * no free space large enough found -- we need to grow the * file */ debug("SAVE", x, z, length, "grow"); file.seek(file.length()); sectorNumber = sectorFree.size(); for (int i = 0; i < sectorsNeeded; ++i) { file.write(emptySector); sectorFree.add(false); } sizeDelta += SECTOR_BYTES * sectorsNeeded; write(sectorNumber, data, length); setOffset(x, z, (sectorNumber << 8) | sectorsNeeded); } } setTimestamp(x, z, (int) (System.currentTimeMillis() / 1000L)); } catch (IOException e) { e.printStackTrace(); } }