1*f9742813SAndroid Build Coastguard WorkerRecipes 2*f9742813SAndroid Build Coastguard Worker======= 3*f9742813SAndroid Build Coastguard Worker 4*f9742813SAndroid Build Coastguard WorkerWe've written some recipes that demonstrate how to solve common problems with Okio. Read through 5*f9742813SAndroid Build Coastguard Workerthem to learn about how everything works together. Cut-and-paste these examples freely; that's what 6*f9742813SAndroid Build Coastguard Workerthey're for. 7*f9742813SAndroid Build Coastguard Worker 8*f9742813SAndroid Build Coastguard WorkerThese recipes work on all platforms: Java, Android, Kotlin/Native, and Kotlin/JS. See 9*f9742813SAndroid Build Coastguard Worker[java.io Recipes](java_io_recipes.md) for samples that integrate Java APIs. 10*f9742813SAndroid Build Coastguard Worker 11*f9742813SAndroid Build Coastguard Worker 12*f9742813SAndroid Build Coastguard WorkerRead a text file line-by-line ([Java][ReadFileLineByLine]/[Kotlin][ReadFileLineByLineKt]) 13*f9742813SAndroid Build Coastguard Worker----------------------------------------------------------------------------------------- 14*f9742813SAndroid Build Coastguard Worker 15*f9742813SAndroid Build Coastguard WorkerUse `FileSystem.source(Path)` to open a source stream to read a file. The returned `Source` 16*f9742813SAndroid Build Coastguard Workerinterface is very small and has limited uses. Instead we wrap the source with a buffer. This has two 17*f9742813SAndroid Build Coastguard Workerbenefits: 18*f9742813SAndroid Build Coastguard Worker 19*f9742813SAndroid Build Coastguard Worker * **It makes the API more powerful.** Instead of the basic methods offered by `Source`, 20*f9742813SAndroid Build Coastguard Worker `BufferedSource` has dozens of methods to address most common problems concisely. 21*f9742813SAndroid Build Coastguard Worker 22*f9742813SAndroid Build Coastguard Worker * **It makes your program run faster.** Buffering allows Okio to get more done with fewer I/O 23*f9742813SAndroid Build Coastguard Worker operations. 24*f9742813SAndroid Build Coastguard Worker 25*f9742813SAndroid Build Coastguard WorkerEach `Source` that is opened needs to be closed. The code that opens the stream is responsible for 26*f9742813SAndroid Build Coastguard Workermaking sure it is closed. 27*f9742813SAndroid Build Coastguard Worker 28*f9742813SAndroid Build Coastguard Worker=== "Java" 29*f9742813SAndroid Build Coastguard Worker 30*f9742813SAndroid Build Coastguard Worker Here we use Java's `try` blocks to close our sources automatically. 31*f9742813SAndroid Build Coastguard Worker 32*f9742813SAndroid Build Coastguard Worker ```java 33*f9742813SAndroid Build Coastguard Worker public void readLines(Path path) throws IOException { 34*f9742813SAndroid Build Coastguard Worker try (Source fileSource = FileSystem.SYSTEM.source(path); 35*f9742813SAndroid Build Coastguard Worker BufferedSource bufferedFileSource = Okio.buffer(fileSource)) { 36*f9742813SAndroid Build Coastguard Worker 37*f9742813SAndroid Build Coastguard Worker while (true) { 38*f9742813SAndroid Build Coastguard Worker String line = bufferedFileSource.readUtf8Line(); 39*f9742813SAndroid Build Coastguard Worker if (line == null) break; 40*f9742813SAndroid Build Coastguard Worker 41*f9742813SAndroid Build Coastguard Worker if (line.contains("square")) { 42*f9742813SAndroid Build Coastguard Worker System.out.println(line); 43*f9742813SAndroid Build Coastguard Worker } 44*f9742813SAndroid Build Coastguard Worker } 45*f9742813SAndroid Build Coastguard Worker 46*f9742813SAndroid Build Coastguard Worker } 47*f9742813SAndroid Build Coastguard Worker } 48*f9742813SAndroid Build Coastguard Worker ``` 49*f9742813SAndroid Build Coastguard Worker 50*f9742813SAndroid Build Coastguard Worker=== "Kotlin" 51*f9742813SAndroid Build Coastguard Worker 52*f9742813SAndroid Build Coastguard Worker This uses `use` to automatically close the streams. This prevents resource leaks, even if an 53*f9742813SAndroid Build Coastguard Worker exception is thrown. 54*f9742813SAndroid Build Coastguard Worker 55*f9742813SAndroid Build Coastguard Worker ```kotlin 56*f9742813SAndroid Build Coastguard Worker fun readLines(path: Path) { 57*f9742813SAndroid Build Coastguard Worker FileSystem.SYSTEM.source(path).use { fileSource -> 58*f9742813SAndroid Build Coastguard Worker fileSource.buffer().use { bufferedFileSource -> 59*f9742813SAndroid Build Coastguard Worker while (true) { 60*f9742813SAndroid Build Coastguard Worker val line = bufferedFileSource.readUtf8Line() ?: break 61*f9742813SAndroid Build Coastguard Worker if ("square" in line) { 62*f9742813SAndroid Build Coastguard Worker println(line) 63*f9742813SAndroid Build Coastguard Worker } 64*f9742813SAndroid Build Coastguard Worker } 65*f9742813SAndroid Build Coastguard Worker } 66*f9742813SAndroid Build Coastguard Worker } 67*f9742813SAndroid Build Coastguard Worker } 68*f9742813SAndroid Build Coastguard Worker ``` 69*f9742813SAndroid Build Coastguard Worker 70*f9742813SAndroid Build Coastguard Worker 71*f9742813SAndroid Build Coastguard WorkerThe `readUtf8Line()` API reads all of the data until the next line delimiter – either `\n`, `\r\n`, 72*f9742813SAndroid Build Coastguard Workeror the end of the file. It returns that data as a string, omitting the delimiter at the end. When it 73*f9742813SAndroid Build Coastguard Workerencounters empty lines the method will return an empty string. If there isn’t any more data to read 74*f9742813SAndroid Build Coastguard Workerit will return null. 75*f9742813SAndroid Build Coastguard Worker 76*f9742813SAndroid Build Coastguard Worker 77*f9742813SAndroid Build Coastguard Worker=== "Java" 78*f9742813SAndroid Build Coastguard Worker 79*f9742813SAndroid Build Coastguard Worker The above Java program can be written more compactly by inlining the `fileSource` variable and 80*f9742813SAndroid Build Coastguard Worker by using a fancy `for` loop instead of a `while`: 81*f9742813SAndroid Build Coastguard Worker 82*f9742813SAndroid Build Coastguard Worker ```java 83*f9742813SAndroid Build Coastguard Worker public void readLines(Path path) throws IOException { 84*f9742813SAndroid Build Coastguard Worker try (BufferedSource source = Okio.buffer(FileSystem.SYSTEM.source(path))) { 85*f9742813SAndroid Build Coastguard Worker for (String line; (line = source.readUtf8Line()) != null; ) { 86*f9742813SAndroid Build Coastguard Worker if (line.contains("square")) { 87*f9742813SAndroid Build Coastguard Worker System.out.println(line); 88*f9742813SAndroid Build Coastguard Worker } 89*f9742813SAndroid Build Coastguard Worker } 90*f9742813SAndroid Build Coastguard Worker } 91*f9742813SAndroid Build Coastguard Worker } 92*f9742813SAndroid Build Coastguard Worker ``` 93*f9742813SAndroid Build Coastguard Worker 94*f9742813SAndroid Build Coastguard Worker=== "Kotlin" 95*f9742813SAndroid Build Coastguard Worker 96*f9742813SAndroid Build Coastguard Worker In Kotlin, we can use `FileSystem.read()` to buffer the source before our block and close the 97*f9742813SAndroid Build Coastguard Worker source afterwards. In the body of the block, `this` is a `BufferedSource`. 98*f9742813SAndroid Build Coastguard Worker 99*f9742813SAndroid Build Coastguard Worker ```kotlin 100*f9742813SAndroid Build Coastguard Worker @Throws(IOException::class) 101*f9742813SAndroid Build Coastguard Worker fun readLines(path: Path) { 102*f9742813SAndroid Build Coastguard Worker FileSystem.SYSTEM.read(path) { 103*f9742813SAndroid Build Coastguard Worker while (true) { 104*f9742813SAndroid Build Coastguard Worker val line = readUtf8Line() ?: break 105*f9742813SAndroid Build Coastguard Worker if ("square" in line) { 106*f9742813SAndroid Build Coastguard Worker println(line) 107*f9742813SAndroid Build Coastguard Worker } 108*f9742813SAndroid Build Coastguard Worker } 109*f9742813SAndroid Build Coastguard Worker } 110*f9742813SAndroid Build Coastguard Worker } 111*f9742813SAndroid Build Coastguard Worker ``` 112*f9742813SAndroid Build Coastguard Worker 113*f9742813SAndroid Build Coastguard WorkerThe `readUtf8Line()` method is suitable for parsing most files. For certain use-cases you may also 114*f9742813SAndroid Build Coastguard Workerconsider `readUtf8LineStrict()`. It is similar but it requires that each line is terminated by `\n` 115*f9742813SAndroid Build Coastguard Workeror `\r\n`. If it encounters the end of the file before that it will throw an `EOFException`. The 116*f9742813SAndroid Build Coastguard Workerstrict variant also permits a byte limit to defend against malformed input. 117*f9742813SAndroid Build Coastguard Worker 118*f9742813SAndroid Build Coastguard Worker=== "Java" 119*f9742813SAndroid Build Coastguard Worker 120*f9742813SAndroid Build Coastguard Worker ```java 121*f9742813SAndroid Build Coastguard Worker public void readLines(Path path) throws IOException { 122*f9742813SAndroid Build Coastguard Worker try (BufferedSource source = Okio.buffer(FileSystem.SYSTEM.source(path))) { 123*f9742813SAndroid Build Coastguard Worker while (!source.exhausted()) { 124*f9742813SAndroid Build Coastguard Worker String line = source.readUtf8LineStrict(1024L); 125*f9742813SAndroid Build Coastguard Worker if (line.contains("square")) { 126*f9742813SAndroid Build Coastguard Worker System.out.println(line); 127*f9742813SAndroid Build Coastguard Worker } 128*f9742813SAndroid Build Coastguard Worker } 129*f9742813SAndroid Build Coastguard Worker } 130*f9742813SAndroid Build Coastguard Worker } 131*f9742813SAndroid Build Coastguard Worker ``` 132*f9742813SAndroid Build Coastguard Worker 133*f9742813SAndroid Build Coastguard Worker=== "Kotlin" 134*f9742813SAndroid Build Coastguard Worker 135*f9742813SAndroid Build Coastguard Worker ```kotlin 136*f9742813SAndroid Build Coastguard Worker @Throws(IOException::class) 137*f9742813SAndroid Build Coastguard Worker fun readLines(path: Path) { 138*f9742813SAndroid Build Coastguard Worker FileSystem.SYSTEM.read(path) { 139*f9742813SAndroid Build Coastguard Worker while (!source.exhausted()) { 140*f9742813SAndroid Build Coastguard Worker val line = source.readUtf8LineStrict(1024) 141*f9742813SAndroid Build Coastguard Worker if ("square" in line) { 142*f9742813SAndroid Build Coastguard Worker println(line) 143*f9742813SAndroid Build Coastguard Worker } 144*f9742813SAndroid Build Coastguard Worker } 145*f9742813SAndroid Build Coastguard Worker } 146*f9742813SAndroid Build Coastguard Worker } 147*f9742813SAndroid Build Coastguard Worker ``` 148*f9742813SAndroid Build Coastguard Worker 149*f9742813SAndroid Build Coastguard Worker 150*f9742813SAndroid Build Coastguard WorkerWrite a text file ([Java][WriteFile]/[Kotlin][WriteFileKt]) 151*f9742813SAndroid Build Coastguard Worker----------------------------------------------------------- 152*f9742813SAndroid Build Coastguard Worker 153*f9742813SAndroid Build Coastguard WorkerAbove we used a `Source` and a `BufferedSource` to read a file. To write, we use a `Sink` and a 154*f9742813SAndroid Build Coastguard Worker`BufferedSink`. The advantages of buffering are the same: a more capable API and better performance. 155*f9742813SAndroid Build Coastguard Worker 156*f9742813SAndroid Build Coastguard Worker```java 157*f9742813SAndroid Build Coastguard Workerpublic void writeEnv(Path path) throws IOException { 158*f9742813SAndroid Build Coastguard Worker try (Sink fileSink = FileSystem.SYSTEM.sink(path); 159*f9742813SAndroid Build Coastguard Worker BufferedSink bufferedSink = Okio.buffer(fileSink)) { 160*f9742813SAndroid Build Coastguard Worker 161*f9742813SAndroid Build Coastguard Worker for (Map.Entry<String, String> entry : System.getenv().entrySet()) { 162*f9742813SAndroid Build Coastguard Worker bufferedSink.writeUtf8(entry.getKey()); 163*f9742813SAndroid Build Coastguard Worker bufferedSink.writeUtf8("="); 164*f9742813SAndroid Build Coastguard Worker bufferedSink.writeUtf8(entry.getValue()); 165*f9742813SAndroid Build Coastguard Worker bufferedSink.writeUtf8("\n"); 166*f9742813SAndroid Build Coastguard Worker } 167*f9742813SAndroid Build Coastguard Worker 168*f9742813SAndroid Build Coastguard Worker } 169*f9742813SAndroid Build Coastguard Worker} 170*f9742813SAndroid Build Coastguard Worker``` 171*f9742813SAndroid Build Coastguard Worker 172*f9742813SAndroid Build Coastguard WorkerThere isn’t an API to write a line of input; instead we manually insert our own newline character. 173*f9742813SAndroid Build Coastguard WorkerMost programs should hardcode `"\n"` as the newline character. In rare situations you may use 174*f9742813SAndroid Build Coastguard Worker`System.lineSeparator()` instead of `"\n"`: it returns `"\r\n"` on Windows and `"\n"` everywhere 175*f9742813SAndroid Build Coastguard Workerelse. 176*f9742813SAndroid Build Coastguard Worker 177*f9742813SAndroid Build Coastguard Worker=== "Java" 178*f9742813SAndroid Build Coastguard Worker 179*f9742813SAndroid Build Coastguard Worker We can write the above program more compactly by inlining the `fileSink` variable and by taking 180*f9742813SAndroid Build Coastguard Worker advantage of method chaining: 181*f9742813SAndroid Build Coastguard Worker 182*f9742813SAndroid Build Coastguard Worker ```java 183*f9742813SAndroid Build Coastguard Worker public void writeEnv(Path path) throws IOException { 184*f9742813SAndroid Build Coastguard Worker try (BufferedSink sink = Okio.buffer(FileSystem.SYSTEM.sink(path))) { 185*f9742813SAndroid Build Coastguard Worker for (Map.Entry<String, String> entry : System.getenv().entrySet()) { 186*f9742813SAndroid Build Coastguard Worker sink.writeUtf8(entry.getKey()) 187*f9742813SAndroid Build Coastguard Worker .writeUtf8("=") 188*f9742813SAndroid Build Coastguard Worker .writeUtf8(entry.getValue()) 189*f9742813SAndroid Build Coastguard Worker .writeUtf8("\n"); 190*f9742813SAndroid Build Coastguard Worker } 191*f9742813SAndroid Build Coastguard Worker } 192*f9742813SAndroid Build Coastguard Worker } 193*f9742813SAndroid Build Coastguard Worker ``` 194*f9742813SAndroid Build Coastguard Worker 195*f9742813SAndroid Build Coastguard Worker=== "Kotlin" 196*f9742813SAndroid Build Coastguard Worker 197*f9742813SAndroid Build Coastguard Worker In Kotlin, we can use `FileSystem.write()` to buffer the sink before our block and close the 198*f9742813SAndroid Build Coastguard Worker sink afterwards. In the body of the block, `this` is a `BufferedSink`. 199*f9742813SAndroid Build Coastguard Worker 200*f9742813SAndroid Build Coastguard Worker ```kotlin 201*f9742813SAndroid Build Coastguard Worker @Throws(IOException::class) 202*f9742813SAndroid Build Coastguard Worker fun writeEnv(path: Path) { 203*f9742813SAndroid Build Coastguard Worker FileSystem.SYSTEM.write(path) { 204*f9742813SAndroid Build Coastguard Worker for ((key, value) in System.getenv()) { 205*f9742813SAndroid Build Coastguard Worker writeUtf8(key) 206*f9742813SAndroid Build Coastguard Worker writeUtf8("=") 207*f9742813SAndroid Build Coastguard Worker writeUtf8(value) 208*f9742813SAndroid Build Coastguard Worker writeUtf8("\n") 209*f9742813SAndroid Build Coastguard Worker } 210*f9742813SAndroid Build Coastguard Worker } 211*f9742813SAndroid Build Coastguard Worker } 212*f9742813SAndroid Build Coastguard Worker ``` 213*f9742813SAndroid Build Coastguard Worker 214*f9742813SAndroid Build Coastguard WorkerIn the above code we make four calls to `writeUtf8()`. Making four calls is more efficient than the 215*f9742813SAndroid Build Coastguard Workercode below because the VM doesn’t have to create and garbage collect a temporary string. 216*f9742813SAndroid Build Coastguard Worker 217*f9742813SAndroid Build Coastguard Worker```java 218*f9742813SAndroid Build Coastguard Workersink.writeUtf8(entry.getKey() + "=" + entry.getValue() + "\n"); // Slower! 219*f9742813SAndroid Build Coastguard Worker``` 220*f9742813SAndroid Build Coastguard Worker 221*f9742813SAndroid Build Coastguard Worker 222*f9742813SAndroid Build Coastguard WorkerUTF-8 ([Java][ExploreCharsets]/[Kotlin][ExploreCharsetsKt]) 223*f9742813SAndroid Build Coastguard Worker----------------------------------------------------------- 224*f9742813SAndroid Build Coastguard Worker 225*f9742813SAndroid Build Coastguard WorkerIn the above APIs you can see that Okio really likes UTF-8. Early computer systems suffered many 226*f9742813SAndroid Build Coastguard Workerincompatible character encodings: ISO-8859-1, ShiftJIS, ASCII, EBCDIC, etc. Writing software to 227*f9742813SAndroid Build Coastguard Workersupport multiple character sets was awful and we didn’t even have emoji! Today we're lucky that the 228*f9742813SAndroid Build Coastguard Workerworld has standardized on UTF-8 everywhere, with some rare uses of other charsets in legacy systems. 229*f9742813SAndroid Build Coastguard Worker 230*f9742813SAndroid Build Coastguard WorkerIf you need another character set, `readString()` and `writeString()` are there for you. These 231*f9742813SAndroid Build Coastguard Worker methods require that you specify a character set. Otherwise you may accidentally create data that 232*f9742813SAndroid Build Coastguard Worker is only readable by the local computer. Most programs should use the UTF-8 methods only. 233*f9742813SAndroid Build Coastguard Worker 234*f9742813SAndroid Build Coastguard WorkerWhen encoding strings you need to be mindful of the different ways that strings are represented and 235*f9742813SAndroid Build Coastguard Workerencoded. When a glyph has an accent or another adornment it may be represented as a single complex 236*f9742813SAndroid Build Coastguard Worker code point (`é`) or as a simple code point (`e`) followed by its modifiers (`´`). When the entire 237*f9742813SAndroid Build Coastguard Worker glyph is a single code point that’s called [NFC][nfc]; when it’s multiple it’s [NFD][nfd]. 238*f9742813SAndroid Build Coastguard Worker 239*f9742813SAndroid Build Coastguard WorkerThough we use UTF-8 whenever we read or write strings in I/O, when they are in memory Java Strings 240*f9742813SAndroid Build Coastguard Workeruse an obsolete character encoding called UTF-16. It is a bad encoding because it uses a 16-bit 241*f9742813SAndroid Build Coastguard Worker`char` for most characters, but some don’t fit. In particular, most emoji use two Java chars. This 242*f9742813SAndroid Build Coastguard Workeris problematic because `String.length()` returns a surprising result: the number of UTF-16 chars and 243*f9742813SAndroid Build Coastguard Workernot the natural number of glyphs. 244*f9742813SAndroid Build Coastguard Worker 245*f9742813SAndroid Build Coastguard Worker| | Café | Café | 246*f9742813SAndroid Build Coastguard Worker| --------------------: | :---------------------------| :------------------------------| 247*f9742813SAndroid Build Coastguard Worker| Form | [NFC][nfc] | [NFD][nfd] | 248*f9742813SAndroid Build Coastguard Worker| Code Points | `c a f é ␣ ` | `c a f e ´ ␣ ` | 249*f9742813SAndroid Build Coastguard Worker| UTF-8 bytes | `43 61 66 c3a9 20 f09f8da9` | `43 61 66 65 cc81 20 f09f8da9` | 250*f9742813SAndroid Build Coastguard Worker| String.codePointCount | 6 | 7 | 251*f9742813SAndroid Build Coastguard Worker| String.length | 7 | 8 | 252*f9742813SAndroid Build Coastguard Worker| Utf8.size | 10 | 11 | 253*f9742813SAndroid Build Coastguard Worker 254*f9742813SAndroid Build Coastguard WorkerFor the most part Okio lets you ignore these problems and focus on your data. But when you need 255*f9742813SAndroid Build Coastguard Workerthem, there are convenient APIs for dealing with low-level UTF-8 strings. 256*f9742813SAndroid Build Coastguard Worker 257*f9742813SAndroid Build Coastguard WorkerUse `Utf8.size()` to count the number of bytes required to encode a string as UTF-8 without actually 258*f9742813SAndroid Build Coastguard Workerencoding it. This is handy in length-prefixed encodings like protocol buffers. 259*f9742813SAndroid Build Coastguard Worker 260*f9742813SAndroid Build Coastguard WorkerUse `BufferedSource.readUtf8CodePoint()` to read a single variable-length code point, and 261*f9742813SAndroid Build Coastguard Worker`BufferedSink.writeUtf8CodePoint()` to write one. 262*f9742813SAndroid Build Coastguard Worker 263*f9742813SAndroid Build Coastguard Worker 264*f9742813SAndroid Build Coastguard Worker=== "Java" 265*f9742813SAndroid Build Coastguard Worker 266*f9742813SAndroid Build Coastguard Worker ```java 267*f9742813SAndroid Build Coastguard Worker public void dumpStringData(String s) throws IOException { 268*f9742813SAndroid Build Coastguard Worker System.out.println(" " + s); 269*f9742813SAndroid Build Coastguard Worker System.out.println(" String.length: " + s.length()); 270*f9742813SAndroid Build Coastguard Worker System.out.println("String.codePointCount: " + s.codePointCount(0, s.length())); 271*f9742813SAndroid Build Coastguard Worker System.out.println(" Utf8.size: " + Utf8.size(s)); 272*f9742813SAndroid Build Coastguard Worker System.out.println(" UTF-8 bytes: " + ByteString.encodeUtf8(s).hex()); 273*f9742813SAndroid Build Coastguard Worker System.out.println(); 274*f9742813SAndroid Build Coastguard Worker } 275*f9742813SAndroid Build Coastguard Worker ``` 276*f9742813SAndroid Build Coastguard Worker 277*f9742813SAndroid Build Coastguard Worker=== "Kotlin" 278*f9742813SAndroid Build Coastguard Worker 279*f9742813SAndroid Build Coastguard Worker ```kotlin 280*f9742813SAndroid Build Coastguard Worker fun dumpStringData(s: String) { 281*f9742813SAndroid Build Coastguard Worker println(" " + s) 282*f9742813SAndroid Build Coastguard Worker println(" String.length: " + s.length) 283*f9742813SAndroid Build Coastguard Worker println("String.codePointCount: " + s.codePointCount(0, s.length)) 284*f9742813SAndroid Build Coastguard Worker println(" Utf8.size: " + s.utf8Size()) 285*f9742813SAndroid Build Coastguard Worker println(" UTF-8 bytes: " + s.encodeUtf8().hex()) 286*f9742813SAndroid Build Coastguard Worker println() 287*f9742813SAndroid Build Coastguard Worker } 288*f9742813SAndroid Build Coastguard Worker ``` 289*f9742813SAndroid Build Coastguard Worker 290*f9742813SAndroid Build Coastguard WorkerGolden Values ([Java][GoldenValue]/[Kotlin][GoldenValueKt]) 291*f9742813SAndroid Build Coastguard Worker----------------------------------------------------------- 292*f9742813SAndroid Build Coastguard Worker 293*f9742813SAndroid Build Coastguard WorkerOkio likes testing. The library itself is heavily tested, and it has features that are often helpful 294*f9742813SAndroid Build Coastguard Workerwhen testing application code. One pattern we’ve found to be quite useful is “golden value” testing. 295*f9742813SAndroid Build Coastguard WorkerThe goal of such tests is to confirm that data encoded with earlier versions of a program can safely 296*f9742813SAndroid Build Coastguard Workerbe decoded by the current program. 297*f9742813SAndroid Build Coastguard Worker 298*f9742813SAndroid Build Coastguard WorkerWe’ll illustrate this by encoding a value using Java Serialization. Though we must disclaim that 299*f9742813SAndroid Build Coastguard WorkerJava Serialization is an awful encoding system and most programs should prefer other formats like 300*f9742813SAndroid Build Coastguard WorkerJSON or protobuf! In any case, here’s a method that takes an object, serializes it, and returns the 301*f9742813SAndroid Build Coastguard Workerresult as a `ByteString`: 302*f9742813SAndroid Build Coastguard Worker 303*f9742813SAndroid Build Coastguard Worker=== "Java" 304*f9742813SAndroid Build Coastguard Worker 305*f9742813SAndroid Build Coastguard Worker ```Java 306*f9742813SAndroid Build Coastguard Worker private ByteString serialize(Object o) throws IOException { 307*f9742813SAndroid Build Coastguard Worker Buffer buffer = new Buffer(); 308*f9742813SAndroid Build Coastguard Worker try (ObjectOutputStream objectOut = new ObjectOutputStream(buffer.outputStream())) { 309*f9742813SAndroid Build Coastguard Worker objectOut.writeObject(o); 310*f9742813SAndroid Build Coastguard Worker } 311*f9742813SAndroid Build Coastguard Worker return buffer.readByteString(); 312*f9742813SAndroid Build Coastguard Worker } 313*f9742813SAndroid Build Coastguard Worker ``` 314*f9742813SAndroid Build Coastguard Worker 315*f9742813SAndroid Build Coastguard Worker=== "Kotlin" 316*f9742813SAndroid Build Coastguard Worker 317*f9742813SAndroid Build Coastguard Worker ```Kotlin 318*f9742813SAndroid Build Coastguard Worker @Throws(IOException::class) 319*f9742813SAndroid Build Coastguard Worker private fun serialize(o: Any?): ByteString { 320*f9742813SAndroid Build Coastguard Worker val buffer = Buffer() 321*f9742813SAndroid Build Coastguard Worker ObjectOutputStream(buffer.outputStream()).use { objectOut -> 322*f9742813SAndroid Build Coastguard Worker objectOut.writeObject(o) 323*f9742813SAndroid Build Coastguard Worker } 324*f9742813SAndroid Build Coastguard Worker return buffer.readByteString() 325*f9742813SAndroid Build Coastguard Worker } 326*f9742813SAndroid Build Coastguard Worker ``` 327*f9742813SAndroid Build Coastguard Worker 328*f9742813SAndroid Build Coastguard WorkerThere’s a lot going on here. 329*f9742813SAndroid Build Coastguard Worker 330*f9742813SAndroid Build Coastguard Worker1. We create a buffer as a holding space for our serialized data. It’s a convenient replacement for 331*f9742813SAndroid Build Coastguard Worker `ByteArrayOutputStream`. 332*f9742813SAndroid Build Coastguard Worker 333*f9742813SAndroid Build Coastguard Worker2. We ask the buffer for its output stream. Writes to a buffer or its output stream always append 334*f9742813SAndroid Build Coastguard Worker data to the end of the buffer. 335*f9742813SAndroid Build Coastguard Worker 336*f9742813SAndroid Build Coastguard Worker3. We create an `ObjectOutputStream` (the encoding API for Java serialization) and write our object. 337*f9742813SAndroid Build Coastguard Worker The try block takes care of closing the stream for us. Note that closing a buffer has no effect. 338*f9742813SAndroid Build Coastguard Worker 339*f9742813SAndroid Build Coastguard Worker4. Finally we read a byte string from the buffer. The `readByteString()` method allows us to specify 340*f9742813SAndroid Build Coastguard Worker how many bytes to read; here we don’t specify a count in order to read the entire thing. Reads 341*f9742813SAndroid Build Coastguard Worker from a buffer always consume data from the front of the buffer. 342*f9742813SAndroid Build Coastguard Worker 343*f9742813SAndroid Build Coastguard WorkerWith our `serialize()` method handy we are ready to compute and print a golden value. 344*f9742813SAndroid Build Coastguard Worker 345*f9742813SAndroid Build Coastguard Worker=== "Java" 346*f9742813SAndroid Build Coastguard Worker 347*f9742813SAndroid Build Coastguard Worker ```Java 348*f9742813SAndroid Build Coastguard Worker Point point = new Point(8.0, 15.0); 349*f9742813SAndroid Build Coastguard Worker ByteString pointBytes = serialize(point); 350*f9742813SAndroid Build Coastguard Worker System.out.println(pointBytes.base64()); 351*f9742813SAndroid Build Coastguard Worker ``` 352*f9742813SAndroid Build Coastguard Worker 353*f9742813SAndroid Build Coastguard Worker=== "Kotlin" 354*f9742813SAndroid Build Coastguard Worker 355*f9742813SAndroid Build Coastguard Worker ```Kotlin 356*f9742813SAndroid Build Coastguard Worker val point = Point(8.0, 15.0) 357*f9742813SAndroid Build Coastguard Worker val pointBytes = serialize(point) 358*f9742813SAndroid Build Coastguard Worker println(pointBytes.base64()) 359*f9742813SAndroid Build Coastguard Worker ``` 360*f9742813SAndroid Build Coastguard Worker 361*f9742813SAndroid Build Coastguard WorkerWe print the `ByteString` as [base64][base64] because it’s a compact format that’s suitable for 362*f9742813SAndroid Build Coastguard Workerembedding in a test case. The program prints this: 363*f9742813SAndroid Build Coastguard Worker 364*f9742813SAndroid Build Coastguard Worker``` 365*f9742813SAndroid Build Coastguard WorkerrO0ABXNyAB5va2lvLnNhbXBsZXMuR29sZGVuVmFsdWUkUG9pbnTdUW8rMji1IwIAAkQAAXhEAAF5eHBAIAAAAAAAAEAuAAAAAAAA 366*f9742813SAndroid Build Coastguard Worker``` 367*f9742813SAndroid Build Coastguard Worker 368*f9742813SAndroid Build Coastguard WorkerThat’s our golden value! We can embed it in our test case using base64 again to convert it back into 369*f9742813SAndroid Build Coastguard Workera `ByteString`: 370*f9742813SAndroid Build Coastguard Worker 371*f9742813SAndroid Build Coastguard Worker=== "Java" 372*f9742813SAndroid Build Coastguard Worker 373*f9742813SAndroid Build Coastguard Worker ```Java 374*f9742813SAndroid Build Coastguard Worker ByteString goldenBytes = ByteString.decodeBase64("rO0ABXNyAB5va2lvLnNhbXBsZ" 375*f9742813SAndroid Build Coastguard Worker + "XMuR29sZGVuVmFsdWUkUG9pbnTdUW8rMji1IwIAAkQAAXhEAAF5eHBAIAAAAAAAAEAuA" 376*f9742813SAndroid Build Coastguard Worker + "AAAAAAA"); 377*f9742813SAndroid Build Coastguard Worker ``` 378*f9742813SAndroid Build Coastguard Worker 379*f9742813SAndroid Build Coastguard Worker=== "Kotlin" 380*f9742813SAndroid Build Coastguard Worker 381*f9742813SAndroid Build Coastguard Worker ```Kotlin 382*f9742813SAndroid Build Coastguard Worker val goldenBytes = ("rO0ABXNyACRva2lvLnNhbXBsZXMuS290bGluR29sZGVuVmFsdWUkUG9pbnRF9yaY7cJ9EwIAA" + 383*f9742813SAndroid Build Coastguard Worker "kQAAXhEAAF5eHBAIAAAAAAAAEAuAAAAAAAA").decodeBase64() 384*f9742813SAndroid Build Coastguard Worker ``` 385*f9742813SAndroid Build Coastguard Worker 386*f9742813SAndroid Build Coastguard WorkerThe next step is to deserialize the `ByteString` back into our value class. This method reverses the 387*f9742813SAndroid Build Coastguard Worker`serialize()` method above: we append a byte string to a buffer then consume it using an 388*f9742813SAndroid Build Coastguard Worker`ObjectInputStream`: 389*f9742813SAndroid Build Coastguard Worker 390*f9742813SAndroid Build Coastguard Worker=== "Java" 391*f9742813SAndroid Build Coastguard Worker 392*f9742813SAndroid Build Coastguard Worker ```Java 393*f9742813SAndroid Build Coastguard Worker private Object deserialize(ByteString byteString) throws IOException, ClassNotFoundException { 394*f9742813SAndroid Build Coastguard Worker Buffer buffer = new Buffer(); 395*f9742813SAndroid Build Coastguard Worker buffer.write(byteString); 396*f9742813SAndroid Build Coastguard Worker try (ObjectInputStream objectIn = new ObjectInputStream(buffer.inputStream())) { 397*f9742813SAndroid Build Coastguard Worker return objectIn.readObject(); 398*f9742813SAndroid Build Coastguard Worker } 399*f9742813SAndroid Build Coastguard Worker } 400*f9742813SAndroid Build Coastguard Worker ``` 401*f9742813SAndroid Build Coastguard Worker 402*f9742813SAndroid Build Coastguard Worker=== "Kotlin" 403*f9742813SAndroid Build Coastguard Worker 404*f9742813SAndroid Build Coastguard Worker ```Kotlin 405*f9742813SAndroid Build Coastguard Worker @Throws(IOException::class, ClassNotFoundException::class) 406*f9742813SAndroid Build Coastguard Worker private fun deserialize(byteString: ByteString): Any? { 407*f9742813SAndroid Build Coastguard Worker val buffer = Buffer() 408*f9742813SAndroid Build Coastguard Worker buffer.write(byteString) 409*f9742813SAndroid Build Coastguard Worker ObjectInputStream(buffer.inputStream()).use { objectIn -> 410*f9742813SAndroid Build Coastguard Worker return objectIn.readObject() 411*f9742813SAndroid Build Coastguard Worker } 412*f9742813SAndroid Build Coastguard Worker } 413*f9742813SAndroid Build Coastguard Worker ``` 414*f9742813SAndroid Build Coastguard Worker 415*f9742813SAndroid Build Coastguard WorkerNow we can test the decoder against the golden value: 416*f9742813SAndroid Build Coastguard Worker 417*f9742813SAndroid Build Coastguard Worker=== "Java" 418*f9742813SAndroid Build Coastguard Worker 419*f9742813SAndroid Build Coastguard Worker ```Java 420*f9742813SAndroid Build Coastguard Worker ByteString goldenBytes = ByteString.decodeBase64("rO0ABXNyAB5va2lvLnNhbXBsZ" 421*f9742813SAndroid Build Coastguard Worker + "XMuR29sZGVuVmFsdWUkUG9pbnTdUW8rMji1IwIAAkQAAXhEAAF5eHBAIAAAAAAAAEAuA" 422*f9742813SAndroid Build Coastguard Worker + "AAAAAAA"); 423*f9742813SAndroid Build Coastguard Worker Point decoded = (Point) deserialize(goldenBytes); 424*f9742813SAndroid Build Coastguard Worker assertEquals(new Point(8.0, 15.0), decoded); 425*f9742813SAndroid Build Coastguard Worker ``` 426*f9742813SAndroid Build Coastguard Worker 427*f9742813SAndroid Build Coastguard Worker=== "Kotlin" 428*f9742813SAndroid Build Coastguard Worker 429*f9742813SAndroid Build Coastguard Worker ```Kotlin 430*f9742813SAndroid Build Coastguard Worker val goldenBytes = ("rO0ABXNyACRva2lvLnNhbXBsZXMuS290bGluR29sZGVuVmFsdWUkUG9pbnRF9yaY7cJ9EwIAA" + 431*f9742813SAndroid Build Coastguard Worker "kQAAXhEAAF5eHBAIAAAAAAAAEAuAAAAAAAA").decodeBase64()!! 432*f9742813SAndroid Build Coastguard Worker val decoded = deserialize(goldenBytes) as Point 433*f9742813SAndroid Build Coastguard Worker assertEquals(point, decoded) 434*f9742813SAndroid Build Coastguard Worker ``` 435*f9742813SAndroid Build Coastguard Worker 436*f9742813SAndroid Build Coastguard WorkerWith this test we can change the serialization of the `Point` class without 437*f9742813SAndroid Build Coastguard Workerbreaking compatibility. 438*f9742813SAndroid Build Coastguard Worker 439*f9742813SAndroid Build Coastguard Worker 440*f9742813SAndroid Build Coastguard WorkerWrite a binary file ([Java][BitmapEncoder]/[Kotlin][BitmapEncoderKt]) 441*f9742813SAndroid Build Coastguard Worker--------------------------------------------------------------------- 442*f9742813SAndroid Build Coastguard Worker 443*f9742813SAndroid Build Coastguard WorkerEncoding a binary file is not unlike encoding a text file. Okio uses the same `BufferedSink` and 444*f9742813SAndroid Build Coastguard Worker`BufferedSource` bytes for both. This is handy for binary formats that include both byte and 445*f9742813SAndroid Build Coastguard Workercharacter data. 446*f9742813SAndroid Build Coastguard Worker 447*f9742813SAndroid Build Coastguard WorkerWriting binary data is more hazardous than text because if you make a mistake it is often quite 448*f9742813SAndroid Build Coastguard Workerdifficult to diagnose. Avoid such mistakes by being careful around these traps: 449*f9742813SAndroid Build Coastguard Worker 450*f9742813SAndroid Build Coastguard Worker * **The width of each field.** This is the number of bytes used. Okio doesn't include a mechanism 451*f9742813SAndroid Build Coastguard Worker to emit partial bytes. If you need that, you’ll need to do your own bit shifting and masking 452*f9742813SAndroid Build Coastguard Worker before writing. 453*f9742813SAndroid Build Coastguard Worker 454*f9742813SAndroid Build Coastguard Worker * **The endianness of each field.** All fields that have more than one byte have _endianness_: 455*f9742813SAndroid Build Coastguard Worker whether the bytes are ordered most-significant to least (big endian) or least-significant to most 456*f9742813SAndroid Build Coastguard Worker (little endian). Okio uses the `Le` suffix for little-endian methods; methods without a suffix 457*f9742813SAndroid Build Coastguard Worker are big-endian. 458*f9742813SAndroid Build Coastguard Worker 459*f9742813SAndroid Build Coastguard Worker * **Signed vs. Unsigned.** Java doesn’t have unsigned primitive types (except for `char`!) so 460*f9742813SAndroid Build Coastguard Worker coping with this is often something that happens at the application layer. To make this a little 461*f9742813SAndroid Build Coastguard Worker easier Okio accepts `int` types for `writeByte()` and `writeShort()`. You can pass an “unsigned” 462*f9742813SAndroid Build Coastguard Worker byte like 255 and Okio will do the right thing. 463*f9742813SAndroid Build Coastguard Worker 464*f9742813SAndroid Build Coastguard Worker| Method | Width | Endianness | Value | Encoded Value | 465*f9742813SAndroid Build Coastguard Worker| :----------- | ----: | :--------- | --------------: | :------------------------ | 466*f9742813SAndroid Build Coastguard Worker| writeByte | 1 | | 3 | `03` | 467*f9742813SAndroid Build Coastguard Worker| writeShort | 2 | big | 3 | `00 03` | 468*f9742813SAndroid Build Coastguard Worker| writeInt | 4 | big | 3 | `00 00 00 03` | 469*f9742813SAndroid Build Coastguard Worker| writeLong | 8 | big | 3 | `00 00 00 00 00 00 00 03` | 470*f9742813SAndroid Build Coastguard Worker| writeShortLe | 2 | little | 3 | `03 00` | 471*f9742813SAndroid Build Coastguard Worker| writeIntLe | 4 | little | 3 | `03 00 00 00` | 472*f9742813SAndroid Build Coastguard Worker| writeLongLe | 8 | little | 3 | `03 00 00 00 00 00 00 00` | 473*f9742813SAndroid Build Coastguard Worker| writeByte | 1 | | Byte.MAX_VALUE | `7f` | 474*f9742813SAndroid Build Coastguard Worker| writeShort | 2 | big | Short.MAX_VALUE | `7f ff` | 475*f9742813SAndroid Build Coastguard Worker| writeInt | 4 | big | Int.MAX_VALUE | `7f ff ff ff` | 476*f9742813SAndroid Build Coastguard Worker| writeLong | 8 | big | Long.MAX_VALUE | `7f ff ff ff ff ff ff ff` | 477*f9742813SAndroid Build Coastguard Worker| writeShortLe | 2 | little | Short.MAX_VALUE | `ff 7f` | 478*f9742813SAndroid Build Coastguard Worker| writeIntLe | 4 | little | Int.MAX_VALUE | `ff ff ff 7f` | 479*f9742813SAndroid Build Coastguard Worker| writeLongLe | 8 | little | Long.MAX_VALUE | `ff ff ff ff ff ff ff 7f` | 480*f9742813SAndroid Build Coastguard Worker 481*f9742813SAndroid Build Coastguard WorkerThis code encodes a bitmap following the [BMP file format][bmp]. 482*f9742813SAndroid Build Coastguard Worker 483*f9742813SAndroid Build Coastguard Worker=== "Java" 484*f9742813SAndroid Build Coastguard Worker 485*f9742813SAndroid Build Coastguard Worker ```Java 486*f9742813SAndroid Build Coastguard Worker void encode(Bitmap bitmap, BufferedSink sink) throws IOException { 487*f9742813SAndroid Build Coastguard Worker int height = bitmap.height(); 488*f9742813SAndroid Build Coastguard Worker int width = bitmap.width(); 489*f9742813SAndroid Build Coastguard Worker 490*f9742813SAndroid Build Coastguard Worker int bytesPerPixel = 3; 491*f9742813SAndroid Build Coastguard Worker int rowByteCountWithoutPadding = (bytesPerPixel * width); 492*f9742813SAndroid Build Coastguard Worker int rowByteCount = ((rowByteCountWithoutPadding + 3) / 4) * 4; 493*f9742813SAndroid Build Coastguard Worker int pixelDataSize = rowByteCount * height; 494*f9742813SAndroid Build Coastguard Worker int bmpHeaderSize = 14; 495*f9742813SAndroid Build Coastguard Worker int dibHeaderSize = 40; 496*f9742813SAndroid Build Coastguard Worker 497*f9742813SAndroid Build Coastguard Worker // BMP Header 498*f9742813SAndroid Build Coastguard Worker sink.writeUtf8("BM"); // ID. 499*f9742813SAndroid Build Coastguard Worker sink.writeIntLe(bmpHeaderSize + dibHeaderSize + pixelDataSize); // File size. 500*f9742813SAndroid Build Coastguard Worker sink.writeShortLe(0); // Unused. 501*f9742813SAndroid Build Coastguard Worker sink.writeShortLe(0); // Unused. 502*f9742813SAndroid Build Coastguard Worker sink.writeIntLe(bmpHeaderSize + dibHeaderSize); // Offset of pixel data. 503*f9742813SAndroid Build Coastguard Worker 504*f9742813SAndroid Build Coastguard Worker // DIB Header 505*f9742813SAndroid Build Coastguard Worker sink.writeIntLe(dibHeaderSize); 506*f9742813SAndroid Build Coastguard Worker sink.writeIntLe(width); 507*f9742813SAndroid Build Coastguard Worker sink.writeIntLe(height); 508*f9742813SAndroid Build Coastguard Worker sink.writeShortLe(1); // Color plane count. 509*f9742813SAndroid Build Coastguard Worker sink.writeShortLe(bytesPerPixel * Byte.SIZE); 510*f9742813SAndroid Build Coastguard Worker sink.writeIntLe(0); // No compression. 511*f9742813SAndroid Build Coastguard Worker sink.writeIntLe(16); // Size of bitmap data including padding. 512*f9742813SAndroid Build Coastguard Worker sink.writeIntLe(2835); // Horizontal print resolution in pixels/meter. (72 dpi). 513*f9742813SAndroid Build Coastguard Worker sink.writeIntLe(2835); // Vertical print resolution in pixels/meter. (72 dpi). 514*f9742813SAndroid Build Coastguard Worker sink.writeIntLe(0); // Palette color count. 515*f9742813SAndroid Build Coastguard Worker sink.writeIntLe(0); // 0 important colors. 516*f9742813SAndroid Build Coastguard Worker 517*f9742813SAndroid Build Coastguard Worker // Pixel data. 518*f9742813SAndroid Build Coastguard Worker for (int y = height - 1; y >= 0; y--) { 519*f9742813SAndroid Build Coastguard Worker for (int x = 0; x < width; x++) { 520*f9742813SAndroid Build Coastguard Worker sink.writeByte(bitmap.blue(x, y)); 521*f9742813SAndroid Build Coastguard Worker sink.writeByte(bitmap.green(x, y)); 522*f9742813SAndroid Build Coastguard Worker sink.writeByte(bitmap.red(x, y)); 523*f9742813SAndroid Build Coastguard Worker } 524*f9742813SAndroid Build Coastguard Worker 525*f9742813SAndroid Build Coastguard Worker // Padding for 4-byte alignment. 526*f9742813SAndroid Build Coastguard Worker for (int p = rowByteCountWithoutPadding; p < rowByteCount; p++) { 527*f9742813SAndroid Build Coastguard Worker sink.writeByte(0); 528*f9742813SAndroid Build Coastguard Worker } 529*f9742813SAndroid Build Coastguard Worker } 530*f9742813SAndroid Build Coastguard Worker } 531*f9742813SAndroid Build Coastguard Worker ``` 532*f9742813SAndroid Build Coastguard Worker 533*f9742813SAndroid Build Coastguard Worker=== "Kotlin" 534*f9742813SAndroid Build Coastguard Worker 535*f9742813SAndroid Build Coastguard Worker ```Kotlin 536*f9742813SAndroid Build Coastguard Worker @Throws(IOException::class) 537*f9742813SAndroid Build Coastguard Worker fun encode(bitmap: Bitmap, sink: BufferedSink) { 538*f9742813SAndroid Build Coastguard Worker val height = bitmap.height 539*f9742813SAndroid Build Coastguard Worker val width = bitmap.width 540*f9742813SAndroid Build Coastguard Worker val bytesPerPixel = 3 541*f9742813SAndroid Build Coastguard Worker val rowByteCountWithoutPadding = bytesPerPixel * width 542*f9742813SAndroid Build Coastguard Worker val rowByteCount = (rowByteCountWithoutPadding + 3) / 4 * 4 543*f9742813SAndroid Build Coastguard Worker val pixelDataSize = rowByteCount * height 544*f9742813SAndroid Build Coastguard Worker val bmpHeaderSize = 14 545*f9742813SAndroid Build Coastguard Worker val dibHeaderSize = 40 546*f9742813SAndroid Build Coastguard Worker 547*f9742813SAndroid Build Coastguard Worker // BMP Header 548*f9742813SAndroid Build Coastguard Worker sink.writeUtf8("BM") // ID. 549*f9742813SAndroid Build Coastguard Worker sink.writeIntLe(bmpHeaderSize + dibHeaderSize + pixelDataSize) // File size. 550*f9742813SAndroid Build Coastguard Worker sink.writeShortLe(0) // Unused. 551*f9742813SAndroid Build Coastguard Worker sink.writeShortLe(0) // Unused. 552*f9742813SAndroid Build Coastguard Worker sink.writeIntLe(bmpHeaderSize + dibHeaderSize) // Offset of pixel data. 553*f9742813SAndroid Build Coastguard Worker 554*f9742813SAndroid Build Coastguard Worker // DIB Header 555*f9742813SAndroid Build Coastguard Worker sink.writeIntLe(dibHeaderSize) 556*f9742813SAndroid Build Coastguard Worker sink.writeIntLe(width) 557*f9742813SAndroid Build Coastguard Worker sink.writeIntLe(height) 558*f9742813SAndroid Build Coastguard Worker sink.writeShortLe(1) // Color plane count. 559*f9742813SAndroid Build Coastguard Worker sink.writeShortLe(bytesPerPixel * Byte.SIZE_BITS) 560*f9742813SAndroid Build Coastguard Worker sink.writeIntLe(0) // No compression. 561*f9742813SAndroid Build Coastguard Worker sink.writeIntLe(16) // Size of bitmap data including padding. 562*f9742813SAndroid Build Coastguard Worker sink.writeIntLe(2835) // Horizontal print resolution in pixels/meter. (72 dpi). 563*f9742813SAndroid Build Coastguard Worker sink.writeIntLe(2835) // Vertical print resolution in pixels/meter. (72 dpi). 564*f9742813SAndroid Build Coastguard Worker sink.writeIntLe(0) // Palette color count. 565*f9742813SAndroid Build Coastguard Worker sink.writeIntLe(0) // 0 important colors. 566*f9742813SAndroid Build Coastguard Worker 567*f9742813SAndroid Build Coastguard Worker // Pixel data. 568*f9742813SAndroid Build Coastguard Worker for (y in height - 1 downTo 0) { 569*f9742813SAndroid Build Coastguard Worker for (x in 0 until width) { 570*f9742813SAndroid Build Coastguard Worker sink.writeByte(bitmap.blue(x, y)) 571*f9742813SAndroid Build Coastguard Worker sink.writeByte(bitmap.green(x, y)) 572*f9742813SAndroid Build Coastguard Worker sink.writeByte(bitmap.red(x, y)) 573*f9742813SAndroid Build Coastguard Worker } 574*f9742813SAndroid Build Coastguard Worker 575*f9742813SAndroid Build Coastguard Worker // Padding for 4-byte alignment. 576*f9742813SAndroid Build Coastguard Worker for (p in rowByteCountWithoutPadding until rowByteCount) { 577*f9742813SAndroid Build Coastguard Worker sink.writeByte(0) 578*f9742813SAndroid Build Coastguard Worker } 579*f9742813SAndroid Build Coastguard Worker } 580*f9742813SAndroid Build Coastguard Worker } 581*f9742813SAndroid Build Coastguard Worker ``` 582*f9742813SAndroid Build Coastguard Worker 583*f9742813SAndroid Build Coastguard WorkerThe trickiest part of this program is the format’s required padding. The BMP format expects each row 584*f9742813SAndroid Build Coastguard Workerto begin on a 4-byte boundary so it is necessary to add zeros to maintain the alignment. 585*f9742813SAndroid Build Coastguard Worker 586*f9742813SAndroid Build Coastguard WorkerEncoding other binary formats is usually quite similar. Some tips: 587*f9742813SAndroid Build Coastguard Worker 588*f9742813SAndroid Build Coastguard Worker * Write tests with golden values! Confirming that your program emits the expected result can make 589*f9742813SAndroid Build Coastguard Worker debugging easier. 590*f9742813SAndroid Build Coastguard Worker * Use `Utf8.size()` to compute the number of bytes of an encoded string. This is essential for 591*f9742813SAndroid Build Coastguard Worker length-prefixed formats. 592*f9742813SAndroid Build Coastguard Worker * Use `Float.floatToIntBits()` and `Double.doubleToLongBits()` to encode floating point values. 593*f9742813SAndroid Build Coastguard Worker 594*f9742813SAndroid Build Coastguard Worker 595*f9742813SAndroid Build Coastguard WorkerCommunicate on a Socket ([Java][SocksProxyServer]/[Kotlin][SocksProxyServerKt]) 596*f9742813SAndroid Build Coastguard Worker------------------------------------------------------------------------------- 597*f9742813SAndroid Build Coastguard Worker 598*f9742813SAndroid Build Coastguard WorkerNote that Okio doesn't yet support sockets on Kotlin/Native or Kotlin/JS. 599*f9742813SAndroid Build Coastguard Worker 600*f9742813SAndroid Build Coastguard WorkerSending and receiving data over the network is a bit like writing and reading files. We use 601*f9742813SAndroid Build Coastguard Worker`BufferedSink` to encode output and `BufferedSource` to decode input. Like files, network protocols 602*f9742813SAndroid Build Coastguard Workercan be text, binary, or a mix of both. But there are also some substantial differences between the 603*f9742813SAndroid Build Coastguard Workernetwork and the file system. 604*f9742813SAndroid Build Coastguard Worker 605*f9742813SAndroid Build Coastguard WorkerWith a file you’re either reading or writing but with the network you can do both! Some protocols 606*f9742813SAndroid Build Coastguard Workerhandle this by taking turns: write a request, read a response, repeat. You can implement this kind 607*f9742813SAndroid Build Coastguard Workerof protocol with a single thread. In other protocols you may read and write simultaneously. 608*f9742813SAndroid Build Coastguard WorkerTypically you’ll want one dedicated thread for reading. For writing you can use either a dedicated 609*f9742813SAndroid Build Coastguard Workerthread or use `synchronized` so that multiple threads can share a sink. Okio’s streams are not safe 610*f9742813SAndroid Build Coastguard Workerfor concurrent use. 611*f9742813SAndroid Build Coastguard Worker 612*f9742813SAndroid Build Coastguard WorkerSinks buffer outbound data to minimize I/O operations. This is efficient but it means you must 613*f9742813SAndroid Build Coastguard Workermanually call `flush()` to transmit data. Typically message-oriented protocols flush after each 614*f9742813SAndroid Build Coastguard Workermessage. Note that Okio will automatically flush when the buffered data exceeds some threshold. This 615*f9742813SAndroid Build Coastguard Workeris intended to save memory and you shouldn’t rely on it for interactive protocols. 616*f9742813SAndroid Build Coastguard Worker 617*f9742813SAndroid Build Coastguard WorkerOkio builds on `java.io.Socket` for connectivity. Create your socket as a server or as a client, 618*f9742813SAndroid Build Coastguard Workerthen use `Okio.source(Socket)` to read and `Okio.sink(Socket)` to write. These APIs also work with 619*f9742813SAndroid Build Coastguard Worker`SSLSocket`. You should use SSL unless you have a very good reason not to! 620*f9742813SAndroid Build Coastguard Worker 621*f9742813SAndroid Build Coastguard WorkerCancel a socket from any thread by calling `Socket.close()`; this will cause its sources and sinks 622*f9742813SAndroid Build Coastguard Workerto immediately fail with an `IOException`. You can also configure timeouts for all socket 623*f9742813SAndroid Build Coastguard Workeroperations. You don’t need a reference to the socket to adjust timeouts: `Source` and `Sink` expose 624*f9742813SAndroid Build Coastguard Workertimeouts directly. This API works even if the streams are decorated. 625*f9742813SAndroid Build Coastguard Worker 626*f9742813SAndroid Build Coastguard WorkerAs a complete example of networking with Okio we wrote a [basic SOCKS proxy][SocksProxyServer] 627*f9742813SAndroid Build Coastguard Workerserver. Some highlights: 628*f9742813SAndroid Build Coastguard Worker 629*f9742813SAndroid Build Coastguard Worker=== "Java" 630*f9742813SAndroid Build Coastguard Worker 631*f9742813SAndroid Build Coastguard Worker ```Java 632*f9742813SAndroid Build Coastguard Worker Socket fromSocket = ... 633*f9742813SAndroid Build Coastguard Worker BufferedSource fromSource = Okio.buffer(Okio.source(fromSocket)); 634*f9742813SAndroid Build Coastguard Worker BufferedSink fromSink = Okio.buffer(Okio.sink(fromSocket)); 635*f9742813SAndroid Build Coastguard Worker ``` 636*f9742813SAndroid Build Coastguard Worker 637*f9742813SAndroid Build Coastguard Worker=== "Kotlin" 638*f9742813SAndroid Build Coastguard Worker 639*f9742813SAndroid Build Coastguard Worker ```Kotlin 640*f9742813SAndroid Build Coastguard Worker val fromSocket: Socket = ... 641*f9742813SAndroid Build Coastguard Worker val fromSource = fromSocket.source().buffer() 642*f9742813SAndroid Build Coastguard Worker val fromSink = fromSocket.sink().buffer() 643*f9742813SAndroid Build Coastguard Worker ``` 644*f9742813SAndroid Build Coastguard Worker 645*f9742813SAndroid Build Coastguard WorkerCreating sources and sinks for sockets is the same as creating them for files. Once you create a 646*f9742813SAndroid Build Coastguard Worker`Source` or `Sink` for a socket you must not use its `InputStream` or `OutputStream`, respectively. 647*f9742813SAndroid Build Coastguard Worker 648*f9742813SAndroid Build Coastguard Worker=== "Java" 649*f9742813SAndroid Build Coastguard Worker 650*f9742813SAndroid Build Coastguard Worker ```Java 651*f9742813SAndroid Build Coastguard Worker Buffer buffer = new Buffer(); 652*f9742813SAndroid Build Coastguard Worker for (long byteCount; (byteCount = source.read(buffer, 8192L)) != -1; ) { 653*f9742813SAndroid Build Coastguard Worker sink.write(buffer, byteCount); 654*f9742813SAndroid Build Coastguard Worker sink.flush(); 655*f9742813SAndroid Build Coastguard Worker } 656*f9742813SAndroid Build Coastguard Worker ``` 657*f9742813SAndroid Build Coastguard Worker 658*f9742813SAndroid Build Coastguard Worker=== "Kotlin" 659*f9742813SAndroid Build Coastguard Worker 660*f9742813SAndroid Build Coastguard Worker ```Kotlin 661*f9742813SAndroid Build Coastguard Worker val buffer = Buffer() 662*f9742813SAndroid Build Coastguard Worker var byteCount: Long 663*f9742813SAndroid Build Coastguard Worker while (source.read(buffer, 8192L).also { byteCount = it } != -1L) { 664*f9742813SAndroid Build Coastguard Worker sink.write(buffer, byteCount) 665*f9742813SAndroid Build Coastguard Worker sink.flush() 666*f9742813SAndroid Build Coastguard Worker } 667*f9742813SAndroid Build Coastguard Worker ``` 668*f9742813SAndroid Build Coastguard Worker 669*f9742813SAndroid Build Coastguard WorkerThe above loop copies data from the source to the sink, flushing after each read. If we didn’t need 670*f9742813SAndroid Build Coastguard Workerthe flushing we could replace this loop with a single call to `BufferedSink.writeAll(Source)`. 671*f9742813SAndroid Build Coastguard Worker 672*f9742813SAndroid Build Coastguard WorkerThe `8192` argument to `read()` is the maximum number of bytes to read before returning. We could 673*f9742813SAndroid Build Coastguard Workerhave passed any value here, but we like 8 KiB because that’s the largest value Okio can do in a 674*f9742813SAndroid Build Coastguard Workersingle system call. Most of the time application code doesn’t need to deal with such limits! 675*f9742813SAndroid Build Coastguard Worker 676*f9742813SAndroid Build Coastguard Worker=== "Java" 677*f9742813SAndroid Build Coastguard Worker 678*f9742813SAndroid Build Coastguard Worker ```Java 679*f9742813SAndroid Build Coastguard Worker int addressType = fromSource.readByte() & 0xff; 680*f9742813SAndroid Build Coastguard Worker int port = fromSource.readShort() & 0xffff; 681*f9742813SAndroid Build Coastguard Worker ``` 682*f9742813SAndroid Build Coastguard Worker 683*f9742813SAndroid Build Coastguard Worker=== "Kotlin" 684*f9742813SAndroid Build Coastguard Worker 685*f9742813SAndroid Build Coastguard Worker ```Kotlin 686*f9742813SAndroid Build Coastguard Worker val addressType = fromSource.readByte().toInt() and 0xff 687*f9742813SAndroid Build Coastguard Worker val port = fromSource.readShort().toInt() and 0xffff 688*f9742813SAndroid Build Coastguard Worker ``` 689*f9742813SAndroid Build Coastguard Worker 690*f9742813SAndroid Build Coastguard WorkerOkio uses signed types like `byte` and `short`, but often protocols want unsigned values. The 691*f9742813SAndroid Build Coastguard Workerbitwise `&` operator is Java’s preferred idiom to convert a signed value into an unsigned value. 692*f9742813SAndroid Build Coastguard WorkerHere’s a cheat sheet for bytes, shorts, and ints: 693*f9742813SAndroid Build Coastguard Worker 694*f9742813SAndroid Build Coastguard Worker| Type | Signed Range | Unsigned Range | Signed to Unsigned | 695*f9742813SAndroid Build Coastguard Worker| :---- | :---------------------------: | :--------------- | :-------------------------- | 696*f9742813SAndroid Build Coastguard Worker| byte | -128..127 | 0..255 | `int u = s & 0xff;` | 697*f9742813SAndroid Build Coastguard Worker| short | -32,768..32,767 | 0..65,535 | `int u = s & 0xffff;` | 698*f9742813SAndroid Build Coastguard Worker| int | -2,147,483,648..2,147,483,647 | 0..4,294,967,295 | `long u = s & 0xffffffffL;` | 699*f9742813SAndroid Build Coastguard Worker 700*f9742813SAndroid Build Coastguard WorkerJava has no primitive type that can represent unsigned longs. 701*f9742813SAndroid Build Coastguard Worker 702*f9742813SAndroid Build Coastguard Worker 703*f9742813SAndroid Build Coastguard WorkerHashing ([Java][Hashing]/[Kotlin][HashingKt]) 704*f9742813SAndroid Build Coastguard Worker--------------------------------------------- 705*f9742813SAndroid Build Coastguard Worker 706*f9742813SAndroid Build Coastguard WorkerWe’re bombarded by hashing in our lives as Java programmers. Early on we're introduced to the 707*f9742813SAndroid Build Coastguard Worker`hashCode()` method, something we know we need to override otherwise unforeseen bad things happen. 708*f9742813SAndroid Build Coastguard WorkerLater we’re shown `LinkedHashMap` and its friends. These build on that `hashCode()` method to 709*f9742813SAndroid Build Coastguard Workerorganize data for fast retrieval. 710*f9742813SAndroid Build Coastguard Worker 711*f9742813SAndroid Build Coastguard WorkerElsewhere we have cryptographic hash functions. These get used all over the place. HTTPS 712*f9742813SAndroid Build Coastguard Workercertificates, Git commits, BitTorrent integrity checking, and Blockchain blocks all use 713*f9742813SAndroid Build Coastguard Workercryptographic hashes. Good use of hashes can improve the performance, privacy, security, and 714*f9742813SAndroid Build Coastguard Workersimplicity of an application. 715*f9742813SAndroid Build Coastguard Worker 716*f9742813SAndroid Build Coastguard WorkerEach cryptographic hash function accepts a variable-length stream of input bytes and produces a 717*f9742813SAndroid Build Coastguard Workerfixed-length byte string value called the “hash”. Hash functions have these important qualities: 718*f9742813SAndroid Build Coastguard Worker 719*f9742813SAndroid Build Coastguard Worker * Deterministic: each input always produces the same output. 720*f9742813SAndroid Build Coastguard Worker * Uniform: each output byte string is equally likely. It is very difficult to find or create pairs 721*f9742813SAndroid Build Coastguard Worker of different inputs that yield the same output. This is called a “collision”. 722*f9742813SAndroid Build Coastguard Worker * Non-reversible: knowing an output doesn't help you to find the input. Note that if you know some 723*f9742813SAndroid Build Coastguard Worker possible inputs you can hash them to see if their hashes match. 724*f9742813SAndroid Build Coastguard Worker * Well-known: the hash is implemented everywhere and rigorously understood. 725*f9742813SAndroid Build Coastguard Worker 726*f9742813SAndroid Build Coastguard WorkerGood hash functions are very cheap to compute (dozens of microseconds) and expensive to reverse 727*f9742813SAndroid Build Coastguard Worker(quintillions of millenia). Steady advances in computing and mathematics have caused once-great hash 728*f9742813SAndroid Build Coastguard Workerfunctions to become inexpensive to reverse. When choosing a hash function, beware that not all are 729*f9742813SAndroid Build Coastguard Workercreated equal! Okio supports these well-known cryptographic hash functions: 730*f9742813SAndroid Build Coastguard Worker 731*f9742813SAndroid Build Coastguard Worker * **MD5**: a 128-bit (16 byte) cryptographic hash. It is both insecure and obsolete because it is 732*f9742813SAndroid Build Coastguard Worker inexpensive to reverse! This hash is offered because it is popular and convenient for use in 733*f9742813SAndroid Build Coastguard Worker legacy systems that are not security-sensitive. 734*f9742813SAndroid Build Coastguard Worker * **SHA-1**: a 160-bit (20 byte) cryptographic hash. It was recently demonstrated that it is 735*f9742813SAndroid Build Coastguard Worker feasible to create SHA-1 collisions. Consider upgrading from SHA-1 to SHA-256. 736*f9742813SAndroid Build Coastguard Worker * **SHA-256**: a 256-bit (32 byte) cryptographic hash. SHA-256 is widely understood and expensive 737*f9742813SAndroid Build Coastguard Worker to reverse. This is the hash most systems should use. 738*f9742813SAndroid Build Coastguard Worker * **SHA-512**: a 512-bit (64 byte) cryptographic hash. It is expensive to reverse. 739*f9742813SAndroid Build Coastguard Worker 740*f9742813SAndroid Build Coastguard WorkerEach hash creates a `ByteString` of the specified length. Use `hex()` to get the conventional 741*f9742813SAndroid Build Coastguard Workerhuman-readable form. Or leave it as a `ByteString` because that’s a convenient model type! 742*f9742813SAndroid Build Coastguard Worker 743*f9742813SAndroid Build Coastguard WorkerOkio can produce cryptographic hashes from byte strings: 744*f9742813SAndroid Build Coastguard Worker 745*f9742813SAndroid Build Coastguard Worker=== "Java" 746*f9742813SAndroid Build Coastguard Worker 747*f9742813SAndroid Build Coastguard Worker ```Java 748*f9742813SAndroid Build Coastguard Worker ByteString byteString = readByteString(Path.get("README.md")); 749*f9742813SAndroid Build Coastguard Worker System.out.println(" md5: " + byteString.md5().hex()); 750*f9742813SAndroid Build Coastguard Worker System.out.println(" sha1: " + byteString.sha1().hex()); 751*f9742813SAndroid Build Coastguard Worker System.out.println("sha256: " + byteString.sha256().hex()); 752*f9742813SAndroid Build Coastguard Worker System.out.println("sha512: " + byteString.sha512().hex()); 753*f9742813SAndroid Build Coastguard Worker ``` 754*f9742813SAndroid Build Coastguard Worker 755*f9742813SAndroid Build Coastguard Worker=== "Kotlin" 756*f9742813SAndroid Build Coastguard Worker 757*f9742813SAndroid Build Coastguard Worker ```Kotlin 758*f9742813SAndroid Build Coastguard Worker val byteString = readByteString("README.md".toPath()) 759*f9742813SAndroid Build Coastguard Worker println(" md5: " + byteString.md5().hex()) 760*f9742813SAndroid Build Coastguard Worker println(" sha1: " + byteString.sha1().hex()) 761*f9742813SAndroid Build Coastguard Worker println(" sha256: " + byteString.sha256().hex()) 762*f9742813SAndroid Build Coastguard Worker println(" sha512: " + byteString.sha512().hex()) 763*f9742813SAndroid Build Coastguard Worker ``` 764*f9742813SAndroid Build Coastguard Worker 765*f9742813SAndroid Build Coastguard WorkerFrom buffers: 766*f9742813SAndroid Build Coastguard Worker 767*f9742813SAndroid Build Coastguard Worker=== "Java" 768*f9742813SAndroid Build Coastguard Worker 769*f9742813SAndroid Build Coastguard Worker ```Java 770*f9742813SAndroid Build Coastguard Worker Buffer buffer = readBuffer(Path.get("README.md")); 771*f9742813SAndroid Build Coastguard Worker System.out.println(" md5: " + buffer.md5().hex()); 772*f9742813SAndroid Build Coastguard Worker System.out.println(" sha1: " + buffer.sha1().hex()); 773*f9742813SAndroid Build Coastguard Worker System.out.println("sha256: " + buffer.sha256().hex()); 774*f9742813SAndroid Build Coastguard Worker System.out.println("sha512: " + buffer.sha512().hex()); 775*f9742813SAndroid Build Coastguard Worker ``` 776*f9742813SAndroid Build Coastguard Worker 777*f9742813SAndroid Build Coastguard Worker=== "Kotlin" 778*f9742813SAndroid Build Coastguard Worker 779*f9742813SAndroid Build Coastguard Worker ```Kotlin 780*f9742813SAndroid Build Coastguard Worker val buffer = readBuffer("README.md".toPath()) 781*f9742813SAndroid Build Coastguard Worker println(" md5: " + buffer.md5().hex()) 782*f9742813SAndroid Build Coastguard Worker println(" sha1: " + buffer.sha1().hex()) 783*f9742813SAndroid Build Coastguard Worker println(" sha256: " + buffer.sha256().hex()) 784*f9742813SAndroid Build Coastguard Worker println(" sha512: " + buffer.sha512().hex()) 785*f9742813SAndroid Build Coastguard Worker ``` 786*f9742813SAndroid Build Coastguard Worker 787*f9742813SAndroid Build Coastguard WorkerWhile streaming from a source: 788*f9742813SAndroid Build Coastguard Worker 789*f9742813SAndroid Build Coastguard Worker=== "Java" 790*f9742813SAndroid Build Coastguard Worker 791*f9742813SAndroid Build Coastguard Worker ```Java 792*f9742813SAndroid Build Coastguard Worker try (HashingSink hashingSink = HashingSink.sha256(Okio.blackhole()); 793*f9742813SAndroid Build Coastguard Worker BufferedSource source = Okio.buffer(FileSystem.SYSTEM.source(path))) { 794*f9742813SAndroid Build Coastguard Worker source.readAll(hashingSink); 795*f9742813SAndroid Build Coastguard Worker System.out.println("sha256: " + hashingSink.hash().hex()); 796*f9742813SAndroid Build Coastguard Worker } 797*f9742813SAndroid Build Coastguard Worker ``` 798*f9742813SAndroid Build Coastguard Worker 799*f9742813SAndroid Build Coastguard Worker=== "Kotlin" 800*f9742813SAndroid Build Coastguard Worker 801*f9742813SAndroid Build Coastguard Worker ```Kotlin 802*f9742813SAndroid Build Coastguard Worker sha256(blackholeSink()).use { hashingSink -> 803*f9742813SAndroid Build Coastguard Worker FileSystem.SYSTEM.source(path).buffer().use { source -> 804*f9742813SAndroid Build Coastguard Worker source.readAll(hashingSink) 805*f9742813SAndroid Build Coastguard Worker println(" sha256: " + hashingSink.hash.hex()) 806*f9742813SAndroid Build Coastguard Worker } 807*f9742813SAndroid Build Coastguard Worker } 808*f9742813SAndroid Build Coastguard Worker ``` 809*f9742813SAndroid Build Coastguard Worker 810*f9742813SAndroid Build Coastguard WorkerWhile streaming to a sink: 811*f9742813SAndroid Build Coastguard Worker 812*f9742813SAndroid Build Coastguard Worker=== "Java" 813*f9742813SAndroid Build Coastguard Worker 814*f9742813SAndroid Build Coastguard Worker ```Java 815*f9742813SAndroid Build Coastguard Worker try (HashingSink hashingSink = HashingSink.sha256(Okio.blackhole()); 816*f9742813SAndroid Build Coastguard Worker BufferedSink sink = Okio.buffer(hashingSink); 817*f9742813SAndroid Build Coastguard Worker Source source = FileSystem.SYSTEM.source(path)) { 818*f9742813SAndroid Build Coastguard Worker sink.writeAll(source); 819*f9742813SAndroid Build Coastguard Worker sink.close(); // Emit anything buffered. 820*f9742813SAndroid Build Coastguard Worker System.out.println("sha256: " + hashingSink.hash().hex()); 821*f9742813SAndroid Build Coastguard Worker } 822*f9742813SAndroid Build Coastguard Worker ``` 823*f9742813SAndroid Build Coastguard Worker 824*f9742813SAndroid Build Coastguard Worker=== "Kotlin" 825*f9742813SAndroid Build Coastguard Worker 826*f9742813SAndroid Build Coastguard Worker ```Kotlin 827*f9742813SAndroid Build Coastguard Worker sha256(blackholeSink()).use { hashingSink -> 828*f9742813SAndroid Build Coastguard Worker hashingSink.buffer().use { sink -> 829*f9742813SAndroid Build Coastguard Worker FileSystem.SYSTEM.source(path).use { source -> 830*f9742813SAndroid Build Coastguard Worker sink.writeAll(source) 831*f9742813SAndroid Build Coastguard Worker sink.close() // Emit anything buffered. 832*f9742813SAndroid Build Coastguard Worker println(" sha256: " + hashingSink.hash.hex()) 833*f9742813SAndroid Build Coastguard Worker } 834*f9742813SAndroid Build Coastguard Worker } 835*f9742813SAndroid Build Coastguard Worker } 836*f9742813SAndroid Build Coastguard Worker ``` 837*f9742813SAndroid Build Coastguard Worker 838*f9742813SAndroid Build Coastguard WorkerOkio also supports HMAC (Hash Message Authentication Code) which combines a secret and a hash. 839*f9742813SAndroid Build Coastguard WorkerApplications use HMAC for data integrity and authentication. 840*f9742813SAndroid Build Coastguard Worker 841*f9742813SAndroid Build Coastguard Worker=== "Java" 842*f9742813SAndroid Build Coastguard Worker 843*f9742813SAndroid Build Coastguard Worker ```Java 844*f9742813SAndroid Build Coastguard Worker ByteString secret = ByteString.decodeHex("7065616e7574627574746572"); 845*f9742813SAndroid Build Coastguard Worker System.out.println("hmacSha256: " + byteString.hmacSha256(secret).hex()); 846*f9742813SAndroid Build Coastguard Worker ``` 847*f9742813SAndroid Build Coastguard Worker 848*f9742813SAndroid Build Coastguard Worker=== "Kotlin" 849*f9742813SAndroid Build Coastguard Worker 850*f9742813SAndroid Build Coastguard Worker ```Kotlin 851*f9742813SAndroid Build Coastguard Worker val secret = "7065616e7574627574746572".decodeHex() 852*f9742813SAndroid Build Coastguard Worker println("hmacSha256: " + byteString.hmacSha256(secret).hex()) 853*f9742813SAndroid Build Coastguard Worker ``` 854*f9742813SAndroid Build Coastguard Worker 855*f9742813SAndroid Build Coastguard WorkerAs with hashing, you can generate an HMAC from a `ByteString`, `Buffer`, `HashingSource`, and 856*f9742813SAndroid Build Coastguard Worker`HashingSink`. Note that Okio doesn’t implement HMAC for MD5. 857*f9742813SAndroid Build Coastguard Worker 858*f9742813SAndroid Build Coastguard WorkerOn Android and Java, Okio uses Java’s `java.security.MessageDigest` for cryptographic hashes and 859*f9742813SAndroid Build Coastguard Worker`javax.crypto.Mac` for HMAC. On other platforms Okio uses its own optimized implementation of 860*f9742813SAndroid Build Coastguard Workerthese algorithms. 861*f9742813SAndroid Build Coastguard Worker 862*f9742813SAndroid Build Coastguard Worker 863*f9742813SAndroid Build Coastguard WorkerEncryption and Decryption 864*f9742813SAndroid Build Coastguard Worker------------------------- 865*f9742813SAndroid Build Coastguard Worker 866*f9742813SAndroid Build Coastguard WorkerOn Android and Java it's easy to encrypt streams. 867*f9742813SAndroid Build Coastguard Worker 868*f9742813SAndroid Build Coastguard WorkerCallers are responsible for the initialization of the encryption or decryption cipher with the 869*f9742813SAndroid Build Coastguard Workerchosen algorithm, the key, and algorithm-specific additional parameters like the initialization 870*f9742813SAndroid Build Coastguard Workervector. The following example shows a typical usage with AES encryption, in which `key` and `iv` 871*f9742813SAndroid Build Coastguard Workerparameters should both be 16 bytes long. 872*f9742813SAndroid Build Coastguard Worker 873*f9742813SAndroid Build Coastguard Worker=== "Java" 874*f9742813SAndroid Build Coastguard Worker 875*f9742813SAndroid Build Coastguard Worker Use `Okio.cipherSink(Sink, Cipher)` or `Okio.cipherSource(Source, Cipher)` to encrypt or decrypt 876*f9742813SAndroid Build Coastguard Worker a stream using a block cipher. 877*f9742813SAndroid Build Coastguard Worker 878*f9742813SAndroid Build Coastguard Worker ```java 879*f9742813SAndroid Build Coastguard Worker void encryptAes(ByteString bytes, Path path, byte[] key, byte[] iv) 880*f9742813SAndroid Build Coastguard Worker throws GeneralSecurityException, IOException { 881*f9742813SAndroid Build Coastguard Worker Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 882*f9742813SAndroid Build Coastguard Worker cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv)); 883*f9742813SAndroid Build Coastguard Worker try (BufferedSink sink = Okio.buffer( 884*f9742813SAndroid Build Coastguard Worker Okio.cipherSink(FileSystem.SYSTEM.sink(path), cipher))) { 885*f9742813SAndroid Build Coastguard Worker sink.write(bytes); 886*f9742813SAndroid Build Coastguard Worker } 887*f9742813SAndroid Build Coastguard Worker } 888*f9742813SAndroid Build Coastguard Worker 889*f9742813SAndroid Build Coastguard Worker ByteString decryptAesToByteString(Path path, byte[] key, byte[] iv) 890*f9742813SAndroid Build Coastguard Worker throws GeneralSecurityException, IOException { 891*f9742813SAndroid Build Coastguard Worker Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 892*f9742813SAndroid Build Coastguard Worker cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv)); 893*f9742813SAndroid Build Coastguard Worker try (BufferedSource source = Okio.buffer( 894*f9742813SAndroid Build Coastguard Worker Okio.cipherSource(FileSystem.SYSTEM.source(path), cipher))) { 895*f9742813SAndroid Build Coastguard Worker return source.readByteString(); 896*f9742813SAndroid Build Coastguard Worker } 897*f9742813SAndroid Build Coastguard Worker } 898*f9742813SAndroid Build Coastguard Worker ``` 899*f9742813SAndroid Build Coastguard Worker 900*f9742813SAndroid Build Coastguard Worker=== "Kotlin" 901*f9742813SAndroid Build Coastguard Worker 902*f9742813SAndroid Build Coastguard Worker Encryption and decryption functions are extensions on `Cipher`: 903*f9742813SAndroid Build Coastguard Worker 904*f9742813SAndroid Build Coastguard Worker ```kotlin 905*f9742813SAndroid Build Coastguard Worker fun encryptAes(bytes: ByteString, path: Path, key: ByteArray, iv: ByteArray) { 906*f9742813SAndroid Build Coastguard Worker val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding") 907*f9742813SAndroid Build Coastguard Worker cipher.init(Cipher.ENCRYPT_MODE, SecretKeySpec(key, "AES"), IvParameterSpec(iv)) 908*f9742813SAndroid Build Coastguard Worker val cipherSink = FileSystem.SYSTEM.sink(path).cipherSink(cipher) 909*f9742813SAndroid Build Coastguard Worker cipherSink.buffer().use { 910*f9742813SAndroid Build Coastguard Worker it.write(bytes) 911*f9742813SAndroid Build Coastguard Worker } 912*f9742813SAndroid Build Coastguard Worker } 913*f9742813SAndroid Build Coastguard Worker 914*f9742813SAndroid Build Coastguard Worker fun decryptAesToByteString(path: Path, key: ByteArray, iv: ByteArray): ByteString { 915*f9742813SAndroid Build Coastguard Worker val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding") 916*f9742813SAndroid Build Coastguard Worker cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(key, "AES"), IvParameterSpec(iv)) 917*f9742813SAndroid Build Coastguard Worker val cipherSource = FileSystem.SYSTEM.source(path).cipherSource(cipher) 918*f9742813SAndroid Build Coastguard Worker return cipherSource.buffer().use { 919*f9742813SAndroid Build Coastguard Worker it.readByteString() 920*f9742813SAndroid Build Coastguard Worker } 921*f9742813SAndroid Build Coastguard Worker } 922*f9742813SAndroid Build Coastguard Worker ``` 923*f9742813SAndroid Build Coastguard Worker 924*f9742813SAndroid Build Coastguard Worker 925*f9742813SAndroid Build Coastguard Worker[base64]: https://tools.ietf.org/html/rfc4648#section-4 926*f9742813SAndroid Build Coastguard Worker[bmp]: https://en.wikipedia.org/wiki/BMP_file_format 927*f9742813SAndroid Build Coastguard Worker[nfd]: https://docs.oracle.com/javase/7/docs/api/java/text/Normalizer.Form.html#NFD 928*f9742813SAndroid Build Coastguard Worker[nfc]: https://docs.oracle.com/javase/7/docs/api/java/text/Normalizer.Form.html#NFC 929*f9742813SAndroid Build Coastguard Worker[BitmapEncoderKt]: https://github.com/square/okio/blob/master/samples/src/jvmMain/kotlin/okio/samples/BitmapEncoder.kt 930*f9742813SAndroid Build Coastguard Worker[BitmapEncoder]: https://github.com/square/okio/blob/master/samples/src/jvmMain/java/okio/samples/BitmapEncoder.java 931*f9742813SAndroid Build Coastguard Worker[ExploreCharsetsKt]: https://github.com/square/okio/blob/master/samples/src/jvmMain/kotlin/okio/samples/ExploreCharsets.kt 932*f9742813SAndroid Build Coastguard Worker[ExploreCharsets]: https://github.com/square/okio/blob/master/samples/src/jvmMain/java/okio/samples/ExploreCharsets.java 933*f9742813SAndroid Build Coastguard Worker[GoldenValueKt]: https://github.com/square/okio/blob/master/samples/src/jvmMain/kotlin/okio/samples/GoldenValue.kt 934*f9742813SAndroid Build Coastguard Worker[GoldenValue]: https://github.com/square/okio/blob/master/samples/src/jvmMain/java/okio/samples/GoldenValue.java 935*f9742813SAndroid Build Coastguard Worker[HashingKt]: https://github.com/square/okio/blob/master/samples/src/jvmMain/kotlin/okio/samples/Hashing.kt 936*f9742813SAndroid Build Coastguard Worker[Hashing]: https://github.com/square/okio/blob/master/samples/src/jvmMain/java/okio/samples/Hashing.java 937*f9742813SAndroid Build Coastguard Worker[ReadFileLineByLine]: https://github.com/square/okio/blob/master/samples/src/jvmMain/java/okio/samples/ReadFileLineByLine.java 938*f9742813SAndroid Build Coastguard Worker[ReadFileLineByLineKt]: https://github.com/square/okio/blob/master/samples/src/jvmMain/kotlin/okio/samples/ReadFileLineByLine.kt 939*f9742813SAndroid Build Coastguard Worker[SocksProxyServerKt]: https://github.com/square/okio/blob/master/samples/src/jvmMain/kotlin/okio/samples/SocksProxyServer.kt 940*f9742813SAndroid Build Coastguard Worker[SocksProxyServer]: https://github.com/square/okio/blob/master/samples/src/jvmMain/java/okio/samples/SocksProxyServer.java 941*f9742813SAndroid Build Coastguard Worker[WriteFile]: https://github.com/square/okio/blob/master/samples/src/jvmMain/java/okio/samples/WriteFile.java 942*f9742813SAndroid Build Coastguard Worker[WriteFileKt]: https://github.com/square/okio/blob/master/samples/src/jvmMain/kotlin/okio/samples/WriteFile.kt 943