1/* Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to deal
5 * in the Software without restriction, including without limitation the rights
6 * to use, copy, modify, merge, publish, distribute, sublicense, and/or
7 * sell copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
9 *
10 * The  above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19 * IN THE SOFTWARE. */
20
21package org.ksoap2.kobjects.mime;
22
23import java.io.*;
24import java.util.*;
25import org.ksoap2.kobjects.base64.*;
26
27public class Decoder {
28
29    InputStream is;
30    Hashtable header;
31    boolean eof;
32    boolean consumed;
33    String boundary;
34    String characterEncoding;
35
36    char[] buf = new char[256];
37
38    // add some kind of buffering here!!!
39
40    private final String readLine() throws IOException {
41
42        int cnt = 0;
43
44        while (true) {
45            int i = is.read();
46            if (i == -1 && cnt == 0)
47                return null;
48            else if (i == -1 || i == '\n')
49                return new String(buf, 0, cnt);
50            else if (i != '\r') {
51                if (cnt >= buf.length) {
52                    char[] tmp = new char[(buf.length * 3) / 2];
53                    System.arraycopy(buf, 0, tmp, 0, buf.length);
54                    buf = tmp;
55                }
56
57                buf[cnt++] = (char) i;
58            }
59        }
60    }
61
62    /**
63     * The "main" element is returned in the
64     * hashtable with an empty key ("") */
65
66    public static Hashtable getHeaderElements(String header) {
67
68        String key = "";
69        int pos = 0;
70        Hashtable result = new Hashtable();
71        int len = header.length();
72
73        while (true) {
74            // skip spaces
75
76            while (pos < len && header.charAt(pos) <= ' ')
77                pos++;
78            if (pos >= len)
79                break;
80
81            if (header.charAt(pos) == '"') {
82                pos++;
83                int cut = header.indexOf('"', pos);
84                if (cut == -1)
85                    throw new RuntimeException("End quote expected in " + header);
86
87                result.put(key, header.substring(pos, cut));
88                pos = cut + 2;
89
90                if (pos >= len)
91                    break;
92                if (header.charAt(pos - 1) != ';')
93                    throw new RuntimeException("; expected in " + header);
94            }
95            else {
96                int cut = header.indexOf(';', pos);
97                if (cut == -1) {
98                    result.put(key, header.substring(pos));
99                    break;
100                }
101                result.put(key, header.substring(pos, cut));
102                pos = cut + 1;
103            }
104
105            int cut = header.indexOf('=', pos);
106
107            if (cut == -1)
108                break;
109
110            key = header.substring(pos, cut).toLowerCase().trim();
111            pos = cut + 1;
112        }
113        //     System.out.println("header: "+result);
114
115        return result;
116    }
117
118    public Decoder(InputStream is, String _bound) throws IOException {
119        this(is, _bound, null);
120    }
121
122    public Decoder(InputStream is, String _bound, String characterEncoding) throws IOException {
123
124        this.characterEncoding = characterEncoding;
125        this.is = is;
126        this.boundary = "--" + _bound;
127
128        //        StringBuffer buf = new StringBuffer();
129
130        String line = null;
131        while (true) {
132            line = readLine();
133            if (line == null)
134                throw new IOException("Unexpected EOF");
135
136            //      System.out.println("line:  '" + line + "'");
137            //      System.out.println("bound: '" + boundary + "'");
138
139            if (line.startsWith(boundary))
140                break;
141            //            buf.append(line);
142        }
143
144        //        data = buf.toString().getBytes();
145        if (line.endsWith("--")) {
146            eof = true;
147            is.close();
148        }
149
150        consumed = true;
151    }
152
153    public Enumeration getHeaderNames() {
154        return header.keys();
155    }
156
157    public String getHeader(String key) {
158        return (String) header.get(key.toLowerCase());
159    }
160
161    public String readContent() throws IOException {
162        ByteArrayOutputStream bos = new ByteArrayOutputStream();
163        readContent(bos);
164        String result = characterEncoding == null
165                ? new String(bos.toByteArray())
166                : new String(bos.toByteArray(), characterEncoding);
167
168        System.out.println("Field content: '" + result + "'");
169        return result;
170    }
171
172    public void readContent(OutputStream os) throws IOException {
173        if (consumed)
174            throw new RuntimeException("Content already consumed!");
175
176        String line = "";
177
178        String contentType = getHeader("Content-Type");
179        //              System.out.println("header: " + header);
180        //              System.out.println("Content-Type: "+contentType);
181
182        if ("base64".equals(getHeader("Content-Transfer-Encoding"))) {
183            ByteArrayOutputStream bos = new ByteArrayOutputStream();
184            while (true) {
185                line = readLine();
186                if (line == null)
187                    throw new IOException("Unexpected EOF");
188                if (line.startsWith(boundary))
189                    break;
190
191                Base64.decode(line, os);
192            }
193        }
194        else {
195
196            String deli = "\r\n" + boundary;
197            int match = 0;
198
199            while (true) {
200                int i = is.read();
201                /*                if (i >= 32 && i <= 127)
202                                    System.out.print((char) i);
203                                else
204                                    System.out.print("#" + i + ";"); */
205                if (i == -1)
206                    throw new RuntimeException("Unexpected EOF");
207
208                if (((char) i) == deli.charAt(match)) {
209                    match++;
210                    if (match == deli.length())
211                        break;
212                }
213                else {
214                    if (match > 0) {
215                        for (int j = 0; j < match; j++)
216                            os.write((byte) deli.charAt(j));
217
218                        match = ((char) i == deli.charAt(0)) ? 1 : 0;
219                    }
220                    if (match == 0)
221                        os.write((byte) i);
222                }
223            }
224
225            line = readLine(); // read crlf and possibly remaining --
226        }
227
228        if (line.endsWith("--"))
229            eof = true;
230
231        consumed = true;
232    }
233
234    // public boolean next() throws IOException {
235
236    //             if(!consumed)
237    //                     readContent(null);
238
239    //     if (eof)
240    //         return false;
241
242    //     // read header
243
244    //     header = new Hashtable();
245    //     String line;
246
247    //     while (true) {
248    //         line = readLine();
249    //         if (line == null || line.equals(""))
250    //             break;
251    //         int cut = line.indexOf(':');
252    //         if (cut == -1)
253    //             throw new IOException("colon missing in multipart header line: " + line);
254
255    //         header.put(
256    //             line.substring(0, cut).trim().toLowerCase(),
257    //             line.substring(cut + 1).trim());
258    /*
259                System.out.println(
260                    "key: '"
261                        + line.substring(0, cut).trim().toLowerCase()
262                        + "' value: '"
263                        + line.substring(cut + 1).trim());*/
264
265    //     }
266
267    //             consumed = false;
268    //
269    //     return true;
270    // }
271}
272