xref: /aosp_15_r20/external/okio/docs/recipes.md (revision f9742813c14b702d71392179818a9e591da8620c)
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