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 //Simplified for Google, Inc. by Marc Blank 23 24 package com.android.exchange.adapter; 25 26 import com.android.exchange.Eas; 27 import com.android.exchange.utility.FileLogger; 28 29 import android.content.ContentValues; 30 import android.util.Log; 31 32 import java.io.ByteArrayOutputStream; 33 import java.io.IOException; 34 import java.io.OutputStream; 35 import java.util.Hashtable; 36 37 public class Serializer { 38 39 private static final String TAG = "Serializer"; 40 private boolean logging = false; // DO NOT CHECK IN WITH THIS TRUE! 41 42 private static final int NOT_PENDING = -1; 43 44 ByteArrayOutputStream out = new ByteArrayOutputStream(); 45 ByteArrayOutputStream buf = new ByteArrayOutputStream(); 46 47 String pending; 48 int pendingTag = NOT_PENDING; 49 int depth; 50 String name; 51 String[] nameStack = new String[20]; 52 53 Hashtable<String, Object> tagTable = new Hashtable<String, Object>(); 54 55 private int tagPage; 56 57 public Serializer() { 58 this(true); 59 } 60 61 public Serializer(boolean startDocument, boolean _logging) { 62 this(true); 63 logging = _logging; 64 } 65 66 public Serializer(boolean startDocument) { 67 super(); 68 if (startDocument) { 69 try { 70 startDocument(); 71 //logging = Eas.PARSER_LOG; 72 } catch (IOException e) { 73 // Nothing to be done 74 } 75 } else { 76 out.write(0); 77 } 78 } 79 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 91 public void done() throws IOException { 92 if (depth != 0) { 93 throw new IOException("Done received with unclosed tags"); 94 } 95 writeInteger(out, 0); 96 out.write(buf.toByteArray()); 97 out.flush(); 98 } 99 100 public void startDocument() throws IOException{ 101 out.write(0x03); // version 1.3 102 out.write(0x01); // unknown or missing public identifier 103 out.write(106); 104 } 105 106 public void checkPendingTag(boolean degenerated) throws IOException { 107 if (pendingTag == NOT_PENDING) 108 return; 109 110 int page = pendingTag >> Tags.PAGE_SHIFT; 111 int tag = pendingTag & Tags.PAGE_MASK; 112 if (page != tagPage) { 113 tagPage = page; 114 buf.write(Wbxml.SWITCH_PAGE); 115 buf.write(page); 116 } 117 118 buf.write(degenerated ? tag : tag | 64); 119 if (logging) { 120 String name = Tags.pages[page][tag - 5]; 121 nameStack[depth] = name; 122 log("<" + name + '>'); 123 } 124 pendingTag = NOT_PENDING; 125 } 126 127 public Serializer start(int tag) throws IOException { 128 checkPendingTag(false); 129 pendingTag = tag; 130 depth++; 131 return this; 132 } 133 134 public Serializer end() throws IOException { 135 if (pendingTag >= 0) { 136 checkPendingTag(true); 137 } else { 138 buf.write(Wbxml.END); 139 if (logging) { 140 log("</" + nameStack[depth] + '>'); 141 } 142 } 143 depth--; 144 return this; 145 } 146 147 public Serializer tag(int t) throws IOException { 148 start(t); 149 end(); 150 return this; 151 } 152 153 public Serializer data(int tag, String value) throws IOException { 154 if (value == null) { 155 Log.e(TAG, "Writing null data for tag: " + tag); 156 } 157 start(tag); 158 text(value); 159 end(); 160 return this; 161 } 162 163 @Override 164 public String toString() { 165 return out.toString(); 166 } 167 168 public byte[] toByteArray() { 169 return out.toByteArray(); 170 } 171 172 public Serializer text(String text) throws IOException { 173 if (text == null) { 174 Log.e(TAG, "Writing null text for pending tag: " + pendingTag); 175 } 176 checkPendingTag(false); 177 buf.write(Wbxml.STR_I); 178 writeLiteralString(buf, text); 179 if (logging) { 180 log(text); 181 } 182 return this; 183 } 184 185 void writeInteger(OutputStream out, int i) throws IOException { 186 byte[] buf = new byte[5]; 187 int idx = 0; 188 189 do { 190 buf[idx++] = (byte) (i & 0x7f); 191 i = i >> 7; 192 } while (i != 0); 193 194 while (idx > 1) { 195 out.write(buf[--idx] | 0x80); 196 } 197 out.write(buf[0]); 198 if (logging) { 199 log(Integer.toString(i)); 200 } 201 } 202 203 void writeLiteralString(OutputStream out, String s) throws IOException { 204 byte[] data = s.getBytes("UTF-8"); 205 out.write(data); 206 out.write(0); 207 } 208 209 void writeStringValue (ContentValues cv, String key, int tag) throws IOException { 210 String value = cv.getAsString(key); 211 if (value != null && value.length() > 0) { 212 data(tag, value); 213 } 214 } 215 } 216