• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1Okio
2====
3
4Okio is a library that complements `java.io` and `java.nio` to make it much
5easier to access, store, and process your data. It started as a component of
6[OkHttp][1], the capable HTTP client included in Android. It's well-exercised
7and ready to solve new problems.
8
9ByteStrings and Buffers
10-----------------------
11
12Okio is built around two types that pack a lot of capability into a
13straightforward API:
14
15 * [**ByteString**][3] is an immutable sequence of bytes. For character data, `String`
16   is fundamental. `ByteString` is String's long-lost brother, making it easy to
17   treat binary data as a value. This class is ergonomic: it knows how to encode
18   and decode itself as hex, base64, and UTF-8.
19
20 * [**Buffer**][4] is a mutable sequence of bytes. Like `ArrayList`, you don't need
21   to size your buffer in advance. You read and write buffers as a queue: write
22   data to the end and read it from the front. There's no obligation to manage
23   positions, limits, or capacities.
24
25Internally, `ByteString` and `Buffer` do some clever things to save CPU and
26memory. If you encode a UTF-8 string as a `ByteString`, it caches a reference to
27that string so that if you decode it later, there's no work to do.
28
29`Buffer` is implemented as a linked list of segments. When you move data from
30one buffer to another, it _reassigns ownership_ of the segments rather than
31copying the data across. This approach is particularly helpful for multithreaded
32programs: a thread that talks to the network can exchange data with a worker
33thread without any copying or ceremony.
34
35Sources and Sinks
36-----------------
37
38An elegant part of the `java.io` design is how streams can be layered for
39transformations like encryption and compression. Okio includes its own stream
40types called [`Source`][5] and [`Sink`][6] that work like `InputStream` and
41`OutputStream`, but with some key differences:
42
43 * **Timeouts.** The streams provide access to the timeouts of the underlying
44   I/O mechanism. Unlike the `java.io` socket streams, both `read()` and
45   `write()` calls honor timeouts.
46
47 * **Easy to implement.** `Source` declares three methods: `read()`, `close()`,
48   and `timeout()`. There are no hazards like `available()` or single-byte reads
49   that cause correctness and performance surprises.
50
51 * **Easy to use.** Although _implementations_ of `Source` and `Sink` have only
52   three methods to write, _callers_ are given a rich API with the
53   [`BufferedSource`][7] and [`BufferedSink`][8] interfaces. These interfaces give you
54   everything you need in one place.
55
56 * **No artificial distinction between byte streams and char streams.** It's all
57   data. Read and write it as bytes, UTF-8 strings, big-endian 32-bit integers,
58   little-endian shorts; whatever you want. No more `InputStreamReader`!
59
60 * **Easy to test.** The `Buffer` class implements both `BufferedSource` and
61   `BufferedSink` so your test code is simple and clear.
62
63Sources and sinks interoperate with `InputStream` and `OutputStream`. You can
64view any `Source` as an `InputStream`, and you can view any `InputStream` as a
65`Source`. Similarly for `Sink` and `OutputStream`.
66
67
68Presentations
69-------------
70
71[A Few “Ok” Libraries][ok_libraries_talk] ([slides][ok_libraries_slides]): An introduction to Okio
72and three libraries written with it.
73
74[Decoding the Secrets of Binary Data][encoding_talk] ([slides][encoding_slides]): How data encoding
75works and how Okio does it.
76
77[Ok Multiplatform!][ok_multiplatform_talk] ([slides][ok_multiplatform_slides]): How we changed
78Okio’s implementation language from Java to Kotlin.
79
80
81Requirements
82------------
83
84Okio supports Android 4.0.3+ (API level 15+) and Java 7+.
85
86Okio depends on the [Kotlin standard library][kotlin]. It is a small library with strong
87backward-compatibility.
88
89
90Recipes
91-------
92
93We've written some recipes that demonstrate how to solve common problems with
94Okio. Read through them to learn about how everything works together.
95Cut-and-paste these examples freely; that's what they're for.
96
97### Read a text file line-by-line ([Java][ReadFileLineByLine]/[Kotlin][ReadFileLineByLineKt])
98
99Use `Okio.source(File)` to open a source stream to read a file. The returned
100`Source` interface is very small and has limited uses. Instead we wrap the
101source with a buffer. This has two benefits:
102
103 * **It makes the API more powerful.** Instead of the basic methods offered by
104   `Source`, `BufferedSource` has dozens of methods to address most common
105   problems concisely.
106
107 * **It makes your program run faster.** Buffering allows Okio to get more done
108   with fewer I/O operations.
109
110Each `Source` that is opened needs to be closed. The code that opens the stream
111is responsible for making sure it is closed.
112
113=== "Java"
114
115    Here we use Java's `try` blocks to close our sources automatically.
116
117    ```java
118    public void readLines(File file) throws IOException {
119      try (Source fileSource = Okio.source(file);
120           BufferedSource bufferedSource = Okio.buffer(fileSource)) {
121
122        while (true) {
123          String line = bufferedSource.readUtf8Line();
124          if (line == null) break;
125
126          if (line.contains("square")) {
127            System.out.println(line);
128          }
129        }
130
131      }
132    }
133    ```
134
135=== "Kotlin"
136
137    Note that static `Okio` methods become extension functions (`Okio.source(file)` =>
138    `file.source()`), and `use` is used to automatically close the streams:
139
140    ```kotlin
141    @Throws(IOException::class)
142    fun readLines(file: File) {
143      file.source().use { fileSource ->
144        fileSource.buffer().use { bufferedFileSource ->
145          while (true) {
146            val line = bufferedFileSource.readUtf8Line() ?: break
147            if ("square" in line) {
148              println(line)
149            }
150          }
151        }
152      }
153    }
154    ```
155
156The `readUtf8Line()` API reads all of the data until the next line delimiter –
157either `\n`, `\r\n`, or the end of the file. It returns that data as a string,
158omitting the delimiter at the end. When it encounters empty lines the method
159will return an empty string. If there isn’t any more data to read it will
160return null.
161
162The above program can be written more compactly by inlining the `fileSource`
163variable and by using a fancy `for` loop instead of a `while`:
164
165```java
166public void readLines(File file) throws IOException {
167  try (BufferedSource source = Okio.buffer(Okio.source(file))) {
168    for (String line; (line = source.readUtf8Line()) != null; ) {
169      if (line.contains("square")) {
170        System.out.println(line);
171      }
172    }
173  }
174}
175```
176
177In Kotlin, we can wrap invocations of `source.readUtf8Line()` into the `generateSequence` builder to
178create a sequence of lines that will end once null is returned. Plus, transforming streams is easy
179thanks to the extension functions:
180
181```kotlin
182@Throws(IOException::class)
183fun readLines(file: File) {
184  file.source().buffer().use { source ->
185    generateSequence { source.readUtf8Line() }
186      .filter { line -> "square" in line }
187      .forEach(::println)
188  }
189}
190```
191
192The `readUtf8Line()` method is suitable for parsing most files. For certain
193use-cases you may also consider `readUtf8LineStrict()`. It is similar but it
194requires that each line is terminated by `\n` or `\r\n`. If it encounters the
195end of the file before that it will throw an `EOFException`. The strict variant
196also permits a byte limit to defend against malformed input.
197
198```java
199public void readLines(File file) throws IOException {
200  try (BufferedSource source = Okio.buffer(Okio.source(file))) {
201    while (!source.exhausted()) {
202      String line = source.readUtf8LineStrict(1024L);
203      if (line.contains("square")) {
204        System.out.println(line);
205      }
206    }
207  }
208}
209```
210
211Here's a similar example written in Kotlin:
212
213```kotlin
214@Throws(IOException::class)
215fun readLines(file: File) {
216  file.source().buffer().use { source ->
217    while (!source.exhausted()) {
218      val line = source.readUtf8LineStrict(1024)
219      if ("square" in line) {
220        println(line)
221      }
222    }
223  }
224}
225```
226
227### Write a text file ([Java][WriteFile]/[Kotlin][WriteFileKt])
228
229Above we used a `Source` and a `BufferedSource` to read a file. To write, we use
230a `Sink` and a `BufferedSink`. The advantages of buffering are the same: a more
231capable API and better performance.
232
233```java
234public void writeEnv(File file) throws IOException {
235  try (Sink fileSink = Okio.sink(file);
236       BufferedSink bufferedSink = Okio.buffer(fileSink)) {
237
238    for (Map.Entry<String, String> entry : System.getenv().entrySet()) {
239      bufferedSink.writeUtf8(entry.getKey());
240      bufferedSink.writeUtf8("=");
241      bufferedSink.writeUtf8(entry.getValue());
242      bufferedSink.writeUtf8("\n");
243    }
244
245  }
246}
247```
248
249There isn’t an API to write a line of input; instead we manually insert our own
250newline character. Most programs should hardcode `"\n"` as the newline
251character. In rare situations you may use `System.lineSeparator()` instead of
252`"\n"`: it returns `"\r\n"` on Windows and `"\n"` everywhere else.
253
254We can write the above program more compactly by inlining the `fileSink`
255variable and by taking advantage of method chaining:
256
257=== "Java"
258
259    ```Java
260    public void writeEnv(File file) throws IOException {
261      try (BufferedSink sink = Okio.buffer(Okio.sink(file))) {
262        for (Map.Entry<String, String> entry : System.getenv().entrySet()) {
263          sink.writeUtf8(entry.getKey())
264              .writeUtf8("=")
265              .writeUtf8(entry.getValue())
266              .writeUtf8("\n");
267        }
268      }
269    }
270    ```
271
272=== "Kotlin"
273
274    ```Kotlin
275    @Throws(IOException::class)
276    fun writeEnv(file: File) {
277      file.sink().buffer().use { sink ->
278        for ((key, value) in System.getenv()) {
279          sink.writeUtf8(key)
280          sink.writeUtf8("=")
281          sink.writeUtf8(value)
282          sink.writeUtf8("\n")
283        }
284      }
285    }
286    ```
287
288In the above code we make four calls to `writeUtf8()`. Making four calls is
289more efficient than the code below because the VM doesn’t have to create and
290garbage collect a temporary string.
291
292```java
293sink.writeUtf8(entry.getKey() + "=" + entry.getValue() + "\n"); // Slower!
294```
295
296### UTF-8 ([Java][ExploreCharsets]/[Kotlin][ExploreCharsetsKt])
297
298In the above APIs you can see that Okio really likes UTF-8. Early computer
299systems suffered many incompatible character encodings: ISO-8859-1, ShiftJIS,
300ASCII, EBCDIC, etc. Writing software to support multiple character sets was
301awful and we didn’t even have emoji! Today we're lucky that the world has
302standardized on UTF-8 everywhere, with some rare uses of other charsets in
303legacy systems.
304
305If you need another character set, `readString()` and `writeString()` are there
306for you. These methods require that you specify a character set. Otherwise you
307may accidentally create data that is only readable by the local computer. Most
308programs should use the UTF-8 methods only.
309
310When encoding strings you need to be mindful of the different ways that strings
311are represented and encoded. When a glyph has an accent or another adornment
312it may be represented as a single complex code point (`é`) or as a simple code
313point (`e`) followed by its modifiers (`´`). When the entire glyph is a single
314code point that’s called [NFC][nfc]; when it’s multiple it’s [NFD][nfd].
315
316Though we use UTF-8 whenever we read or write strings in I/O, when they are in
317memory Java Strings use an obsolete character encoding called UTF-16. It is a
318bad encoding because it uses a 16-bit `char` for most characters, but some don’t
319fit. In particular, most emoji use two Java chars. This is problematic because
320`String.length()` returns a surprising result: the number of UTF-16 chars and
321not the natural number of glyphs.
322
323|                       | Café ��                     | Café ��                        |
324| --------------------: | :---------------------------| :------------------------------|
325|                  Form | [NFC][nfc]                  | [NFD][nfd]                     |
326|           Code Points | `c  a  f  é    ␣   ��     ` | `c  a  f  e  ´    ␣   ��     ` |
327|           UTF-8 bytes | `43 61 66 c3a9 20 f09f8da9` | `43 61 66 65 cc81 20 f09f8da9` |
328| String.codePointCount | 6                           | 7                              |
329|         String.length | 7                           | 8                              |
330|             Utf8.size | 10                          | 11                             |
331
332For the most part Okio lets you ignore these problems and focus on your data.
333But when you need them, there are convenient APIs for dealing with low-level
334UTF-8 strings.
335
336Use `Utf8.size()` to count the number of bytes required to encode a string as
337UTF-8 without actually encoding it. This is handy in length-prefixed encodings
338like protocol buffers.
339
340Use `BufferedSource.readUtf8CodePoint()` to read a single variable-length code
341point, and `BufferedSink.writeUtf8CodePoint()` to write one.
342
343### Golden Values ([Java][GoldenValue]/[Kotlin][GoldenValueKt])
344
345Okio likes testing. The library itself is heavily tested, and it has features
346that are often helpful when testing application code. One pattern we’ve found to
347be quite useful is “golden value” testing. The goal of such tests is to confirm
348that data encoded with earlier versions of a program can safely be decoded by
349the current program.
350
351We’ll illustrate this by encoding a value using Java Serialization. Though we
352must disclaim that Java Serialization is an awful encoding system and most
353programs should prefer other formats like JSON or protobuf! In any case, here’s
354a method that takes an object, serializes it, and returns the result as a
355`ByteString`:
356
357=== "Java"
358
359    ```Java
360    private ByteString serialize(Object o) throws IOException {
361      Buffer buffer = new Buffer();
362      try (ObjectOutputStream objectOut = new ObjectOutputStream(buffer.outputStream())) {
363        objectOut.writeObject(o);
364      }
365      return buffer.readByteString();
366    }
367    ```
368
369=== "Kotlin"
370
371    ```Kotlin
372    @Throws(IOException::class)
373    private fun serialize(o: Any?): ByteString {
374      val buffer = Buffer()
375      ObjectOutputStream(buffer.outputStream()).use { objectOut ->
376        objectOut.writeObject(o)
377      }
378      return buffer.readByteString()
379    }
380    ```
381
382There’s a lot going on here.
383
3841. We create a buffer as a holding space for our serialized data. It’s a convenient
385   replacement for `ByteArrayOutputStream`.
386
3872. We ask the buffer for its output stream. Writes to a buffer or its output stream
388   always append data to the end of the buffer.
389
3903. We create an `ObjectOutputStream` (the encoding API for Java serialization) and
391   write our object. The try block takes care of closing the stream for us. Note
392   that closing a buffer has no effect.
393
3944. Finally we read a byte string from the buffer. The `readByteString()` method
395   allows us to specify how many bytes to read; here we don’t specify a count in
396   order to read the entire thing. Reads from a buffer always consume data from
397   the front of the buffer.
398
399With our `serialize()` method handy we are ready to compute and print a golden
400value.
401
402=== "Java"
403
404    ```Java
405    Point point = new Point(8.0, 15.0);
406    ByteString pointBytes = serialize(point);
407    System.out.println(pointBytes.base64());
408    ```
409
410=== "Kotlin"
411
412    ```Kotlin
413    val point = Point(8.0, 15.0)
414    val pointBytes = serialize(point)
415    println(pointBytes.base64())
416    ```
417
418We print the `ByteString` as [base64][base64] because it’s a compact format
419that’s suitable for embedding in a test case. The program prints this:
420
421```
422rO0ABXNyAB5va2lvLnNhbXBsZXMuR29sZGVuVmFsdWUkUG9pbnTdUW8rMji1IwIAAkQAAXhEAAF5eHBAIAAAAAAAAEAuAAAAAAAA
423```
424
425That’s our golden value! We can embed it in our test case using base64 again
426to convert it back into a `ByteString`:
427
428=== "Java"
429
430    ```Java
431    ByteString goldenBytes = ByteString.decodeBase64("rO0ABXNyAB5va2lvLnNhbXBsZ"
432        + "XMuR29sZGVuVmFsdWUkUG9pbnTdUW8rMji1IwIAAkQAAXhEAAF5eHBAIAAAAAAAAEAuA"
433        + "AAAAAAA");
434    ```
435
436=== "Kotlin"
437
438    ```Kotlin
439    val goldenBytes = ("rO0ABXNyACRva2lvLnNhbXBsZXMuS290bGluR29sZGVuVmFsdWUkUG9pbnRF9yaY7cJ9EwIAA" +
440      "kQAAXhEAAF5eHBAIAAAAAAAAEAuAAAAAAAA").decodeBase64()
441    ```
442
443The next step is to deserialize the `ByteString` back into our value class. This
444method reverses the `serialize()` method above: we append a byte string to a
445buffer then consume it using an `ObjectInputStream`:
446
447=== "Java"
448
449    ```Java
450    private Object deserialize(ByteString byteString) throws IOException, ClassNotFoundException {
451      Buffer buffer = new Buffer();
452      buffer.write(byteString);
453      try (ObjectInputStream objectIn = new ObjectInputStream(buffer.inputStream())) {
454        return objectIn.readObject();
455      }
456    }
457    ```
458
459=== "Kotlin"
460
461    ```Kotlin
462    @Throws(IOException::class, ClassNotFoundException::class)
463    private fun deserialize(byteString: ByteString): Any? {
464      val buffer = Buffer()
465      buffer.write(byteString)
466      ObjectInputStream(buffer.inputStream()).use { objectIn ->
467        return objectIn.readObject()
468      }
469    }
470    ```
471
472Now we can test the decoder against the golden value:
473
474=== "Java"
475
476    ```Java
477    ByteString goldenBytes = ByteString.decodeBase64("rO0ABXNyAB5va2lvLnNhbXBsZ"
478        + "XMuR29sZGVuVmFsdWUkUG9pbnTdUW8rMji1IwIAAkQAAXhEAAF5eHBAIAAAAAAAAEAuA"
479        + "AAAAAAA");
480    Point decoded = (Point) deserialize(goldenBytes);
481    assertEquals(new Point(8.0, 15.0), decoded);
482    ```
483
484=== "Kotlin"
485
486    ```Kotlin
487    val goldenBytes = ("rO0ABXNyACRva2lvLnNhbXBsZXMuS290bGluR29sZGVuVmFsdWUkUG9pbnRF9yaY7cJ9EwIAA" +
488      "kQAAXhEAAF5eHBAIAAAAAAAAEAuAAAAAAAA").decodeBase64()!!
489    val decoded = deserialize(goldenBytes) as Point
490    assertEquals(point, decoded)
491    ```
492
493With this test we can change the serialization of the `Point` class without
494breaking compatibility.
495
496
497### Write a binary file ([Java][BitmapEncoder]/[Kotlin][BitmapEncoderKt])
498
499Encoding a binary file is not unlike encoding a text file. Okio uses the same
500`BufferedSink` and `BufferedSource` bytes for both. This is handy for binary
501formats that include both byte and character data.
502
503Writing binary data is more hazardous than text because if you make a mistake it
504is often quite difficult to diagnose. Avoid such mistakes by being careful
505around these traps:
506
507 * **The width of each field.** This is the number of bytes used. Okio doesn't
508   include a mechanism to emit partial bytes. If you need that, you’ll need to
509   do your own bit shifting and masking before writing.
510
511 * **The endianness of each field.** All fields that have more than one byte
512   have _endianness_: whether the bytes are ordered most-significant to least
513   (big endian) or least-significant to most (little endian). Okio uses the `Le`
514   suffix for little-endian methods; methods without a suffix are big-endian.
515
516 * **Signed vs. Unsigned.** Java doesn’t have unsigned primitive types (except
517   for `char`!) so coping with this is often something that happens at the
518   application layer. To make this a little easier Okio accepts `int` types for
519   `writeByte()` and `writeShort()`. You can pass an “unsigned” byte like 255
520   and Okio will do the right thing.
521
522| Method       | Width | Endianness |           Value | Encoded Value             |
523| :----------- | ----: | :--------- | --------------: | :------------------------ |
524| writeByte    |     1 |            |               3 | `03`                      |
525| writeShort   |     2 | big        |               3 | `00 03`                   |
526| writeInt     |     4 | big        |               3 | `00 00 00 03`             |
527| writeLong    |     8 | big        |               3 | `00 00 00 00 00 00 00 03` |
528| writeShortLe |     2 | little     |               3 | `03 00`                   |
529| writeIntLe   |     4 | little     |               3 | `03 00 00 00`             |
530| writeLongLe  |     8 | little     |               3 | `03 00 00 00 00 00 00 00` |
531| writeByte    |     1 |            |  Byte.MAX_VALUE | `7f`                      |
532| writeShort   |     2 | big        | Short.MAX_VALUE | `7f ff`                   |
533| writeInt     |     4 | big        |   Int.MAX_VALUE | `7f ff ff ff`             |
534| writeLong    |     8 | big        |  Long.MAX_VALUE | `7f ff ff ff ff ff ff ff` |
535| writeShortLe |     2 | little     | Short.MAX_VALUE | `ff 7f`                   |
536| writeIntLe   |     4 | little     |   Int.MAX_VALUE | `ff ff ff 7f`             |
537| writeLongLe  |     8 | little     |  Long.MAX_VALUE | `ff ff ff ff ff ff ff 7f` |
538
539This code encodes a bitmap following the [BMP file format][bmp].
540
541=== "Java"
542
543    ```Java
544    void encode(Bitmap bitmap, BufferedSink sink) throws IOException {
545      int height = bitmap.height();
546      int width = bitmap.width();
547
548      int bytesPerPixel = 3;
549      int rowByteCountWithoutPadding = (bytesPerPixel * width);
550      int rowByteCount = ((rowByteCountWithoutPadding + 3) / 4) * 4;
551      int pixelDataSize = rowByteCount * height;
552      int bmpHeaderSize = 14;
553      int dibHeaderSize = 40;
554
555      // BMP Header
556      sink.writeUtf8("BM"); // ID.
557      sink.writeIntLe(bmpHeaderSize + dibHeaderSize + pixelDataSize); // File size.
558      sink.writeShortLe(0); // Unused.
559      sink.writeShortLe(0); // Unused.
560      sink.writeIntLe(bmpHeaderSize + dibHeaderSize); // Offset of pixel data.
561
562      // DIB Header
563      sink.writeIntLe(dibHeaderSize);
564      sink.writeIntLe(width);
565      sink.writeIntLe(height);
566      sink.writeShortLe(1);  // Color plane count.
567      sink.writeShortLe(bytesPerPixel * Byte.SIZE);
568      sink.writeIntLe(0);    // No compression.
569      sink.writeIntLe(16);   // Size of bitmap data including padding.
570      sink.writeIntLe(2835); // Horizontal print resolution in pixels/meter. (72 dpi).
571      sink.writeIntLe(2835); // Vertical print resolution in pixels/meter. (72 dpi).
572      sink.writeIntLe(0);    // Palette color count.
573      sink.writeIntLe(0);    // 0 important colors.
574
575      // Pixel data.
576      for (int y = height - 1; y >= 0; y--) {
577        for (int x = 0; x < width; x++) {
578          sink.writeByte(bitmap.blue(x, y));
579          sink.writeByte(bitmap.green(x, y));
580          sink.writeByte(bitmap.red(x, y));
581        }
582
583        // Padding for 4-byte alignment.
584        for (int p = rowByteCountWithoutPadding; p < rowByteCount; p++) {
585          sink.writeByte(0);
586        }
587      }
588    }
589    ```
590
591=== "Kotlin"
592
593    ```Kotlin
594    @Throws(IOException::class)
595    fun encode(bitmap: Bitmap, sink: BufferedSink) {
596      val height = bitmap.height
597      val width = bitmap.width
598      val bytesPerPixel = 3
599      val rowByteCountWithoutPadding = bytesPerPixel * width
600      val rowByteCount = (rowByteCountWithoutPadding + 3) / 4 * 4
601      val pixelDataSize = rowByteCount * height
602      val bmpHeaderSize = 14
603      val dibHeaderSize = 40
604
605      // BMP Header
606      sink.writeUtf8("BM") // ID.
607      sink.writeIntLe(bmpHeaderSize + dibHeaderSize + pixelDataSize) // File size.
608      sink.writeShortLe(0) // Unused.
609      sink.writeShortLe(0) // Unused.
610      sink.writeIntLe(bmpHeaderSize + dibHeaderSize) // Offset of pixel data.
611
612      // DIB Header
613      sink.writeIntLe(dibHeaderSize)
614      sink.writeIntLe(width)
615      sink.writeIntLe(height)
616      sink.writeShortLe(1) // Color plane count.
617      sink.writeShortLe(bytesPerPixel * Byte.SIZE_BITS)
618      sink.writeIntLe(0) // No compression.
619      sink.writeIntLe(16) // Size of bitmap data including padding.
620      sink.writeIntLe(2835) // Horizontal print resolution in pixels/meter. (72 dpi).
621      sink.writeIntLe(2835) // Vertical print resolution in pixels/meter. (72 dpi).
622      sink.writeIntLe(0) // Palette color count.
623      sink.writeIntLe(0) // 0 important colors.
624
625      // Pixel data.
626      for (y in height - 1 downTo 0) {
627        for (x in 0 until width) {
628          sink.writeByte(bitmap.blue(x, y))
629          sink.writeByte(bitmap.green(x, y))
630          sink.writeByte(bitmap.red(x, y))
631        }
632
633        // Padding for 4-byte alignment.
634        for (p in rowByteCountWithoutPadding until rowByteCount) {
635          sink.writeByte(0)
636        }
637      }
638    }
639    ```
640
641The trickiest part of this program is the format’s required padding. The BMP
642format expects each row to begin on a 4-byte boundary so it is necessary to add
643zeros to maintain the alignment.
644
645Encoding other binary formats is usually quite similar. Some tips:
646
647 * Write tests with golden values! Confirming that your program emits the
648   expected result can make debugging easier.
649 * Use `Utf8.size()` to compute the number of bytes of an encoded string. This
650   is essential for length-prefixed formats.
651 * Use `Float.floatToIntBits()` and `Double.doubleToLongBits()` to encode
652   floating point values.
653
654
655### Communicate on a Socket ([Java][SocksProxyServer]/[Kotlin][SocksProxyServerKt])
656
657Sending and receiving data over the network is a bit like writing and reading
658files. We use `BufferedSink` to encode output and `BufferedSource` to decode
659input. Like files, network protocols can be text, binary, or a mix of both. But
660there are also some substantial differences between the network and the
661file system.
662
663With a file you’re either reading or writing but with the network you can do
664both! Some protocols handle this by taking turns: write a request, read a
665response, repeat. You can implement this kind of protocol with a single thread.
666In other protocols you may read and write simultaneously. Typically you’ll want
667one dedicated thread for reading. For writing you can use either a dedicated
668thread or use `synchronized` so that multiple threads can share a sink. Okio’s
669streams are not safe for concurrent use.
670
671Sinks buffer outbound data to minimize I/O operations. This is efficient but it
672means you must manually call `flush()` to transmit data. Typically
673message-oriented protocols flush after each message. Note that Okio will
674automatically flush when the buffered data exceeds some threshold. This is
675intended to save memory and you shouldn’t rely on it for interactive protocols.
676
677Okio builds on `java.io.Socket` for connectivity. Create your socket as a server
678or as a client, then use `Okio.source(Socket)` to read and `Okio.sink(Socket)`
679to write. These APIs also work with `SSLSocket`. You should use SSL unless you
680have a very good reason not to!
681
682Cancel a socket from any thread by calling `Socket.close()`; this will cause its
683sources and sinks to immediately fail with an `IOException`. You can also
684configure timeouts for all socket operations. You don’t need a reference to the
685socket to adjust timeouts: `Source` and `Sink` expose timeouts directly. This
686API works even if the streams are decorated.
687
688As a complete example of networking with Okio we wrote a [basic SOCKS
689proxy][SocksProxyServer] server. Some highlights:
690
691=== "Java"
692
693    ```Java
694    Socket fromSocket = ...
695    BufferedSource fromSource = Okio.buffer(Okio.source(fromSocket));
696    BufferedSink fromSink = Okio.buffer(Okio.sink(fromSocket));
697    ```
698
699=== "Kotlin"
700
701    ```Kotlin
702    val fromSocket: Socket = ...
703    val fromSource = fromSocket.source().buffer()
704    val fromSink = fromSocket.sink().buffer()
705    ```
706
707Creating sources and sinks for sockets is the same as creating them for files.
708Once you create a `Source` or `Sink` for a socket you must not use its
709`InputStream` or `OutputStream`, respectively.
710
711=== "Java"
712
713    ```Java
714    Buffer buffer = new Buffer();
715    for (long byteCount; (byteCount = source.read(buffer, 8192L)) != -1; ) {
716      sink.write(buffer, byteCount);
717      sink.flush();
718    }
719    ```
720
721=== "Kotlin"
722
723    ```Kotlin
724    val buffer = Buffer()
725    var byteCount: Long
726    while (source.read(buffer, 8192L).also { byteCount = it } != -1L) {
727      sink.write(buffer, byteCount)
728      sink.flush()
729    }
730    ```
731
732The above loop copies data from the source to the sink, flushing after each
733read. If we didn’t need the flushing we could replace this loop with a single
734call to `BufferedSink.writeAll(Source)`.
735
736The `8192` argument to `read()` is the maximum number of bytes to read before
737returning. We could have passed any value here, but we like 8 KiB because that’s
738the largest value Okio can do in a single system call. Most of the time
739application code doesn’t need to deal with such limits!
740
741=== "Java"
742
743    ```Java
744    int addressType = fromSource.readByte() & 0xff;
745    int port = fromSource.readShort() & 0xffff;
746    ```
747
748=== "Kotlin"
749
750    ```Kotlin
751    val addressType = fromSource.readByte().toInt() and 0xff
752    val port = fromSource.readShort().toInt() and 0xffff
753    ```
754
755Okio uses signed types like `byte` and `short`, but often protocols want
756unsigned values. The bitwise `&` operator is Java’s preferred idiom to convert
757a signed value into an unsigned value. Here’s a cheat sheet for bytes, shorts,
758and ints:
759
760| Type  | Signed Range                  | Unsigned Range   | Signed to Unsigned          |
761| :---- | :---------------------------: | :--------------- | :-------------------------- |
762| byte  | -128..127                     | 0..255           | `int u = s & 0xff;`         |
763| short | -32,768..32,767               | 0..65,535        | `int u = s & 0xffff;`       |
764| int   | -2,147,483,648..2,147,483,647 | 0..4,294,967,295 | `long u = s & 0xffffffffL;` |
765
766Java has no primitive type that can represent unsigned longs.
767
768
769### Hashing ([Java][Hashing]/[Kotlin][HashingKt])
770
771We’re bombarded by hashing in our lives as Java programmers. Early on we're introduced to the
772`hashCode()` method, something we know we need to override otherwise unforeseen bad things happen.
773Later we’re shown `LinkedHashMap` and its friends. These build on that `hashCode()` method to
774organize data for fast retrieval.
775
776Elsewhere we have cryptographic hash functions. These get used all over the place. HTTPS
777certificates, Git commits, BitTorrent integrity checking, and Blockchain blocks all use
778cryptographic hashes. Good use of hashes can improve the performance, privacy, security, and
779simplicity of an application.
780
781Each cryptographic hash function accepts a variable-length stream of input bytes and produces a
782fixed-length byte string value called the “hash”. Hash functions have these important qualities:
783
784 * Deterministic: each input always produces the same output.
785 * Uniform: each output byte string is equally likely. It is very difficult to find or create pairs
786   of different inputs that yield the same output. This is called a “collision”.
787 * Non-reversible: knowing an output doesn't help you to find the input. Note that if you know some
788   possible inputs you can hash them to see if their hashes match.
789 * Well-known: the hash is implemented everywhere and rigorously understood.
790
791Good hash functions are very cheap to compute (dozens of microseconds) and expensive to reverse
792(quintillions of millenia). Steady advances in computing and mathematics have caused once-great hash
793functions to become inexpensive to reverse. When choosing a hash function, beware that not all are
794created equal! Okio supports these well-known cryptographic hash functions:
795
796 * **MD5**: a 128-bit (16 byte) cryptographic hash. It is both insecure and obsolete because it is
797   inexpensive to reverse! This hash is offered because it is popular and convenient for use in
798   legacy systems that are not security-sensitive.
799 * **SHA-1**: a 160-bit (20 byte) cryptographic hash. It was recently demonstrated that it is
800   feasible to create SHA-1 collisions. Consider upgrading from SHA-1 to SHA-256.
801 * **SHA-256**: a 256-bit (32 byte) cryptographic hash. SHA-256 is widely understood and expensive
802   to reverse. This is the hash most systems should use.
803 * **SHA-512**: a 512-bit (64 byte) cryptographic hash. It is expensive to reverse.
804
805Each hash creates a `ByteString` of the specified length. Use `hex()` to get the conventional
806human-readable form. Or leave it as a `ByteString` because that’s a convenient model type!
807
808Okio can produce cryptographic hashes from byte strings:
809
810=== "Java"
811
812    ```Java
813    ByteString byteString = readByteString(new File("README.md"));
814    System.out.println("   md5: " + byteString.md5().hex());
815    System.out.println("  sha1: " + byteString.sha1().hex());
816    System.out.println("sha256: " + byteString.sha256().hex());
817    System.out.println("sha512: " + byteString.sha512().hex());
818    ```
819
820=== "Kotlin"
821
822    ```Kotlin
823    val byteString = readByteString(File("README.md"))
824    println("       md5: " + byteString.md5().hex())
825    println("      sha1: " + byteString.sha1().hex())
826    println("    sha256: " + byteString.sha256().hex())
827    println("    sha512: " + byteString.sha512().hex())
828    ```
829
830From buffers:
831
832=== "Java"
833
834    ```Java
835    Buffer buffer = readBuffer(new File("README.md"));
836    System.out.println("   md5: " + buffer.md5().hex());
837    System.out.println("  sha1: " + buffer.sha1().hex());
838    System.out.println("sha256: " + buffer.sha256().hex());
839    System.out.println("sha512: " + buffer.sha512().hex());
840    ```
841
842=== "Kotlin"
843
844    ```Kotlin
845    val buffer = readBuffer(File("README.md"))
846    println("       md5: " + buffer.md5().hex())
847    println("      sha1: " + buffer.sha1().hex())
848    println("    sha256: " + buffer.sha256().hex())
849    println("    sha512: " + buffer.sha512().hex())
850    ```
851
852While streaming from a source:
853
854=== "Java"
855
856    ```Java
857    try (HashingSink hashingSink = HashingSink.sha256(Okio.blackhole());
858         BufferedSource source = Okio.buffer(Okio.source(file))) {
859      source.readAll(hashingSink);
860      System.out.println("sha256: " + hashingSink.hash().hex());
861    }
862    ```
863
864=== "Kotlin"
865
866    ```Kotlin
867    sha256(blackholeSink()).use { hashingSink ->
868      file.source().buffer().use { source ->
869        source.readAll(hashingSink)
870        println("    sha256: " + hashingSink.hash.hex())
871      }
872    }
873    ```
874
875While streaming to a sink:
876
877=== "Java"
878
879    ```Java
880    try (HashingSink hashingSink = HashingSink.sha256(Okio.blackhole());
881         BufferedSink sink = Okio.buffer(hashingSink);
882         Source source = Okio.source(file)) {
883      sink.writeAll(source);
884      sink.close(); // Emit anything buffered.
885      System.out.println("sha256: " + hashingSink.hash().hex());
886    }
887    ```
888
889=== "Kotlin"
890
891    ```Kotlin
892    sha256(blackholeSink()).use { hashingSink ->
893      hashingSink.buffer().use { sink ->
894        file.source().use { source ->
895          sink.writeAll(source)
896          sink.close() // Emit anything buffered.
897          println("    sha256: " + hashingSink.hash.hex())
898        }
899      }
900    }
901    ```
902
903Okio also supports HMAC (Hash Message Authentication Code) which combines a secret and a hash.
904Applications use HMAC for data integrity and authentication.
905
906=== "Java"
907
908    ```Java
909    ByteString secret = ByteString.decodeHex("7065616e7574627574746572");
910    System.out.println("hmacSha256: " + byteString.hmacSha256(secret).hex());
911    ```
912
913=== "Kotlin"
914
915    ```Kotlin
916    val secret = "7065616e7574627574746572".decodeHex()
917    println("hmacSha256: " + byteString.hmacSha256(secret).hex())
918    ```
919
920As with hashing, you can generate an HMAC from a `ByteString`, `Buffer`, `HashingSource`, and
921`HashingSink`. Note that Okio doesn’t implement HMAC for MD5. Okio uses Java’s
922`java.security.MessageDigest` for cryptographic hashes and `javax.crypto.Mac` for HMAC.
923
924### Encryption and Decryption
925
926Use `Okio.cipherSink(Sink, Cipher)` or `Okio.cipherSource(Source, Cipher)` to encrypt or decrypt a
927stream using a block cipher.
928
929Callers are responsible for the initialization of the encryption or decryption cipher with the
930chosen algorithm, the key, and algorithm-specific additional parameters like the initialization
931vector. The following example shows a typical usage with AES encryption, in which `key` and `iv`
932parameters should both be 16 bytes long.
933
934```java
935void encryptAes(ByteString bytes, File file, byte[] key, byte[] iv)
936    throws GeneralSecurityException, IOException {
937  Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
938  cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv));
939  try (BufferedSink sink = Okio.buffer(Okio.cipherSink(Okio.sink(file), cipher))) {
940    sink.write(bytes);
941  }
942}
943
944ByteString decryptAesToByteString(File file, byte[] key, byte[] iv)
945    throws GeneralSecurityException, IOException {
946  Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
947  cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv));
948  try (BufferedSource source = Okio.buffer(Okio.cipherSource(Okio.source(file), cipher))) {
949    return source.readByteString();
950  }
951}
952```
953
954In Kotlin, these encryption and decryption methods are extensions on `Cipher`:
955
956```kotlin
957fun encryptAes(bytes: ByteString, file: File, key: ByteArray, iv: ByteArray) {
958  val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
959  cipher.init(Cipher.ENCRYPT_MODE, SecretKeySpec(key, "AES"), IvParameterSpec(iv))
960  val cipherSink = file.sink().cipherSink(cipher)
961  cipherSink.buffer().use {
962    it.write(bytes)
963  }
964}
965
966fun decryptAesToByteString(file: File, key: ByteArray, iv: ByteArray): ByteString {
967  val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
968  cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(key, "AES"), IvParameterSpec(iv))
969  val cipherSource = file.source().cipherSource(cipher)
970  return cipherSource.buffer().use {
971    it.readByteString()
972  }
973}
974```
975
976File System Examples
977--------------------
978
979Okio's recently gained a multiplatform file system API. These examples work on JVM, native, and
980Node.js platforms. In the examples below `fileSystem` is an instance of [FileSystem] such as
981`FileSystem.SYSTEM` or `FakeFileSystem`.
982
983Read all of `readme.md` as a string:
984
985```
986val path = "readme.md".toPath()
987val entireFileString = fileSystem.read(path) {
988  readUtf8()
989}
990```
991
992Read all of `thumbnail.png` as a [ByteString][3]:
993
994```
995val path = "thumbnail.png".toPath()
996val entireFileByteString = fileSystem.read(path) {
997  readByteString()
998}
999```
1000
1001Read all lines of `/etc/hosts` into a `List<String>`:
1002
1003```
1004val path = "/etc/hosts".toPath()
1005val allLines = fileSystem.read(path) {
1006  generateSequence { readUtf8Line() }.toList()
1007}
1008```
1009
1010Read the prefix of `index.html` that precedes the first `<html>` substring:
1011
1012```
1013val path = "index.html".toPath()
1014val untilHtmlTag = fileSystem.read(path) {
1015  val htmlTag = indexOf("<html>".encodeUtf8())
1016  if (htmlTag != -1L) readUtf8(htmlTag) else null
1017}
1018```
1019
1020Write `readme.md` as a string:
1021
1022```
1023val path = "readme.md".toPath()
1024fileSystem.write(path) {
1025  writeUtf8(
1026    """
1027    |Hello, World
1028    |------------
1029    |
1030    |This is a sample file.
1031    |""".trimMargin()
1032  )
1033}
1034```
1035
1036Write `data.bin` as a [ByteString][3]:
1037
1038```
1039val path = "data.bin".toPath()
1040fileSystem.write(path) {
1041  val byteString = "68656c6c6f20776f726c640a".decodeHex()
1042  write(byteString)
1043}
1044```
1045
1046Write `readme.md` from a `List<String>`:
1047
1048```
1049val path = "readme.md".toPath()
1050val lines = listOf(
1051  "Hello, World",
1052  "------------",
1053  "",
1054  "This is a sample file.",
1055  ""
1056)
1057fileSystem.write(path) {
1058  for (line in lines) {
1059    writeUtf8(line)
1060    writeUtf8("\n")
1061  }
1062}
1063```
1064
1065Generate `binary.txt` programmatically:
1066
1067```
1068val path = "binary.txt".toPath()
1069fileSystem.write(path) {
1070  for (i in 1 until 100) {
1071    writeUtf8("$i ${i.toString(2)}")
1072    writeUtf8("\n")
1073  }
1074}
1075```
1076
1077
1078Releases
1079--------
1080
1081Our [change log][changelog] has release history.
1082
1083```kotlin
1084implementation("com.squareup.okio:okio:2.10.0")
1085```
1086
1087<details>
1088   <summary>Snapshot builds are also available</summary>
1089
1090```kotlin
1091repositories {
1092    maven {
1093        url = uri("https://oss.sonatype.org/content/repositories/snapshots/")
1094    }
1095}
1096
1097dependencies {
1098   implementation("com.squareup.okio:okio:2.10.0")
1099}
1100```
1101
1102</details>
1103
1104
1105R8 / ProGuard
1106--------
1107
1108If you are using R8 or ProGuard add the options from [this file][proguard].
1109
1110
1111License
1112--------
1113
1114    Copyright 2013 Square, Inc.
1115
1116    Licensed under the Apache License, Version 2.0 (the "License");
1117    you may not use this file except in compliance with the License.
1118    You may obtain a copy of the License at
1119
1120       http://www.apache.org/licenses/LICENSE-2.0
1121
1122    Unless required by applicable law or agreed to in writing, software
1123    distributed under the License is distributed on an "AS IS" BASIS,
1124    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1125    See the License for the specific language governing permissions and
1126    limitations under the License.
1127
1128 [1]: https://github.com/square/okhttp
1129 [3]: https://square.github.io/okio/2.x/okio/okio/-byte-string/index.html
1130 [4]: https://square.github.io/okio/2.x/okio/okio/-buffer/index.html
1131 [5]: https://square.github.io/okio/2.x/okio/okio/-source/index.html
1132 [6]: https://square.github.io/okio/2.x/okio/okio/-sink/index.html
1133 [7]: https://square.github.io/okio/2.x/okio/okio/-buffered-source/index.html
1134 [8]: https://square.github.io/okio/2.x/okio/okio/-buffered-sink/index.html
1135 [changelog]: http://square.github.io/okio/changelog/
1136 [javadoc]: https://square.github.io/okio/2.x/okio/okio/index.html
1137 [nfd]: https://docs.oracle.com/javase/7/docs/api/java/text/Normalizer.Form.html#NFD
1138 [nfc]: https://docs.oracle.com/javase/7/docs/api/java/text/Normalizer.Form.html#NFC
1139 [base64]: https://tools.ietf.org/html/rfc4648#section-4
1140 [bmp]: https://en.wikipedia.org/wiki/BMP_file_format
1141 [kotlin]: https://kotlinlang.org/
1142 [ok_libraries_talk]: https://www.youtube.com/watch?v=WvyScM_S88c
1143 [ok_libraries_slides]: https://speakerdeck.com/jakewharton/a-few-ok-libraries-droidcon-mtl-2015
1144 [encoding_talk]: https://www.youtube.com/watch?v=T_p22jMZSrk
1145 [encoding_slides]: https://speakerdeck.com/swankjesse/decoding-the-secrets-of-binary-data-droidcon-nyc-2016
1146 [ok_multiplatform_talk]: https://www.youtube.com/watch?v=Q8B4eDirgk0
1147 [ok_multiplatform_slides]: https://speakerdeck.com/swankjesse/ok-multiplatform
1148 [ReadFileLineByLine]: https://github.com/square/okio/blob/master/samples/src/jvmMain/java/okio/samples/ReadFileLineByLine.java
1149 [ReadFileLineByLineKt]: https://github.com/square/okio/blob/master/samples/src/jvmMain/kotlin/okio/samples/ReadFileLineByLine.kt
1150 [WriteFile]: https://github.com/square/okio/blob/master/samples/src/jvmMain/java/okio/samples/WriteFile.java
1151 [WriteFileKt]: https://github.com/square/okio/blob/master/samples/src/jvmMain/kotlin/okio/samples/WriteFile.kt
1152 [ExploreCharsets]: https://github.com/square/okio/blob/master/samples/src/jvmMain/java/okio/samples/ExploreCharsets.java
1153 [ExploreCharsetsKt]: https://github.com/square/okio/blob/master/samples/src/jvmMain/kotlin/okio/samples/ExploreCharsets.kt
1154 [FileSystem]: https://square.github.io/okio/2.x/okio/okio/-file-system/index.html
1155 [GoldenValue]: https://github.com/square/okio/blob/master/samples/src/jvmMain/java/okio/samples/GoldenValue.java
1156 [GoldenValueKt]: https://github.com/square/okio/blob/master/samples/src/jvmMain/kotlin/okio/samples/GoldenValue.kt
1157 [BitmapEncoder]: https://github.com/square/okio/blob/master/samples/src/jvmMain/java/okio/samples/BitmapEncoder.java
1158 [BitmapEncoderKt]: https://github.com/square/okio/blob/master/samples/src/jvmMain/kotlin/okio/samples/BitmapEncoder.kt
1159 [SocksProxyServer]: https://github.com/square/okio/blob/master/samples/src/jvmMain/java/okio/samples/SocksProxyServer.java
1160 [SocksProxyServerKt]: https://github.com/square/okio/blob/master/samples/src/jvmMain/kotlin/okio/samples/SocksProxyServer.kt
1161 [Hashing]: https://github.com/square/okio/blob/master/samples/src/jvmMain/java/okio/samples/Hashing.java
1162 [HashingKt]: https://github.com/square/okio/blob/master/samples/src/jvmMain/kotlin/okio/samples/Hashing.kt
1163 [proguard]: https://github.com/square/okio/blob/master/okio/src/jvmMain/resources/META-INF/proguard/okio.pro
1164