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