• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
21 //Contributors: Jonathan Cox, Bogdan Onoiu, Jerry Tian
22 // Greatly simplified for Google, Inc. by Marc Blank
23 
24 package com.android.exchange.adapter;
25 
26 import android.content.ContentValues;
27 import android.util.Log;
28 
29 import com.android.exchange.Eas;
30 import com.android.exchange.utility.FileLogger;
31 import com.google.common.annotations.VisibleForTesting;
32 
33 import java.io.ByteArrayOutputStream;
34 import java.io.IOException;
35 import java.io.InputStream;
36 import java.io.OutputStream;
37 
38 public class Serializer {
39     private static final String TAG = "Serializer";
40     private static final int BUFFER_SIZE = 16*1024;
41     private static final int NOT_PENDING = -1;
42 
43     private final OutputStream mOutput;
44     private int mPendingTag = NOT_PENDING;
45     private int mDepth;
46     private String[] mNameStack = new String[20];
47     private int mTagPage = 0;
48     private boolean mLogging = Log.isLoggable(TAG, Log.VERBOSE);
49 
Serializer()50     public Serializer() throws IOException {
51         this(new ByteArrayOutputStream(), true);
52     }
53 
Serializer(OutputStream os)54     public Serializer(OutputStream os) throws IOException {
55         this(os, true);
56     }
57 
58     @VisibleForTesting
Serializer(boolean startDocument)59     public Serializer(boolean startDocument) throws IOException {
60         this(new ByteArrayOutputStream(), startDocument);
61     }
62 
63     /**
64      * Base constructor
65      * @param outputStream the stream we're serializing to
66      * @param startDocument whether or not to start a document
67      * @param _logging whether or not to log our output
68      * @throws IOException
69      */
Serializer(OutputStream outputStream, boolean startDocument)70     public Serializer(OutputStream outputStream, boolean startDocument) throws IOException {
71         super();
72         mOutput = outputStream;
73         if (startDocument) {
74             startDocument();
75         } else {
76             mOutput.write(0);
77         }
78     }
79 
log(String str)80     void log(String str) {
81         int cr = str.indexOf('\n');
82         if (cr > 0) {
83             str = str.substring(0, cr);
84         }
85         Log.v(TAG, str);
86         if (Eas.FILE_LOG) {
87             FileLogger.log(TAG, str);
88         }
89     }
90 
done()91     public void done() throws IOException {
92         if (mDepth != 0) {
93             throw new IOException("Done received with unclosed tags");
94         }
95         mOutput.flush();
96     }
97 
startDocument()98     public void startDocument() throws IOException{
99         mOutput.write(0x03); // version 1.3
100         mOutput.write(0x01); // unknown or missing public identifier
101         mOutput.write(106);  // UTF-8
102         mOutput.write(0);    // 0 length string array
103     }
104 
checkPendingTag(boolean degenerated)105     public void checkPendingTag(boolean degenerated) throws IOException {
106         if (mPendingTag == NOT_PENDING)
107             return;
108 
109         int page = mPendingTag >> Tags.PAGE_SHIFT;
110         int tag = mPendingTag & Tags.PAGE_MASK;
111         if (page != mTagPage) {
112             mTagPage = page;
113             mOutput.write(Wbxml.SWITCH_PAGE);
114             mOutput.write(page);
115         }
116 
117         mOutput.write(degenerated ? tag : tag | Wbxml.WITH_CONTENT);
118         if (mLogging) {
119             String name = Tags.pages[page][tag - 5];
120             mNameStack[mDepth] = name;
121             log("<" + name + '>');
122         }
123         mPendingTag = NOT_PENDING;
124     }
125 
start(int tag)126     public Serializer start(int tag) throws IOException {
127         checkPendingTag(false);
128         mPendingTag = tag;
129         mDepth++;
130         return this;
131     }
132 
end()133     public Serializer end() throws IOException {
134         if (mPendingTag >= 0) {
135             checkPendingTag(true);
136         } else {
137             mOutput.write(Wbxml.END);
138             if (mLogging) {
139                 log("</" + mNameStack[mDepth] + '>');
140             }
141         }
142         mDepth--;
143         return this;
144     }
145 
tag(int t)146     public Serializer tag(int t) throws IOException {
147         start(t);
148         end();
149         return this;
150     }
151 
data(int tag, String value)152     public Serializer data(int tag, String value) throws IOException {
153         if (value == null) {
154             Log.e(TAG, "Writing null data for tag: " + tag);
155         }
156         start(tag);
157         text(value);
158         end();
159         return this;
160     }
161 
text(String text)162     public Serializer text(String text) throws IOException {
163         if (text == null) {
164             Log.e(TAG, "Writing null text for pending tag: " + mPendingTag);
165         }
166         checkPendingTag(false);
167         mOutput.write(Wbxml.STR_I);
168         writeLiteralString(mOutput, text);
169         if (mLogging) {
170             log(text);
171         }
172         return this;
173     }
174 
opaque(InputStream is, int length)175     public Serializer opaque(InputStream is, int length) throws IOException {
176         checkPendingTag(false);
177         mOutput.write(Wbxml.OPAQUE);
178         writeInteger(mOutput, length);
179         if (mLogging) {
180             log("Opaque, length: " + length);
181         }
182         // Now write out the opaque data in batches
183         byte[] buffer = new byte[BUFFER_SIZE];
184         while (length > 0) {
185             int bytesRead = is.read(buffer, 0, (int)Math.min(BUFFER_SIZE, length));
186             if (bytesRead == -1) {
187                 break;
188             }
189             mOutput.write(buffer, 0, bytesRead);
190             length -= bytesRead;
191         }
192         return this;
193     }
194 
opaqueWithoutData(int length)195     public Serializer opaqueWithoutData(int length) throws IOException {
196         checkPendingTag(false);
197         mOutput.write(Wbxml.OPAQUE);
198         writeInteger(mOutput, length);
199         return this;
200     }
201 
writeInteger(OutputStream out, int i)202     void writeInteger(OutputStream out, int i) throws IOException {
203         byte[] buf = new byte[5];
204         int idx = 0;
205 
206         do {
207             buf[idx++] = (byte) (i & 0x7f);
208             i = i >> 7;
209         } while (i != 0);
210 
211         while (idx > 1) {
212             out.write(buf[--idx] | 0x80);
213         }
214         out.write(buf[0]);
215         if (mLogging) {
216             log(Integer.toString(i));
217         }
218     }
219 
writeLiteralString(OutputStream out, String s)220     void writeLiteralString(OutputStream out, String s) throws IOException {
221         byte[] data = s.getBytes("UTF-8");
222         out.write(data);
223         out.write(0);
224     }
225 
writeStringValue(ContentValues cv, String key, int tag)226     void writeStringValue (ContentValues cv, String key, int tag) throws IOException {
227         String value = cv.getAsString(key);
228         if (value != null && value.length() > 0) {
229             data(tag, value);
230         } else {
231             tag(tag);
232         }
233     }
234 
235     @Override
toString()236     public String toString() {
237         if (mOutput instanceof ByteArrayOutputStream) {
238             return ((ByteArrayOutputStream)mOutput).toString();
239         }
240         throw new IllegalStateException();
241     }
242 
toByteArray()243     public byte[] toByteArray() {
244         if (mOutput instanceof ByteArrayOutputStream) {
245             return ((ByteArrayOutputStream)mOutput).toByteArray();
246         }
247         throw new IllegalStateException();
248     }
249 
250 }
251