| 
					
				 | 
			
			
				@@ -0,0 +1,179 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Protocol Buffers - Google's data interchange format 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Copyright 2013 Google Inc.  All rights reserved. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// http://code.google.com/p/protobuf/ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Redistribution and use in source and binary forms, with or without 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// modification, are permitted provided that the following conditions are 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// met: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//     * Redistributions of source code must retain the above copyright 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// notice, this list of conditions and the following disclaimer. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//     * Redistributions in binary form must reproduce the above 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// copyright notice, this list of conditions and the following disclaimer 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// in the documentation and/or other materials provided with the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// distribution. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//     * Neither the name of Google Inc. nor the names of its 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// contributors may be used to endorse or promote products derived from 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// this software without specific prior written permission. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+package com.google.protobuf.nano; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.lang.reflect.Array; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.lang.reflect.Field; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.lang.reflect.Modifier; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Static helper methods for printing nano protos. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @author flynn@google.com Andrew Flynn 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+public final class MessageNanoPrinter { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // Do not allow instantiation 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private MessageNanoPrinter() {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private static final String INDENT = "  "; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private static final int MAX_STRING_LEN = 200; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * Returns an text representation of a MessageNano suitable for debugging. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * <p>Employs Java reflection on the given object and recursively prints primitive fields, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * groups, and messages.</p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public static <T extends MessageNano> String print(T message) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (message == null) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return "null"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        StringBuffer buf = new StringBuffer(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            print(message.getClass().getSimpleName(), message.getClass(), message, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    new StringBuffer(), buf); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } catch (IllegalAccessException e) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return "Error printing proto: " + e.getMessage(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return buf.toString(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * Function that will print the given message/class into the StringBuffer. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * Meant to be called recursively. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private static void print(String identifier, Class<?> clazz, Object message, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            StringBuffer indentBuf, StringBuffer buf) throws IllegalAccessException { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (MessageNano.class.isAssignableFrom(clazz)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Nano proto message 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            buf.append(indentBuf).append(identifier); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // If null, just print it and return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (message == null) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                buf.append(": ").append(message).append("\n"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            indentBuf.append(INDENT); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            buf.append(" <\n"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            for (Field field : clazz.getFields()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // Proto fields are public, non-static variables that do not begin or end with '_' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                int modifiers = field.getModifiers(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                String fieldName = field.getName(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if ((modifiers & Modifier.PUBLIC) != Modifier.PUBLIC 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        || (modifiers & Modifier.STATIC) == Modifier.STATIC 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        || fieldName.startsWith("_") || fieldName.endsWith("_")) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                Class <?> fieldType = field.getType(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                Object value = field.get(message); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (fieldType.isArray()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Class<?> arrayType = fieldType.getComponentType(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    // bytes is special since it's not repeated, but is represented by an array 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if (arrayType == byte.class) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        print(fieldName, fieldType, value, indentBuf, buf); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        int len = Array.getLength(value); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        for (int i = 0; i < len; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            Object elem = Array.get(value, i); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            print(fieldName, arrayType, elem, indentBuf, buf); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    print(fieldName, fieldType, value, indentBuf, buf); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            indentBuf.delete(indentBuf.length() - INDENT.length(), indentBuf.length()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            buf.append(indentBuf).append(">\n"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Primitive value 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            identifier = deCamelCaseify(identifier); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            buf.append(indentBuf).append(identifier).append(": "); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (message instanceof String) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                String stringMessage = sanitizeString((String) message); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                buf.append("\"").append(stringMessage).append("\""); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                buf.append(message); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            buf.append("\n"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * Converts an identifier of the format "FieldName" into "field_name". 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private static String deCamelCaseify(String identifier) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        StringBuffer out = new StringBuffer(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for (int i = 0; i < identifier.length(); i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            char currentChar = identifier.charAt(i); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (i == 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                out.append(Character.toLowerCase(currentChar)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } else if (Character.isUpperCase(currentChar)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                out.append('_').append(Character.toLowerCase(currentChar)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                out.append(currentChar); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return out.toString(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * Shortens and escapes the given string. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private static String sanitizeString(String str) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (!str.startsWith("http") && str.length() > MAX_STRING_LEN) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Trim non-URL strings. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            str = str.substring(0, MAX_STRING_LEN) + "[...]"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return escapeString(str); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * Escape everything except for low ASCII code points. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private static String escapeString(String str) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int strLen = str.length(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        StringBuilder b = new StringBuilder(strLen); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for (int i = 0; i < strLen; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            char original = str.charAt(i); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (original >= ' ' && original <= '~' && original != '"' && original != '\'') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                b.append(original); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                b.append(String.format("\\u%04x", (int) original)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return b.toString(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 |