1b5840353SAdam Hornáček /* 2b5840353SAdam Hornáček * CDDL HEADER START 3b5840353SAdam Hornáček * 4b5840353SAdam Hornáček * The contents of this file are subject to the terms of the 5b5840353SAdam Hornáček * Common Development and Distribution License (the "License"). 6b5840353SAdam Hornáček * You may not use this file except in compliance with the License. 7b5840353SAdam Hornáček * 8b5840353SAdam Hornáček * See LICENSE.txt included in this distribution for the specific 9b5840353SAdam Hornáček * language governing permissions and limitations under the License. 10b5840353SAdam Hornáček * 11b5840353SAdam Hornáček * When distributing Covered Code, include this CDDL HEADER in each 12b5840353SAdam Hornáček * file and include the License file at LICENSE.txt. 13b5840353SAdam Hornáček * If applicable, add the following below this CDDL HEADER, with the 14b5840353SAdam Hornáček * fields enclosed by brackets "[]" replaced with your own identifying 15b5840353SAdam Hornáček * information: Portions Copyright [yyyy] [name of copyright owner] 16b5840353SAdam Hornáček * 17b5840353SAdam Hornáček * CDDL HEADER END 18b5840353SAdam Hornáček */ 19b5840353SAdam Hornáček 20b5840353SAdam Hornáček /* 2152d10766SAdam Hornacek * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. 22*750b3115SChris Fraire * Portions Copyright (c) 2018, 2021, Chris Fraire <cfraire@me.com>. 23b5840353SAdam Hornáček */ 249805b761SAdam Hornáček package org.opengrok.indexer.util; 25b5840353SAdam Hornáček 26a8758e23SChris Fraire import org.opengrok.indexer.analysis.CtagsReader; 27a8758e23SChris Fraire import org.opengrok.indexer.analysis.Definitions; 28a8758e23SChris Fraire import org.opengrok.indexer.analysis.StreamSource; 29b5840353SAdam Hornáček import java.io.BufferedInputStream; 30b5840353SAdam Hornáček import java.io.BufferedReader; 31b5840353SAdam Hornáček import java.io.ByteArrayOutputStream; 32b5840353SAdam Hornáček import java.io.IOException; 33b5840353SAdam Hornáček import java.io.InputStream; 34b5840353SAdam Hornáček import java.io.InputStreamReader; 35a8758e23SChris Fraire import java.io.Reader; 36a8758e23SChris Fraire import java.nio.charset.StandardCharsets; 37787af926SChris Fraire import java.util.ArrayList; 38787af926SChris Fraire import java.util.List; 39a8758e23SChris Fraire 4052d10766SAdam Hornacek import static org.junit.jupiter.api.Assertions.assertNotNull; 41b5840353SAdam Hornáček 42b5840353SAdam Hornáček /** 431161d3e8SAdam Hornacek * Represents a container for stream utility methods. 44b5840353SAdam Hornáček */ 45b5840353SAdam Hornáček public class StreamUtils { 46b5840353SAdam Hornáček /** 47b5840353SAdam Hornáček * Read a stream fully to an in-memory byte array. 48b5840353SAdam Hornáček * @param iss a defined stream at the chosen starting position 49b5840353SAdam Hornáček * @return a defined instance 50b5840353SAdam Hornáček * @throws IOException if I/O fails 51b5840353SAdam Hornáček */ copyStream(InputStream iss)52b5840353SAdam Hornáček public static byte[] copyStream(InputStream iss) throws IOException { 53b5840353SAdam Hornáček 54b5840353SAdam Hornáček ByteArrayOutputStream baosExp = new ByteArrayOutputStream(); 55b5840353SAdam Hornáček byte[] buffer = new byte[8192]; 56b5840353SAdam Hornáček int read; 57b5840353SAdam Hornáček do { 58b5840353SAdam Hornáček read = iss.read(buffer, 0, buffer.length); 59b5840353SAdam Hornáček if (read > 0) { 60b5840353SAdam Hornáček baosExp.write(buffer, 0, read); 61b5840353SAdam Hornáček } 62b5840353SAdam Hornáček } while (read >= 0); 63b5840353SAdam Hornáček 64b5840353SAdam Hornáček baosExp.close(); 65b5840353SAdam Hornáček return baosExp.toByteArray(); 66b5840353SAdam Hornáček } 67b5840353SAdam Hornáček 68a8758e23SChris Fraire /** 69a8758e23SChris Fraire * Read all bytes from the specified reader. 70a8758e23SChris Fraire * @param in a required instance 71a8758e23SChris Fraire * @return a defined instance 72a8758e23SChris Fraire * @throws IOException thrown if I/O error occurs while reading 73a8758e23SChris Fraire */ readToEnd(Reader in)74a8758e23SChris Fraire public static String readToEnd(Reader in) throws IOException { 75a8758e23SChris Fraire 76a8758e23SChris Fraire StringBuilder result = new StringBuilder(); 77a8758e23SChris Fraire char[] buf = new char[8 * 1024]; 78a8758e23SChris Fraire int charsRead; 79a8758e23SChris Fraire while ((charsRead = in.read(buf, 0, buf.length)) != -1) { 80a8758e23SChris Fraire result.append(buf, 0, charsRead); 81a8758e23SChris Fraire } 82a8758e23SChris Fraire 83a8758e23SChris Fraire return result.toString(); 84a8758e23SChris Fraire } 85a8758e23SChris Fraire readTagsFromResource(String resourceName)86a8758e23SChris Fraire public static Definitions readTagsFromResource(String resourceName) 87b5840353SAdam Hornáček throws IOException { 88a8758e23SChris Fraire return readTagsFromResource(resourceName, null); 89b5840353SAdam Hornáček } 90b5840353SAdam Hornáček readTagsFromResource(String tagsResourceName, String rawResourceName)91b5840353SAdam Hornáček public static Definitions readTagsFromResource(String tagsResourceName, 92b5840353SAdam Hornáček String rawResourceName) throws IOException { 93b5840353SAdam Hornáček return readTagsFromResource(tagsResourceName, rawResourceName, 0); 94b5840353SAdam Hornáček } 95b5840353SAdam Hornáček readTagsFromResource(String tagsResourceName, String rawResourceName, int tabSize)96b5840353SAdam Hornáček public static Definitions readTagsFromResource(String tagsResourceName, 97b5840353SAdam Hornáček String rawResourceName, int tabSize) throws IOException { 98b5840353SAdam Hornáček 99b5840353SAdam Hornáček InputStream res = StreamUtils.class.getClassLoader(). 100b5840353SAdam Hornáček getResourceAsStream(tagsResourceName); 10152d10766SAdam Hornacek assertNotNull(res, tagsResourceName + " as resource"); 102b5840353SAdam Hornáček 103b5840353SAdam Hornáček BufferedReader in = new BufferedReader(new InputStreamReader( 104a8758e23SChris Fraire res, StandardCharsets.UTF_8)); 105b5840353SAdam Hornáček 106b5840353SAdam Hornáček CtagsReader rdr = new CtagsReader(); 107b5840353SAdam Hornáček rdr.setTabSize(tabSize); 108b5840353SAdam Hornáček if (rawResourceName != null) { 109b5840353SAdam Hornáček rdr.setSplitterSupplier(() -> { 110a8758e23SChris Fraire /* 111b5840353SAdam Hornáček * This should return truly raw content, as the CtagsReader will 112b5840353SAdam Hornáček * expand tabs according to its setting. 113b5840353SAdam Hornáček */ 114b5840353SAdam Hornáček SourceSplitter splitter = new SourceSplitter(); 115b5840353SAdam Hornáček StreamSource src = sourceFromEmbedded(rawResourceName); 116b5840353SAdam Hornáček try { 117b5840353SAdam Hornáček splitter.reset(src); 118b5840353SAdam Hornáček } catch (IOException ex) { 119b5840353SAdam Hornáček System.err.println(ex.toString()); 120b5840353SAdam Hornáček return null; 121b5840353SAdam Hornáček } 122b5840353SAdam Hornáček return splitter; 123b5840353SAdam Hornáček }); 124b5840353SAdam Hornáček } 125b5840353SAdam Hornáček 126b5840353SAdam Hornáček String line; 127b5840353SAdam Hornáček while ((line = in.readLine()) != null) { 128b5840353SAdam Hornáček rdr.readLine(line); 129b5840353SAdam Hornáček } 130b5840353SAdam Hornáček return rdr.getDefinitions(); 131b5840353SAdam Hornáček } 132b5840353SAdam Hornáček 133b5840353SAdam Hornáček /** 134a8758e23SChris Fraire * Gets a {@link Reader} from a specified resource name or raises an 135a8758e23SChris Fraire * assertion error if no defined stream is available. 136a8758e23SChris Fraire * @param resourceName a required name 137a8758e23SChris Fraire * @return a defined instance 138a8758e23SChris Fraire * @throws IOException thrown on I/O error 139a8758e23SChris Fraire */ readerFromResource(String resourceName)140a8758e23SChris Fraire public static Reader readerFromResource(String resourceName) 141a8758e23SChris Fraire throws IOException { 142a8758e23SChris Fraire 143a8758e23SChris Fraire InputStream res = StreamUtils.class.getClassLoader(). 144a8758e23SChris Fraire getResourceAsStream(resourceName); 14552d10766SAdam Hornacek assertNotNull(res, resourceName + " should be gettable"); 146*750b3115SChris Fraire return IOUtils.createBOMStrippedReader(res, StandardCharsets.UTF_8.name()); 147a8758e23SChris Fraire } 148a8758e23SChris Fraire 149a8758e23SChris Fraire /** 150b5840353SAdam Hornáček * Creates a {@code StreamSource} instance that reads data from an 151b5840353SAdam Hornáček * embedded resource. 152b5840353SAdam Hornáček * @param resourceName a required resource name 153b5840353SAdam Hornáček * @return a stream source that reads from {@code name} 154b5840353SAdam Hornáček */ sourceFromEmbedded(String resourceName)155b5840353SAdam Hornáček public static StreamSource sourceFromEmbedded(String resourceName) { 156b5840353SAdam Hornáček return new StreamSource() { 157b5840353SAdam Hornáček @Override 158a8758e23SChris Fraire public InputStream getStream() { 159b5840353SAdam Hornáček InputStream res = StreamUtils.class.getClassLoader(). 160b5840353SAdam Hornáček getResourceAsStream(resourceName); 16152d10766SAdam Hornacek assertNotNull(res, "resource " + resourceName); 162b5840353SAdam Hornáček return new BufferedInputStream(res); 163b5840353SAdam Hornáček } 164b5840353SAdam Hornáček }; 165b5840353SAdam Hornáček } 166b5840353SAdam Hornáček 167787af926SChris Fraire /** 168787af926SChris Fraire * Parses symbols, one per line (trimmed), from a resource stream, but 169787af926SChris Fraire * recognizing a hash character {@code '#'} as starting a line comment that 170787af926SChris Fraire * is not included in a symbol. 171787af926SChris Fraire * @return a defined instance 172787af926SChris Fraire */ 173787af926SChris Fraire public static List<String> readSampleSymbols(InputStream symbolsResource) throws IOException { 174787af926SChris Fraire List<String> result = new ArrayList<>(); 175787af926SChris Fraire try (BufferedReader rdr = new BufferedReader(new InputStreamReader(symbolsResource, 176787af926SChris Fraire StandardCharsets.UTF_8))) { 177787af926SChris Fraire String line; 178787af926SChris Fraire while ((line = rdr.readLine()) != null) { 179787af926SChris Fraire int hashOffset = line.indexOf('#'); 180787af926SChris Fraire if (hashOffset != -1) { 181787af926SChris Fraire line = line.substring(0, hashOffset); 182787af926SChris Fraire } 183787af926SChris Fraire result.add(line.trim()); 184787af926SChris Fraire } 185787af926SChris Fraire } 186787af926SChris Fraire return result; 187787af926SChris Fraire } 188787af926SChris Fraire 1891161d3e8SAdam Hornacek // private to enforce static 190b5840353SAdam Hornáček private StreamUtils() { 191b5840353SAdam Hornáček } 192b5840353SAdam Hornáček } 193