diff --git a/binding/java/src/main/java/org/lionsoul/ip2region/xdb/Searcher.java b/binding/java/src/main/java/org/lionsoul/ip2region/xdb/Searcher.java index f7ce54f..6152cdd 100644 --- a/binding/java/src/main/java/org/lionsoul/ip2region/xdb/Searcher.java +++ b/binding/java/src/main/java/org/lionsoul/ip2region/xdb/Searcher.java @@ -11,6 +11,7 @@ import java.io.File; // @Date 2022/06/23 import java.io.IOException; +import java.io.InputStream; import java.io.RandomAccessFile; public class Searcher { @@ -195,7 +196,9 @@ public class Searcher { ); } + // --- // --- static util function + // --- read xdb header public static Header loadHeader(RandomAccessFile handle) throws IOException { handle.seek(0); @@ -215,6 +218,12 @@ public class Searcher { return loadHeaderFromFile(new File(xdbPath)); } + public static Header loadHeaderFromBuffer(LongByteArray cBuffer) throws IOException { + return new Header(cBuffer.slice(0, HeaderInfoLength)); + } + + // --- read xdb vector index + public static byte[] loadVectorIndex(RandomAccessFile handle) throws IOException { handle.seek(HeaderInfoLength); int len = VectorIndexRows * VectorIndexCols * VectorIndexSize; @@ -238,6 +247,13 @@ public class Searcher { return loadVectorIndexFromFile(new File(xdbPath)); } + public static byte[] loadVectorIndexFromBuffer(LongByteArray cBuffer) throws IOException { + final int len = VectorIndexRows * VectorIndexCols * VectorIndexSize; + return cBuffer.slice(HeaderInfoLength, len); + } + + // --- read xdb content + public static LongByteArray loadContent(RandomAccessFile handle) throws IOException { handle.seek(0); // check the length and do the buff load @@ -268,6 +284,45 @@ public class Searcher { return loadContentFromFile(new File(xdbPath)); } + public static LongByteArray loadContentFromInputStream(InputStream is) throws IOException { + final LongByteArray byteArray = new LongByteArray(); + while (true) { + boolean done = false; + + // read at most MAX_WRITE_BYTES bytes + int rLen, tBytes = 0; + final byte[] buff = new byte[MAX_WRITE_BYTES]; + while (true) { + rLen = is.read(buff, tBytes, buff.length - tBytes); + if (rLen == -1) { + // reach the end of the stream + done = true; + break; + } else if (rLen == 0) { + // the entire buff was filled + break; + } + + tBytes += rLen; + } + + // check and copy the buffer with its actual filled bytes + if (tBytes == buff.length) { + byteArray.append(buff); + } else { + final byte[] nBuff = new byte[tBytes]; + System.arraycopy(buff, 0, nBuff, 0, tBytes); + byteArray.append(nBuff); + } + + if (done) { + break; + } + } + + return byteArray; + } + // --- verify util function // Verify if the current Searcher could be used to search the specified xdb file. @@ -276,9 +331,7 @@ public class Searcher { // // @Note: You Just need to check this ONCE when the service starts // Or use another process (eg, A command) to check once Just to confirm the suitability. - public static void verify(RandomAccessFile handle) throws IOException, XdbException { - final Header header = loadHeader(handle); - + public static void verify(Header header, long fileBytes) throws IOException, XdbException { // get the runtime ptr bytes int runtimePtrBytes = 0; if (header.version == STRUCTURE_20) { @@ -292,11 +345,15 @@ public class Searcher { // 1, confirm the xdb file size // to ensure that the maximum file pointer does not overflow final long maxFilePtr = (1L << (runtimePtrBytes * 8)) - 1; - if (handle.length() > maxFilePtr) { + if (fileBytes > maxFilePtr) { throw new XdbException("xdb file exceeds the maximum supported bytes: "+maxFilePtr+""); } } + public static void verify(RandomAccessFile handle) throws IOException, XdbException { + verify(loadHeader(handle), handle.length()); + } + public static void verifyFromFile(File xdbFile) throws IOException, XdbException { final RandomAccessFile handle = new RandomAccessFile(xdbFile, "r"); verify(handle);