+ * The supplied configChooser will be used to choose a configuration.
+ * @param configChooser
+ */
+ public void setEGLConfigChooser(EGLConfigChooser configChooser) {
+ if (mGLThread != null) {
+ throw new IllegalStateException(
+ "setRenderer has already been called for this instance.");
+ }
+ mEGLConfigChooser = configChooser;
+ }
+
+ /**
+ * Set the EGLConfigChooser associated with this view. If this method is
+ * called, it must be called before {@link #setRenderer(Renderer)}
+ * is called.
+ *
+ * This method installs a config chooser which will choose a config
+ * as close to 16-bit RGB as possible, with or without an optional depth
+ * buffer as close to 16-bits as possible.
+ *
+ * If no setEGLConfigChooser method is called, then by default the
+ * view will choose a config as close to 16-bit RGB as possible, with
+ * a depth buffer as close to 16-bits as possible.
+ *
+ * @param needDepth
+ */
+ public void setEGLConfigChooser(boolean needDepth) {
+ setEGLConfigChooser(new SimpleEGLConfigChooser(needDepth));
+ }
+
+ /**
+ * Set the EGLConfigChooser associated with this view. If this method is
+ * called, it must be called before {@link #setRenderer(Renderer)}
+ * is called.
+ *
+ * This method installs a config chooser which will choose a config
+ * with at least the specified component sizes, and as close
+ * to the specified component sizes as possible.
+ *
+ */
+ public void setEGLConfigChooser(int redSize, int greenSize, int blueSize,
+ int alphaSize, int depthSize, int stencilSize) {
+ setEGLConfigChooser(new ComponentSizeChooser(redSize, greenSize,
+ blueSize, alphaSize, depthSize, stencilSize));
+ }
/**
* Set the rendering mode. When the renderMode is
* RENDERMODE_CONTINUOUSLY, the renderer is called
@@ -199,11 +253,6 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
* A generic renderer interface.
*/
public interface Renderer {
- /**
- * @return the EGL configuration specification desired by the renderer.
- */
- int[] getConfigSpec();
-
/**
* Surface created.
* Called when the surface is created. Called when the application
@@ -234,6 +283,140 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
void onDrawFrame(GL10 gl);
}
+ /**
+ * An interface for choosing a configuration from a list of
+ * potential configurations.
+ *
+ */
+ public interface EGLConfigChooser {
+ /**
+ * Choose a configuration from the list. Implementors typically
+ * implement this method by calling
+ * {@link EGL10#eglChooseConfig} and iterating through the results.
+ * @param egl the EGL10 for the current display.
+ * @param display the current display.
+ * @return the chosen configuration.
+ */
+ EGLConfig chooseConfig(EGL10 egl, EGLDisplay display);
+ }
+
+ private static abstract class BaseConfigChooser
+ implements EGLConfigChooser {
+ public BaseConfigChooser(int[] configSpec) {
+ mConfigSpec = configSpec;
+ }
+ public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
+ int[] num_config = new int[1];
+ egl.eglChooseConfig(display, mConfigSpec, null, 0, num_config);
+
+ int numConfigs = num_config[0];
+
+ if (numConfigs <= 0) {
+ throw new IllegalArgumentException(
+ "No configs match configSpec");
+ }
+
+ EGLConfig[] configs = new EGLConfig[numConfigs];
+ egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs,
+ num_config);
+ EGLConfig config = chooseConfig(egl, display, configs);
+ if (config == null) {
+ throw new IllegalArgumentException("No config chosen");
+ }
+ return config;
+ }
+
+ abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
+ EGLConfig[] configs);
+
+ protected int[] mConfigSpec;
+ }
+
+ private static class ComponentSizeChooser extends BaseConfigChooser {
+ public ComponentSizeChooser(int redSize, int greenSize, int blueSize,
+ int alphaSize, int depthSize, int stencilSize) {
+ super(new int[] {
+ EGL10.EGL_RED_SIZE, redSize,
+ EGL10.EGL_GREEN_SIZE, greenSize,
+ EGL10.EGL_BLUE_SIZE, blueSize,
+ EGL10.EGL_ALPHA_SIZE, alphaSize,
+ EGL10.EGL_DEPTH_SIZE, depthSize,
+ EGL10.EGL_STENCIL_SIZE, stencilSize,
+ EGL10.EGL_NONE});
+ mValue = new int[1];
+ mRedSize = redSize;
+ mGreenSize = greenSize;
+ mBlueSize = blueSize;
+ mAlphaSize = alphaSize;
+ mDepthSize = depthSize;
+ mStencilSize = stencilSize;
+ }
+
+ @Override
+ public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
+ EGLConfig[] configs) {
+ EGLConfig closestConfig = null;
+ int closestDistance = 1000;
+ for(EGLConfig config : configs) {
+ int r = findConfigAttrib(egl, display, config,
+ EGL10.EGL_RED_SIZE, 0);
+ int g = findConfigAttrib(egl, display, config,
+ EGL10.EGL_GREEN_SIZE, 0);
+ int b = findConfigAttrib(egl, display, config,
+ EGL10.EGL_BLUE_SIZE, 0);
+ int a = findConfigAttrib(egl, display, config,
+ EGL10.EGL_ALPHA_SIZE, 0);
+ int d = findConfigAttrib(egl, display, config,
+ EGL10.EGL_DEPTH_SIZE, 0);
+ int s = findConfigAttrib(egl, display, config,
+ EGL10.EGL_STENCIL_SIZE, 0);
+ int distance = Math.abs(r - mRedSize)
+ + Math.abs(g - mGreenSize)
+ + Math.abs(b - mBlueSize) + Math.abs(a - mAlphaSize)
+ + Math.abs(d - mDepthSize) + Math.abs(s - mStencilSize);
+ if (distance < closestDistance) {
+ closestDistance = distance;
+ closestConfig = config;
+ }
+ }
+ return closestConfig;
+ }
+
+ private int findConfigAttrib(EGL10 egl, EGLDisplay display,
+ EGLConfig config, int attribute, int defaultValue) {
+
+ if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
+ return mValue[0];
+ }
+ return defaultValue;
+ }
+
+ private int[] mValue;
+ // Subclasses can adjust these values:
+ protected int mRedSize;
+ protected int mGreenSize;
+ protected int mBlueSize;
+ protected int mAlphaSize;
+ protected int mDepthSize;
+ protected int mStencilSize;
+ }
+
+ /**
+ * This class will choose a supported surface as close to
+ * RGB565 as possible, with or without a depth buffer.
+ *
+ */
+ private static class SimpleEGLConfigChooser extends ComponentSizeChooser {
+ public SimpleEGLConfigChooser(boolean withDepthBuffer) {
+ super(4, 4, 4, 0, withDepthBuffer ? 16 : 0, 0);
+ // Adjust target values. This way we'll accept a 4444 or
+ // 555 buffer if there's no 565 buffer available.
+ mRedSize = 5;
+ mGreenSize = 6;
+ mBlueSize = 5;
+ }
+ }
+
/**
* An EGL helper class.
*/
@@ -247,7 +430,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
* Initialize EGL for a given configuration spec.
* @param configSpec
*/
- public void start(int[] configSpec){
+ public void start(){
/*
* Get an EGL instance
*/
@@ -263,12 +446,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
*/
int[] version = new int[2];
mEgl.eglInitialize(mEglDisplay, version);
-
- EGLConfig[] configs = new EGLConfig[1];
- int[] num_config = new int[1];
- mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1,
- num_config);
- mEglConfig = configs[0];
+ mEglConfig = mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);
/*
* Create an OpenGL ES context. This must be done only once, an
@@ -418,12 +596,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
private void guardedRun() throws InterruptedException {
mEglHelper = new EglHelper();
- /*
- * Specify a configuration for our opengl session
- * and grab the first configuration that matches is
- */
- int[] configSpec = mRenderer.getConfigSpec();
- mEglHelper.start(configSpec);
+ mEglHelper.start();
GL10 gl = null;
boolean tellRendererSurfaceCreated = true;
@@ -463,7 +636,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
mRequestRender = false;
}
if (needStart) {
- mEglHelper.start(configSpec);
+ mEglHelper.start();
tellRendererSurfaceCreated = true;
changed = true;
}
@@ -656,6 +829,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
private boolean mSizeChanged = true;
private GLThread mGLThread;
+ private EGLConfigChooser mEGLConfigChooser;
private GLWrapper mGLWrapper;
private int mDebugFlags;
}
--
cgit v1.2.3-59-g8ed1b
From 8c0d68f6695f4a0c98c12314eea81afcd59ea52d Mon Sep 17 00:00:00 2001
From: Romain Guy <>
Date: Tue, 24 Mar 2009 22:49:43 -0700
Subject: Automated import from //branches/donutburger/...@142490,142490
---
core/res/res/values/public.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 09012c92f9ed..d691702b4d13 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1051,7 +1051,7 @@
-
--
cgit v1.2.3-59-g8ed1b
From 52fc2180fa535d12838498e877b6d7557c4024dd Mon Sep 17 00:00:00 2001
From: Daisuke Miyakawa <>
Date: Tue, 24 Mar 2009 22:52:27 -0700
Subject: Automated import from //branches/donutburger/...@142509,142509
---
core/java/android/syncml/pim/PropertyNode.java | 137 +-
core/java/android/syncml/pim/VBuilder.java | 13 +-
core/java/android/syncml/pim/VDataBuilder.java | 220 +++-
.../java/android/syncml/pim/vcard/VCardParser.java | 3 +-
.../android/syncml/pim/vcard/VCardParser_V21.java | 1379 ++++++++------------
.../android/syncml/pim/vcard/VCardParser_V30.java | 348 +++--
.../syncml/pim/vcard/VCardVersionException.java | 29 +
tests/AndroidTests/res/raw/v21_backslash.vcf | 5 +
tests/AndroidTests/res/raw/v21_complicated.vcf | 106 ++
tests/AndroidTests/res/raw/v21_japanese_1.vcf | 6 +
tests/AndroidTests/res/raw/v21_japanese_2.vcf | 10 +
tests/AndroidTests/res/raw/v21_multiple_entry.vcf | 33 +
tests/AndroidTests/res/raw/v21_simple.vcf | 4 +
tests/AndroidTests/res/raw/v30_simple.vcf | 13 +
.../src/com/android/unit_tests/VCardTests.java | 773 +++++++++++
15 files changed, 2069 insertions(+), 1010 deletions(-)
create mode 100644 core/java/android/syncml/pim/vcard/VCardVersionException.java
create mode 100644 tests/AndroidTests/res/raw/v21_backslash.vcf
create mode 100644 tests/AndroidTests/res/raw/v21_complicated.vcf
create mode 100644 tests/AndroidTests/res/raw/v21_japanese_1.vcf
create mode 100644 tests/AndroidTests/res/raw/v21_japanese_2.vcf
create mode 100644 tests/AndroidTests/res/raw/v21_multiple_entry.vcf
create mode 100644 tests/AndroidTests/res/raw/v21_simple.vcf
create mode 100644 tests/AndroidTests/res/raw/v30_simple.vcf
create mode 100644 tests/AndroidTests/src/com/android/unit_tests/VCardTests.java
diff --git a/core/java/android/syncml/pim/PropertyNode.java b/core/java/android/syncml/pim/PropertyNode.java
index 13d4930c8f82..cc5249905efe 100644
--- a/core/java/android/syncml/pim/PropertyNode.java
+++ b/core/java/android/syncml/pim/PropertyNode.java
@@ -16,25 +16,142 @@
package android.syncml.pim;
-import java.util.ArrayList;
-import java.util.Collection;
-
import android.content.ContentValues;
+import android.util.Log;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
public class PropertyNode {
public String propName;
- public String propValue = "";
+ public String propValue;
- public Collection propValue_vector;
+ public List propValue_vector;
- /** Store value as byte[],after decode. */
- public byte[] propValue_byts;
+ /** Store value as byte[],after decode.
+ * Used when propValue is encoded by something like BASE64, QUOTED-PRINTABLE, etc.
+ */
+ public byte[] propValue_bytes;
- /** param store: key=paramType, value=paramValue */
- public ContentValues paraMap = new ContentValues();
+ /** param store: key=paramType, value=paramValue
+ * Note that currently PropertyNode class does not support multiple param-values
+ * defined in vCard 3.0 (See also RFC 2426). multiple-values are stored as
+ * one String value like "A,B", not ["A", "B"]...
+ * TODO: fix this.
+ */
+ public ContentValues paramMap;
/** Only for TYPE=??? param store. */
- public ArrayList paraMap_TYPE = new ArrayList();
+ public Set paramMap_TYPE;
+
+ /** Store group values. Used only in VCard. */
+ public Set propGroupSet;
+
+ public PropertyNode() {
+ propValue = "";
+ paramMap = new ContentValues();
+ paramMap_TYPE = new HashSet();
+ propGroupSet = new HashSet();
+ }
+
+ public PropertyNode(
+ String propName, String propValue, List propValue_vector,
+ byte[] propValue_bytes, ContentValues paramMap, Set paramMap_TYPE,
+ Set propGroupSet) {
+ this.propName = propName;
+ if (propValue != null) {
+ this.propValue = propValue;
+ } else {
+ this.propValue = "";
+ }
+ this.propValue_vector = propValue_vector;
+ this.propValue_bytes = propValue_bytes;
+ if (paramMap != null) {
+ this.paramMap = paramMap;
+ } else {
+ this.paramMap = new ContentValues();
+ }
+ if (paramMap_TYPE != null) {
+ this.paramMap_TYPE = paramMap_TYPE;
+ } else {
+ this.paramMap_TYPE = new HashSet();
+ }
+ if (propGroupSet != null) {
+ this.propGroupSet = propGroupSet;
+ } else {
+ this.propGroupSet = new HashSet();
+ }
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof PropertyNode)) {
+ return false;
+ }
+
+ PropertyNode node = (PropertyNode)obj;
+
+ if (propName == null || !propName.equals(node.propName)) {
+ return false;
+ } else if (!paramMap.equals(node.paramMap)) {
+ return false;
+ } else if (!paramMap_TYPE.equals(node.paramMap_TYPE)) {
+ return false;
+ } else if (!propGroupSet.equals(node.propGroupSet)) {
+ return false;
+ }
+
+ if (propValue_bytes != null && Arrays.equals(propValue_bytes, node.propValue_bytes)) {
+ return true;
+ } else {
+ // Log.d("@@@", propValue + ", " + node.propValue);
+ if (!propValue.equals(node.propValue)) {
+ return false;
+ }
+
+ // The value in propValue_vector is not decoded even if it should be
+ // decoded by BASE64 or QUOTED-PRINTABLE. When the size of propValue_vector
+ // is 1, the encoded value is stored in propValue, so we do not have to
+ // check it.
+ if (propValue_vector != null) {
+ // Log.d("@@@", "===" + propValue_vector + ", " + node.propValue_vector);
+ return (propValue_vector.equals(node.propValue_vector) ||
+ (propValue_vector.size() == 1));
+ } else if (node.propValue_vector != null) {
+ // Log.d("@@@", "===" + propValue_vector + ", " + node.propValue_vector);
+ return (node.propValue_vector.equals(propValue_vector) ||
+ (node.propValue_vector.size() == 1));
+ } else {
+ return true;
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("propName: ");
+ builder.append(propName);
+ builder.append(", paramMap: ");
+ builder.append(paramMap.toString());
+ builder.append(", propmMap_TYPE: ");
+ builder.append(paramMap_TYPE.toString());
+ builder.append(", propGroupSet: ");
+ builder.append(propGroupSet.toString());
+ if (propValue_vector != null && propValue_vector.size() > 1) {
+ builder.append(", propValue_vector size: ");
+ builder.append(propValue_vector.size());
+ }
+ if (propValue_bytes != null) {
+ builder.append(", propValue_bytes size: ");
+ builder.append(propValue_bytes.length);
+ }
+ builder.append(", propValue: ");
+ builder.append(propValue);
+ return builder.toString();
+ }
}
diff --git a/core/java/android/syncml/pim/VBuilder.java b/core/java/android/syncml/pim/VBuilder.java
index 822c2cef034b..452864526608 100644
--- a/core/java/android/syncml/pim/VBuilder.java
+++ b/core/java/android/syncml/pim/VBuilder.java
@@ -16,7 +16,7 @@
package android.syncml.pim;
-import java.util.Collection;
+import java.util.List;
public interface VBuilder {
void start();
@@ -37,10 +37,15 @@ public interface VBuilder {
void endProperty();
+ /**
+ * @param group
+ */
+ void propertyGroup(String group);
+
/**
* @param name
- * a.N
- * a.N
+ * N
+ * N
*/
void propertyName(String name);
@@ -58,5 +63,5 @@ public interface VBuilder {
*/
void propertyParamValue(String value);
- void propertyValues(Collection values);
+ void propertyValues(List values);
}
diff --git a/core/java/android/syncml/pim/VDataBuilder.java b/core/java/android/syncml/pim/VDataBuilder.java
index f0a0cb9be633..8c67cf5bfa03 100644
--- a/core/java/android/syncml/pim/VDataBuilder.java
+++ b/core/java/android/syncml/pim/VDataBuilder.java
@@ -16,11 +16,19 @@
package android.syncml.pim;
+import android.content.ContentValues;
+import android.util.Log;
+
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.net.QuotedPrintableCodec;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.List;
+import java.util.Vector;
/**
* Store the parse result to custom datastruct: VNode, PropertyNode
@@ -29,14 +37,32 @@ import java.util.Collection;
* PropertyNode: standy by a property line of a card.
*/
public class VDataBuilder implements VBuilder {
+ static private String LOG_TAG = "VDATABuilder";
/** type=VNode */
- public ArrayList vNodeList = new ArrayList();
- int nodeListPos = 0;
- VNode curVNode;
- PropertyNode curPropNode;
- String curParamType;
+ public List vNodeList = new ArrayList();
+ private int mNodeListPos = 0;
+ private VNode mCurrentVNode;
+ private PropertyNode mCurrentPropNode;
+ private String mCurrentParamType;
+
+ /**
+ * Assumes that each String can be encoded into byte array using this encoding.
+ */
+ private String mCharset;
+
+ private boolean mStrictLineBreakParsing;
+
+ public VDataBuilder() {
+ mCharset = "ISO-8859-1";
+ mStrictLineBreakParsing = false;
+ }
+ public VDataBuilder(String encoding, boolean strictLineBreakParsing) {
+ mCharset = encoding;
+ mStrictLineBreakParsing = strictLineBreakParsing;
+ }
+
public void start() {
}
@@ -48,79 +74,171 @@ public class VDataBuilder implements VBuilder {
vnode.parseStatus = 1;
vnode.VName = type;
vNodeList.add(vnode);
- nodeListPos = vNodeList.size()-1;
- curVNode = vNodeList.get(nodeListPos);
+ mNodeListPos = vNodeList.size()-1;
+ mCurrentVNode = vNodeList.get(mNodeListPos);
}
public void endRecord() {
- VNode endNode = vNodeList.get(nodeListPos);
+ VNode endNode = vNodeList.get(mNodeListPos);
endNode.parseStatus = 0;
- while(nodeListPos > 0){
- nodeListPos--;
- if((vNodeList.get(nodeListPos)).parseStatus == 1)
+ while(mNodeListPos > 0){
+ mNodeListPos--;
+ if((vNodeList.get(mNodeListPos)).parseStatus == 1)
break;
}
- curVNode = vNodeList.get(nodeListPos);
+ mCurrentVNode = vNodeList.get(mNodeListPos);
}
public void startProperty() {
- // System.out.println("+ startProperty. ");
+ // System.out.println("+ startProperty. ");
}
public void endProperty() {
- // System.out.println("- endProperty. ");
+ // System.out.println("- endProperty. ");
}
-
+
public void propertyName(String name) {
- curPropNode = new PropertyNode();
- curPropNode.propName = name;
+ mCurrentPropNode = new PropertyNode();
+ mCurrentPropNode.propName = name;
}
+ // Used only in VCard.
+ public void propertyGroup(String group) {
+ mCurrentPropNode.propGroupSet.add(group);
+ }
+
public void propertyParamType(String type) {
- curParamType = type;
+ mCurrentParamType = type;
}
public void propertyParamValue(String value) {
- if(curParamType == null)
- curPropNode.paraMap_TYPE.add(value);
- else if(curParamType.equalsIgnoreCase("TYPE"))
- curPropNode.paraMap_TYPE.add(value);
- else
- curPropNode.paraMap.put(curParamType, value);
-
- curParamType = null;
- }
-
- public void propertyValues(Collection values) {
- curPropNode.propValue_vector = values;
- curPropNode.propValue = listToString(values);
- //decode value string to propValue_byts
- if(curPropNode.paraMap.containsKey("ENCODING")){
- if(curPropNode.paraMap.getAsString("ENCODING").
- equalsIgnoreCase("BASE64")){
- curPropNode.propValue_byts =
- Base64.decodeBase64(curPropNode.propValue.
+ if (mCurrentParamType == null ||
+ mCurrentParamType.equalsIgnoreCase("TYPE")) {
+ mCurrentPropNode.paramMap_TYPE.add(value);
+ } else {
+ mCurrentPropNode.paramMap.put(mCurrentParamType, value);
+ }
+
+ mCurrentParamType = null;
+ }
+
+ private String encodeString(String originalString, String targetEncoding) {
+ Charset charset = Charset.forName(mCharset);
+ ByteBuffer byteBuffer = charset.encode(originalString);
+ // byteBuffer.array() "may" return byte array which is larger than
+ // byteBuffer.remaining(). Here, we keep on the safe side.
+ byte[] bytes = new byte[byteBuffer.remaining()];
+ byteBuffer.get(bytes);
+ try {
+ return new String(bytes, targetEncoding);
+ } catch (UnsupportedEncodingException e) {
+ return null;
+ }
+ }
+
+ public void propertyValues(List values) {
+ ContentValues paramMap = mCurrentPropNode.paramMap;
+
+ String charsetString = paramMap.getAsString("CHARSET");
+
+ boolean setupParamValues = false;
+ //decode value string to propValue_bytes
+ if (paramMap.containsKey("ENCODING")) {
+ String encoding = paramMap.getAsString("ENCODING");
+ if (encoding.equalsIgnoreCase("BASE64") ||
+ encoding.equalsIgnoreCase("B")) {
+ if (values.size() > 1) {
+ Log.e(LOG_TAG,
+ ("BASE64 encoding is used while " +
+ "there are multiple values (" + values.size()));
+ }
+ mCurrentPropNode.propValue_bytes =
+ Base64.decodeBase64(values.get(0).
replaceAll(" ","").replaceAll("\t","").
replaceAll("\r\n","").
getBytes());
}
- if(curPropNode.paraMap.getAsString("ENCODING").
- equalsIgnoreCase("QUOTED-PRINTABLE")){
+
+ if(encoding.equalsIgnoreCase("QUOTED-PRINTABLE")){
+ // if CHARSET is defined, we translate each String into the Charset.
+ List tmpValues = new ArrayList();
+ Vector byteVector = new Vector();
+ int size = 0;
try{
- curPropNode.propValue_byts =
- QuotedPrintableCodec.decodeQuotedPrintable(
- curPropNode.propValue.
- replaceAll("= ", " ").replaceAll("=\t", "\t").
- getBytes() );
- curPropNode.propValue =
- new String(curPropNode.propValue_byts);
- }catch(Exception e){
- System.out.println("=Decode quoted-printable exception.");
- e.printStackTrace();
+ for (String value : values) {
+ String quotedPrintable = value
+ .replaceAll("= ", " ").replaceAll("=\t", "\t");
+ String[] lines;
+ if (mStrictLineBreakParsing) {
+ lines = quotedPrintable.split("\r\n");
+ } else {
+ lines = quotedPrintable
+ .replace("\r\n", "\n").replace("\r", "\n").split("\n");
+ }
+ StringBuilder builder = new StringBuilder();
+ for (String line : lines) {
+ if (line.endsWith("=")) {
+ line = line.substring(0, line.length() - 1);
+ }
+ builder.append(line);
+ }
+ byte[] bytes = QuotedPrintableCodec.decodeQuotedPrintable(
+ builder.toString().getBytes());
+ if (charsetString != null) {
+ try {
+ tmpValues.add(new String(bytes, charsetString));
+ } catch (UnsupportedEncodingException e) {
+ Log.e(LOG_TAG, "Failed to encode: charset=" + charsetString);
+ tmpValues.add(new String(bytes));
+ }
+ } else {
+ tmpValues.add(new String(bytes));
+ }
+ byteVector.add(bytes);
+ size += bytes.length;
+ } // for (String value : values) {
+ mCurrentPropNode.propValue_vector = tmpValues;
+ mCurrentPropNode.propValue = listToString(tmpValues);
+
+ mCurrentPropNode.propValue_bytes = new byte[size];
+
+ {
+ byte[] tmpBytes = mCurrentPropNode.propValue_bytes;
+ int index = 0;
+ for (byte[] bytes : byteVector) {
+ int length = bytes.length;
+ for (int i = 0; i < length; i++, index++) {
+ tmpBytes[index] = bytes[i];
+ }
+ }
+ }
+ setupParamValues = true;
+ } catch(Exception e) {
+ Log.e(LOG_TAG, "Failed to decode quoted-printable: " + e);
}
+ } // QUOTED-PRINTABLE
+ } // ENCODING
+
+ if (!setupParamValues) {
+ // if CHARSET is defined, we translate each String into the Charset.
+ if (charsetString != null) {
+ List tmpValues = new ArrayList();
+ for (String value : values) {
+ String result = encodeString(value, charsetString);
+ if (result != null) {
+ tmpValues.add(result);
+ } else {
+ Log.e(LOG_TAG, "Failed to encode: charset=" + charsetString);
+ tmpValues.add(value);
+ }
+ }
+ values = tmpValues;
}
+
+ mCurrentPropNode.propValue_vector = values;
+ mCurrentPropNode.propValue = listToString(values);
}
- curVNode.propList.add(curPropNode);
+ mCurrentVNode.propList.add(mCurrentPropNode);
}
private String listToString(Collection list){
@@ -134,7 +252,7 @@ public class VDataBuilder implements VBuilder {
}
return typeListB.toString();
}
-
+
public String getResult(){
return null;
}
diff --git a/core/java/android/syncml/pim/vcard/VCardParser.java b/core/java/android/syncml/pim/vcard/VCardParser.java
index 3926243c3aad..6dad852d1e56 100644
--- a/core/java/android/syncml/pim/vcard/VCardParser.java
+++ b/core/java/android/syncml/pim/vcard/VCardParser.java
@@ -26,7 +26,8 @@ import java.io.IOException;
public class VCardParser {
- VParser mParser = null;
+ // TODO: fix this.
+ VCardParser_V21 mParser = null;
public final static String VERSION_VCARD21 = "vcard2.1";
diff --git a/core/java/android/syncml/pim/vcard/VCardParser_V21.java b/core/java/android/syncml/pim/vcard/VCardParser_V21.java
index b6fa03291360..f853c5e383fa 100644
--- a/core/java/android/syncml/pim/vcard/VCardParser_V21.java
+++ b/core/java/android/syncml/pim/vcard/VCardParser_V21.java
@@ -16,21 +16,24 @@
package android.syncml.pim.vcard;
-import android.syncml.pim.VParser;
+import android.syncml.pim.VBuilder;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* This class is used to parse vcard. Please refer to vCard Specification 2.1
*/
-public class VCardParser_V21 extends VParser {
+public class VCardParser_V21 {
/** Store the known-type */
- private static final HashSet mKnownTypeSet = new HashSet(
+ private static final HashSet sKnownTypeSet = new HashSet(
Arrays.asList("DOM", "INTL", "POSTAL", "PARCEL", "HOME", "WORK",
"PREF", "VOICE", "FAX", "MSG", "CELL", "PAGER", "BBS",
"MODEM", "CAR", "ISDN", "VIDEO", "AOL", "APPLELINK",
@@ -39,13 +42,40 @@ public class VCardParser_V21 extends VParser {
"CGM", "WMF", "BMP", "MET", "PMB", "DIB", "PICT", "TIFF",
"PDF", "PS", "JPEG", "QTIME", "MPEG", "MPEG2", "AVI",
"WAVE", "AIFF", "PCM", "X509", "PGP"));
-
- /** Store the name */
- private static final HashSet mName = new HashSet(Arrays
- .asList("LOGO", "PHOTO", "LABEL", "FN", "TITLE", "SOUND",
- "VERSION", "TEL", "EMAIL", "TZ", "GEO", "NOTE", "URL",
- "BDAY", "ROLE", "REV", "UID", "KEY", "MAILER"));
-
+
+ /** Store the known-value */
+ private static final HashSet sKnownValueSet = new HashSet(
+ Arrays.asList("INLINE", "URL", "CONTENT-ID", "CID"));
+
+ /** Store the property name available in vCard 2.1 */
+ // NICKNAME is not supported in vCard 2.1, but some vCard may contain.
+ private static final HashSet sAvailablePropertyNameV21 =
+ new HashSet(Arrays.asList(
+ "LOGO", "PHOTO", "LABEL", "FN", "TITLE", "SOUND",
+ "VERSION", "TEL", "EMAIL", "TZ", "GEO", "NOTE", "URL",
+ "BDAY", "ROLE", "REV", "UID", "KEY", "MAILER",
+ "NICKNAME"));
+
+ // Though vCard 2.1 specification does not allow "B" encoding, some data may have it.
+ // We allow it for safety...
+ private static final HashSet sAvailableEncodingV21 =
+ new HashSet(Arrays.asList(
+ "7BIT", "8BIT", "QUOTED-PRINTABLE", "BASE64", "B"));
+
+ // Used only for parsing END:VCARD.
+ private String mPreviousLine;
+
+ /** The builder to build parsed data */
+ protected VBuilder mBuilder = null;
+
+ /** The encoding type */
+ protected String mEncoding = null;
+
+ protected final String sDefaultEncoding = "8BIT";
+
+ // Should not directly read a line from this. Use getLine() instead.
+ protected BufferedReader mReader;
+
/**
* Create a new VCard parser.
*/
@@ -55,916 +85,597 @@ public class VCardParser_V21 extends VParser {
/**
* Parse the file at the given position
- *
- * @param offset
- * the given position to parse
- * @return vcard length
+ * vcard_file = [wsls] vcard [wsls]
*/
- protected int parseVFile(int offset) {
- return parseVCardFile(offset);
+ protected void parseVCardFile() throws IOException, VCardException {
+ while (parseOneVCard()) {
+ }
}
+ protected String getVersion() {
+ return "2.1";
+ }
+
/**
- * [wsls] vcard [wsls]
+ * @return true when the propertyName is a valid property name.
*/
- int parseVCardFile(int offset) {
- int ret = 0, sum = 0;
-
- /* remove \t \r\n */
- while ((ret = parseWsls(offset)) != PARSE_ERROR) {
- offset += ret;
- sum += ret;
- }
-
- ret = parseVCard(offset); // BEGIN:VCARD ... END:VCARD
- if (ret != PARSE_ERROR) {
- offset += ret;
- sum += ret;
- } else {
- return PARSE_ERROR;
- }
+ protected boolean isValidPropertyName(String propertyName) {
+ return sAvailablePropertyNameV21.contains(propertyName.toUpperCase());
+ }
- /* remove \t \r\n */
- while ((ret = parseWsls(offset)) != PARSE_ERROR) {
- offset += ret;
- sum += ret;
+ /**
+ * @return true when the encoding is a valid encoding.
+ */
+ protected boolean isValidEncoding(String encoding) {
+ return sAvailableEncodingV21.contains(encoding.toUpperCase());
+ }
+
+ /**
+ * @return String. It may be null, or its length may be 0
+ * @throws IOException
+ */
+ protected String getLine() throws IOException {
+ return mReader.readLine();
+ }
+
+ /**
+ * @return String with it's length > 0
+ * @throws IOException
+ * @throws VCardException when the stream reached end of line
+ */
+ protected String getNonEmptyLine() throws IOException, VCardException {
+ String line;
+ while (true) {
+ line = getLine();
+ if (line == null) {
+ throw new VCardException("Reached end of buffer.");
+ } else if (line.trim().length() > 0) {
+ return line;
+ }
}
- return sum;
}
-
+
/**
- * "BEGIN" [ws] ":" [ws] "VCARD" [ws] 1*CRLF items *CRLF "END" [ws] ":"
- * "VCARD"
+ * vcard = "BEGIN" [ws] ":" [ws] "VCARD" [ws] 1*CRLF
+ * items *CRLF
+ * "END" [ws] ":" [ws] "VCARD"
*/
- private int parseVCard(int offset) {
- int ret = 0, sum = 0;
-
- /* BEGIN */
- ret = parseString(offset, "BEGIN", false);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
+ private boolean parseOneVCard() throws IOException, VCardException {
+ if (!readBeginVCard()) {
+ return false;
}
- offset += ret;
- sum += ret;
-
- /* [ws] */
- ret = removeWs(offset);
- offset += ret;
- sum += ret;
-
- /* colon */
- ret = parseString(offset, ":", false);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
+ parseItems();
+ readEndVCard();
+ return true;
+ }
+
+ /**
+ * @return True when successful. False when reaching the end of line
+ * @throws IOException
+ * @throws VCardException
+ */
+ protected boolean readBeginVCard() throws IOException, VCardException {
+ String line;
+ while (true) {
+ line = getLine();
+ if (line == null) {
+ return false;
+ } else if (line.trim().length() > 0) {
+ break;
+ }
}
- offset += ret;
- sum += ret;
-
- /* [ws] */
- ret = removeWs(offset);
- offset += ret;
- sum += ret;
-
- /* VCARD */
- ret = parseString(offset, "VCARD", false);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
+ String[] strArray = line.split(":", 2);
+
+ // Though vCard specification does not allow lower cases,
+ // some data may have them, so we allow it.
+ if (!(strArray.length == 2 &&
+ strArray[0].trim().equalsIgnoreCase("BEGIN") &&
+ strArray[1].trim().equalsIgnoreCase("VCARD"))) {
+ throw new VCardException("BEGIN:VCARD != \"" + line + "\"");
}
- offset += ret;
- sum += ret;
+
if (mBuilder != null) {
mBuilder.startRecord("VCARD");
}
- /* [ws] */
- ret = removeWs(offset);
- offset += ret;
- sum += ret;
-
- /* 1*CRLF */
- ret = parseCrlf(offset);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
- while ((ret = parseCrlf(offset)) != PARSE_ERROR) {
- offset += ret;
- sum += ret;
- }
-
- ret = parseItems(offset);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
-
- /* *CRLF */
- while ((ret = parseCrlf(offset)) != PARSE_ERROR) {
- offset += ret;
- sum += ret;
- }
-
- /* END */
- ret = parseString(offset, "END", false);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
-
- /* [ws] */
- ret = removeWs(offset);
- offset += ret;
- sum += ret;
-
- /* colon */
- ret = parseString(offset, ":", false);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
-
- /* [ws] */
- ret = removeWs(offset);
- offset += ret;
- sum += ret;
-
- /* VCARD */
- ret = parseString(offset, "VCARD", false);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- // offset += ret;
- sum += ret;
+ return true;
+ }
+
+ protected void readEndVCard() throws VCardException {
+ // Though vCard specification does not allow lower cases,
+ // some data may have them, so we allow it.
+ String[] strArray = mPreviousLine.split(":", 2);
+ if (!(strArray.length == 2 &&
+ strArray[0].trim().equalsIgnoreCase("END") &&
+ strArray[1].trim().equalsIgnoreCase("VCARD"))) {
+ throw new VCardException("END:VCARD != \"" + mPreviousLine + "\"");
+ }
+
if (mBuilder != null) {
mBuilder.endRecord();
}
-
- return sum;
}
-
+
/**
- * items *CRLF item / item
+ * items = *CRLF item
+ * / item
*/
- private int parseItems(int offset) {
+ protected void parseItems() throws IOException, VCardException {
/* items *CRLF item / item */
- int ret = 0, sum = 0;
-
+ boolean ended = false;
+
if (mBuilder != null) {
mBuilder.startProperty();
}
- ret = parseItem(offset);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
- if (mBuilder != null) {
- mBuilder.endProperty();
- }
- for (;;) {
- while ((ret = parseCrlf(offset)) != PARSE_ERROR) {
- offset += ret;
- sum += ret;
+ try {
+ ended = parseItem();
+ } finally {
+ if (mBuilder != null) {
+ mBuilder.endProperty();
}
+ }
+
+ while (!ended) {
// follow VCARD ,it wont reach endProperty
if (mBuilder != null) {
mBuilder.startProperty();
}
-
- ret = parseItem(offset);
- if (ret == PARSE_ERROR) {
- break;
- }
- offset += ret;
- sum += ret;
- if (mBuilder != null) {
- mBuilder.endProperty();
+ try {
+ ended = parseItem();
+ } finally {
+ if (mBuilder != null) {
+ mBuilder.endProperty();
+ }
}
}
-
- return sum;
}
/**
- * item0 / item1 / item2
+ * item = [groups "."] name [params] ":" value CRLF
+ * / [groups "."] "ADR" [params] ":" addressparts CRLF
+ * / [groups "."] "ORG" [params] ":" orgparts CRLF
+ * / [groups "."] "N" [params] ":" nameparts CRLF
+ * / [groups "."] "AGENT" [params] ":" vcard CRLF
*/
- private int parseItem(int offset) {
- int ret = 0, sum = 0;
- mEncoding = mDefaultEncoding;
-
- ret = parseItem0(offset);
- if (ret != PARSE_ERROR) {
- sum += ret;
- return sum;
- }
-
- ret = parseItem1(offset);
- if (ret != PARSE_ERROR) {
- sum += ret;
- return sum;
- }
-
- ret = parseItem2(offset);
- if (ret != PARSE_ERROR) {
- sum += ret;
- return sum;
- }
-
- return PARSE_ERROR;
- }
-
- /** [groups "."] name [params] ":" value CRLF */
- private int parseItem0(int offset) {
- int ret = 0, sum = 0, start = offset;
- String proName = "", proValue = "";
-
- ret = parseGroupsWithDot(offset);
- if (ret != PARSE_ERROR) {
- offset += ret;
- sum += ret;
- }
-
- ret = parseName(offset);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
- if (mBuilder != null) {
- proName = mBuffer.substring(start, offset).trim();
- mBuilder.propertyName(proName);
- }
-
- ret = parseParams(offset);
- if (ret != PARSE_ERROR) {
- offset += ret;
- sum += ret;
- }
-
- ret = parseString(offset, ":", false);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
-
- start = offset;
- ret = parseValue(offset);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
- proValue = mBuffer.substring(start, offset);
- if (proName.equals("VERSION") && !proValue.equals("2.1")) {
- return PARSE_ERROR;
- }
- if (mBuilder != null) {
- ArrayList v = new ArrayList();
- v.add(proValue);
- mBuilder.propertyValues(v);
- }
-
- ret = parseCrlf(offset);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- sum += ret;
-
- return sum;
- }
-
- /** "ADR" "ORG" "N" with semi-colon separated content */
- private int parseItem1(int offset) {
- int ret = 0, sum = 0, start = offset;
-
- ret = parseGroupsWithDot(offset);
- if (ret != PARSE_ERROR) {
- offset += ret;
- sum += ret;
- }
-
- if ((ret = parseString(offset, "ADR", true)) == PARSE_ERROR
- && (ret = parseString(offset, "ORG", true)) == PARSE_ERROR
- && (ret = parseString(offset, "N", true)) == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
+ protected boolean parseItem() throws IOException, VCardException {
+ mEncoding = sDefaultEncoding;
+
+ // params = ";" [ws] paramlist
+ String line = getNonEmptyLine();
+ String[] strArray = line.split(":", 2);
+ if (strArray.length < 2) {
+ throw new VCardException("Invalid line(\":\" does not exist): " + line);
+ }
+ String propertyValue = strArray[1];
+ String[] groupNameParamsArray = strArray[0].split(";");
+ String groupAndName = groupNameParamsArray[0].trim();
+ String[] groupNameArray = groupAndName.split("\\.");
+ int length = groupNameArray.length;
+ String propertyName = groupNameArray[length - 1];
if (mBuilder != null) {
- mBuilder.propertyName(mBuffer.substring(start, offset).trim());
- }
-
- ret = parseParams(offset);
- if (ret != PARSE_ERROR) {
- offset += ret;
- sum += ret;
- }
-
- ret = parseString(offset, ":", false);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
-
- start = offset;
- ret = parseValue(offset);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
- if (mBuilder != null) {
- int end = 0;
- ArrayList v = new ArrayList();
- Pattern p = Pattern
- .compile("([^;\\\\]*(\\\\[\\\\;:,])*[^;\\\\]*)(;?)");
- Matcher m = p.matcher(mBuffer.substring(start, offset));
- while (m.find()) {
- String s = escapeTranslator(m.group(1));
- v.add(s);
- end = m.end();
- if (offset == start + end) {
- String endValue = m.group(3);
- if (";".equals(endValue)) {
- v.add("");
- }
- break;
- }
+ mBuilder.propertyName(propertyName);
+ for (int i = 0; i < length - 1; i++) {
+ mBuilder.propertyGroup(groupNameArray[i]);
}
- mBuilder.propertyValues(v);
}
-
- ret = parseCrlf(offset);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- sum += ret;
-
- return sum;
+ if (propertyName.equalsIgnoreCase("END")) {
+ mPreviousLine = line;
+ return true;
+ }
+
+ length = groupNameParamsArray.length;
+ for (int i = 1; i < length; i++) {
+ handleParams(groupNameParamsArray[i]);
+ }
+
+ if (isValidPropertyName(propertyName) ||
+ propertyName.startsWith("X-")) {
+ if (propertyName.equals("VERSION") &&
+ !propertyValue.equals(getVersion())) {
+ throw new VCardVersionException("Incompatible version: " +
+ propertyValue + " != " + getVersion());
+ }
+ handlePropertyValue(propertyName, propertyValue);
+ return false;
+ } else if (propertyName.equals("ADR") ||
+ propertyName.equals("ORG") ||
+ propertyName.equals("N")) {
+ handleMultiplePropertyValue(propertyName, propertyValue);
+ return false;
+ } else if (propertyName.equals("AGENT")) {
+ handleAgent(propertyValue);
+ return false;
+ }
+
+ throw new VCardException("Unknown property name: \"" +
+ propertyName + "\"");
}
- /** [groups] "." "AGENT" [params] ":" vcard CRLF */
- private int parseItem2(int offset) {
- int ret = 0, sum = 0, start = offset;
-
- ret = parseGroupsWithDot(offset);
- if (ret != PARSE_ERROR) {
- offset += ret;
- sum += ret;
- }
-
- ret = parseString(offset, "AGENT", true);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
- if (mBuilder != null) {
- mBuilder.propertyName(mBuffer.substring(start, offset));
- }
-
- ret = parseParams(offset);
- if (ret != PARSE_ERROR) {
- offset += ret;
- sum += ret;
- }
-
- ret = parseString(offset, ":", false);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
-
- ret = parseCrlf(offset);
- if (ret != PARSE_ERROR) {
- offset += ret;
- sum += ret;
- }
-
- ret = parseVCard(offset);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
- if (mBuilder != null) {
- mBuilder.propertyValues(new ArrayList());
- }
-
- ret = parseCrlf(offset);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
+ /**
+ * params = ";" [ws] paramlist
+ * paramlist = paramlist [ws] ";" [ws] param
+ * / param
+ * param = "TYPE" [ws] "=" [ws] ptypeval
+ * / "VALUE" [ws] "=" [ws] pvalueval
+ * / "ENCODING" [ws] "=" [ws] pencodingval
+ * / "CHARSET" [ws] "=" [ws] charsetval
+ * / "LANGUAGE" [ws] "=" [ws] langval
+ * / "X-" word [ws] "=" [ws] word
+ * / knowntype
+ */
+ protected void handleParams(String params) throws VCardException {
+ String[] strArray = params.split("=", 2);
+ if (strArray.length == 2) {
+ String paramName = strArray[0].trim();
+ String paramValue = strArray[1].trim();
+ if (paramName.equals("TYPE")) {
+ handleType(paramValue);
+ } else if (paramName.equals("VALUE")) {
+ handleValue(paramValue);
+ } else if (paramName.equals("ENCODING")) {
+ handleEncoding(paramValue);
+ } else if (paramName.equals("CHARSET")) {
+ handleCharset(paramValue);
+ } else if (paramName.equals("LANGUAGE")) {
+ handleLanguage(paramValue);
+ } else if (paramName.startsWith("X-")) {
+ handleAnyParam(paramName, paramValue);
+ } else {
+ throw new VCardException("Unknown type \"" + paramName + "\"");
+ }
+ } else {
+ handleType(strArray[0]);
}
- sum += ret;
-
- return sum;
}
-
- private int parseGroupsWithDot(int offset) {
- int ret = 0, sum = 0;
- /* [groups "."] */
- ret = parseGroups(offset);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
-
- ret = parseString(offset, ".", false);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- sum += ret;
-
- return sum;
+
+ /**
+ * typeval = knowntype / "X-" word
+ */
+ protected void handleType(String ptypeval) throws VCardException {
+ if (sKnownTypeSet.contains(ptypeval.toUpperCase()) ||
+ ptypeval.startsWith("X-")) {
+ if (mBuilder != null) {
+ mBuilder.propertyParamType("TYPE");
+ mBuilder.propertyParamValue(ptypeval.toUpperCase());
+ }
+ } else {
+ throw new VCardException("Unknown type: \"" + ptypeval + "\"");
+ }
}
-
- /** ";" [ws] paramlist */
- private int parseParams(int offset) {
- int ret = 0, sum = 0;
-
- ret = parseString(offset, ";", false);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
-
- ret = removeWs(offset);
- offset += ret;
- sum += ret;
-
- ret = parseParamList(offset);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
+
+ /**
+ * pvalueval = "INLINE" / "URL" / "CONTENT-ID" / "CID" / "X-" word
+ */
+ protected void handleValue(String pvalueval) throws VCardException {
+ if (sKnownValueSet.contains(pvalueval.toUpperCase()) ||
+ pvalueval.startsWith("X-")) {
+ if (mBuilder != null) {
+ mBuilder.propertyParamType("VALUE");
+ mBuilder.propertyParamValue(pvalueval);
+ }
+ } else {
+ throw new VCardException("Unknown value \"" + pvalueval + "\"");
}
- sum += ret;
-
- return sum;
}
-
+
/**
- * paramlist [ws] ";" [ws] param / param
+ * pencodingval = "7BIT" / "8BIT" / "QUOTED-PRINTABLE" / "BASE64" / "X-" word
*/
- private int parseParamList(int offset) {
- int ret = 0, sum = 0;
-
- ret = parseParam(offset);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
-
- int offsetTemp = offset;
- int sumTemp = sum;
- for (;;) {
- ret = removeWs(offsetTemp);
- offsetTemp += ret;
- sumTemp += ret;
-
- ret = parseString(offsetTemp, ";", false);
- if (ret == PARSE_ERROR) {
- return sum;
- }
- offsetTemp += ret;
- sumTemp += ret;
-
- ret = removeWs(offsetTemp);
- offsetTemp += ret;
- sumTemp += ret;
-
- ret = parseParam(offsetTemp);
- if (ret == PARSE_ERROR) {
- break;
+ protected void handleEncoding(String pencodingval) throws VCardException {
+ if (isValidEncoding(pencodingval) ||
+ pencodingval.startsWith("X-")) {
+ if (mBuilder != null) {
+ mBuilder.propertyParamType("ENCODING");
+ mBuilder.propertyParamValue(pencodingval);
}
- offsetTemp += ret;
- sumTemp += ret;
-
- // offset = offsetTemp;
- sum = sumTemp;
+ mEncoding = pencodingval;
+ } else {
+ throw new VCardException("Unknown encoding \"" + pencodingval + "\"");
}
- return sum;
}
-
+
/**
- * param0 / param1 / param2 / param3 / param4 / param5 / knowntype
- * TYPE / VALUE / ENDCODING / CHARSET / LANGUAGE ...
+ * vCard specification only allows us-ascii and iso-8859-xxx (See RFC 1521),
+ * but some vCard contains other charset, so we allow them.
*/
- private int parseParam(int offset) {
- int ret = 0, sum = 0;
-
- ret = parseParam0(offset);
- if (ret != PARSE_ERROR) {
- sum += ret;
- return sum;
- }
-
- ret = parseParam1(offset);
- if (ret != PARSE_ERROR) {
- sum += ret;
- return sum;
- }
-
- ret = parseParam2(offset);
- if (ret != PARSE_ERROR) {
- sum += ret;
- return sum;
- }
-
- ret = parseParam3(offset);
- if (ret != PARSE_ERROR) {
- sum += ret;
- return sum;
- }
-
- ret = parseParam4(offset);
- if (ret != PARSE_ERROR) {
- sum += ret;
- return sum;
- }
-
- ret = parseParam5(offset);
- if (ret != PARSE_ERROR) {
- sum += ret;
- return sum;
- }
-
- int start = offset;
- ret = parseKnownType(offset);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
+ protected void handleCharset(String charsetval) {
if (mBuilder != null) {
- mBuilder.propertyParamType(null);
- mBuilder.propertyParamValue(mBuffer.substring(start, offset));
+ mBuilder.propertyParamType("CHARSET");
+ mBuilder.propertyParamValue(charsetval);
}
-
- return sum;
}
-
- /** "TYPE" [ws] "=" [ws] ptypeval */
- private int parseParam0(int offset) {
- int ret = 0, sum = 0, start = offset;
-
- ret = parseString(offset, "TYPE", true);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
- if (mBuilder != null) {
- mBuilder.propertyParamType(mBuffer.substring(start, offset));
- }
-
- ret = removeWs(offset);
- offset += ret;
- sum += ret;
-
- ret = parseString(offset, "=", false);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
+
+ /**
+ * See also Section 7.1 of RFC 1521
+ */
+ protected void handleLanguage(String langval) throws VCardException {
+ String[] strArray = langval.split("-");
+ if (strArray.length != 2) {
+ throw new VCardException("Invalid Language: \"" + langval + "\"");
+ }
+ String tmp = strArray[0];
+ int length = tmp.length();
+ for (int i = 0; i < length; i++) {
+ if (!isLetter(tmp.charAt(i))) {
+ throw new VCardException("Invalid Language: \"" + langval + "\"");
+ }
}
- offset += ret;
- sum += ret;
-
- ret = removeWs(offset);
- offset += ret;
- sum += ret;
-
- start = offset;
- ret = parsePTypeVal(offset);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
+ tmp = strArray[1];
+ length = tmp.length();
+ for (int i = 0; i < length; i++) {
+ if (!isLetter(tmp.charAt(i))) {
+ throw new VCardException("Invalid Language: \"" + langval + "\"");
+ }
}
- offset += ret;
- sum += ret;
if (mBuilder != null) {
- mBuilder.propertyParamValue(mBuffer.substring(start, offset));
+ mBuilder.propertyParamType("LANGUAGE");
+ mBuilder.propertyParamValue(langval);
}
-
- return sum;
-
}
- /** "VALUE" [ws] "=" [ws] pvalueval */
- private int parseParam1(int offset) {
- int ret = 0, sum = 0, start = offset;
-
- ret = parseString(offset, "VALUE", true);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
- if (mBuilder != null) {
- mBuilder.propertyParamType(mBuffer.substring(start, offset));
- }
-
- ret = removeWs(offset);
- offset += ret;
- sum += ret;
-
- ret = parseString(offset, "=", false);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
-
- ret = removeWs(offset);
- offset += ret;
- sum += ret;
-
- start = offset;
- ret = parsePValueVal(offset);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
+ /**
+ * Mainly for "X-" type. This accepts any kind of type without check.
+ */
+ protected void handleAnyParam(String paramName, String paramValue) {
if (mBuilder != null) {
- mBuilder.propertyParamValue(mBuffer.substring(start, offset));
+ mBuilder.propertyParamType(paramName);
+ mBuilder.propertyParamValue(paramValue);
}
-
- return sum;
}
-
- /** "ENCODING" [ws] "=" [ws] pencodingval */
- private int parseParam2(int offset) {
- int ret = 0, sum = 0, start = offset;
-
- ret = parseString(offset, "ENCODING", true);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
- if (mBuilder != null) {
- mBuilder.propertyParamType(mBuffer.substring(start, offset));
- }
-
- ret = removeWs(offset);
- offset += ret;
- sum += ret;
-
- ret = parseString(offset, "=", false);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
-
- ret = removeWs(offset);
- offset += ret;
- sum += ret;
-
- start = offset;
- ret = parsePEncodingVal(offset);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
- if (mBuilder != null) {
- mBuilder.propertyParamValue(mBuffer.substring(start, offset));
+
+ protected void handlePropertyValue(
+ String propertyName, String propertyValue) throws
+ IOException, VCardException {
+ if (mEncoding == null || mEncoding.equalsIgnoreCase("7BIT")
+ || mEncoding.equalsIgnoreCase("8BIT")
+ || mEncoding.toUpperCase().startsWith("X-")) {
+ if (mBuilder != null) {
+ ArrayList v = new ArrayList();
+ v.add(maybeUnescapeText(propertyValue));
+ mBuilder.propertyValues(v);
+ }
+ } else if (mEncoding.equalsIgnoreCase("QUOTED-PRINTABLE")) {
+ String result = getQuotedPrintable(propertyValue);
+ if (mBuilder != null) {
+ ArrayList v = new ArrayList();
+ v.add(result);
+ mBuilder.propertyValues(v);
+ }
+ } else if (mEncoding.equalsIgnoreCase("BASE64") ||
+ mEncoding.equalsIgnoreCase("B")) {
+ String result = getBase64(propertyValue);
+ if (mBuilder != null) {
+ ArrayList v = new ArrayList();
+ v.add(result);
+ mBuilder.propertyValues(v);
+ }
+ } else {
+ throw new VCardException("Unknown encoding: \"" + mEncoding + "\"");
}
-
- return sum;
-
}
-
- /** "CHARSET" [ws] "=" [ws] charsetval */
- private int parseParam3(int offset) {
- int ret = 0, sum = 0, start = offset;
-
- ret = parseString(offset, "CHARSET", true);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
- if (mBuilder != null) {
- mBuilder.propertyParamType(mBuffer.substring(start, offset));
- }
-
- ret = removeWs(offset);
- offset += ret;
- sum += ret;
-
- ret = parseString(offset, "=", false);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
-
- ret = removeWs(offset);
- offset += ret;
- sum += ret;
-
- start = offset;
- ret = parseCharsetVal(offset);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
- if (mBuilder != null) {
- mBuilder.propertyParamValue(mBuffer.substring(start, offset));
+
+ protected String getQuotedPrintable(String firstString) throws IOException, VCardException {
+ // Specifically, there may be some padding between = and CRLF.
+ // See the following:
+ //
+ // qp-line := *(qp-segment transport-padding CRLF)
+ // qp-part transport-padding
+ // qp-segment := qp-section *(SPACE / TAB) "="
+ // ; Maximum length of 76 characters
+ //
+ // e.g. (from RFC 2045)
+ // Now's the time =
+ // for all folk to come=
+ // to the aid of their country.
+ if (firstString.trim().endsWith("=")) {
+ // remove "transport-padding"
+ int pos = firstString.length() - 1;
+ while(firstString.charAt(pos) != '=') {
+ }
+ StringBuilder builder = new StringBuilder();
+ builder.append(firstString.substring(0, pos + 1));
+ builder.append("\r\n");
+ String line;
+ while (true) {
+ line = getLine();
+ if (line == null) {
+ throw new VCardException(
+ "File ended during parsing quoted-printable String");
+ }
+ if (line.trim().endsWith("=")) {
+ // remove "transport-padding"
+ pos = line.length() - 1;
+ while(line.charAt(pos) != '=') {
+ }
+ builder.append(line.substring(0, pos + 1));
+ builder.append("\r\n");
+ } else {
+ builder.append(line);
+ break;
+ }
+ }
+ return builder.toString();
+ } else {
+ return firstString;
}
-
- return sum;
}
-
- /** "LANGUAGE" [ws] "=" [ws] langval */
- private int parseParam4(int offset) {
- int ret = 0, sum = 0, start = offset;
-
- ret = parseString(offset, "LANGUAGE", true);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
- if (mBuilder != null) {
- mBuilder.propertyParamType(mBuffer.substring(start, offset));
- }
-
- ret = removeWs(offset);
- offset += ret;
- sum += ret;
-
- ret = parseString(offset, "=", false);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
-
- ret = removeWs(offset);
- offset += ret;
- sum += ret;
-
- start = offset;
- ret = parseLangVal(offset);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
- if (mBuilder != null) {
- mBuilder.propertyParamValue(mBuffer.substring(start, offset));
+
+ protected String getBase64(String firstString) throws IOException, VCardException {
+ StringBuilder builder = new StringBuilder();
+ builder.append(firstString);
+
+ while (true) {
+ String line = getLine();
+ if (line == null) {
+ throw new VCardException(
+ "File ended during parsing BASE64 binary");
+ }
+ if (line.length() == 0) {
+ break;
+ }
+ builder.append(line);
}
-
- return sum;
-
+
+ return builder.toString();
}
-
- /** "X-" word [ws] "=" [ws] word */
- private int parseParam5(int offset) {
- int ret = 0, sum = 0, start = offset;
-
- ret = parseXWord(offset);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
- if (mBuilder != null) {
- mBuilder.propertyParamType(mBuffer.substring(start, offset));
- }
-
- ret = removeWs(offset);
- offset += ret;
- sum += ret;
-
- ret = parseString(offset, "=", false);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
+
+ /**
+ * Mainly for "ADR", "ORG", and "N"
+ * We do not care the number of strnosemi here.
+ *
+ * addressparts = 0*6(strnosemi ";") strnosemi
+ * ; PO Box, Extended Addr, Street, Locality, Region,
+ * Postal Code, Country Name
+ * orgparts = *(strnosemi ";") strnosemi
+ * ; First is Organization Name,
+ * remainder are Organization Units.
+ * nameparts = 0*4(strnosemi ";") strnosemi
+ * ; Family, Given, Middle, Prefix, Suffix.
+ * ; Example:Public;John;Q.;Reverend Dr.;III, Esq.
+ * strnosemi = *(*nonsemi ("\;" / "\" CRLF)) *nonsemi
+ * ; To include a semicolon in this string, it must be escaped
+ * ; with a "\" character.
+ *
+ * We are not sure whether we should add "\" CRLF to each value.
+ * For now, we exclude them.
+ */
+ protected void handleMultiplePropertyValue(
+ String propertyName, String propertyValue) throws IOException, VCardException {
+ // vCard 2.1 does not allow QUOTED-PRINTABLE here, but some data have it.
+ if (mEncoding.equalsIgnoreCase("QUOTED-PRINTABLE")) {
+ propertyValue = getQuotedPrintable(propertyValue);
+ }
+
+ if (propertyValue.endsWith("\\")) {
+ StringBuilder builder = new StringBuilder();
+ // builder.append(propertyValue);
+ builder.append(propertyValue.substring(0, propertyValue.length() - 1));
+ try {
+ String line;
+ while (true) {
+ line = getNonEmptyLine();
+ // builder.append("\r\n");
+ // builder.append(line);
+ if (!line.endsWith("\\")) {
+ builder.append(line);
+ break;
+ } else {
+ builder.append(line.substring(0, line.length() - 1));
+ }
+ }
+ } catch (IOException e) {
+ throw new VCardException(
+ "IOException is throw during reading propertyValue" + e);
+ }
+ // Now, propertyValue may contain "\r\n"
+ propertyValue = builder.toString();
}
- offset += ret;
- sum += ret;
- ret = removeWs(offset);
- offset += ret;
- sum += ret;
-
- start = offset;
- ret = parseWord(offset);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
if (mBuilder != null) {
- mBuilder.propertyParamValue(mBuffer.substring(start, offset));
+ // In String#replaceAll() and Pattern class, "\\\\" means single slash.
+
+ final String IMPOSSIBLE_STRING = "\0";
+ // First replace two backslashes with impossible strings.
+ propertyValue = propertyValue.replaceAll("\\\\\\\\", IMPOSSIBLE_STRING);
+
+ // Now, split propertyValue with ; whose previous char is not back slash.
+ Pattern pattern = Pattern.compile("(? arrayList = new ArrayList();
+ for (String str : strArray) {
+ // Replace impossible strings with original two backslashes
+ arrayList.add(
+ unescapeText(str.replaceAll(IMPOSSIBLE_STRING, "\\\\\\\\")));
+ }
+ mBuilder.propertyValues(arrayList);
}
-
- return sum;
}
-
+
/**
- * knowntype: "DOM" / "INTL" / ...
+ * vCard 2.1 specifies AGENT allows one vcard entry. It is not encoded at all.
*/
- private int parseKnownType(int offset) {
- String word = getWord(offset);
-
- if (mKnownTypeSet.contains(word.toUpperCase())) {
- return word.length();
- }
- return PARSE_ERROR;
+ protected void handleAgent(String propertyValue) throws IOException, VCardException {
+ String[] strArray = propertyValue.split(":", 2);
+ if (!(strArray.length == 2 ||
+ strArray[0].trim().equalsIgnoreCase("BEGIN") &&
+ strArray[1].trim().equalsIgnoreCase("VCARD"))) {
+ throw new VCardException("BEGIN:VCARD != \"" + propertyValue + "\"");
+ }
+ parseItems();
+ readEndVCard();
}
-
- /** knowntype / "X-" word */
- private int parsePTypeVal(int offset) {
- int ret = 0, sum = 0;
-
- ret = parseKnownType(offset);
- if (ret != PARSE_ERROR) {
- sum += ret;
- return sum;
- }
-
- ret = parseXWord(offset);
- if (ret != PARSE_ERROR) {
- sum += ret;
- return sum;
- }
- sum += ret;
-
- return sum;
+
+ /**
+ * For vCard 3.0.
+ */
+ protected String maybeUnescapeText(String text) {
+ return text;
}
-
- /** "LOGO" /.../ XWord, case insensitive */
- private int parseName(int offset) {
- int ret = 0;
- ret = parseXWord(offset);
- if (ret != PARSE_ERROR) {
- return ret;
- }
- String word = getWord(offset).toUpperCase();
- if (mName.contains(word)) {
- return word.length();
- }
- return PARSE_ERROR;
+
+ /**
+ * Convert escaped text into unescaped text.
+ */
+ protected String unescapeText(String text) {
+ // Original vCard 2.1 specification does not allow transformation
+ // "\:" -> ":", "\," -> ",", and "\\" -> "\", but previous implementation of
+ // this class allowed them, so keep it as is.
+ // In String#replaceAll(), "\\\\" means single slash.
+ return text.replaceAll("\\\\;", ";")
+ .replaceAll("\\\\:", ":")
+ .replaceAll("\\\\,", ",")
+ .replaceAll("\\\\\\\\", "\\\\");
}
+
+ /**
+ * Parse the given stream and constructs VCardDataBuilder object.
+ * Note that vCard 2.1 specification allows "CHARSET" parameter, and some career sets
+ * local encoding to it. For example, Japanese phone career uses Shift_JIS, which
+ * is not formally allowed in vCard specification.
+ * As a result, there is a case where the encoding given here does not do well with
+ * the "CHARSET".
+ *
+ * In order to avoid such cases, It may be fine to use "ISO-8859-1" as an encoding,
+ * and to encode each localized String afterward.
+ *
+ * RFC 2426 "recommends" (not forces) to use UTF-8, so it may be OK to use
+ * UTF-8 as an encoding when parsing vCard 3.0. But note that some Japanese
+ * phone uses Shift_JIS as a charset (e.g. W61SH), and another uses
+ * "CHARSET=SHIFT_JIS", which is explicitly prohibited in vCard 3.0 specification
+ * (e.g. W53K).
+ *
+ * @param is
+ * The source to parse.
+ * @param charset
+ * The charset.
+ * @param builder
+ * The v builder which used to construct data.
+ * @return Return true for success, otherwise false.
+ * @throws IOException
+ */
+ public boolean parse(InputStream is, String charset, VBuilder builder)
+ throws IOException, VCardException {
+ // TODO: If we really need to allow only CRLF as line break,
+ // we will have to develop our own BufferedReader().
+ mReader = new BufferedReader(new InputStreamReader(is, charset));
+
+ mBuilder = builder;
- /** groups "." word / word */
- private int parseGroups(int offset) {
- int ret = 0, sum = 0;
-
- ret = parseWord(offset);
- if (ret == PARSE_ERROR) {
- return PARSE_ERROR;
+ if (mBuilder != null) {
+ mBuilder.start();
}
- offset += ret;
- sum += ret;
-
- for (;;) {
- ret = parseString(offset, ".", false);
- if (ret == PARSE_ERROR) {
- break;
- }
-
- int ret1 = parseWord(offset);
- if (ret1 == PARSE_ERROR) {
- break;
- }
- offset += ret + ret1;
- sum += ret + ret1;
+ parseVCardFile();
+ if (mBuilder != null) {
+ mBuilder.end();
}
- return sum;
+ return true;
}
-
- /**
- * Translate escape characters("\\", "\;") which define in vcard2.1 spec.
- * But for fault tolerance, we will translate "\:" and "\,", which isn't
- * define in vcard2.1 explicitly, as the same behavior as other client.
- *
- * @param str:
- * the string will be translated.
- * @return the string which do not contain any escape character in vcard2.1
- */
- private String escapeTranslator(String str) {
- if (null == str)
- return null;
-
- String tmp = str.replace("\\\\", "\n\r\n");
- tmp = tmp.replace("\\;", ";");
- tmp = tmp.replace("\\:", ":");
- tmp = tmp.replace("\\,", ",");
- tmp = tmp.replace("\n\r\n", "\\");
- return tmp;
+
+ private boolean isLetter(char ch) {
+ if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {
+ return true;
+ }
+ return false;
}
}
diff --git a/core/java/android/syncml/pim/vcard/VCardParser_V30.java b/core/java/android/syncml/pim/vcard/VCardParser_V30.java
index c56cfed82908..901bd49ef006 100644
--- a/core/java/android/syncml/pim/vcard/VCardParser_V30.java
+++ b/core/java/android/syncml/pim/vcard/VCardParser_V30.java
@@ -16,142 +16,270 @@
package android.syncml.pim.vcard;
-import android.syncml.pim.VBuilder;
-
-import java.io.ByteArrayInputStream;
import java.io.IOException;
-import java.io.InputStream;
+import java.util.ArrayList;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.HashSet;
/**
* This class is used to parse vcard3.0.
- * It get useful data refer from android contact, and alter to vCard 2.1 format.
- * Then reuse vcard 2.1 parser to analyze the result.
- * Please refer to vCard Specification 3.0
+ * Please refer to vCard Specification 3.0 (http://tools.ietf.org/html/rfc2426)
*/
public class VCardParser_V30 extends VCardParser_V21 {
- private static final String V21LINEBREAKER = "\r\n";
-
private static final HashSet acceptablePropsWithParam = new HashSet(
- Arrays.asList("PHOTO", "LOGO", "TEL", "EMAIL", "ADR"));
-
- private static final HashSet acceptablePropsWithoutParam = new HashSet(
- Arrays.asList("ORG", "NOTE", "TITLE", "FN", "N"));
-
- private static final HashMap propV30ToV21Map = new HashMap();
+ Arrays.asList(
+ "LOGO", "PHOTO", "LABEL", "FN", "TITLE", "SOUND",
+ "VERSION", "TEL", "EMAIL", "TZ", "GEO", "NOTE", "URL",
+ "BDAY", "ROLE", "REV", "UID", "KEY", "MAILER", // 2.1
+ "NAME", "PROFILE", "SOURCE", "NICKNAME", "CLASS",
+ "SORT-STRING", "CATEGORIES", "PRODID")); // 3.0
+
+ // Although "7bit" and "BASE64" is not allowed in vCard 3.0, we allow it for safety.
+ private static final HashSet sAcceptableEncodingV30 = new HashSet(
+ Arrays.asList("7BIT", "8BIT", "BASE64", "B"));
+
+ // Although RFC 2426 specifies some property must not have parameters, we allow it,
+ // since there may be some careers which violates the RFC...
+ private static final HashSet acceptablePropsWithoutParam = new HashSet();
- static {
- propV30ToV21Map.put("PHOTO", "PHOTO");
- propV30ToV21Map.put("LOGO", "PHOTO");
+ private String mPreviousLine;
+
+ @Override
+ protected String getVersion() {
+ return "3.0";
}
-
+
@Override
- public boolean parse(InputStream is, String encoding, VBuilder builder)
- throws IOException {
- // get useful info for android contact, and alter to vCard 2.1
- byte[] bytes = new byte[is.available()];
- is.read(bytes);
- String scStr = new String(bytes);
- StringBuilder v21str = new StringBuilder("");
-
- String[] strlist = splitProperty(scStr);
-
- if ("BEGIN:vCard".equals(strlist[0])
- || "BEGIN:VCARD".equals(strlist[0])) {
- v21str.append("BEGIN:VCARD" + V21LINEBREAKER);
+ protected boolean isValidPropertyName(String propertyName) {
+ return acceptablePropsWithParam.contains(propertyName) ||
+ acceptablePropsWithoutParam.contains(propertyName);
+ }
+
+ @Override
+ protected boolean isValidEncoding(String encoding) {
+ return sAcceptableEncodingV30.contains(encoding.toUpperCase());
+ }
+
+ @Override
+ protected String getLine() throws IOException {
+ if (mPreviousLine != null) {
+ String ret = mPreviousLine;
+ mPreviousLine = null;
+ return ret;
} else {
- return false;
+ return mReader.readLine();
}
-
- for (int i = 1; i < strlist.length - 1; i++) {// for ever property
- // line
- String propName;
- String params;
- String value;
-
- String line = strlist[i];
- if ("".equals(line)) { // line breaker is useful in encoding string
- v21str.append(V21LINEBREAKER);
- continue;
- }
-
- String[] contentline = line.split(":", 2);
- String propNameAndParam = contentline[0];
- value = (contentline.length > 1) ? contentline[1] : "";
- if (propNameAndParam.length() > 0) {
- String[] nameAndParams = propNameAndParam.split(";", 2);
- propName = nameAndParams[0];
- params = (nameAndParams.length > 1) ? nameAndParams[1] : "";
-
- if (acceptablePropsWithParam.contains(propName)
- || acceptablePropsWithoutParam.contains(propName)) {
- v21str.append(mapContentlineV30ToV21(propName, params,
- value));
+ }
+
+ /**
+ * vCard 3.0 requires that the line with space at the beginning of the line
+ * must be combined with previous line.
+ */
+ @Override
+ protected String getNonEmptyLine() throws IOException, VCardException {
+ String line;
+ StringBuilder builder = null;
+ while (true) {
+ line = mReader.readLine();
+ if (line == null) {
+ if (builder != null) {
+ return builder.toString();
+ } else if (mPreviousLine != null) {
+ String ret = mPreviousLine;
+ mPreviousLine = null;
+ return ret;
+ }
+ throw new VCardException("Reached end of buffer.");
+ } else if (line.length() == 0) {
+ if (builder != null) {
+ return builder.toString();
+ } else if (mPreviousLine != null) {
+ String ret = mPreviousLine;
+ mPreviousLine = null;
+ return ret;
+ }
+ } else if (line.charAt(0) == ' ' || line.charAt(0) == '\t') {
+ if (builder != null) {
+ // TODO: Check whether MIME requires only one whitespace.
+ builder.append(line.substring(1));
+ } else if (mPreviousLine != null) {
+ builder = new StringBuilder();
+ builder.append(mPreviousLine);
+ mPreviousLine = null;
+ builder.append(line.substring(1));
+ } else {
+ throw new VCardException("Space exists at the beginning of the line");
+ }
+ } else {
+ if (mPreviousLine == null) {
+ mPreviousLine = line;
+ } else {
+ String ret = mPreviousLine;
+ mPreviousLine = line;
+ return ret;
}
}
- }// end for
-
- if ("END:vCard".equals(strlist[strlist.length - 1])
- || "END:VCARD".equals(strlist[strlist.length - 1])) {
- v21str.append("END:VCARD" + V21LINEBREAKER);
- } else {
- return false;
}
-
- return super.parse(
- // use vCard 2.1 parser
- new ByteArrayInputStream(v21str.toString().getBytes()),
- encoding, builder);
}
-
+
+
/**
- * Convert V30 string to V21 string
- *
- * @param propName
- * The name of property
- * @param params
- * parameter of property
- * @param value
- * value of property
- * @return the converted string
+ * vcard = [group "."] "BEGIN" ":" "VCARD" 1*CRLF
+ * 1*(contentline)
+ * ;A vCard object MUST include the VERSION, FN and N types.
+ * [group "."] "END" ":" "VCARD" 1*CRLF
*/
- private String mapContentlineV30ToV21(String propName, String params,
- String value) {
- String result;
+ @Override
+ protected boolean readBeginVCard() throws IOException, VCardException {
+ // TODO: vCard 3.0 supports group.
+ return super.readBeginVCard();
+ }
+
+ @Override
+ protected void readEndVCard() throws VCardException {
+ // TODO: vCard 3.0 supports group.
+ super.readEndVCard();
+ }
- if (propV30ToV21Map.containsKey(propName)) {
- result = propV30ToV21Map.get(propName);
- } else {
- result = propName;
+ /**
+ * vCard 3.0 allows iana-token as paramType, while vCard 2.1 does not.
+ */
+ @Override
+ protected void handleParams(String params) throws VCardException {
+ try {
+ super.handleParams(params);
+ } catch (VCardException e) {
+ // maybe IANA type
+ String[] strArray = params.split("=", 2);
+ if (strArray.length == 2) {
+ handleAnyParam(strArray[0], strArray[1]);
+ } else {
+ // Must not come here in the current implementation.
+ throw new VCardException(
+ "Unknown params value: " + params);
+ }
+ }
+ }
+
+ @Override
+ protected void handleAnyParam(String paramName, String paramValue) {
+ // vCard 3.0 accept comma-separated multiple values, but
+ // current PropertyNode does not accept it.
+ // For now, we do not split the values.
+ //
+ // TODO: fix this.
+ super.handleAnyParam(paramName, paramValue);
+ }
+
+ /**
+ * vCard 3.0 defines
+ *
+ * param = param-name "=" param-value *("," param-value)
+ * param-name = iana-token / x-name
+ * param-value = ptext / quoted-string
+ * quoted-string = DQUOTE QSAFE-CHAR DQUOTE
+ */
+ @Override
+ protected void handleType(String ptypevalues) {
+ String[] ptypeArray = ptypevalues.split(",");
+ mBuilder.propertyParamType("TYPE");
+ for (String value : ptypeArray) {
+ int length = value.length();
+ if (length >= 2 && value.startsWith("\"") && value.endsWith("\"")) {
+ mBuilder.propertyParamValue(value.substring(1, value.length() - 1));
+ } else {
+ mBuilder.propertyParamValue(value);
+ }
}
- // Alter parameter part of property to vCard 2.1 format
- if (acceptablePropsWithParam.contains(propName) && params.length() > 0)
- result = result
- + ";"
- + params.replaceAll(",", ";").replaceAll("ENCODING=B",
- "ENCODING=BASE64").replaceAll("ENCODING=b",
- "ENCODING=BASE64");
+ }
- return result + ":" + value + V21LINEBREAKER;
+ @Override
+ protected void handleAgent(String propertyValue) throws VCardException {
+ // The way how vCard 3.0 supports "AGENT" is completely different from vCard 2.0.
+ //
+ // e.g.
+ // AGENT:BEGIN:VCARD\nFN:Joe Friday\nTEL:+1-919-555-7878\n
+ // TITLE:Area Administrator\, Assistant\n EMAIL\;TYPE=INTERN\n
+ // ET:jfriday@host.com\nEND:VCARD\n
+ //
+ // TODO: fix this.
+ //
+ // issue:
+ // vCard 3.0 also allows this as an example.
+ //
+ // AGENT;VALUE=uri:
+ // CID:JQPUBLIC.part3.960129T083020.xyzMail@host3.com
+ //
+ // This is not VCARD. Should we support this?
+ throw new VCardException("AGENT in vCard 3.0 is not supported yet.");
+ }
+
+ // vCard 3.0 supports "B" as BASE64 encoding.
+ @Override
+ protected void handlePropertyValue(
+ String propertyName, String propertyValue) throws
+ IOException, VCardException {
+ if (mEncoding != null && mEncoding.equalsIgnoreCase("B")) {
+ String result = getBase64(propertyValue);
+ if (mBuilder != null) {
+ ArrayList v = new ArrayList();
+ v.add(result);
+ mBuilder.propertyValues(v);
+ }
+ }
+
+ super.handlePropertyValue(propertyName, propertyValue);
+ }
+
+ /**
+ * vCard 3.0 does not require two CRLF at the last of BASE64 data.
+ * It only requires that data should be MIME-encoded.
+ */
+ @Override
+ protected String getBase64(String firstString) throws IOException, VCardException {
+ StringBuilder builder = new StringBuilder();
+ builder.append(firstString);
+
+ while (true) {
+ String line = getLine();
+ if (line == null) {
+ throw new VCardException(
+ "File ended during parsing BASE64 binary");
+ }
+ if (line.length() == 0) {
+ break;
+ } else if (!line.startsWith(" ") && !line.startsWith("\t")) {
+ mPreviousLine = line;
+ break;
+ }
+ builder.append(line);
+ }
+
+ return builder.toString();
+ }
+
+ /**
+ * Return unescapeText(text).
+ * In vCard 3.0, 8bit text is always encoded.
+ */
+ @Override
+ protected String maybeUnescapeText(String text) {
+ return unescapeText(text);
}
/**
- * Split ever property line to Stringp[], not split folding line.
- *
- * @param scStr
- * the string to be splitted
- * @return a list of splitted string
+ * ESCAPED-CHAR = "\\" / "\;" / "\," / "\n" / "\N")
+ * ; \\ encodes \, \n or \N encodes newline
+ * ; \; encodes ;, \, encodes ,
*/
- private String[] splitProperty(String scStr) {
- /*
- * Property splitted by \n, and unfold folding lines by removing
- * CRLF+LWSP-char
- */
- scStr = scStr.replaceAll("\r\n", "\n").replaceAll("\n ", "")
- .replaceAll("\n\t", "");
- String[] strs = scStr.split("\n");
- return strs;
+ @Override
+ protected String unescapeText(String text) {
+ // In String#replaceAll(), "\\\\" means single slash.
+ return text.replaceAll("\\\\;", ";")
+ .replaceAll("\\\\:", ":")
+ .replaceAll("\\\\,", ",")
+ .replaceAll("\\\\n", "\r\n")
+ .replaceAll("\\\\N", "\r\n")
+ .replaceAll("\\\\\\\\", "\\\\");
}
}
diff --git a/core/java/android/syncml/pim/vcard/VCardVersionException.java b/core/java/android/syncml/pim/vcard/VCardVersionException.java
new file mode 100644
index 000000000000..1ca88d120095
--- /dev/null
+++ b/core/java/android/syncml/pim/vcard/VCardVersionException.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.syncml.pim.vcard;
+
+/**
+ * VCardException used only when the version of the vCard is different.
+ */
+public class VCardVersionException extends VCardException {
+ public VCardVersionException() {
+ }
+
+ public VCardVersionException(String message) {
+ super(message);
+ }
+}
diff --git a/tests/AndroidTests/res/raw/v21_backslash.vcf b/tests/AndroidTests/res/raw/v21_backslash.vcf
new file mode 100644
index 000000000000..bd3002b32b10
--- /dev/null
+++ b/tests/AndroidTests/res/raw/v21_backslash.vcf
@@ -0,0 +1,5 @@
+BEGIN:VCARD
+VERSION:2.1
+N:;A\;B\\;C\\\;;D;\:E;\\\\;
+FN:A;B\C\;D:E\\
+END:VCARD
diff --git a/tests/AndroidTests/res/raw/v21_complicated.vcf b/tests/AndroidTests/res/raw/v21_complicated.vcf
new file mode 100644
index 000000000000..de34e1668f73
--- /dev/null
+++ b/tests/AndroidTests/res/raw/v21_complicated.vcf
@@ -0,0 +1,106 @@
+BEGIN:VCARD
+VERSION:2.1
+N:Gump;Forrest;Hoge;Pos;Tao
+FN:Joe Due
+ORG:Gump Shrimp Co.;Sales Dept.\;Manager;Fish keeper
+ROLE:Fish Cake Keeper!
+X-CLASS:PUBLIC
+TITLE:Shrimp Man
+TEL;WORK;VOICE:(111) 555-1212
+TEL;HOME;VOICE:(404) 555-1212
+TEL;CELL:0311111111
+TEL;VIDEO:0322222222
+TEL;VOICE:0333333333
+ADR;WORK:;;100 Waters Edge;Baytown;LA;30314;United States of America
+LABEL;WORK;ENCODING=QUOTED-PRINTABLE:100 Waters Edge=0D=0ABaytown, LA 30314=0D=0AUnited States of America
+ADR;HOME:;;42 Plantation St.;Baytown;LA;30314;United States of America
+LABEL;HOME;ENCODING=QUOTED-PRINTABLE:42 Plantation St.=0D=0A=
+Baytown, LA 30314=0D=0A=
+United States of America
+EMAIL;PREF;INTERNET:forrestgump@walladalla.com
+EMAIL;CELL:cell@example.com
+NOTE:The following note is the example from RFC 2045.
+NOTE;ENCODING=QUOTED-PRINTABLE:Now's the time =
+for all folk to come=
+ to the aid of their country.
+
+PHOTO;ENCODING=BASE64;TYPE=JPEG:
+ /9j/4QoPRXhpZgAATU0AKgAAAAgADQEOAAIAAAAPAAAAqgEPAAIAAAAHAAAAugEQAAIAAAAG
+ AAAAwgESAAMAAAABAAEAAAEaAAUAAAABAAAAyAEbAAUAAAABAAAA0AEoAAMAAAABAAIAAAEx
+ AAIAAAAOAAAA2AEyAAIAAAAUAAAA5gITAAMAAAABAAEAAIKYAAIAAAAOAAAA+odpAAQAAAAB
+ AAABhMSlAAcAAAB8AAABCAAABB4yMDA4MTAyOTEzNTUzMQAARG9Db01vAABEOTA1aQAAAABI
+ AAAAAQAAAEgAAAABRDkwNWkgVmVyMS4wMAAyMDA4OjEwOjI5IDEzOjU1OjQ3ACAgICAgICAg
+ ICAgICAAUHJpbnRJTQAwMzAwAAAABgABABQAFAACAQAAAAADAAAANAEABQAAAAEBAQAAAAEQ
+ gAAAAAAAEQkAACcQAAAPCwAAJxAAAAWXAAAnEAAACLAAACcQAAAcAQAAJxAAAAJeAAAnEAAA
+ AIsAACcQAAADywAAJxAAABvlAAAnEAAogpoABQAAAAEAAANqgp0ABQAAAAEAAANyiCIAAwAA
+ AAEAAgAAkAAABwAAAAQwMjIwkAMAAgAAABQAAAN6kAQAAgAAABQAAAOOkQEABwAAAAQBAgMA
+ kQIABQAAAAEAAAOikgEACgAAAAEAAAOqkgIABQAAAAEAAAOykgQACgAAAAEAAAO6kgUABQAA
+ AAEAAAPCkgcAAwAAAAEAAgAAkggAAwAAAAEAAAAAkgkAAwAAAAEAAAAAkgoABQAAAAEAAAPK
+ knwABwAAAAEAAAAAkoYABwAAABYAAAPSoAAABwAAAAQwMTAwoAEAAwAAAAEAAQAAoAIAAwAA
+ AAEAYAAAoAMAAwAAAAEASAAAoAUABAAAAAEAAAQAog4ABQAAAAEAAAPoog8ABQAAAAEAAAPw
+ ohAAAwAAAAEAAgAAohcAAwAAAAEAAgAAowAABwAAAAEDAAAAowEABwAAAAEBAAAApAEAAwAA
+ AAEAAAAApAIAAwAAAAEAAAAApAMAAwAAAAEAAAAApAQABQAAAAEAAAP4pAUAAwAAAAEAHQAA
+ pAYAAwAAAAEAAAAApAcAAwAAAAEAAAAApAgAAwAAAAEAAAAApAkAAwAAAAEAAAAApAoAAwAA
+ AAEAAAAApAwAAwAAAAEAAgAAAAAAAAAAAFMAACcQAAABXgAAAGQyMDA4OjEwOjI5IDEzOjU1
+ OjMxADIwMDg6MTA6MjkgMTM6NTU6NDcAAAApiAAAGwAAAAKyAAAAZAAAAV4AAABkAAAAAAAA
+ AGQAAAAlAAAACgAADpIAAAPoAAAAAAAAAAAyMDA4MTAyOTEzNTUzMQAAICoAAAAKAAAq4gAA
+ AAoAAAAAAAAAAQACAAEAAgAAAARSOTgAAAIABwAAAAQwMTAwAAAAAAAGAQMAAwAAAAEABgAA
+ ARoABQAAAAEAAARsARsABQAAAAEAAAR0ASgAAwAAAAEAAgAAAgEABAAAAAEAAAR8AgIABAAA
+ AAEAAAWLAAAAAAAAAEgAAAABAAAASAAAAAH/2P/bAIQAIBYYHBgUIBwaHCQiICYwUDQwLCww
+ YkZKOlB0Znp4cmZwboCQuJyAiK6KbnCg2qKuvsTO0M58muLy4MjwuMrOxgEiJCQwKjBeNDRe
+ xoRwhMbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbG
+ /8AAEQgAeACgAwEhAAIRAQMRAf/EAaIAAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKCxAA
+ AgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkK
+ FhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWG
+ h4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl
+ 5ufo6erx8vP09fb3+Pn6AQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJCgsRAAIBAgQEAwQH
+ BQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBka
+ JicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKT
+ lJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz
+ 9PX29/j5+v/aAAwDAQACEQMRAD8AFFSqKkZIoqRVpgSKKeBTEOApwFADsUYpgIRSEUANIppF
+ ICNhUTCgCMio2FICJhULCgC0oqVaAJFFSqKBkgFOApiHCnCgB2KMUCENJQA0imEUDGMKiYUA
+ RtUbUgIWqJhQBZSpFoAlWpVoGPFPFMQ7tSK2ODQA4yKO9HmKe9FxAzDHFIOlAAaYaAGNUTUD
+ ImqNqQETVE1AE6VKKAJFNSqaAHg08GmANIFFQM5Y5qJMBuT60ZNQIcrkVYSQMKuLGKaaasQx
+ qiagZE1RtSAjaomoAkQ1KpoAlU1IpoAkU07OBTArO+5qkV12Y71lfUBmaKkCRSuznrTFba2a
+ oCwGyM0E1qIjY1GxoGRNUZNICNqiagByGplNAEimpFNMB4YDvSucpxSYEIU04KazsAu1qArU
+ WELtPpTSposBNETt5pxNaoCNjUbGgCNjUZoGRtUTUgFU1KpoAkBqQHigCFnO7rUqOdlZp6gA
+ c+tODn1pXAXzD60eYfWncQvmNSGQ07gOMhCVEJGz1ptgS5yKYxqwGE1GxoAiamGkMapqVTQB
+ Kpp+eKAICfmqWM/Kaz6gANOBqQFzRmmAuaTNACsfkqMHmm9wJs8U0mtRDGNRsaAI2phpDI1N
+ SqaAJFNSA8UCISfmqSM/Kaz6jAHmnA1ICg0uaAFzSZpgKx+SmDrTe4E2eKaTWoiMmmMaAIzT
+ DSGRKakU0ASKaeDTERseakjPyms+oxAacDUgOBpc0gFzSZpgOY/KKYv3qrqIlpprQBjGoyaA
+ GGmmkMgU1IppgPBqQGgQu0Gn4wvFKwEQpwNZDHZpc0ALmigRKBleaQKBWtgA001QDGqM0gGm
+ mGkMrqakBoAepp4NMRIDTwaAE2A008GokgHxjd1pzKFpW0uAg5NSBBTirgOpDWgDTTTQAw0w
+ 0gGGmmgZWBp4pASKaeDTEOBp4NADwajbrUyBEkXWnSUdAGr1qeiAMSkNWAhphoAaaYaQDDTT
+ SGVRTwaYDxTwaBDwaeDQA4GlK5oauIeo20pGaLaAKqgU6hKwBSGmAhphoAaaYaQxhpppDKgN
+ PFMB4p4oEPFOBpgPBp4NAhwpwoAWloAKSgBDTTQMYaYaQDTTTSGA/9n/2wCEAAoHBwgHBgoI
+ CAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4+JS5ESUM8SDc9
+ PjsBCgsLDg0OHBAQHDsoIig7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7
+ Ozs7Ozs7Ozs7Ozs7O//AABEIAEgAYAMBIQACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAA
+ AQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNC
+ scEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hp
+ anN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS
+ 09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcI
+ CQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVi
+ ctEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4
+ eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY
+ 2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/AJ7SLgcVr20I4rNFGvbQAAHFaEUX
+ SrQi5HCMdKk8oY6VSJYx4hjpVaWMelAFC4iGDxWPdR8mkxmRdxjBrEvI+tZjN20xtHNbNqAc
+ UIDXg6Cr0WKtCY8XKQOyzOB3FKNWsyceZ+lS6sY6NkjvPSdwImBHUmmy4q076oCjOODWPdgc
+ 0MpGPdAYNYl4o5rNjNKzkyorZtXxihAa1vIDip7m9Frb7/4jwKcnyxbEzN3ieJppZsyZ4U1H
+ urzZau4mWVlNrGk0UuWPVa1YroXEIkHfrXZh5W90RWncAHmsi6bJNdQ0ZNw3BrGuiMGs2Mks
+ puBzWzbzdOaEBeOpR2oUtkk9hTru7iuo4m8wgemKyqTi04sBsfkEf68j8KlUQZz9o/SuZRj3
+ JYriAji4/Sp7W6htbV2aXcu70ramoxle4gN7HcIXjbis+4k5NdaaauhmVcv1rHuW61DGiG1m
+ 6c1s20/TmgAv5vmj57VKk3+ixnPc1xVV70h9CVJuOtSrL71hFgxzScUkkn+iY/2q1i9xDrGT
+ 9y31pJ5Otd1L+GhMy7mTrWXO2SapjRn28vTmta3nxjmgGOvJd2w1Kkv+ipz/ABGuOoveYdCe
+ ObjrU6y5rlsA8ycUksn+ij/eNaw6iJLNsW59zTJn6816FP4EJmbO+Saz5m602UjIgk4HNadv
+ LwKaBl+MpIMOMipp490SCJeF7CoqQvF2JuRqWQ4YEGrSiQJuKnHrXByMpki73GFBNXIoh9n2
+ SrnnOK6MPTbd3sSwIVF2qMCqkzHmuy1lYRnTHrVGWpZaMKB+BWlbycYoQM0IZDxzV+GU8c1a
+ IYy5Y+dnHatAsfsAHfArmS1mPoh1gT8x9qtk1rQX7tCe5DIapzGtGBQm71SlqGWjnIH6Vowt
+ zmhAy/E3vV6F6tEMuxlWIyAfrVxCCAO1VZEEyYA4AApxNGwyJ+lVJRUsaKMw61SlFQzRAP/Z
+
+X-ATTRIBUTE:Some String
+BDAY:19800101
+GEO:35.6563854,139.6994233
+URL:http://www.example.com/
+REV:20080424T195243Z
+END:VCARD
\ No newline at end of file
diff --git a/tests/AndroidTests/res/raw/v21_japanese_1.vcf b/tests/AndroidTests/res/raw/v21_japanese_1.vcf
new file mode 100644
index 000000000000..d05e2fffb180
--- /dev/null
+++ b/tests/AndroidTests/res/raw/v21_japanese_1.vcf
@@ -0,0 +1,6 @@
+BEGIN:VCARD
+VERSION:2.1
+N;CHARSET=SHIFT_JIS:ˆÀ“¡ƒƒCƒh;;;;
+SOUND;X-IRMC-N;CHARSET=SHIFT_JIS:±ÝÄÞ³Û²ÄÞ;;;;
+TEL;PREF;VOICE:0300000000
+END:VCARD
diff --git a/tests/AndroidTests/res/raw/v21_japanese_2.vcf b/tests/AndroidTests/res/raw/v21_japanese_2.vcf
new file mode 100644
index 000000000000..fa54acbc89c7
--- /dev/null
+++ b/tests/AndroidTests/res/raw/v21_japanese_2.vcf
@@ -0,0 +1,10 @@
+BEGIN:VCARD
+VERSION:2.1
+FN;CHARSET=SHIFT_JIS:ˆÀ“¡ ƒƒCƒh 1
+N;CHARSET=SHIFT_JIS:ˆÀ“¡;ƒƒCƒh1;;;
+SOUND;X-IRMC-N;CHARSET=SHIFT_JIS:±ÝÄÞ³;Û²ÄÞ1;;;
+ADR;HOME;CHARSET=SHIFT_JIS;ENCODING=QUOTED-PRINTABLE:;=93=8C=8B=9E=93=73=
+=8F=61=92=4A=8B=E6=8D=F7=8B=75=92=AC26-1=83=5A=83=8B=83=8A=83=41=83=93=
+=83=5E=83=8F=81=5B6=8A=4B;;;;150-8512;
+NOTE;CHARSET=SHIFT_JIS;ENCODING=QUOTED-PRINTABLE:=83=81=83=82
+END:VCARD
diff --git a/tests/AndroidTests/res/raw/v21_multiple_entry.vcf b/tests/AndroidTests/res/raw/v21_multiple_entry.vcf
new file mode 100644
index 000000000000..ebbb19a4bc3f
--- /dev/null
+++ b/tests/AndroidTests/res/raw/v21_multiple_entry.vcf
@@ -0,0 +1,33 @@
+BEGIN:VCARD
+VERSION:2.1
+N;CHARSET=SHIFT_JIS:ˆÀ“¡ƒƒCƒh3;;;;
+SOUND;X-IRMC-N;CHARSET=SHIFT_JIS:±ÝÄÞ³Û²ÄÞ3;;;;
+TEL;X-NEC-SECRET:9
+TEL;X-NEC-HOTEL:10
+TEL;X-NEC-SCHOOL:11
+TEL;HOME;FAX:12
+END:VCARD
+
+
+BEGIN:VCARD
+VERSION:2.1
+N;CHARSET=SHIFT_JIS:ˆÀ“¡ƒƒCƒh4;;;;
+SOUND;X-IRMC-N;CHARSET=SHIFT_JIS:±ÝÄÞ³Û²ÄÞ4;;;;
+TEL;MODEM:13
+TEL;PAGER:14
+TEL;X-NEC-FAMILY:15
+TEL;X-NEC-GIRL:16
+END:VCARD
+
+
+BEGIN:VCARD
+VERSION:2.1
+N;CHARSET=SHIFT_JIS:ˆÀ“¡ƒƒCƒh5;;;;
+SOUND;X-IRMC-N;CHARSET=SHIFT_JIS:±ÝÄÞ³Û²ÄÞ5;;;;
+TEL;X-NEC-BOY:17
+TEL;X-NEC-FRIEND:18
+TEL;X-NEC-PHS:19
+TEL;X-NEC-RESTAURANT:20
+END:VCARD
+
+
diff --git a/tests/AndroidTests/res/raw/v21_simple.vcf b/tests/AndroidTests/res/raw/v21_simple.vcf
new file mode 100644
index 000000000000..beddabb96086
--- /dev/null
+++ b/tests/AndroidTests/res/raw/v21_simple.vcf
@@ -0,0 +1,4 @@
+BEGIN:VCARD
+N:Ando;Roid;
+FN:Ando Roid
+END:VCARD
diff --git a/tests/AndroidTests/res/raw/v30_simple.vcf b/tests/AndroidTests/res/raw/v30_simple.vcf
new file mode 100644
index 000000000000..418661f7468a
--- /dev/null
+++ b/tests/AndroidTests/res/raw/v30_simple.vcf
@@ -0,0 +1,13 @@
+BEGIN:VCARD
+VERSION:3.0
+FN:And Roid
+N:And;Roid;;;
+ORG:Open;Handset; Alliance
+SORT-STRING:android
+TEL;TYPE=PREF;TYPE=VOICE:0300000000
+CLASS:PUBLIC
+X-GNO:0
+X-GN:group0
+X-REDUCTION:0
+REV:20081031T065854Z
+END:VCARD
diff --git a/tests/AndroidTests/src/com/android/unit_tests/VCardTests.java b/tests/AndroidTests/src/com/android/unit_tests/VCardTests.java
new file mode 100644
index 000000000000..b7f562ddc947
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/VCardTests.java
@@ -0,0 +1,773 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.content.ContentValues;
+import android.syncml.pim.PropertyNode;
+import android.syncml.pim.VDataBuilder;
+import android.syncml.pim.VNode;
+import android.syncml.pim.vcard.VCardException;
+import android.syncml.pim.vcard.VCardParser_V21;
+import android.syncml.pim.vcard.VCardParser_V30;
+import android.test.AndroidTestCase;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Vector;
+
+public class VCardTests extends AndroidTestCase {
+
+ private class PropertyNodesVerifier {
+ private HashMap> mPropertyNodeMap;
+ public PropertyNodesVerifier(PropertyNode... nodes) {
+ mPropertyNodeMap = new HashMap>();
+ for (PropertyNode propertyNode : nodes) {
+ String propName = propertyNode.propName;
+ Vector expectedNodes =
+ mPropertyNodeMap.get(propName);
+ if (expectedNodes == null) {
+ expectedNodes = new Vector();
+ mPropertyNodeMap.put(propName, expectedNodes);
+ }
+ expectedNodes.add(propertyNode);
+ }
+ }
+
+ public void verify(VNode vnode) {
+ for (PropertyNode propertyNode : vnode.propList) {
+ String propName = propertyNode.propName;
+ Vector nodes = mPropertyNodeMap.get(propName);
+ if (nodes == null) {
+ fail("Unexpected propName \"" + propName + "\" exists.");
+ }
+ boolean successful = false;
+ int size = nodes.size();
+ for (int i = 0; i < size; i++) {
+ PropertyNode expectedNode = nodes.get(i);
+ if (expectedNode.propName.equals(propName)) {
+ if (expectedNode.equals(propertyNode)) {
+ successful = true;
+ nodes.remove(i);
+ if (nodes.size() == 0) {
+ mPropertyNodeMap.remove(propName);
+ }
+ break;
+ } else {
+ fail("Property \"" + propName + "\" has wrong value.\n"
+ + "expected: " + expectedNode.toString()
+ + "\n actual: " + propertyNode.toString());
+ }
+ }
+ }
+ if (!successful) {
+ fail("Unexpected property \"" + propName + "\" exists.");
+ }
+ }
+ if (mPropertyNodeMap.size() != 0) {
+ Vector expectedProps = new Vector();
+ for (Vector nodes : mPropertyNodeMap.values()) {
+ for (PropertyNode node : nodes) {
+ expectedProps.add(node.propName);
+ }
+ }
+ fail("expected props " + Arrays.toString(expectedProps.toArray()) +
+ " was not found");
+ }
+ }
+ }
+
+ public void testV21SimpleCase() throws IOException, VCardException {
+ VCardParser_V21 parser = new VCardParser_V21();
+ VDataBuilder builder = new VDataBuilder();
+ InputStream is = getContext().getResources().openRawResource(R.raw.v21_simple);
+ assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
+ is.close();
+ assertEquals(1, builder.vNodeList.size());
+ PropertyNodesVerifier verifier = new PropertyNodesVerifier(
+ new PropertyNode("N", "Ando;Roid;",
+ Arrays.asList("Ando", "Roid", ""),
+ null, null, null, null),
+ new PropertyNode("FN", "Ando Roid",
+ null, null, null, null, null));
+ verifier.verify(builder.vNodeList.get(0));
+ }
+
+ public void testV21BackslashCase() throws IOException, VCardException {
+ VCardParser_V21 parser = new VCardParser_V21();
+ VDataBuilder builder = new VDataBuilder();
+ InputStream is = getContext().getResources().openRawResource(R.raw.v21_backslash);
+ assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
+ is.close();
+ assertEquals(1, builder.vNodeList.size());
+ PropertyNodesVerifier verifier = new PropertyNodesVerifier(
+ new PropertyNode("VERSION", "2.1",
+ null, null, null, null, null),
+ new PropertyNode("N", ";A;B\\;C\\;;D;:E;\\\\;",
+ Arrays.asList("", "A;B\\", "C\\;", "D", ":E", "\\\\", ""),
+ null, null, null, null),
+ new PropertyNode("FN", "A;B\\C\\;D:E\\\\",
+ null, null, null, null, null));
+ verifier.verify(builder.vNodeList.get(0));
+ }
+
+ public void testV21ComplicatedCase() throws IOException, VCardException {
+ VCardParser_V21 parser = new VCardParser_V21();
+ VDataBuilder builder = new VDataBuilder();
+ InputStream is = getContext().getResources().openRawResource(R.raw.v21_complicated);
+ assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
+ is.close();
+ assertEquals(1, builder.vNodeList.size());
+ ContentValues contentValuesForQP = new ContentValues();
+ contentValuesForQP.put("ENCODING", "QUOTED-PRINTABLE");
+ ContentValues contentValuesForPhoto = new ContentValues();
+ contentValuesForPhoto.put("ENCODING", "BASE64");
+ // Push data into int array at first since values like 0x80 are
+ // interpreted as int by the compiler and casting all of them is
+ // cumbersome...
+ int[] photoIntArray = {
+ 0xff, 0xd8, 0xff, 0xe1, 0x0a, 0x0f, 0x45, 0x78, 0x69, 0x66, 0x00,
+ 0x00, 0x4d, 0x4d, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0d,
+ 0x01, 0x0e, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
+ 0xaa, 0x01, 0x0f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
+ 0x00, 0xba, 0x01, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00,
+ 0x00, 0x00, 0xc2, 0x01, 0x12, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x01, 0x00, 0x00, 0x01, 0x1a, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x1b, 0x00, 0x05, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0xd0, 0x01, 0x28, 0x00, 0x03, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x01, 0x31, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xd8, 0x01, 0x32, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xe6, 0x02, 0x13,
+ 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x82,
+ 0x98, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xfa,
+ 0x87, 0x69, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x84, 0xc4, 0xa5, 0x00, 0x07, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00,
+ 0x01, 0x08, 0x00, 0x00, 0x04, 0x1e, 0x32, 0x30, 0x30, 0x38, 0x31,
+ 0x30, 0x32, 0x39, 0x31, 0x33, 0x35, 0x35, 0x33, 0x31, 0x00, 0x00,
+ 0x44, 0x6f, 0x43, 0x6f, 0x4d, 0x6f, 0x00, 0x00, 0x44, 0x39, 0x30,
+ 0x35, 0x69, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x44, 0x39, 0x30,
+ 0x35, 0x69, 0x20, 0x56, 0x65, 0x72, 0x31, 0x2e, 0x30, 0x30, 0x00,
+ 0x32, 0x30, 0x30, 0x38, 0x3a, 0x31, 0x30, 0x3a, 0x32, 0x39, 0x20,
+ 0x31, 0x33, 0x3a, 0x35, 0x35, 0x3a, 0x34, 0x37, 0x00, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x00, 0x50, 0x72, 0x69, 0x6e, 0x74, 0x49, 0x4d, 0x00, 0x30, 0x33,
+ 0x30, 0x30, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x14, 0x00,
+ 0x14, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
+ 0x00, 0x34, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,
+ 0x00, 0x00, 0x00, 0x01, 0x10, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x09, 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x0f, 0x0b, 0x00,
+ 0x00, 0x27, 0x10, 0x00, 0x00, 0x05, 0x97, 0x00, 0x00, 0x27, 0x10,
+ 0x00, 0x00, 0x08, 0xb0, 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x1c,
+ 0x01, 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x02, 0x5e, 0x00, 0x00,
+ 0x27, 0x10, 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x27, 0x10, 0x00,
+ 0x00, 0x03, 0xcb, 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x1b, 0xe5,
+ 0x00, 0x00, 0x27, 0x10, 0x00, 0x28, 0x82, 0x9a, 0x00, 0x05, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x6a, 0x82, 0x9d, 0x00, 0x05,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x72, 0x88, 0x22, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x90, 0x00,
+ 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x30, 0x32, 0x32, 0x30, 0x90,
+ 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x03, 0x7a,
+ 0x90, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x03,
+ 0x8e, 0x91, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x01, 0x02,
+ 0x03, 0x00, 0x91, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x03, 0xa2, 0x92, 0x01, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x03, 0xaa, 0x92, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x03, 0xb2, 0x92, 0x04, 0x00, 0x0a, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x03, 0xba, 0x92, 0x05, 0x00, 0x05, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xc2, 0x92, 0x07, 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x92, 0x08, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x92, 0x09,
+ 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x92,
+ 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xca,
+ 0x92, 0x7c, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x92, 0x86, 0x00, 0x07, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00,
+ 0x03, 0xd2, 0xa0, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x30,
+ 0x31, 0x30, 0x30, 0xa0, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x01, 0x00, 0x00, 0xa0, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x60, 0x00, 0x00, 0xa0, 0x03, 0x00, 0x03, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x48, 0x00, 0x00, 0xa0, 0x05, 0x00, 0x04, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x0e, 0x00, 0x05,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xe8, 0xa2, 0x0f, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xf0, 0xa2, 0x10,
+ 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0xa2,
+ 0x17, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00,
+ 0xa3, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00,
+ 0x00, 0xa3, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00,
+ 0x00, 0x00, 0xa4, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0xa4, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0xa4, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x04, 0x00, 0x05, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x03, 0xf8, 0xa4, 0x05, 0x00, 0x03, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x1d, 0x00, 0x00, 0xa4, 0x06, 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x07, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x08,
+ 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4,
+ 0x09, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0xa4, 0x0a, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0xa4, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x00,
+ 0x00, 0x27, 0x10, 0x00, 0x00, 0x01, 0x5e, 0x00, 0x00, 0x00, 0x64,
+ 0x32, 0x30, 0x30, 0x38, 0x3a, 0x31, 0x30, 0x3a, 0x32, 0x39, 0x20,
+ 0x31, 0x33, 0x3a, 0x35, 0x35, 0x3a, 0x33, 0x31, 0x00, 0x32, 0x30,
+ 0x30, 0x38, 0x3a, 0x31, 0x30, 0x3a, 0x32, 0x39, 0x20, 0x31, 0x33,
+ 0x3a, 0x35, 0x35, 0x3a, 0x34, 0x37, 0x00, 0x00, 0x00, 0x29, 0x88,
+ 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x02, 0xb2, 0x00, 0x00, 0x00,
+ 0x64, 0x00, 0x00, 0x01, 0x5e, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x25, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x0e, 0x92, 0x00, 0x00, 0x03, 0xe8,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x30, 0x30,
+ 0x38, 0x31, 0x30, 0x32, 0x39, 0x31, 0x33, 0x35, 0x35, 0x33, 0x31,
+ 0x00, 0x00, 0x20, 0x2a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x2a,
+ 0xe2, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x04, 0x52, 0x39, 0x38, 0x00, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00,
+ 0x00, 0x04, 0x30, 0x31, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x06, 0x01, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x06,
+ 0x00, 0x00, 0x01, 0x1a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x04, 0x6c, 0x01, 0x1b, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x04, 0x74, 0x01, 0x28, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x02, 0x00, 0x00, 0x02, 0x01, 0x00, 0x04, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x04, 0x7c, 0x02, 0x02, 0x00, 0x04, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x05, 0x8b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x48, 0x00, 0x00, 0x00, 0x01, 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84,
+ 0x00, 0x20, 0x16, 0x18, 0x1c, 0x18, 0x14, 0x20, 0x1c, 0x1a, 0x1c,
+ 0x24, 0x22, 0x20, 0x26, 0x30, 0x50, 0x34, 0x30, 0x2c, 0x2c, 0x30,
+ 0x62, 0x46, 0x4a, 0x3a, 0x50, 0x74, 0x66, 0x7a, 0x78, 0x72, 0x66,
+ 0x70, 0x6e, 0x80, 0x90, 0xb8, 0x9c, 0x80, 0x88, 0xae, 0x8a, 0x6e,
+ 0x70, 0xa0, 0xda, 0xa2, 0xae, 0xbe, 0xc4, 0xce, 0xd0, 0xce, 0x7c,
+ 0x9a, 0xe2, 0xf2, 0xe0, 0xc8, 0xf0, 0xb8, 0xca, 0xce, 0xc6, 0x01,
+ 0x22, 0x24, 0x24, 0x30, 0x2a, 0x30, 0x5e, 0x34, 0x34, 0x5e, 0xc6,
+ 0x84, 0x70, 0x84, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xff, 0xc0,
+ 0x00, 0x11, 0x08, 0x00, 0x78, 0x00, 0xa0, 0x03, 0x01, 0x21, 0x00,
+ 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xc4, 0x01, 0xa2, 0x00,
+ 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03,
+ 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01,
+ 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31,
+ 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81,
+ 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19,
+ 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
+ 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65,
+ 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92,
+ 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4,
+ 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8,
+ 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+ 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1,
+ 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x01, 0x00,
+ 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04,
+ 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77,
+ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12,
+ 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14,
+ 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15,
+ 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17,
+ 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
+ 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65,
+ 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a,
+ 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3,
+ 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5,
+ 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
+ 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2,
+ 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff, 0xda, 0x00,
+ 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00,
+ 0x14, 0x54, 0xaa, 0x2a, 0x46, 0x48, 0xa2, 0xa4, 0x55, 0xa6, 0x04,
+ 0x8a, 0x29, 0xe0, 0x53, 0x10, 0xe0, 0x29, 0xc0, 0x50, 0x03, 0xb1,
+ 0x46, 0x29, 0x80, 0x84, 0x52, 0x11, 0x40, 0x0d, 0x22, 0x9a, 0x45,
+ 0x20, 0x23, 0x61, 0x51, 0x30, 0xa0, 0x08, 0xc8, 0xa8, 0xd8, 0x52,
+ 0x02, 0x26, 0x15, 0x0b, 0x0a, 0x00, 0xb4, 0xa2, 0xa5, 0x5a, 0x00,
+ 0x91, 0x45, 0x4a, 0xa2, 0x81, 0x92, 0x01, 0x4e, 0x02, 0x98, 0x87,
+ 0x0a, 0x70, 0xa0, 0x07, 0x62, 0x8c, 0x50, 0x21, 0x0d, 0x25, 0x00,
+ 0x34, 0x8a, 0x61, 0x14, 0x0c, 0x63, 0x0a, 0x89, 0x85, 0x00, 0x46,
+ 0xd5, 0x1b, 0x52, 0x02, 0x16, 0xa8, 0x98, 0x50, 0x05, 0x94, 0xa9,
+ 0x16, 0x80, 0x25, 0x5a, 0x95, 0x68, 0x18, 0xf1, 0x4f, 0x14, 0xc4,
+ 0x3b, 0xb5, 0x22, 0xb6, 0x38, 0x34, 0x00, 0xe3, 0x22, 0x8e, 0xf4,
+ 0x79, 0x8a, 0x7b, 0xd1, 0x71, 0x03, 0x30, 0xc7, 0x14, 0x83, 0xa5,
+ 0x00, 0x06, 0x98, 0x68, 0x01, 0x8d, 0x51, 0x35, 0x03, 0x22, 0x6a,
+ 0x8d, 0xa9, 0x01, 0x13, 0x54, 0x4d, 0x40, 0x13, 0xa5, 0x4a, 0x28,
+ 0x02, 0x45, 0x35, 0x2a, 0x9a, 0x00, 0x78, 0x34, 0xf0, 0x69, 0x80,
+ 0x34, 0x81, 0x45, 0x40, 0xce, 0x58, 0xe6, 0xa2, 0x4c, 0x06, 0xe4,
+ 0xfa, 0xd1, 0x93, 0x50, 0x21, 0xca, 0xe4, 0x55, 0x84, 0x90, 0x30,
+ 0xab, 0x8b, 0x18, 0xa6, 0x9a, 0x6a, 0xc4, 0x31, 0xaa, 0x26, 0xa0,
+ 0x64, 0x4d, 0x51, 0xb5, 0x20, 0x23, 0x6a, 0x89, 0xa8, 0x02, 0x44,
+ 0x35, 0x2a, 0x9a, 0x00, 0x95, 0x4d, 0x48, 0xa6, 0x80, 0x24, 0x53,
+ 0x4e, 0xce, 0x05, 0x30, 0x2b, 0x3b, 0xee, 0x6a, 0x91, 0x5d, 0x76,
+ 0x63, 0xbd, 0x65, 0x7d, 0x40, 0x66, 0x68, 0xa9, 0x02, 0x45, 0x2b,
+ 0xb3, 0x9e, 0xb4, 0xc5, 0x6d, 0xad, 0x9a, 0xa0, 0x2c, 0x06, 0xc8,
+ 0xcd, 0x04, 0xd6, 0xa2, 0x23, 0x63, 0x51, 0xb1, 0xa0, 0x64, 0x4d,
+ 0x51, 0x93, 0x48, 0x08, 0xda, 0xa2, 0x6a, 0x00, 0x72, 0x1a, 0x99,
+ 0x4d, 0x00, 0x48, 0xa6, 0xa4, 0x53, 0x4c, 0x07, 0x86, 0x03, 0xbd,
+ 0x2b, 0x9c, 0xa7, 0x14, 0x98, 0x10, 0x85, 0x34, 0xe0, 0xa6, 0xb3,
+ 0xb0, 0x0b, 0xb5, 0xa8, 0x0a, 0xd4, 0x58, 0x42, 0xed, 0x3e, 0x94,
+ 0xd2, 0xa6, 0x8b, 0x01, 0x34, 0x44, 0xed, 0xe6, 0x9c, 0x4d, 0x6a,
+ 0x80, 0x8d, 0x8d, 0x46, 0xc6, 0x80, 0x23, 0x63, 0x51, 0x9a, 0x06,
+ 0x46, 0xd5, 0x13, 0x52, 0x01, 0x54, 0xd4, 0xaa, 0x68, 0x02, 0x40,
+ 0x6a, 0x40, 0x78, 0xa0, 0x08, 0x59, 0xce, 0xee, 0xb5, 0x2a, 0x39,
+ 0xd9, 0x59, 0xa7, 0xa8, 0x00, 0x73, 0xeb, 0x4e, 0x0e, 0x7d, 0x69,
+ 0x5c, 0x05, 0xf3, 0x0f, 0xad, 0x1e, 0x61, 0xf5, 0xa7, 0x71, 0x0b,
+ 0xe6, 0x35, 0x21, 0x90, 0xd3, 0xb8, 0x0e, 0x32, 0x10, 0x95, 0x10,
+ 0x91, 0xb3, 0xd6, 0x9b, 0x60, 0x4b, 0x9c, 0x8a, 0x63, 0x1a, 0xb0,
+ 0x18, 0x4d, 0x46, 0xc6, 0x80, 0x22, 0x6a, 0x61, 0xa4, 0x31, 0xaa,
+ 0x6a, 0x55, 0x34, 0x01, 0x2a, 0x9a, 0x7e, 0x78, 0xa0, 0x08, 0x09,
+ 0xf9, 0xaa, 0x58, 0xcf, 0xca, 0x6b, 0x3e, 0xa0, 0x00, 0xd3, 0x81,
+ 0xa9, 0x01, 0x73, 0x46, 0x69, 0x80, 0xb9, 0xa4, 0xcd, 0x00, 0x2b,
+ 0x1f, 0x92, 0xa3, 0x07, 0x9a, 0x6f, 0x70, 0x26, 0xcf, 0x14, 0xd2,
+ 0x6b, 0x51, 0x0c, 0x63, 0x51, 0xb1, 0xa0, 0x08, 0xda, 0x98, 0x69,
+ 0x0c, 0x8d, 0x4d, 0x4a, 0xa6, 0x80, 0x24, 0x53, 0x52, 0x03, 0xc5,
+ 0x02, 0x21, 0x27, 0xe6, 0xa9, 0x23, 0x3f, 0x29, 0xac, 0xfa, 0x8c,
+ 0x01, 0xe6, 0x9c, 0x0d, 0x48, 0x0a, 0x0d, 0x2e, 0x68, 0x01, 0x73,
+ 0x49, 0x9a, 0x60, 0x2b, 0x1f, 0x92, 0x98, 0x3a, 0xd3, 0x7b, 0x81,
+ 0x36, 0x78, 0xa6, 0x93, 0x5a, 0x88, 0x8c, 0x9a, 0x63, 0x1a, 0x00,
+ 0x8c, 0xd3, 0x0d, 0x21, 0x91, 0x29, 0xa9, 0x14, 0xd0, 0x04, 0x8a,
+ 0x69, 0xe0, 0xd3, 0x11, 0x1b, 0x1e, 0x6a, 0x48, 0xcf, 0xca, 0x6b,
+ 0x3e, 0xa3, 0x10, 0x1a, 0x70, 0x35, 0x20, 0x38, 0x1a, 0x5c, 0xd2,
+ 0x01, 0x73, 0x49, 0x9a, 0x60, 0x39, 0x8f, 0xca, 0x29, 0x8b, 0xf7,
+ 0xaa, 0xba, 0x88, 0x96, 0x9a, 0x6b, 0x40, 0x18, 0xc6, 0xa3, 0x26,
+ 0x80, 0x18, 0x69, 0xa6, 0x90, 0xc8, 0x14, 0xd4, 0x8a, 0x69, 0x80,
+ 0xf0, 0x6a, 0x40, 0x68, 0x10, 0xbb, 0x41, 0xa7, 0xe3, 0x0b, 0xc5,
+ 0x2b, 0x01, 0x10, 0xa7, 0x03, 0x59, 0x0c, 0x76, 0x69, 0x73, 0x40,
+ 0x0b, 0x9a, 0x28, 0x11, 0x28, 0x19, 0x5e, 0x69, 0x02, 0x81, 0x5a,
+ 0xd8, 0x00, 0xd3, 0x4d, 0x50, 0x0c, 0x6a, 0x8c, 0xd2, 0x01, 0xa6,
+ 0x98, 0x69, 0x0c, 0xae, 0xa6, 0xa4, 0x06, 0x80, 0x1e, 0xa6, 0x9e,
+ 0x0d, 0x31, 0x12, 0x03, 0x4f, 0x06, 0x80, 0x13, 0x60, 0x34, 0xd3,
+ 0xc1, 0xa8, 0x92, 0x01, 0xf1, 0x8d, 0xdd, 0x69, 0xcc, 0xa1, 0x69,
+ 0x5b, 0x4b, 0x80, 0x83, 0x93, 0x52, 0x04, 0x14, 0xe2, 0xae, 0x03,
+ 0xa9, 0x0d, 0x68, 0x03, 0x4d, 0x34, 0xd0, 0x03, 0x0d, 0x30, 0xd2,
+ 0x01, 0x86, 0x9a, 0x68, 0x19, 0x58, 0x1a, 0x78, 0xa4, 0x04, 0x8a,
+ 0x69, 0xe0, 0xd3, 0x10, 0xe0, 0x69, 0xe0, 0xd0, 0x03, 0xc1, 0xa8,
+ 0xdb, 0xad, 0x4c, 0x81, 0x12, 0x45, 0xd6, 0x9d, 0x25, 0x1d, 0x00,
+ 0x6a, 0xf5, 0xa9, 0xe8, 0x80, 0x31, 0x29, 0x0d, 0x58, 0x08, 0x69,
+ 0x86, 0x80, 0x1a, 0x69, 0x86, 0x90, 0x0c, 0x34, 0xd3, 0x48, 0x65,
+ 0x51, 0x4f, 0x06, 0x98, 0x0f, 0x14, 0xf0, 0x68, 0x10, 0xf0, 0x69,
+ 0xe0, 0xd0, 0x03, 0x81, 0xa5, 0x2b, 0x9a, 0x1a, 0xb8, 0x87, 0xa8,
+ 0xdb, 0x4a, 0x46, 0x68, 0xb6, 0x80, 0x2a, 0xa8, 0x14, 0xea, 0x12,
+ 0xb0, 0x05, 0x21, 0xa6, 0x02, 0x1a, 0x61, 0xa0, 0x06, 0x9a, 0x61,
+ 0xa4, 0x31, 0x86, 0x9a, 0x69, 0x0c, 0xa8, 0x0d, 0x3c, 0x53, 0x01,
+ 0xe2, 0x9e, 0x28, 0x10, 0xf1, 0x4e, 0x06, 0x98, 0x0f, 0x06, 0x9e,
+ 0x0d, 0x02, 0x1c, 0x29, 0xc2, 0x80, 0x16, 0x96, 0x80, 0x0a, 0x4a,
+ 0x00, 0x43, 0x4d, 0x34, 0x0c, 0x61, 0xa6, 0x1a, 0x40, 0x34, 0xd3,
+ 0x4d, 0x21, 0x80, 0xff, 0xd9, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0a,
+ 0x07, 0x07, 0x08, 0x07, 0x06, 0x0a, 0x08, 0x08, 0x08, 0x0b, 0x0a,
+ 0x0a, 0x0b, 0x0e, 0x18, 0x10, 0x0e, 0x0d, 0x0d, 0x0e, 0x1d, 0x15,
+ 0x16, 0x11, 0x18, 0x23, 0x1f, 0x25, 0x24, 0x22, 0x1f, 0x22, 0x21,
+ 0x26, 0x2b, 0x37, 0x2f, 0x26, 0x29, 0x34, 0x29, 0x21, 0x22, 0x30,
+ 0x41, 0x31, 0x34, 0x39, 0x3b, 0x3e, 0x3e, 0x3e, 0x25, 0x2e, 0x44,
+ 0x49, 0x43, 0x3c, 0x48, 0x37, 0x3d, 0x3e, 0x3b, 0x01, 0x0a, 0x0b,
+ 0x0b, 0x0e, 0x0d, 0x0e, 0x1c, 0x10, 0x10, 0x1c, 0x3b, 0x28, 0x22,
+ 0x28, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
+ 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
+ 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
+ 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
+ 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xc0, 0x00, 0x11,
+ 0x08, 0x00, 0x48, 0x00, 0x60, 0x03, 0x01, 0x21, 0x00, 0x02, 0x11,
+ 0x01, 0x03, 0x11, 0x01, 0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x01,
+ 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02,
+ 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01,
+ 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06,
+ 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1,
+ 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33,
+ 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25,
+ 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54,
+ 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
+ 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
+ 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6,
+ 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8,
+ 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca,
+ 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3,
+ 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x01, 0x00, 0x03, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03,
+ 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01,
+ 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51,
+ 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+ 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72,
+ 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19,
+ 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54,
+ 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
+ 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93,
+ 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+ 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
+ 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4,
+ 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff, 0xda, 0x00, 0x0c, 0x03,
+ 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, 0x9e, 0xd2,
+ 0x2e, 0x07, 0x15, 0xaf, 0x6d, 0x08, 0xe2, 0xb3, 0x45, 0x1a, 0xf6,
+ 0xd0, 0x00, 0x01, 0xc5, 0x68, 0x45, 0x17, 0x4a, 0xb4, 0x22, 0xe4,
+ 0x70, 0x8c, 0x74, 0xa9, 0x3c, 0xa1, 0x8e, 0x95, 0x48, 0x96, 0x31,
+ 0xe2, 0x18, 0xe9, 0x55, 0xa5, 0x8c, 0x7a, 0x50, 0x05, 0x0b, 0x88,
+ 0x86, 0x0f, 0x15, 0x8f, 0x75, 0x1f, 0x26, 0x93, 0x19, 0x91, 0x77,
+ 0x18, 0xc1, 0xac, 0x4b, 0xc8, 0xfa, 0xd6, 0x63, 0x37, 0x6d, 0x31,
+ 0xb4, 0x73, 0x5b, 0x36, 0xa0, 0x1c, 0x50, 0x80, 0xd7, 0x83, 0xa0,
+ 0xab, 0xd1, 0x62, 0xad, 0x09, 0x8f, 0x17, 0x29, 0x03, 0xb2, 0xcc,
+ 0xe0, 0x77, 0x14, 0xa3, 0x56, 0xb3, 0x27, 0x1e, 0x67, 0xe9, 0x52,
+ 0xea, 0xc6, 0x3a, 0x36, 0x48, 0xef, 0x3d, 0x27, 0x70, 0x22, 0x60,
+ 0x47, 0x52, 0x69, 0xb2, 0xe2, 0xad, 0x3b, 0xea, 0x80, 0xa3, 0x38,
+ 0xe0, 0xd6, 0x3d, 0xd8, 0x1c, 0xd0, 0xca, 0x46, 0x3d, 0xd0, 0x18,
+ 0x35, 0x89, 0x78, 0xa3, 0x9a, 0xcd, 0x8c, 0xd2, 0xb3, 0x93, 0x2a,
+ 0x2b, 0x66, 0xd5, 0xf1, 0x8a, 0x10, 0x1a, 0xd6, 0xf2, 0x03, 0x8a,
+ 0x9e, 0xe6, 0xf4, 0x5a, 0xdb, 0xef, 0xfe, 0x23, 0xc0, 0xa7, 0x27,
+ 0xcb, 0x16, 0xc4, 0xcc, 0xdd, 0xe2, 0x78, 0x9a, 0x69, 0x66, 0xcc,
+ 0x99, 0xe1, 0x4d, 0x47, 0xba, 0xbc, 0xd9, 0x6a, 0xee, 0x26, 0x59,
+ 0x59, 0x4d, 0xac, 0x69, 0x34, 0x52, 0xe5, 0x8f, 0x55, 0xad, 0x58,
+ 0xae, 0x85, 0xc4, 0x22, 0x41, 0xdf, 0xad, 0x76, 0x61, 0xe5, 0x6f,
+ 0x74, 0x45, 0x69, 0xdc, 0x00, 0x79, 0xac, 0x8b, 0xa6, 0xc9, 0x35,
+ 0xd4, 0x34, 0x64, 0xdc, 0x37, 0x06, 0xb1, 0xae, 0x88, 0xc1, 0xac,
+ 0xd8, 0xc9, 0x2c, 0xa6, 0xe0, 0x73, 0x5b, 0x36, 0xf3, 0x74, 0xe6,
+ 0x84, 0x05, 0xe3, 0xa9, 0x47, 0x6a, 0x14, 0xb6, 0x49, 0x3d, 0x85,
+ 0x3a, 0xee, 0xee, 0x2b, 0xa8, 0xe2, 0x6f, 0x30, 0x81, 0xe9, 0x8a,
+ 0xca, 0xa4, 0xe2, 0xd3, 0x8b, 0x01, 0xb1, 0xf9, 0x04, 0x7f, 0xaf,
+ 0x23, 0xf0, 0xa9, 0x54, 0x41, 0x9c, 0xfd, 0xa3, 0xf4, 0xae, 0x65,
+ 0x18, 0xf7, 0x25, 0x8a, 0xe2, 0x02, 0x38, 0xb8, 0xfd, 0x2a, 0x7b,
+ 0x5b, 0xa8, 0x6d, 0x6d, 0x5d, 0x9a, 0x5d, 0xcb, 0xbb, 0xd2, 0xb6,
+ 0xa6, 0xa3, 0x19, 0x5e, 0xe2, 0x03, 0x7b, 0x1d, 0xc2, 0x17, 0x8d,
+ 0xb8, 0xac, 0xfb, 0x89, 0x39, 0x35, 0xd6, 0x9a, 0x6a, 0xe8, 0x66,
+ 0x55, 0xcb, 0xf5, 0xac, 0x7b, 0x96, 0xeb, 0x50, 0xc6, 0x88, 0x6d,
+ 0x66, 0xe9, 0xcd, 0x6c, 0xdb, 0x4f, 0xd3, 0x9a, 0x00, 0x2f, 0xe6,
+ 0xf9, 0xa3, 0xe7, 0xb5, 0x4a, 0x93, 0x7f, 0xa2, 0xc6, 0x73, 0xdc,
+ 0xd7, 0x15, 0x55, 0xef, 0x48, 0x7d, 0x09, 0x52, 0x6e, 0x3a, 0xd4,
+ 0xab, 0x2f, 0xbd, 0x61, 0x16, 0x0c, 0x73, 0x49, 0xc5, 0x24, 0x92,
+ 0x7f, 0xa2, 0x63, 0xfd, 0xaa, 0xd6, 0x2f, 0x71, 0x0e, 0xb1, 0x93,
+ 0xf7, 0x2d, 0xf5, 0xa4, 0x9e, 0x4e, 0xb5, 0xdd, 0x4b, 0xf8, 0x68,
+ 0x4c, 0xcb, 0xb9, 0x93, 0xad, 0x65, 0xce, 0xd9, 0x26, 0xa9, 0x8d,
+ 0x19, 0xf6, 0xf2, 0xf4, 0xe6, 0xb5, 0xad, 0xe7, 0xc6, 0x39, 0xa0,
+ 0x18, 0xeb, 0xc9, 0x77, 0x6c, 0x35, 0x2a, 0x4b, 0xfe, 0x8a, 0x9c,
+ 0xff, 0x00, 0x11, 0xae, 0x3a, 0x8b, 0xde, 0x61, 0xd0, 0x9e, 0x39,
+ 0xb8, 0xeb, 0x53, 0xac, 0xb9, 0xae, 0x5b, 0x00, 0xf3, 0x27, 0x14,
+ 0x92, 0xc9, 0xfe, 0x8a, 0x3f, 0xde, 0x35, 0xac, 0x3a, 0x88, 0x92,
+ 0xcd, 0xb1, 0x6e, 0x7d, 0xcd, 0x32, 0x67, 0xeb, 0xcd, 0x7a, 0x14,
+ 0xfe, 0x04, 0x26, 0x66, 0xce, 0xf9, 0x26, 0xb3, 0xe6, 0x6e, 0xb4,
+ 0xd9, 0x48, 0xc8, 0x82, 0x4e, 0x07, 0x35, 0xa7, 0x6f, 0x2f, 0x02,
+ 0x9a, 0x06, 0x5f, 0x8c, 0xa4, 0x83, 0x0e, 0x32, 0x2a, 0x69, 0xe3,
+ 0xdd, 0x12, 0x08, 0x97, 0x85, 0xec, 0x2a, 0x2a, 0x42, 0xf1, 0x76,
+ 0x26, 0xe4, 0x6a, 0x59, 0x0e, 0x18, 0x10, 0x6a, 0xd2, 0x89, 0x02,
+ 0x6e, 0x2a, 0x71, 0xeb, 0x5c, 0x1c, 0x8c, 0xa6, 0x48, 0xbb, 0xdc,
+ 0x61, 0x41, 0x35, 0x72, 0x28, 0x87, 0xd9, 0xf6, 0x4a, 0xb9, 0xe7,
+ 0x38, 0xae, 0x8c, 0x3d, 0x36, 0xdd, 0xde, 0xc4, 0xb0, 0x21, 0x51,
+ 0x76, 0xa8, 0xc0, 0xaa, 0x93, 0x31, 0xe6, 0xbb, 0x2d, 0x65, 0x61,
+ 0x19, 0xd3, 0x1e, 0xb5, 0x46, 0x5a, 0x96, 0x5a, 0x30, 0xa0, 0x7e,
+ 0x05, 0x69, 0x5b, 0xc9, 0xc6, 0x28, 0x40, 0xcd, 0x08, 0x64, 0x3c,
+ 0x73, 0x57, 0xe1, 0x94, 0xf1, 0xcd, 0x5a, 0x21, 0x8c, 0xb9, 0x63,
+ 0xe7, 0x67, 0x1d, 0xab, 0x40, 0xb1, 0xfb, 0x00, 0x1d, 0xf0, 0x2b,
+ 0x99, 0x2d, 0x66, 0x3e, 0x88, 0x75, 0x81, 0x3f, 0x31, 0xf6, 0xab,
+ 0x64, 0xd6, 0xb4, 0x17, 0xee, 0xd0, 0x9e, 0xe4, 0x32, 0x1a, 0xa7,
+ 0x31, 0xad, 0x18, 0x14, 0x26, 0xef, 0x54, 0xa5, 0xa8, 0x65, 0xa3,
+ 0x9c, 0x81, 0xfa, 0x56, 0x8c, 0x2d, 0xce, 0x68, 0x40, 0xcb, 0xf1,
+ 0x37, 0xbd, 0x5e, 0x85, 0xea, 0xd1, 0x0c, 0xbb, 0x19, 0x56, 0x23,
+ 0x20, 0x1f, 0xad, 0x5c, 0x42, 0x08, 0x03, 0xb5, 0x55, 0x91, 0x04,
+ 0xc9, 0x80, 0x38, 0x00, 0x0a, 0x71, 0x34, 0x6c, 0x32, 0x27, 0xe9,
+ 0x55, 0x25, 0x15, 0x2c, 0x68, 0xa3, 0x30, 0xeb, 0x54, 0xa5, 0x15,
+ 0x0c, 0xd1, 0x00, 0xff, 0xd9};
+ int length = photoIntArray.length;
+ byte[] photoByteArray = new byte[length];
+ for (int i = 0; i < length; i++) {
+ photoByteArray[i] = (byte)photoIntArray[i];
+ }
+ PropertyNodesVerifier verifier = new PropertyNodesVerifier(
+ new PropertyNode("VERSION", "2.1",
+ null, null, null, null, null),
+ new PropertyNode("N", "Gump;Forrest;Hoge;Pos;Tao",
+ Arrays.asList("Gump", "Forrest",
+ "Hoge", "Pos", "Tao"),
+ null, null, null, null),
+ new PropertyNode("FN", "Joe Due",
+ null, null, null, null, null),
+ new PropertyNode("ORG",
+ "Gump Shrimp Co.;Sales Dept.;Manager;Fish keeper",
+ Arrays.asList("Gump Shrimp Co.",
+ "Sales Dept.;Manager",
+ "Fish keeper"),
+ null, null, null, null),
+ new PropertyNode("ROLE", "Fish Cake Keeper!",
+ null, null, null, null, null),
+ new PropertyNode("TITLE", "Shrimp Man",
+ null, null, null, null, null),
+ new PropertyNode("X-CLASS", "PUBLIC",
+ null, null, null, null, null),
+ new PropertyNode("TEL", "(111) 555-1212",
+ null, null, null,
+ new HashSet(Arrays.asList("WORK", "VOICE")), null),
+ new PropertyNode("TEL", "(404) 555-1212",
+ null, null, null,
+ new HashSet(Arrays.asList("HOME", "VOICE")), null),
+ new PropertyNode("TEL", "0311111111",
+ null, null, null,
+ new HashSet(Arrays.asList("CELL")), null),
+ new PropertyNode("TEL", "0322222222",
+ null, null, null,
+ new HashSet(Arrays.asList("VIDEO")), null),
+ new PropertyNode("TEL", "0333333333",
+ null, null, null,
+ new HashSet(Arrays.asList("VOICE")), null),
+ new PropertyNode("ADR",
+ ";;100 Waters Edge;Baytown;LA;30314;United States of America",
+ Arrays.asList("", "", "100 Waters Edge", "Baytown",
+ "LA", "30314", "United States of America"),
+ null, null,
+ new HashSet(Arrays.asList("WORK")), null),
+ new PropertyNode("LABEL",
+ "100 Waters Edge\r\nBaytown, LA 30314\r\nUnited States of America",
+ null, null, contentValuesForQP,
+ new HashSet(Arrays.asList("WORK")), null),
+ new PropertyNode("ADR",
+ ";;42 Plantation St.;Baytown;LA;30314;United States of America",
+ Arrays.asList("", "", "42 Plantation St.", "Baytown",
+ "LA", "30314", "United States of America"), null, null,
+ new HashSet(Arrays.asList("HOME")), null),
+ new PropertyNode("LABEL",
+ "42 Plantation St.\r\nBaytown, LA 30314\r\nUnited States of America",
+ null, null, contentValuesForQP,
+ new HashSet(Arrays.asList("HOME")), null),
+ new PropertyNode("EMAIL", "forrestgump@walladalla.com",
+ null, null, null,
+ new HashSet(Arrays.asList("PREF", "INTERNET")), null),
+ new PropertyNode("EMAIL", "cell@example.com",
+ null, null, null,
+ new HashSet(Arrays.asList("CELL")), null),
+ new PropertyNode("NOTE", "The following note is the example from RFC 2045.",
+ null, null, null, null, null),
+ new PropertyNode("NOTE",
+ "Now's the time for all folk to come to the aid of their country.",
+ null, null, contentValuesForQP, null, null),
+ new PropertyNode("PHOTO", null,
+ null, photoByteArray, contentValuesForPhoto,
+ new HashSet(Arrays.asList("JPEG")), null),
+ new PropertyNode("X-ATTRIBUTE", "Some String",
+ null, null, null, null, null),
+ new PropertyNode("BDAY", "19800101",
+ null, null, null, null, null),
+ new PropertyNode("GEO", "35.6563854,139.6994233",
+ null, null, null, null, null),
+ new PropertyNode("URL", "http://www.example.com/",
+ null, null, null, null, null),
+ new PropertyNode("REV", "20080424T195243Z",
+ null, null, null, null, null));
+ verifier.verify(builder.vNodeList.get(0));
+ }
+
+ public void testV21Japanese1() throws IOException, VCardException {
+ VCardParser_V21 parser = new VCardParser_V21();
+ VDataBuilder builder = new VDataBuilder();
+ InputStream is = getContext().getResources().openRawResource(R.raw.v21_japanese_1);
+ assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
+ is.close();
+ assertEquals(1, builder.vNodeList.size());
+ ContentValues contentValuesForShiftJis = new ContentValues();
+ contentValuesForShiftJis.put("CHARSET", "SHIFT_JIS");
+ ContentValues contentValuesForQP = new ContentValues();
+ contentValuesForQP.put("ENCODING", "QUOTED-PRINTABLE");
+ contentValuesForQP.put("CHARSET", "SHIFT_JIS");
+ // Though Japanese careers append ";;;;" at the end of the value of "SOUND",
+ // vCard 2.1/3.0 specification does not allow multiple values.
+ // Do not need to handle it as multiple values.
+ PropertyNodesVerifier verifier = new PropertyNodesVerifier(
+ new PropertyNode("VERSION", "2.1",
+ null, null, null, null, null),
+ new PropertyNode("N", "\u5B89\u85E4\u30ED\u30A4\u30C9;;;;",
+ Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9", "", "", "", ""),
+ null, contentValuesForShiftJis, null, null),
+ new PropertyNode("SOUND",
+ "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E;;;;",
+ null, null, contentValuesForShiftJis,
+ new HashSet(Arrays.asList("X-IRMC-N")), null),
+ new PropertyNode("TEL", "0300000000",
+ null, null, null,
+ new HashSet(Arrays.asList("VOICE", "PREF")), null));
+ verifier.verify(builder.vNodeList.get(0));
+ }
+
+ public void testV21Japanese2() throws IOException, VCardException {
+ VCardParser_V21 parser = new VCardParser_V21();
+ VDataBuilder builder = new VDataBuilder();
+ InputStream is = getContext().getResources().openRawResource(R.raw.v21_japanese_2);
+ assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
+ is.close();
+ assertEquals(1, builder.vNodeList.size());
+ ContentValues contentValuesForShiftJis = new ContentValues();
+ contentValuesForShiftJis.put("CHARSET", "SHIFT_JIS");
+ ContentValues contentValuesForQP = new ContentValues();
+ contentValuesForQP.put("ENCODING", "QUOTED-PRINTABLE");
+ contentValuesForQP.put("CHARSET", "SHIFT_JIS");
+ PropertyNodesVerifier verifier = new PropertyNodesVerifier(
+ new PropertyNode("VERSION", "2.1",
+ null, null, null, null, null),
+ new PropertyNode("N", "\u5B89\u85E4;\u30ED\u30A4\u30C9\u0031;;;",
+ Arrays.asList("\u5B89\u85E4", "\u30ED\u30A4\u30C9\u0031",
+ "", "", ""),
+ null, contentValuesForShiftJis, null, null),
+ new PropertyNode("FN",
+ "\u5B89\u85E4\u0020\u30ED\u30A4\u30C9\u0020\u0031",
+ null, null, contentValuesForShiftJis, null, null),
+ new PropertyNode("SOUND",
+ ("\uFF71\uFF9D\uFF84\uFF9E\uFF73" +
+ ";\uFF9B\uFF72\uFF84\uFF9E\u0031;;;"),
+ null, null, contentValuesForShiftJis,
+ new HashSet(Arrays.asList("X-IRMC-N")), null),
+ new PropertyNode("ADR",
+ (";\u6771\u4EAC\u90FD\u6E0B\u8C37\u533A\u685C" +
+ "\u4E18\u753A\u0032\u0036\u002D\u0031\u30BB" +
+ "\u30EB\u30EA\u30A2\u30F3\u30BF\u30EF\u30FC\u0036" +
+ "\u968E;;;;150-8512;"),
+ Arrays.asList("",
+ "\u6771\u4EAC\u90FD\u6E0B\u8C37\u533A\u685C" +
+ "\u4E18\u753A\u0032\u0036\u002D\u0031\u30BB" +
+ "\u30EB\u30EA\u30A2\u30F3\u30BF\u30EF\u30FC" +
+ "\u0036\u968E", "", "", "", "150-8512", ""),
+ null, contentValuesForQP,
+ new HashSet(Arrays.asList("HOME")), null),
+ new PropertyNode("NOTE", "\u30E1\u30E2",
+ null, null, contentValuesForQP, null, null));
+ verifier.verify(builder.vNodeList.get(0));
+ }
+
+ public void testV21MultipleEntryCase() throws IOException, VCardException {
+ VCardParser_V21 parser = new VCardParser_V21();
+ VDataBuilder builder = new VDataBuilder();
+ InputStream is = getContext().getResources().openRawResource(R.raw.v21_multiple_entry);
+ assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
+ is.close();
+ assertEquals(3, builder.vNodeList.size());
+ ContentValues contentValuesForShiftJis = new ContentValues();
+ contentValuesForShiftJis.put("CHARSET", "SHIFT_JIS");
+ PropertyNodesVerifier verifier = new PropertyNodesVerifier(
+ new PropertyNode("VERSION", "2.1",
+ null, null, null, null, null),
+ new PropertyNode("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0033;;;;",
+ Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0033", "", "", "", ""),
+ null, contentValuesForShiftJis, null, null),
+ new PropertyNode("SOUND",
+ "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0033;;;;",
+ null, null, contentValuesForShiftJis,
+ new HashSet(Arrays.asList("X-IRMC-N")), null),
+ new PropertyNode("TEL", "9",
+ null, null, null,
+ new HashSet(Arrays.asList("X-NEC-SECRET")), null),
+ new PropertyNode("TEL", "10",
+ null, null, null,
+ new HashSet(Arrays.asList("X-NEC-HOTEL")), null),
+ new PropertyNode("TEL", "11",
+ null, null, null,
+ new HashSet(Arrays.asList("X-NEC-SCHOOL")), null),
+ new PropertyNode("TEL", "12",
+ null, null, null,
+ new HashSet(Arrays.asList("FAX", "HOME")), null));
+ verifier.verify(builder.vNodeList.get(0));
+
+ verifier = new PropertyNodesVerifier(
+ new PropertyNode("VERSION", "2.1",
+ null, null, null, null, null),
+ new PropertyNode("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0034;;;;",
+ Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0034", "", "", "", ""),
+ null, contentValuesForShiftJis, null, null),
+ new PropertyNode("SOUND",
+ "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0034;;;;",
+ null, null, contentValuesForShiftJis,
+ new HashSet(Arrays.asList("X-IRMC-N")), null),
+ new PropertyNode("TEL", "13",
+ null, null, null,
+ new HashSet(Arrays.asList("MODEM")), null),
+ new PropertyNode("TEL", "14",
+ null, null, null,
+ new HashSet(Arrays.asList("PAGER")), null),
+ new PropertyNode("TEL", "15",
+ null, null, null,
+ new HashSet(Arrays.asList("X-NEC-FAMILY")), null),
+ new PropertyNode("TEL", "16",
+ null, null, null,
+ new HashSet(Arrays.asList("X-NEC-GIRL")), null));
+ verifier.verify(builder.vNodeList.get(1));
+ verifier = new PropertyNodesVerifier(
+ new PropertyNode("VERSION", "2.1",
+ null, null, null, null, null),
+ new PropertyNode("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0035;;;;",
+ Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0035", "", "", "", ""),
+ null, contentValuesForShiftJis, null, null),
+ new PropertyNode("SOUND",
+ "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0035;;;;",
+ null, null, contentValuesForShiftJis,
+ new HashSet(Arrays.asList("X-IRMC-N")), null),
+ new PropertyNode("TEL", "17",
+ null, null, null,
+ new HashSet(Arrays.asList("X-NEC-BOY")), null),
+ new PropertyNode("TEL", "18",
+ null, null, null,
+ new HashSet(Arrays.asList("X-NEC-FRIEND")), null),
+ new PropertyNode("TEL", "19",
+ null, null, null,
+ new HashSet(Arrays.asList("X-NEC-PHS")), null),
+ new PropertyNode("TEL", "20",
+ null, null, null,
+ new HashSet(Arrays.asList("X-NEC-RESTAURANT")), null));
+ verifier.verify(builder.vNodeList.get(2));
+ }
+
+ public void testV30SimpleCase() throws IOException, VCardException {
+ VCardParser_V21 parser = new VCardParser_V30();
+ VDataBuilder builder = new VDataBuilder();
+ InputStream is = getContext().getResources().openRawResource(R.raw.v30_simple);
+ assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
+ is.close();
+ assertEquals(1, builder.vNodeList.size());
+ PropertyNodesVerifier verifier = new PropertyNodesVerifier(
+ new PropertyNode("VERSION", "3.0",
+ null, null, null, null, null),
+ new PropertyNode("FN", "And Roid",
+ null, null, null, null, null),
+ new PropertyNode("N", "And;Roid;;;",
+ Arrays.asList("And", "Roid", "", "", ""),
+ null, null, null, null),
+ new PropertyNode("ORG", "Open;Handset; Alliance",
+ Arrays.asList("Open", "Handset", " Alliance"),
+ null, null, null, null),
+ new PropertyNode("SORT-STRING", "android", null, null, null, null, null),
+ new PropertyNode("TEL", "0300000000",
+ null, null, null,
+ new HashSet(Arrays.asList("PREF", "VOICE")), null),
+ new PropertyNode("CLASS", "PUBLIC", null, null, null, null, null),
+ new PropertyNode("X-GNO", "0", null, null, null, null, null),
+ new PropertyNode("X-GN", "group0", null, null, null, null, null),
+ new PropertyNode("X-REDUCTION", "0",
+ null, null, null, null, null),
+ new PropertyNode("REV", "20081031T065854Z",
+ null, null, null, null, null));
+ verifier.verify(builder.vNodeList.get(0));
+ }
+}
--
cgit v1.2.3-59-g8ed1b
From b8488808899d27ea3d2c9d0091745012e13e3554 Mon Sep 17 00:00:00 2001
From: Jack Palevich <>
Date: Wed, 25 Mar 2009 15:30:56 -0700
Subject: Automated import from //branches/donutburger/...@142687,142687
---
opengl/java/android/opengl/GLU.java | 171 +++++++++++++++++++-----------------
1 file changed, 88 insertions(+), 83 deletions(-)
diff --git a/opengl/java/android/opengl/GLU.java b/opengl/java/android/opengl/GLU.java
index 0152f42b0e41..49a43d07d9b8 100644
--- a/opengl/java/android/opengl/GLU.java
+++ b/opengl/java/android/opengl/GLU.java
@@ -20,14 +20,14 @@ import javax.microedition.khronos.opengles.GL10;
/**
* A set of GL utilities inspired by the OpenGL Utility Toolkit.
- *
+ *
*/
public class GLU {
/**
* Return an error string from a GL or GLU error code.
- *
+ *
* @param error - a GL or GLU error code.
* @return the error string for the input error code, or NULL if the input
* was not a valid GL or GLU error code.
@@ -56,7 +56,7 @@ public class GLU {
/**
* Define a viewing transformation in terms of an eye point, a center of
* view, and an up vector.
- *
+ *
* @param gl a GL10 interface
* @param eyeX eye point X
* @param eyeY eye point Y
@@ -89,46 +89,48 @@ public class GLU {
float sx = fy * upZ - fz * upY;
float sy = fz * upX - fx * upZ;
float sz = fx * upY - fy * upX;
-
+
// and normalize s
float rls = 1.0f / Matrix.length(sx, sy, sz);
sx *= rls;
sy *= rls;
sz *= rls;
-
+
// compute u = s x f
float ux = sy * fz - sz * fy;
float uy = sz * fx - sx * fz;
float uz = sx * fy - sy * fx;
- float[] m = new float[16];
- m[0] = sx;
- m[1] = ux;
- m[2] = -fx;
- m[3] = 0.0f;
-
- m[4] = sy;
- m[5] = uy;
- m[6] = -fy;
- m[7] = 0.0f;
-
- m[8] = sz;
- m[9] = uz;
- m[10] = -fz;
- m[11] = 0.0f;
-
- m[12] = 0.0f;
- m[13] = 0.0f;
- m[14] = 0.0f;
- m[15] = 1.0f;
-
- gl.glMultMatrixf(m, 0);
+ float[] scratch = sScratch;
+ synchronized(scratch) {
+ scratch[0] = sx;
+ scratch[1] = ux;
+ scratch[2] = -fx;
+ scratch[3] = 0.0f;
+
+ scratch[4] = sy;
+ scratch[5] = uy;
+ scratch[6] = -fy;
+ scratch[7] = 0.0f;
+
+ scratch[8] = sz;
+ scratch[9] = uz;
+ scratch[10] = -fz;
+ scratch[11] = 0.0f;
+
+ scratch[12] = 0.0f;
+ scratch[13] = 0.0f;
+ scratch[14] = 0.0f;
+ scratch[15] = 1.0f;
+
+ gl.glMultMatrixf(scratch, 0);
+ }
gl.glTranslatef(-eyeX, -eyeY, -eyeZ);
}
/**
* Set up a 2D orthographic projection matrix
- *
+ *
* @param gl
* @param left
* @param right
@@ -142,7 +144,7 @@ public class GLU {
/**
* Set up a perspective projection matrix
- *
+ *
* @param gl a GL10 interface
* @param fovy specifies the field of view angle, in degrees, in the Y
* direction.
@@ -170,7 +172,7 @@ public class GLU {
*
* Note that you can use the OES_matrix_get extension, if present, to get
* the current modelView and projection matrices.
- *
+ *
* @param objX object coordinates X
* @param objY object coordinates Y
* @param objZ object coordinates Z
@@ -193,35 +195,39 @@ public class GLU {
public static int gluProject(float objX, float objY, float objZ,
float[] model, int modelOffset, float[] project, int projectOffset,
int[] view, int viewOffset, float[] win, int winOffset) {
- float[] m = new float[16];
- Matrix.multiplyMM(m, 0, project, projectOffset, model, modelOffset);
-
- float[] v = new float[4];
-
- v[0] = objX;
- v[1] = objY;
- v[2] = objZ;
- v[3] = 1.0f;
-
- float[] v2 = new float[4];
-
- Matrix.multiplyMV(v2, 0, m, 0, v, 0);
-
- float w = v2[3];
- if (w == 0.0f) {
- return GL10.GL_FALSE;
+ float[] scratch = sScratch;
+ synchronized(scratch) {
+ final int M_OFFSET = 0; // 0..15
+ final int V_OFFSET = 16; // 16..19
+ final int V2_OFFSET = 20; // 20..23
+ Matrix.multiplyMM(scratch, M_OFFSET, project, projectOffset,
+ model, modelOffset);
+
+ scratch[V_OFFSET + 0] = objX;
+ scratch[V_OFFSET + 1] = objY;
+ scratch[V_OFFSET + 2] = objZ;
+ scratch[V_OFFSET + 3] = 1.0f;
+
+ Matrix.multiplyMV(scratch, V2_OFFSET,
+ scratch, M_OFFSET, scratch, V_OFFSET);
+
+ float w = scratch[V2_OFFSET + 3];
+ if (w == 0.0f) {
+ return GL10.GL_FALSE;
+ }
+
+ float rw = 1.0f / w;
+
+ win[winOffset] =
+ view[viewOffset] + view[viewOffset + 2]
+ * (scratch[V2_OFFSET + 0] * rw + 1.0f)
+ * 0.5f;
+ win[winOffset + 1] =
+ view[viewOffset + 1] + view[viewOffset + 3]
+ * (scratch[V2_OFFSET + 1] * rw + 1.0f) * 0.5f;
+ win[winOffset + 2] = (scratch[V2_OFFSET + 2] * rw + 1.0f) * 0.5f;
}
- float rw = 1.0f / w;
-
- win[winOffset] =
- view[viewOffset] + view[viewOffset + 2] * (v2[0] * rw + 1.0f)
- * 0.5f;
- win[winOffset + 1] =
- view[viewOffset + 1] + view[viewOffset + 3]
- * (v2[1] * rw + 1.0f) * 0.5f;
- win[winOffset + 2] = (v2[2] * rw + 1.0f) * 0.5f;
-
return GL10.GL_TRUE;
}
@@ -232,7 +238,7 @@ public class GLU {
*
* Note that you can use the OES_matrix_get extension, if present, to get
* the current modelView and projection matrices.
- *
+ *
* @param winX window coordinates X
* @param winY window coordinates Y
* @param winZ window coordinates Z
@@ -255,34 +261,33 @@ public class GLU {
public static int gluUnProject(float winX, float winY, float winZ,
float[] model, int modelOffset, float[] project, int projectOffset,
int[] view, int viewOffset, float[] obj, int objOffset) {
- float[] pm = new float[16];
- Matrix.multiplyMM(pm, 0, project, projectOffset, model, modelOffset);
-
- float[] invPM = new float[16];
- if (!Matrix.invertM(invPM, 0, pm, 0)) {
- return GL10.GL_FALSE;
+ float[] scratch = sScratch;
+ synchronized(scratch) {
+ final int PM_OFFSET = 0; // 0..15
+ final int INVPM_OFFSET = 16; // 16..31
+ final int V_OFFSET = 0; // 0..3 Reuses PM_OFFSET space
+ Matrix.multiplyMM(scratch, PM_OFFSET, project, projectOffset,
+ model, modelOffset);
+
+ if (!Matrix.invertM(scratch, INVPM_OFFSET, scratch, PM_OFFSET)) {
+ return GL10.GL_FALSE;
+ }
+
+ scratch[V_OFFSET + 0] =
+ 2.0f * (winX - view[viewOffset + 0]) / view[viewOffset + 2]
+ - 1.0f;
+ scratch[V_OFFSET + 1] =
+ 2.0f * (winY - view[viewOffset + 1]) / view[viewOffset + 3]
+ - 1.0f;
+ scratch[V_OFFSET + 2] = 2.0f * winZ - 1.0f;
+ scratch[V_OFFSET + 3] = 1.0f;
+
+ Matrix.multiplyMV(obj, objOffset, scratch, INVPM_OFFSET,
+ scratch, V_OFFSET);
}
- float[] v = new float[4];
-
- v[0] =
- 2.0f * (winX - view[viewOffset + 0]) / view[viewOffset + 2]
- - 1.0f;
- v[1] =
- 2.0f * (winY - view[viewOffset + 1]) / view[viewOffset + 3]
- - 1.0f;
- v[2] = 2.0f * winZ - 1.0f;
- v[3] = 1.0f;
-
- float[] v2 = new float[4];
-
- Matrix.multiplyMV(v2, 0, invPM, 0, v, 0);
-
- obj[objOffset] = v2[0];
- obj[objOffset + 1] = v2[1];
- obj[objOffset + 2] = v2[2];
-
return GL10.GL_TRUE;
}
+ private static final float[] sScratch = new float[32];
}
--
cgit v1.2.3-59-g8ed1b
From 66c54ab2d9685883762d8fdfec43fbda50b470a6 Mon Sep 17 00:00:00 2001
From: Dave Sparks <>
Date: Wed, 25 Mar 2009 15:43:23 -0700
Subject: Automated import from //branches/donutburger/...@142693,142693
---
data/sounds/effects/camera_click.ogg | Bin 5593 -> 4851 bytes
data/sounds/effects/camera_click.wav | Bin 0 -> 13030 bytes
2 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 data/sounds/effects/camera_click.wav
diff --git a/data/sounds/effects/camera_click.ogg b/data/sounds/effects/camera_click.ogg
index 0a769ff91464..52512ac0a054 100644
Binary files a/data/sounds/effects/camera_click.ogg and b/data/sounds/effects/camera_click.ogg differ
diff --git a/data/sounds/effects/camera_click.wav b/data/sounds/effects/camera_click.wav
new file mode 100644
index 000000000000..7043bc7b21a9
Binary files /dev/null and b/data/sounds/effects/camera_click.wav differ
--
cgit v1.2.3-59-g8ed1b
From cf58974d66e898877a96e802bf853bdf190fe9a8 Mon Sep 17 00:00:00 2001
From: Karl Rosaen <>
Date: Wed, 25 Mar 2009 16:01:38 -0700
Subject: Automated import from //branches/donutburger/...@142698,142698
---
core/res/res/drawable/expander_ic_maximized.9.png | Bin 2081 -> 1653 bytes
core/res/res/drawable/expander_ic_minimized.9.png | Bin 2052 -> 1647 bytes
2 files changed, 0 insertions(+), 0 deletions(-)
diff --git a/core/res/res/drawable/expander_ic_maximized.9.png b/core/res/res/drawable/expander_ic_maximized.9.png
index bad4b8202655..69710a8ae72a 100644
Binary files a/core/res/res/drawable/expander_ic_maximized.9.png and b/core/res/res/drawable/expander_ic_maximized.9.png differ
diff --git a/core/res/res/drawable/expander_ic_minimized.9.png b/core/res/res/drawable/expander_ic_minimized.9.png
index af89072eb745..ff17e49561ef 100644
Binary files a/core/res/res/drawable/expander_ic_minimized.9.png and b/core/res/res/drawable/expander_ic_minimized.9.png differ
--
cgit v1.2.3-59-g8ed1b
From 00ba76670fd06d9c51cce36a74c384a212f705b5 Mon Sep 17 00:00:00 2001
From: Eric Fischer <>
Date: Wed, 25 Mar 2009 16:08:50 -0700
Subject: Automated import from //branches/donutburger/...@142700,142700
---
core/java/android/text/Html.java | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java
index 200bbf4a1500..70e12970e6c2 100644
--- a/core/java/android/text/Html.java
+++ b/core/java/android/text/Html.java
@@ -152,10 +152,13 @@ public class Html {
next = text.nextSpanTransition(i, len, ParagraphStyle.class);
ParagraphStyle[] style = text.getSpans(i, next, ParagraphStyle.class);
String elements = " ";
+ boolean needDiv = false;
+
for(int j = 0; j < style.length; j++) {
if (style[j] instanceof AlignmentSpan) {
Layout.Alignment align =
((AlignmentSpan) style[j]).getAlignment();
+ needDiv = true;
if (align == Layout.Alignment.ALIGN_CENTER) {
elements = "align=\"center\" " + elements;
} else if (align == Layout.Alignment.ALIGN_OPPOSITE) {
@@ -165,13 +168,13 @@ public class Html {
}
}
}
- if (style.length > 0) {
+ if (needDiv) {
out.append("
");
}
withinDiv(out, text, i, next);
- if (style.length > 0) {
+ if (needDiv) {
out.append("
");
}
}
--
cgit v1.2.3-59-g8ed1b
From 3aadcd9ed4f509b6f6562059ff175184f148cb71 Mon Sep 17 00:00:00 2001
From: Raphael Moll <>
Date: Wed, 25 Mar 2009 16:33:12 -0700
Subject: Automated import from //branches/donutburger/...@142710,142710
---
core/res/res/values/attrs.xml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 310948960ae2..6e82bbf2d752 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1221,7 +1221,8 @@
-
+
-
+ "機内モード"
"機内モードON"
"機内モードOFF"
"セーフモード"
-
-
+ "Androidシステム"
"料金ã®ç™ºç”Ÿã™ã‚‹ã‚µãƒ¼ãƒ“ス"
"料金ã®ç™ºç”Ÿã™ã‚‹æ“作をアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"
"é€å—ä¿¡ã—ãŸãƒ¡ãƒƒã‚»ãƒ¼ã‚¸"
@@ -294,10 +292,8 @@
"無線通信ã‹ã‚‰ã®ä½ç½®æ›´æ–°é€šçŸ¥ã‚’有効/無効ã«ã™ã‚‹ã“ã¨ã‚’許å¯ã—ã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã§ã¯ä½¿ç”¨ã—ã¾ã›ã‚“。"
"ãƒã‚§ãƒƒã‚¯ã‚¤ãƒ³ãƒ—ãƒãƒ‘ティã¸ã®ã‚¢ã‚¯ã‚»ã‚¹"
"ãƒã‚§ãƒƒã‚¯ã‚¤ãƒ³ã‚µãƒ¼ãƒ“スãŒã‚¢ãƒƒãƒ—ãƒãƒ¼ãƒ‰ã—ãŸãƒ—ãƒãƒ‘ティã¸ã®èªã¿æ›¸ãを許å¯ã—ã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã§ã¯ä½¿ç”¨ã—ã¾ã›ã‚“。"
-
-
-
-
+ "ウィジェットã®é¸æŠž"
+ "ã©ã®ã‚¢ãƒ—リケーションãŒã©ã®ã‚¦ã‚£ã‚¸ã‚§ãƒƒãƒˆã‚’使用ã§ãã‚‹ã‹ã‚·ã‚¹ãƒ†ãƒ ã«æŒ‡å®šã™ã‚‹ã“ã¨ã‚’ã“ã®ã‚¢ãƒ—リケーションã«è¨±å¯ã—ã¾ã™ã€‚ã“れã«ã‚ˆã‚Šã€ã‚¢ãƒ—リケーション間ã§å€‹äººãƒ‡ãƒ¼ã‚¿ã«ã‚¢ã‚¯ã‚»ã‚¹ã§ãるよã†ã«ãªã‚Šã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã§ã¯ä½¿ç”¨ã—ã¾ã›ã‚“。"
"端末ステータスã®å¤‰æ›´"
"端末ã®é›»è©±æ©Ÿèƒ½ã®ã‚³ãƒ³ãƒˆãƒãƒ¼ãƒ«ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚アプリケーションã¯ã€ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã®åˆ‡ã‚Šæ›¿ãˆã€æºå¸¯é›»è©±ã®ç„¡ç·šé€šä¿¡ã®ã‚ªãƒ³/オフãªã©ã‚’通知ã›ãšã«è¡Œã†ã“ã¨ãŒã§ãã¾ã™ã€‚"
"端末ステータスã®èªã¿å–り"
@@ -397,7 +393,7 @@
"PINコードを入力"
"PINã‚³ãƒ¼ãƒ‰ãŒæ£ã—ãã‚りã¾ã›ã‚“。"
- "ãƒãƒƒã‚¯ã‚’解除ã™ã‚‹ã«ã¯MENUã€0ã‚ーã®é †ã«æŠ¼ã—ã¾ã™ã€‚"
+ "MENUã€0ã‚ーã§ãƒãƒƒã‚¯è§£é™¤"
"ç·Šæ€¥é€šå ±ç•ªå·"
"(通信サービスãªã—)"
"ç”»é¢ãƒãƒƒã‚¯ä¸"
@@ -407,8 +403,7 @@
"ç·Šæ€¥é€šå ±"
"一致ã—ã¾ã—ãŸ"
"やり直ã—ã¦ãã ã•ã„"
-
-
+ "å……é›»ä¸ï¼ˆ%d%%)"
"å……é›»ã—ã¦ãã ã•ã„。"
"SIMã‚«ãƒ¼ãƒ‰ãŒæŒ¿å…¥ã•れã¦ã„ã¾ã›ã‚“"
"SIMã‚«ãƒ¼ãƒ‰ãŒæŒ¿å…¥ã•れã¦ã„ã¾ã›ã‚“"
@@ -424,8 +419,7 @@
"%d秒後ã«ã‚„り直ã—ã¦ãã ã•ã„。"
"パターンを忘れãŸå ´åˆ"
"パターンã®ã‚¨ãƒ©ãƒ¼ãŒå¤šã™ãŽã¾ã™"
-
-
+ "Googleアカウントã§ãƒã‚°ã‚¤ãƒ³ã—ã¦ãƒãƒƒã‚¯è§£é™¤"
"ユーザーå (メール)"
"パスワード"
"ãƒã‚°ã‚¤ãƒ³"
@@ -433,16 +427,13 @@
"h:mm AA"
"%-l:%M%P"
"%-l:%M%p"
-
-
-
-
+ "%-l%P"
+ "%-l%p"
"通知を消去"
"通知ãªã—"
"æ“作ä¸"
"通知"
-
-
+ "%d%%"
"å……é›»ä¸..."
"å……é›»ã—ã¦ãã ã•ã„"
"é›»æ± ãŒæ®‹ã‚Šå°‘ãªããªã£ã¦ã„ã¾ã™:"
@@ -564,8 +555,7 @@
"毎月"
"毎年"
"動画をå†ç”Ÿã§ãã¾ã›ã‚“"
-
-
+ "ã“ã®å‹•ç”»ã¯ã”使用ã®ç«¯æœ«ã§ã‚¹ãƒˆãƒªãƒ¼ãƒŸãƒ³ã‚°ã§ãã¾ã›ã‚“。"
"ã“ã®å‹•ç”»ã¯å†ç”Ÿã§ãã¾ã›ã‚“。"
"OK"
"AM"
@@ -592,13 +582,11 @@
"æ£åˆ"
"åˆå‰0時"
"åˆå‰0時"
-
-
+ "%B%-dæ—¥"
"%Yå¹´%B%-dæ—¥"
-
-
+ "%Y年%B月"
"%H:%M:%S"
"%Y/%B/%-d %H:%M:%S"
"%2$s月%3$s日~%7$s月%8$s日"
@@ -626,9 +614,8 @@
"%4$s/%2$s/%3$s%5$s~%9$s/%7$s/%8$s%10$s"
"%4$s/%2$s/%3$s%1$s%5$s~%9$s/%7$s/%8$s%6$s%10$s"
"%Y/%b/%-d"
-
-
- "%b%-dæ—¥"
+ "%Y年%b月"
+ "%b/%-d"
"日曜日"
@@ -811,22 +798,14 @@
"一致ã™ã‚‹ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
"コンãƒãƒ¼ãƒãƒ³ãƒˆä½¿ç”¨çжæ³ã«é–¢ã™ã‚‹çµ±è¨ˆæƒ…å ±ã®æ›´æ–°"
"åŽé›†ã•れãŸã‚³ãƒ³ãƒãƒ¼ãƒãƒ³ãƒˆä½¿ç”¨çжæ³ã«é–¢ã™ã‚‹çµ±è¨ˆæƒ…å ±ã®å¤‰æ›´ã‚’許å¯ã—ã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã§ã¯ä½¿ç”¨ã—ã¾ã›ã‚“。"
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ "ダブルタップã§ã‚ºãƒ¼ãƒ ã—ã¾ã™"
+ "ウィジェットã®å±•開エラー"
+ "移動"
+ "検索"
+ "é€ä¿¡"
+ "次ã¸"
+ "完了"
+ "実行"
--
cgit v1.2.3-59-g8ed1b
From 9ed4a4b0d7dadeadd57bd81e2cc538670d9654b9 Mon Sep 17 00:00:00 2001
From: Dianne Hackborn <>
Date: Wed, 25 Mar 2009 17:10:37 -0700
Subject: Automated import from //branches/donutburger/...@142722,142722
---
.../com/android/server/PowerManagerService.java | 49 +++++++++++++---------
.../com/android/server/WindowManagerService.java | 9 +++-
2 files changed, 38 insertions(+), 20 deletions(-)
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index a900b3e5a307..bbca40148ee0 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -1373,8 +1373,9 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
}
private void updateLightsLocked(int newState, int forceState) {
- int oldState = mPowerState;
- int difference = (newState ^ oldState) | forceState;
+ final int oldState = mPowerState;
+ final int realDifference = (newState ^ oldState);
+ final int difference = realDifference | forceState;
if (difference == 0) {
return;
}
@@ -1430,22 +1431,29 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
if ((difference & (SCREEN_ON_BIT | SCREEN_BRIGHT_BIT)) != 0) {
if (ANIMATE_SCREEN_LIGHTS) {
- int nominalCurrentValue;
- switch (oldState & (SCREEN_BRIGHT_BIT|SCREEN_ON_BIT)) {
- case SCREEN_BRIGHT_BIT | SCREEN_ON_BIT:
- nominalCurrentValue = preferredBrightness;
- break;
- case SCREEN_ON_BIT:
- nominalCurrentValue = Power.BRIGHTNESS_DIM;
- break;
- case 0:
- nominalCurrentValue = Power.BRIGHTNESS_OFF;
- break;
- case SCREEN_BRIGHT_BIT:
- default:
- // not possible
- nominalCurrentValue = (int)mScreenBrightness.curValue;
- break;
+ int nominalCurrentValue = -1;
+ // If there was an actual difference in the light state, then
+ // figure out the "ideal" current value based on the previous
+ // state. Otherwise, this is a change due to the brightness
+ // override, so we want to animate from whatever the current
+ // value is.
+ if ((realDifference & (SCREEN_ON_BIT | SCREEN_BRIGHT_BIT)) != 0) {
+ switch (oldState & (SCREEN_BRIGHT_BIT|SCREEN_ON_BIT)) {
+ case SCREEN_BRIGHT_BIT | SCREEN_ON_BIT:
+ nominalCurrentValue = preferredBrightness;
+ break;
+ case SCREEN_ON_BIT:
+ nominalCurrentValue = Power.BRIGHTNESS_DIM;
+ break;
+ case 0:
+ nominalCurrentValue = Power.BRIGHTNESS_OFF;
+ break;
+ case SCREEN_BRIGHT_BIT:
+ default:
+ // not possible
+ nominalCurrentValue = (int)mScreenBrightness.curValue;
+ break;
+ }
}
if ((newState & SCREEN_BRIGHT_BIT) == 0) {
// dim or turn off backlight, depending on if the screen is on
@@ -1575,7 +1583,9 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
curValue = (float)initialValue;
}
targetValue = target;
- delta = (targetValue-nominalCurrentValue) / stepsToTarget;
+ delta = (targetValue -
+ (nominalCurrentValue >= 0 ? nominalCurrentValue : curValue))
+ / stepsToTarget;
if (mSpew) {
String noticeMe = nominalCurrentValue == curValue ? "" : " ******************";
Log.i(TAG, "Setting target " + mask + ": cur=" + curValue
@@ -1596,6 +1606,7 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
int curIntValue = (int)curValue;
boolean more = true;
if (delta == 0) {
+ curValue = curIntValue = targetValue;
more = false;
} else if (delta > 0) {
if (curIntValue >= targetValue) {
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 56f8bc15d92f..ed8b23af3552 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -7799,6 +7799,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
boolean blurring = false;
boolean dimming = false;
boolean covered = false;
+ boolean syswin = false;
for (i=N-1; i>=0; i--) {
WindowState w = (WindowState)mWindows.get(i);
@@ -8058,9 +8059,15 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
holdScreen = w.mSession;
}
- if (w.mAttrs.screenBrightness >= 0 && screenBrightness < 0) {
+ if (!syswin && w.mAttrs.screenBrightness >= 0
+ && screenBrightness < 0) {
screenBrightness = w.mAttrs.screenBrightness;
}
+ if (attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG
+ || attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD
+ || attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_ERROR) {
+ syswin = true;
+ }
}
if (w.isFullscreenOpaque(dw, dh)) {
// This window completely covers everything behind it,
--
cgit v1.2.3-59-g8ed1b
From eecc5c973ed44a4a094ef3c36130ee008f384333 Mon Sep 17 00:00:00 2001
From: Dianne Hackborn <>
Date: Wed, 25 Mar 2009 17:24:35 -0700
Subject: Automated import from //branches/donutburger/...@142727,142727
---
libs/ui/EventHub.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index 3b29b094db66..7c2fc8e54b1a 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -245,6 +245,7 @@ EventHub::device_t* EventHub::getDevice(int32_t deviceId) const
int32_t id = deviceId & ID_MASK;
if (id >= mNumDevicesById || id < 0) return NULL;
device_t* dev = mDevicesById[id].device;
+ if (dev == NULL) return NULL;
if (dev->id == deviceId) {
return dev;
}
--
cgit v1.2.3-59-g8ed1b
From 2d8c060bbc590c0f398c7a2c7a8b3e35111929f4 Mon Sep 17 00:00:00 2001
From: Nick Pelly <>
Date: Wed, 25 Mar 2009 17:33:56 -0700
Subject: Automated import from //branches/donutburger/...@142766,142766
---
core/java/android/bluetooth/BluetoothHeadset.java | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 1dbe0cccda51..e1984353e88c 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -82,6 +82,12 @@ public class BluetoothHeadset {
/** Default priority for headsets that should not be auto-connected */
public static final int PRIORITY_OFF = 0;
+ /** The voice dialer 'works' but the user experience is poor. The voice
+ * recognizer has trouble dealing with the 8kHz SCO signal, and it still
+ * requires visual confirmation. Disable for cupcake.
+ */
+ public static final boolean DISABLE_BT_VOICE_DIALING = true;
+
/**
* An interface for notifying BluetoothHeadset IPC clients when they have
* been connected to the BluetoothHeadset service.
--
cgit v1.2.3-59-g8ed1b
From 2ad63a9d773ba987e85ee6a23b0a0724d86d4b0e Mon Sep 17 00:00:00 2001
From: Chris Tate <>
Date: Wed, 25 Mar 2009 17:36:48 -0700
Subject: Automated import from //branches/donutburger/...@142784,142784
---
.../java/com/android/server/WindowManagerService.java | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index ed8b23af3552..19ab21d822c4 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -8551,6 +8551,15 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
private void startFreezingDisplayLocked() {
if (mDisplayFrozen) {
+ // Freezing the display also suspends key event delivery, to
+ // keep events from going astray while the display is reconfigured.
+ // If someone has changed orientation again while the screen is
+ // still frozen, the events will continue to be blocked while the
+ // successive orientation change is processed. To prevent spurious
+ // ANRs, we reset the event dispatch timeout in this case.
+ synchronized (mKeyWaiter) {
+ mKeyWaiter.mWasFrozen = true;
+ }
return;
}
@@ -8594,10 +8603,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
Surface.unfreezeDisplay(0);
- // Freezing the display also suspends key event delivery, to
- // keep events from going astray while the display is reconfigured.
- // Now that we're back, notify the key waiter that we're alive
- // again and it should restart its timeouts.
+ // Reset the key delivery timeout on unfreeze, too. We force a wakeup here
+ // too because regular key delivery processing should resume immediately.
synchronized (mKeyWaiter) {
mKeyWaiter.mWasFrozen = true;
mKeyWaiter.notifyAll();
--
cgit v1.2.3-59-g8ed1b
From f0138614acd239a43a0b6cb97b0ea845f82925f4 Mon Sep 17 00:00:00 2001
From: Amith Yamasani <>
Date: Wed, 25 Mar 2009 17:39:37 -0700
Subject: Automated import from //branches/donutburger/...@142787,142787
---
api/current.xml | 13 +++++++++++
core/java/android/text/AutoText.java | 45 ++++++++++++++++++++++++++++++------
2 files changed, 51 insertions(+), 7 deletions(-)
diff --git a/api/current.xml b/api/current.xml
index 2b2673085675..d366f290a279 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -101918,6 +101918,19 @@
+