Merge branch 'origin/develop' after merging websocket into develop.
diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 0000000..b799adc
--- /dev/null
+++ b/.DS_Store
Binary files differ
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..807133c
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,29 @@
+Copyright (c) 2012, Regents of the University of California
+All rights reserved.
+
+Authors of individual source files and components are listed in the
+respective files.
+
+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 the Regents of the University of California 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 REGENTS 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.
+
diff --git a/README b/README
index 28a09fa..ad9e4ba 100644
--- a/README
+++ b/README
@@ -1,9 +1,33 @@
First native version of the NDN protocol written in Javascript ( Also refereed to as CCN )
-The goal of this project is to improve the current implementation of the lwNDN API that allows users to create applications running on top of the NDN network. The goal is to have a lightweight version of the protocol, which can run on browsers. The main intent is to enable browser-based applications to use NDN directly without requiring a binary build of the CCNx code. In particular, the goal is to have an AJAX-style dynamic data access. The goal is also to have a lighter version of the protocol, which would be better suited for embedded systems. Furthermore, the goal is that lwNDN communicates with CCNx nodes (routers).
+The goal of this project is to improve the current implementation of the NDN-JS API that allows users to create applications running on top of the NDN network. The goal is to have a lightweight version of the protocol, which can run on browsers. The main intent is to enable browser-based applications to use NDN directly without requiring a binary build of the CCNx code. In particular, the goal is to have an AJAX-style dynamic data access. The goal is also to have a lighter version of the protocol, which would be better suited for embedded systems. Furthermore, the goal is that NDN-JS communicates with CCNx nodes (routers).
-The current status of lwNDN allows for JavaScript applications running on browsers to send interest packets and retrieve data packets. This includes encoding and decoding data packets.
+The current status of NDN-JS allows for JavaScript applications running on browsers to send interest packets and retrieve data packets. This includes encoding and decoding data packets.
This is currently done in the following way:
-createRoute('borges.metwi.ucla.edu', 9695); var contentObject = queryPrefix('/ndn/ucla.edu/apps/hydra/mainvideo'); console.log(contentObject.content);
\ No newline at end of file
+var ndn = new NDN();
+var contentObject = ndn.get('/ndn/ucla.edu/apps/hydra/mainvideo');
+console.log(contentObject.content);
+
+* Firefox extension for ccnx protocol
+
+NDN-JS also includes a Firefox extension for the ccnx protocol. To install in Firefox, open
+Tools > Add-ons. In the "gear" or "wrench" menu, click Install Add-on From File and open
+js/ccnxProtocol.xpi in this distribution. Restart Firefox.
+
+Firefox uses the extension to load any URI starting with ccnx, for example
+ccnx:/ndn/ucla.edu/apps/lwndn-test/trig-table
+
+When the page is loaded, the extension updates address bar with the full matched name from the
+retrieved content object including the version, but without the implicit digest or segment number
+(see below).
+
+A URI for content with multiple segments is handled as follows.
+If the URI has a segment number, just retrieve that segment and return the content to the browser.
+
+Otherwise look at the name in the returned ContentObject. If the returned name has no segment number,
+just return the content to the browser. If the name has a segment number which isn't 0, store it
+and express an interest for segment 0. Read segments in order and return each content to the browser
+as we go until we get the segment for FinalBlockID.
+
diff --git a/java/JavaPlugin.jar b/java/JavaPlugin.jar
new file mode 100644
index 0000000..8fa1090
--- /dev/null
+++ b/java/JavaPlugin.jar
Binary files differ
diff --git a/java/JavaSocketBridge.java b/java/JavaSocketBridge.java
index a8f064d..d484103 100644
--- a/java/JavaSocketBridge.java
+++ b/java/JavaSocketBridge.java
@@ -1,131 +1,488 @@
// @author: ucla-cs
+// See COPYING for copyright and distribution information.
import java.applet.*;
import javax.swing.*;
import netscape.javascript.*;
+import java.lang.reflect.InvocationTargetException;
import java.net.*;
+import java.nio.ByteBuffer;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.DatagramChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
import java.security.AccessController;
import java.security.PrivilegedAction;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.Timer;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
import java.io.*;
+
+
public class JavaSocketBridge extends JApplet {
- private final static int PACKETSIZE = 3000 ;
+ static String protocol = "TCP";
+
+ static volatile Hashtable<String, SocketChannel> connections = new Hashtable<String, SocketChannel>();
+
+
+
+ volatile String result = "";
+
+ //static ConcurrentHashMap hm = null;
+ static boolean isBrowser = true;
+
+
+
+
+ private final static int PACKETSIZE = 8192 ;
// Instance variables
static JSObject browser = null; // The browser
- static ConcurrentHashMap hm = null;
+ protected Selector _ncReadSelector = null;
+ protected Selector _ncWriteSelector = null;
- // Initialize
+
+ // Initialize automatically called by browser
public void init(){
- browser = JSObject.getWindow(this);
+
+ try{
+ browser = JSObject.getWindow(this);
+ }
+ catch(Exception e){
+ error( "ERROR IN INIT" + e.toString());
+ }
}
- public String connectAndStart(final String ip, final int por, final String interest){
+ //start automatically called by browser
+ public void start(){
+ try {
+ browser.call("java_socket_bridge_ready", null);
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ error("ERROR IN START" +e.toString());
+ }
+
+ }
+
+ public String getOLD(final String h, final int p, final String interest, final int timeout){
return AccessController.doPrivileged(
new PrivilegedAction<String>() {
public String run() {
- DatagramSocket socket = null ;
- byte[] output = null;
- try
- {
- // Convert the arguments first, to ensure that they are valid
- InetAddress host = InetAddress.getByName( ip ) ;
- int port = por ;
+ Socket sock=null;
+ OutputStream out=null;
+ InputStream in=null;
- // Construct the socket
- socket = new DatagramSocket() ;
+ try{
- byte [] data = hex2Byte(interest);
- DatagramPacket packet = new DatagramPacket( data, data.length, host, port ) ;
+ sock=new Socket(h,p);
- // Send it
- socket.send( packet ) ;
- // Set a receive timeout, 2000 milliseconds
- socket.setSoTimeout( 4000 ) ;
+ String word= interest;
- // Prepare the packet for receive
- packet.setData( new byte[PACKETSIZE] ) ;
- // Wait for a response from the server
- socket.receive( packet ) ;
+ in = sock.getInputStream();
- // Print the response
- output = packet.getData() ;
+ out=sock.getOutputStream();
- }
- catch( Exception e )
- {
- error(e.toString());
- System.out.println( e ) ;
- }
- finally
- {
- if( socket != null )
- socket.close() ;
+
+ System.out.println("Your string is"+word);
+
+ out.write(hex2Bytes(word));
+ out.flush();
+ sock.shutdownOutput();
+
+ ByteArrayOutputStream serverinput=new ByteArrayOutputStream();
+
+ int len=0;
+ byte[] buf=new byte[PACKETSIZE];
+ while ((len = in.read(buf))>=0) {
+ serverinput.write(buf, 0, len);
+ }
+
+ String outputString = bytes2Hex(buf);
+
+ System.out.println("Your string is "+word+" converted to byte "+outputString);
+
+ return outputString;
+
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ error(e);
}
- if(output!=null)
- return byte2hex(output);
- else
- return "";
+
+ finally{
+
+ try {
+ sock.close();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ error(e);
+ }
+
+ }
+
+ return "ERROR";
}
}
+
);
+ }
+
+ public String get(final String h, final int p, final String interest,final int timeout){
+ return AccessController.doPrivileged(
+ new PrivilegedAction<String>() {
+ public String run() {
+ Thread t = new Thread( new Runnable(){
+ public void run(){
+
+ SocketChannel sChannelCloser = null;
+ try{
+
+ final SocketChannel sChannel = open(h,p);
+
+ sChannelCloser=sChannel;
+
+ sChannel.socket().setSoTimeout(timeout);
+
+ ByteBuffer buffer = ByteBuffer.wrap(hex2Bytes(interest));
+
+ System.out.println("WRITING BYTES:"+interest);
+
+ while(buffer.hasRemaining())
+ sChannel.write(buffer);
+
+ ByteBuffer bufferReceiver = ByteBuffer.allocate(PACKETSIZE);
+
+ buffer.clear();
+ sChannel.read(bufferReceiver);
+
+ String output = bytes2Hex(bufferReceiver.array(), bufferReceiver.position());
+ System.out.println("RECEIVED BYTES:" +output);
+
+ result=output;
+
+ return ;
+
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ error(e);
+ }
+ finally{
+
+ try {
+ sChannelCloser.close();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ error(e);
+ }
+
+ }
+
+
+
+ //return "STARTED GETTING";
+
+ }
+ }
+
+ );
+
+ t.start();
+
+ Long start = System.currentTimeMillis();
+ Long current = System.currentTimeMillis();
+
+ while(t.isAlive() && current-start < timeout ){
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ error(e);
+ }
+ current = System.currentTimeMillis();
+ }
+ if(current-start >= timeout){
+ t.stop();
+ return "TIMEOUT EXPIRED";
+ }
+ else{
+ return result;
+
+ }
+
+
+ }
+ }
+
+ );
+ }
+
+
+ // Report an error
+ public static void receivedInterest( String data,String name){
+
+ Object[] arguments = new Object[2];
+ arguments[0] = data;
+ arguments[1] = name;
+
+
+ try {
+ browser.call("on_socket_received_interest", arguments);
+ } catch (JSException e) {
+ // TODO Auto-generated catch block
+ error(e.getMessage());
+ }
}
- public String sendContentObject(final String ip, final int por, final String interest){
+ public String put(final String h, final int p, final String interest,final String name, final String toReturn){
return AccessController.doPrivileged(
new PrivilegedAction<String>() {
public String run() {
- DatagramSocket socket = null ;
- byte[] output = null;
- try
- {
- // Convert the arguments first, to ensure that they are valid
- InetAddress host = InetAddress.getByName( ip ) ;
- int port = por ;
- // Construct the socket
- socket = new DatagramSocket() ;
+ SocketChannel sChannelCloser = null;
+ try{
+
+ final SocketChannel sChannel = open(h,p);
+ sChannelCloser=sChannel;
+
+ //FIRST TIME
+ //ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
+
+ ByteBuffer buffer = ByteBuffer.wrap(hex2Bytes(interest));
+
+ System.out.println("WRITING BYTES:"+interest);
+ while(buffer.hasRemaining())
+ sChannel.write(buffer);
+
+ ByteBuffer bufferReceiver = ByteBuffer.allocate(PACKETSIZE);
+
+ buffer.clear();
+ sChannel.read(bufferReceiver);
+
+ System.out.println("RECEIVED BYTES:" + bytes2Hex(bufferReceiver.array()));
- byte [] data = hex2Byte(interest);
- DatagramPacket packet = new DatagramPacket( data, data.length, host, port ) ;
- // Send it
- socket.send( packet );
+
+ Thread t = new Thread( new Runnable(){
+ public void run(){
+ //sChannel.
+ while(true){
+
+ try{
+
+ ByteBuffer bufferReceiver = ByteBuffer.allocate(PACKETSIZE);
+
+ bufferReceiver.clear();
+ sChannel.read(bufferReceiver);
+
+ String receivedHexBytes = bytes2Hex(bufferReceiver.array());
+
+ System.out.println("RECEIVED BYTES:" + receivedHexBytes);
+
+
+ System.out.println("name is "+name);
+
+ //connections.put(name, sChannel);
+
+ //System.out.println("name is "+name);
+
+ //receivedInterest(receivedHexBytes,name);
+
+
+ //byte[] output = hex2Bytes("048202aa03b208855dea25cca4d3967c774cc6e709a140d91f9d74e97a665cbb106568ee94f998d8b22fbe2b8d2fc43bd9363b501a50f2d770a7882aaf0792c20359f54da27d4a5b5a29be7d349c656e60fd37c92cf4e4aae256af04161e561aa4323512b38799c43d7a2ec4e35c3e19599b12c5ee3a5f0994837461c05c294a8b596f960e9287520000f2faad726f63636f000001a203e2028548398bad0eeb58e9cc64720e84f4947fe1c1eb310055181ed0b4c2d920ef6e590002bab504fcc5336e9c0001e201da0a9530819f300d06092a864886f70d010101050003818d003081890281810092e67426906bae66a3f4910bade5a2d24e2b7ed0d7a3e16f368c258e848f30115f6e95f5e0ee64505ed3da08be6ee599d395f611ffb096a9c258171518f0c6b3612a94681d29e44619227ac268e5d450abac89820d96188f507d15fb40d8780ccb76a012f7ce4f4efe2b8ba431ef993e31da867adffb069003808bceef9ff4d10203010001000000019abd424f4e4a4f55520000");
+
+ byte[] output = hex2Bytes(toReturn);
+
+
+ ByteBuffer outputBuffer = ByteBuffer.wrap(output);
+
+ //byte[] output = hex2Bytes("048202aa03b208857d7f003e50fc79aca1563842832db26c5e313bec0940ce795dd8adc34e7fd2cadee7b44b28737d59c061240da60d0733e2bcc760c7656a0f03b20a987c1a1fb94bb93648243c48fde222bc21b85062f186ffdc15f637cfe83f35ab11e3564e7e83a26de39a0faf3991f469f0f376fca535fb1be28ede72b433547b4977f0f3000000f2faa574657374000001a203e20285189f9df9814d134883758f9c5541ba957a4464d8756f34870cf981143f56779a0002bab504fcbf24f6f60001e201da0a9530819f300d06092a864886f70d010101050003818d0030818902818100c0a2c68770c339ed3152b90cde701ba588652f358854460b36b866c6e76272013232df351f10841ac49e35a6bc644f9c9caacd9aa0cd0e1835a34162c9208049d3f1f893d0b9566854133a763756df45297328d595ba6b6459fd311d5e1c97ce5278fa076dde765090c7221670ad54689958cc5fb46699482c5ac16c301dba1f0203010001000000019abd424f4e4a4f55520000");
+
+ while(outputBuffer.hasRemaining())
+ sChannel.write(outputBuffer);
+
+ System.out.println("SENT BACK SOME DATA");
+
+
+ }
+ catch(Exception e){
+ error(e);
+ try {
+ sChannel.close();
+ } catch (IOException e1) {
+ // TODO Auto-generated catch block
+ error(e1);
+ }
+ System.exit(0);
+
+ }
+ }
+
+ }});
+
+ t.start();
+
+ return "STARTED PUBLISHING";
+
+ //return receivedHexBytes;
+
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ error(e);
+
+ try {
+ System.out.println("CLOSING THE CONNECTION");
+ sChannelCloser.close();
+ } catch (IOException ex) {
+ // TODO Auto-generated catch block
+ error(ex);
+
+ }
}
- catch( Exception e )
- {
- error(e.toString());
- System.out.println( e ) ;
- }
- finally
- {
- if( socket != null )
- socket.close() ;
- }
+ return "FAILURE";
- if(output!=null)
- return byte2hex(output);
- else
- return "";
+
+
}
}
);
+ }
+
+
+
+ /**
+ * Not used
+ */
+ public String putAnswer(final String s, final String dataBack){
+
+ final SocketChannel sChannel = connections.get(s);
+
+
+ byte[] output = hex2Bytes(dataBack);
+
+ ByteBuffer outputBuffer = ByteBuffer.wrap(output);
+
+ //byte[] output = hex2Bytes("048202aa03b208857d7f003e50fc79aca1563842832db26c5e313bec0940ce795dd8adc34e7fd2cadee7b44b28737d59c061240da60d0733e2bcc760c7656a0f03b20a987c1a1fb94bb93648243c48fde222bc21b85062f186ffdc15f637cfe83f35ab11e3564e7e83a26de39a0faf3991f469f0f376fca535fb1be28ede72b433547b4977f0f3000000f2faa574657374000001a203e20285189f9df9814d134883758f9c5541ba957a4464d8756f34870cf981143f56779a0002bab504fcbf24f6f60001e201da0a9530819f300d06092a864886f70d010101050003818d0030818902818100c0a2c68770c339ed3152b90cde701ba588652f358854460b36b866c6e76272013232df351f10841ac49e35a6bc644f9c9caacd9aa0cd0e1835a34162c9208049d3f1f893d0b9566854133a763756df45297328d595ba6b6459fd311d5e1c97ce5278fa076dde765090c7221670ad54689958cc5fb46699482c5ac16c301dba1f0203010001000000019abd424f4e4a4f55520000");
+
+
+
+ try{
+ while(outputBuffer.hasRemaining())
+ sChannel.write(outputBuffer);
+
+
+ ByteBuffer bufferReceiver = ByteBuffer.allocate(PACKETSIZE);
+
+ bufferReceiver.clear();
+ sChannel.read(bufferReceiver);
+
+ String receivedHexBytes = bytes2Hex(bufferReceiver.array());
+ System.out.println("RECEIVED BYTES:" + receivedHexBytes);
+
+
+ receivedInterest(receivedHexBytes,s);
+
+ }
+ catch (Exception e) {
+ // TODO Auto-generated catch block
+ error(e);
+
+ try {
+ System.out.println("CLOSING THE CONNECTION");
+ sChannel.close();
+ } catch (IOException ex) {
+ // TODO Auto-generated catch block
+ error(ex);
+ return "FAILURE";
+ }
+ }
+
+ return "SUCCESS";
}
- public static byte[] hex2Byte(String str)
+
+ public SocketChannel open(String host, int ip) throws IOException{
+ // Create a non-blocking socket channel
+ SocketChannel sChannel = SocketChannel.open();
+
+ //sChannel.configureBlocking(false);
+
+ // Send a connection request to the server; this method is non-blocking
+ sChannel.connect(new InetSocketAddress(host, ip));
+
+ // Before the socket is usable, the connection must be completed
+ // by calling finishConnect(), which is non-blocking
+
+ _ncReadSelector = Selector.open();
+ //sChannel.configureBlocking(false);
+ //sChannel.register(_ncReadSelector, SelectionKey.OP_READ);
+ _ncWriteSelector = Selector.open();
+ //sChannel.register(_ncWriteSelector, SelectionKey.OP_WRITE);
+
+
+ while (!sChannel.finishConnect()) {
+ // Do something else
+ System.out.println("TRYING TO CONNECT");
+ }
+ System.out.println("CONNECTED TO " +host +":"+ip);
+
+ return sChannel;
+ }
+
+
+ public static void error(Exception ex){
+ StringWriter sw = new StringWriter();
+ ex.printStackTrace(new PrintWriter(sw));
+ String exceptionAsStrting = sw.toString();
+
+ error(exceptionAsStrting );
+ }
+ // Report an error
+ public static void error(String message){
+
+ System.out.println("RECEIVED AN ERROR");
+ message = "Java Socket Bridge ERROR: " + message;
+ Object[] arguments = new Object[1];
+ arguments[0] = message;
+
+ if(isBrowser){
+ try {
+ browser.call("on_socket_error", arguments);
+ } catch (JSException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ else{
+ System.out.println(message);
+ }
+ }
+
+
+
+
+ // Log something
+ public void log(String message){
+ System.out.println(message);
+ }
+
+
+ public static byte[] hex2Bytes(String str)
{
byte[] bytes = new byte[str.length() / 2];
for (int i = 0; i < bytes.length; i++)
@@ -136,13 +493,13 @@
return bytes;
}
- public static String byte2hex(byte[] b)
+ public static String bytes2Hex(byte[] b, int length)
{
// String Buffer can be used instead
String hs = "";
String stmp = "";
- for (int n = 0; n < b.length; n++)
+ for (int n = 0; n < length; n++)
{
stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
@@ -155,7 +512,7 @@
hs = hs + stmp;
}
- if (n < b.length - 1)
+ if (n < length - 1)
{
hs = hs + "";
}
@@ -163,116 +520,44 @@
return hs;
}
-
-
- // Main
- // Note: This method loops over and over to handle requests becuase only
- // this thread gets the elevated security policy. Java == stupid.
- public void start(){
- try {
- browser.call("java_socket_bridge_ready", null);
- } catch (JSException e) {
- // TODO Auto-generated catch block
- error(e.getMessage());
- }
-
- }
-
-
- // Report an error
- public static void error(String message){
- message = "Java Socket Bridge ERROR: " + message;
- Object[] arguments = new Object[1];
- arguments[0] = message;
- try {
- browser.call("on_socket_error", arguments);
- } catch (JSException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
-
- // Report an error
- public static void receivedInterest(String IP,int port, byte[] data){
-
-
- Object[] arguments = new Object[3];
- arguments[0] = IP;
- arguments[1] = port;
- arguments[2] = byte2hex( data );
-
- try {
- browser.call("on_socket_received_interest", arguments);
- } catch (JSException e) {
- // TODO Auto-generated catch block
- error(e.getMessage());
- }
-
- }
-
-
- public static void connectAndStartAndPublish()
+ public static String bytes2Hex(byte[] b)
{
-
- AccessController.doPrivileged(
- new PrivilegedAction<String>() {
- public String run() {
- Thread t = new Thread( new Runnable(){
- public void run(){
+ return bytes2Hex(b, b.length);
+ }
- String message;
- try{
- DatagramSocket serverSocket = new DatagramSocket(9876);
- byte[] receiveData = new byte[1024];
- byte[] sendData = new byte[1024];
- while(true)
- {
- DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
- serverSocket.receive(receivePacket);
+ public static void main(String[] args) throws IOException {
- //String sentence = new String( receivePacket.getData());
+ JavaSocketBridge b = new JavaSocketBridge();
- //System.out.println("RECEIVED: " + sentence);
+ //System.out.println( b.get("127.0.0.1",9695 ,"01D2F2FAA4657374000000", 1000));
+
+ //System.out.println( b.get("127.0.0.1",9695 ,"01D2F2FAA574657374000000", 1000));
+
+ //System.out.println( b.putSend("127.0.0.1",9695 ,"01d2f2faa563636e7800fa0285e0a01e093968f9740ce7f4361babf5bb05a4e55aaca5e58f73eddeb8e013aa8f00fabd73656c6672656700fa1bf5048202aa03b2088568cf069cdfdedad97ad9358f7e2446ca581eaa22ed9eb4e482fe616b35840533ba4f9d321155d6c34915dff7352de5e60bddb17e32f893cd89056cfd291011a5c3742312a083c2628fed4ddffb04cf51e6860eb1dbd43ff9b59736e62ec1a69218ce0acfdd9da896a617f609c12225f14a63876488b38d3a7b9fc1757d9058470000f20001a203e2028547ab87ece0e191c5e946f839507bc875c63c7032e42c347c135a952e7187c9300002bab504fcb2a6a0250001e201da0a9530819f300d06092a864886f70d010101050003818d003081890281810089b8f8b42d8aa31148d9f2a0c38d3fee7c73f60ea444d08fd886114a689cfe235c49bf9e256489390c19d961aabd5ee6d9e9e133282cd68b046609fe0a81be76c683cb150f3d035231b25745530fc887fbd137d6ef9c05d795fdb78f84eeab6f7dcbd1aa64b3920d96cfe941b66967bb2892baef1995bea231a4dc89c383e8550203010001000000019a0585058a04cabe73656c6672656700f2faad726f63636f000003e20285e0a01e093968f9740ce7f4361babf5bb05a4e55aaca5e58f73eddeb8e013aa8f0004fa8e330003d2d63231343734383336343700000000000002d28e310000",1000));
+
+ //System.out.println( b.putSend("127.0.0.1",9695 ,"01D2F2FAA574657374000000",1000));
- InetAddress IPAddress = receivePacket.getAddress();
+ //System.out.println( b.getSend("127.0.0.1",9695 ,"01D2F2FAA574657374000000", 1000));
- int port = receivePacket.getPort();
+ //System.out.println( b.get("localhost",9695 ,"01d2f2fafd",3000));
- byte[] receivedData = receivePacket.getData();
-
- receivedInterest( IPAddress.getHostAddress() , port, receivedData);
-
- //String capitalizedSentence = sentence.toUpperCase();
-
- //DATA PACKET HERE!
+ //System.out.println( b.get("localhost",9695 ,"01D2F2FAA574657374000",3000));
- //sendData = capitalizedSentence.getBytes();
-
- //DatagramPacket sendPacket =
- // new DatagramPacket(sendData, sendData.length, IPAddress, port);
- //serverSocket.send(sendPacket);
- }
- }
- catch(Exception e){
- error("Exception " + e + "FAILURE, ERROR IN SOCKET CONECTION");
- }
+ //System.out.println( b.getOLD("localhost",9695 ,"01d2f2fafdc12e4d2e532e6c6f63616c686f737400fabdc12e4d2e53525600faa563636e6400fa9d4b4559000002d28e310000",1000));
- }
- });
+ //System.out.println( b.putSend("localhost",9695 ,"01d2f2faa563636e7800fa0285e0a01e093968f9740ce7f4361babf5bb05a4e55aaca5e58f73eddeb8e013aa8f00fabd73656c6672656700fa1bf5048202aa03b208854a18988c72aee624da28e2e1acbccb209b8e89429041985521ed68f95a1c546872fba3d854b1377dc249b6d8ec5935e5069256c97a7f6d8a62e86222ccd2cfe5097aed3fe5ede6732ce191a8680d78e39d0c5058a2b7bb0f0687994e9f045de346b66c46498547a08da1f2f0cdfafba3afdfe7107931935ede79040137ba94a90000f20001a203e202851a4860caa4991e829bcdc9429fb711d52440968d23560726606050bf147acffc0002bab504fcb3f03aa40001e201da0a9530819f300d06092a864886f70d010101050003818d00308189028181008ed27580e3d1c4c67672208665133a1ba12d8ebf5cad8e054571926b3ff0782a04c71703384021a6cefb6616b66cbd8a679b761d69d6373a851546e26f7105510b4c23be9a3c7f2e652e100ecc1471855730659f1477ce4e8504ad1fd8f44116baaeae2ff67eec33abba790157a79bf5039e5a528a471d9d67c94e70117ed7490203010001000000019a0585058a04cabe73656c6672656700f2faad726f63636f000003e20285e0a01e093968f9740ce7f4361babf5bb05a4e55aaca5e58f73eddeb8e013aa8f0004fa8e330003d2d63231343734383336343700000000000002d28e310000", 1000));
- t.start();
- return "SUCCESS";
+ //b.putSend("localhost",9695 ,"01d2f2faa563636e7800fa0285e0a01e093968f9740ce7f4361babf5bb05a4e55aaca5e58f73eddeb8e013aa8f00fabd73656c6672656700fa1bf5048202aa03b208854a18988c72aee624da28e2e1acbccb209b8e89429041985521ed68f95a1c546872fba3d854b1377dc249b6d8ec5935e5069256c97a7f6d8a62e86222ccd2cfe5097aed3fe5ede6732ce191a8680d78e39d0c5058a2b7bb0f0687994e9f045de346b66c46498547a08da1f2f0cdfafba3afdfe7107931935ede79040137ba94a90000f20001a203e202851a4860caa4991e829bcdc9429fb711d52440968d23560726606050bf147acffc0002bab504fcb3f03aa40001e201da0a9530819f300d06092a864886f70d010101050003818d00308189028181008ed27580e3d1c4c67672208665133a1ba12d8ebf5cad8e054571926b3ff0782a04c71703384021a6cefb6616b66cbd8a679b761d69d6373a851546e26f7105510b4c23be9a3c7f2e652e100ecc1471855730659f1477ce4e8504ad1fd8f44116baaeae2ff67eec33abba790157a79bf5039e5a528a471d9d67c94e70117ed7490203010001000000019a0585058a04cabe73656c6672656700f2faad726f63636f000003e20285e0a01e093968f9740ce7f4361babf5bb05a4e55aaca5e58f73eddeb8e013aa8f0004fa8e330003d2d63231343734383336343700000000000002d28e310000", 1000);
+ //NewTest(54567);
- }
+ //System.out.println( b.put());
-
- }
- );
+ //connections.put("meki", SocketChannel.open());
}
diff --git a/js/.DS_Store b/js/.DS_Store
index d3e1ca3..df19300 100644
--- a/js/.DS_Store
+++ b/js/.DS_Store
Binary files differ
diff --git a/js/Closure.js b/js/Closure.js
new file mode 100644
index 0000000..a06daad
--- /dev/null
+++ b/js/Closure.js
@@ -0,0 +1,64 @@
+/*
+ * @author: ucla-cs
+ * See COPYING for copyright and distribution information.
+ * Provide the callback closure for the async communication methods in the NDN class.
+ * This is a port of Closure.py from PyCCN, written by:
+ * Derek Kulinski <takeda@takeda.tk>
+ * Jeff Burke <jburke@ucla.edu>
+ */
+
+/*
+ * Create a subclass of Closure and pass an object to async calls.
+ */
+var Closure = function Closure() {
+ // I don't think storing NDN's closure is needed
+ // and it creates a reference loop, as of now both
+ // of those variables are never set -- Derek
+ //
+ // Use instance variables to return data to callback
+ this.ndn_data = null; // this holds the ndn_closure
+ this.ndn_data_dirty = false;
+};
+
+// Upcall result
+Closure.RESULT_ERR = -1; // upcall detected an error
+Closure.RESULT_OK = 0; // normal upcall return
+Closure.RESULT_REEXPRESS = 1; // reexpress the same interest again
+Closure.RESULT_INTEREST_CONSUMED = 2; // upcall claims to consume interest
+Closure.RESULT_VERIFY = 3; // force an unverified result to be verified
+Closure.RESULT_FETCHKEY = 4; // get the key in the key locator and re-call the interest
+ // with the key available in the local storage
+
+// Upcall kind
+Closure.UPCALL_FINAL = 0; // handler is about to be deregistered
+Closure.UPCALL_INTEREST = 1; // incoming interest
+Closure.UPCALL_CONSUMED_INTEREST = 2; // incoming interest, someone has answered
+Closure.UPCALL_CONTENT = 3; // incoming verified content
+Closure.UPCALL_INTEREST_TIMED_OUT = 4; // interest timed out
+Closure.UPCALL_CONTENT_UNVERIFIED = 5; // content that has not been verified
+Closure.UPCALL_CONTENT_BAD = 6; // verification failed
+
+/*
+ * Override this in your subclass.
+ * If you're getting strange errors in upcall()
+ * check your code whether you're returning a value.
+ */
+Closure.prototype.upcall = function(kind, upcallInfo) {
+ //dump('upcall ' + this + " " + kind + " " + upcallInfo + "\n");
+ return Closure.RESULT_OK;
+};
+
+var UpcallInfo = function UpcallInfo(ndn, interest, matchedComps, contentObject) {
+ this.ndn = ndn; // NDN object (not used)
+ this.interest = interest; // Interest object
+ this.matchedComps = matchedComps; // int
+ this.contentObject = contentObject; // Content object
+};
+
+UpcallInfo.prototype.toString = function() {
+ var ret = "ndn = " + this.ndn;
+ ret += "\nInterest = " + this.interest;
+ ret += "\nmatchedComps = " + this.matchedComps;
+ ret += "\nContentObject: " + this.contentObject;
+ return ret;
+}
diff --git a/js/ContentName.js b/js/ContentName.js
deleted file mode 100644
index 8c12188..0000000
--- a/js/ContentName.js
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * @author: ucla-cs
- * This class represents ContentName
- */
-
-
-var ContentName = function ContentName(_Components){
-
-
- this.SCHEME = "ccnx:";
-
- this.ORIGINAL_SCHEME = "ccn:";
-
- this.SEPARATOR = "/";
- this.ROOT = null;
-
- if( typeof _Components == 'string') {
-
- if(LOG>3)console.log('Content Name String '+_Components);
- this.Components = createNameArray(_Components);
- }
- else if(typeof _Components === 'object' && _Components instanceof Array ){
-
- if(LOG>4)console.log('Content Name Array '+_Components);
- this.Components = _Components;
-
- }
- else if(_Components==null){
- this.Components =[];
- }
- else{
-
- if(LOG>1)console.log("NO CONTENT NAME GIVEN");
-
- }
-};
-
-function createNameArray(name){
-
-
- //message = decodeURIComponent(message);
- name = unescape(name);
-
- var array = name.split('/');
-
-
- if(name[0]=="/")
- array=array.slice(1,array.length);
-
- if(name[name.length-1]=="/")
- array=array.slice(0,array.length-1);
-
- return array;
-}
-
-
-ContentName.prototype.decode = function(/*XMLDecoder*/ decoder) {
- decoder.readStartElement(this.getElementLabel());
-
-
- this.Components = new Array(); //new ArrayList<byte []>();
-
- while (decoder.peekStartElement(CCNProtocolDTags.Component)) {
- this.add(decoder.readBinaryElement(CCNProtocolDTags.Component));
- }
-
- decoder.readEndElement();
-};
-
-ContentName.prototype.encode = function(/*XMLEncoder*/ encoder) {
-
- if( this.Components ==null )
- throw new Exception("CANNOT ENCODE EMPTY CONTENT NAME");
-
- encoder.writeStartElement(this.getElementLabel());
- var count = this.Components.length;
- for (var i=0; i < count; i++) {
- encoder.writeElement(CCNProtocolDTags.Component, this.Components[i]);
- }
- encoder.writeEndElement();
-};
-
-ContentName.prototype.getElementLabel = function(){
- return CCNProtocolDTags.Name;
-};
-
-ContentName.prototype.add = function(param){
- return this.Components.push(param);
-};
-
diff --git a/js/ContentObject.js b/js/ContentObject.js
index e120a98..62aa9fc 100644
--- a/js/ContentObject.js
+++ b/js/ContentObject.js
@@ -1,62 +1,86 @@
/*
* @author: ucla-cs
+ * See COPYING for copyright and distribution information.
* This class represents ContentObject Objects
*/
-var ContentObject = function ContentObject(_Name,_SignedInfo,_Content,_Signature){
+var ContentObject = function ContentObject(_name,_signedInfo,_content,_signature){
- if (typeof _Name === 'string'){
- this.Name = new ContentName(_Name);
+ if (typeof _name === 'string'){
+ this.name = new Name(_name);
}
else{
- //TODO Check the class of _Name
- this.Name = _Name;
+ //TODO Check the class of _name
+ this.name = _name;
}
- this.SignedInfo = _SignedInfo;
- this.Content=_Content;
- this.Signature = _Signature;
+ this.signedInfo = _signedInfo;
+ this.content=_content;
+ this.signature = _signature;
- this.StartSIG = null;
- this.EndSIG = null;
+ this.startSIG = null;
+ this.endSIG = null;
- this.StartSignedInfo = null;
- this.EndContent = null;
+ this.startSignedInfo = null;
+ this.endContent = null;
this.rawSignatureData = null;
};
ContentObject.prototype.sign = function(){
- var n1 = this.encodeObject(this.Name);
- var n2 = this.encodeObject(this.SignedInfo);
+
+ var n1 = this.encodeObject(this.name);
+ var n2 = this.encodeObject(this.signedInfo);
var n3 = this.encodeContent();
+ /*console.log('sign: ');
+ console.log(n1);
+ console.log(n2);
+ console.log(n3);*/
- var n = n1.concat(n2,n3);
- if(LOG>2)console.log('Signature Data is (binary) '+n);
+ //var n = n1.concat(n2,n3);
+ var tempBuf = new ArrayBuffer(n1.length + n2.length + n3.length);
+ var n = new Uint8Array(tempBuf);
+ //console.log(n);
+ n.set(n1, 0);
+ //console.log(n);
+ n.set(n2, n1.length);
+ //console.log(n);
+ n.set(n3, n1.length + n2.length);
+ //console.log(n);
- if(LOG>2)console.log('Signature Data is (RawString) '+ toString(n) );
- if(LOG>2)console.log(toString(n) );
+ if(LOG>4)console.log('Signature Data is (binary) '+n);
+ if(LOG>4)console.log('Signature Data is (RawString)');
+
+ if(LOG>4)console.log( DataUtils.toString(n) );
+
+ //var sig = DataUtils.toString(n);
+
var rsa = new RSAKey();
rsa.readPrivateKeyFromPEMString(globalKeyManager.privateKey);
-
- var hSig = rsa.signString(toString(n), "sha256");
-
- if(LOG>2)console.log('SIGNATURE SAVED IS');
- if(LOG>2)console.log(hSig);
-
- if(LOG>2)console.log(toNumbers(hSig.trim()));
+ //var hSig = rsa.signString(sig, "sha256");
- this.Signature.Signature = toNumbers(hSig.trim());
+ var hSig = rsa.signByteArrayWithSHA256(n);
+
+
+ if(LOG>4)console.log('SIGNATURE SAVED IS');
+
+ if(LOG>4)console.log(hSig);
+
+ if(LOG>4)console.log( DataUtils.toNumbers(hSig.trim()));
+
+ this.signature.signature = DataUtils.toNumbers(hSig.trim());
+
+
};
ContentObject.prototype.encodeObject = function encodeObject(obj){
var enc = new BinaryXMLEncoder();
- obj.encode(enc);
+ obj.to_ccnb(enc);
var num = enc.getReducedOstream();
@@ -68,7 +92,7 @@
ContentObject.prototype.encodeContent = function encodeContent(obj){
var enc = new BinaryXMLEncoder();
- enc.writeElement(CCNProtocolDTags.Content, this.Content);
+ enc.writeElement(CCNProtocolDTags.Content, this.content);
var num = enc.getReducedOstream();
@@ -79,47 +103,43 @@
ContentObject.prototype.saveRawData = function(bytes){
- var sigBits = bytes.slice(this.StartSIG, this.EndSIG );
-
- //var sigIngoPlusContentBits = bytes.slice(this.StartSignedInfo, this.EndContent );
-
- //var concat = sigBits.concat(sigIngoPlusContentBits);
-
- //this.rawSignatureData = concat;
+ var sigBits = bytes.subarray(this.startSIG, this.endSIG);
this.rawSignatureData = sigBits;
};
-ContentObject.prototype.decode = function(/*XMLDecoder*/ decoder) {
+ContentObject.prototype.from_ccnb = function(/*XMLDecoder*/ decoder) {
+
+ // TODO VALIDATE THAT ALL FIELDS EXCEPT SIGNATURE ARE PRESENT
decoder.readStartElement(this.getElementLabel());
-
+
if( decoder.peekStartElement(CCNProtocolDTags.Signature) ){
- this.Signature = new Signature();
- this.Signature.decode(decoder);
+ this.signature = new Signature();
+ this.signature.from_ccnb(decoder);
}
- //this.EndSIG = decoder.offset;
+ //this.endSIG = decoder.offset;
- this.StartSIG = decoder.offset;
+ this.startSIG = decoder.offset;
- this.Name = new ContentName();
- this.Name.decode(decoder);
+ this.name = new Name();
+ this.name.from_ccnb(decoder);
- //this.StartSignedInfo = decoder.offset;
+ //this.startSignedInfo = decoder.offset;
if( decoder.peekStartElement(CCNProtocolDTags.SignedInfo) ){
- this.SignedInfo = new SignedInfo();
- this.SignedInfo.decode(decoder);
+ this.signedInfo = new SignedInfo();
+ this.signedInfo.from_ccnb(decoder);
}
- this.Content = decoder.readBinaryElement(CCNProtocolDTags.Content);
+ this.content = decoder.readBinaryElement(CCNProtocolDTags.Content);
- //this.EndContent = decoder.offset;
- this.EndSIG = decoder.offset;
+ //this.endContent = decoder.offset;
+ this.endSIG = decoder.offset;
decoder.readEndElement();
@@ -127,9 +147,9 @@
this.saveRawData(decoder.istream);
};
-ContentObject.prototype.encode = function(/*XMLEncoder*/ encoder) {
+ContentObject.prototype.to_ccnb = function(/*XMLEncoder*/ encoder) {
- //TODO verify Name, SignedInfo and Signature is present
+ //TODO verify name, SignedInfo and Signature is present
encoder.writeStartElement(this.getElementLabel());
@@ -137,26 +157,26 @@
- if(null!=this.Signature) this.Signature.encode(encoder);
+ if(null!=this.signature) this.signature.to_ccnb(encoder);
- this.StartSIG = encoder.offset;
+ this.startSIG = encoder.offset;
- if(null!=this.Name) this.Name.encode(encoder);
+ if(null!=this.name) this.name.to_ccnb(encoder);
- //this.EndSIG = encoder.offset;
- //this.StartSignedInfo = encoder.offset;
+ //this.endSIG = encoder.offset;
+ //this.startSignedInfo = encoder.offset;
- if(null!=this.SignedInfo) this.SignedInfo.encode(encoder);
+ if(null!=this.signedInfo) this.signedInfo.to_ccnb(encoder);
- encoder.writeElement(CCNProtocolDTags.Content, this.Content);
+ encoder.writeElement(CCNProtocolDTags.Content, this.content);
- this.EndSIG = encoder.offset;
+ this.endSIG = encoder.offset;
- //this.EndContent = encoder.offset;
+ //this.endContent = encoder.offset;
encoder.writeEndElement();
@@ -166,3 +186,276 @@
};
ContentObject.prototype.getElementLabel= function(){return CCNProtocolDTags.ContentObject;};
+
+/**
+ * Signature
+ */
+var Signature = function Signature(_witness,_signature,_digestAlgorithm) {
+
+ this.Witness = _witness;//byte [] _witness;
+ this.signature = _signature;//byte [] _signature;
+ this.digestAlgorithm = _digestAlgorithm//String _digestAlgorithm;
+};
+
+var generateSignature = function(contentName,content,signedinfo){
+
+ var enc = new BinaryXMLEncoder();
+ contentName.to_ccnb(enc);
+ var hex1 = toHex(enc.getReducedOstream());
+
+ var enc = new BinaryXMLEncoder();
+ content.to_ccnb(enc);
+ var hex2 = toHex(enc.getReducedOstream());
+
+ var enc = new BinaryXMLEncoder();
+ signedinfo.to_ccnb(enc);
+ var hex3 = toHex(enc.getReducedOstream());
+
+ var hex = hex1+hex2+hex3;
+
+ //globalKeyManager.sig
+
+};
+
+Signature.prototype.from_ccnb =function( decoder) {
+ decoder.readStartElement(this.getElementLabel());
+
+ if(LOG>4)console.log('STARTED DECODING SIGNATURE ');
+
+ if (decoder.peekStartElement(CCNProtocolDTags.DigestAlgorithm)) {
+
+ if(LOG>4)console.log('DIGIEST ALGORITHM FOUND');
+ this.digestAlgorithm = decoder.readUTF8Element(CCNProtocolDTags.DigestAlgorithm);
+ }
+ if (decoder.peekStartElement(CCNProtocolDTags.Witness)) {
+ if(LOG>4)console.log('WITNESS FOUND FOUND');
+ this.Witness = decoder.readBinaryElement(CCNProtocolDTags.Witness);
+ }
+
+ //FORCE TO READ A SIGNATURE
+
+ //if(LOG>4)console.log('SIGNATURE FOUND ');
+ this.signature = decoder.readBinaryElement(CCNProtocolDTags.SignatureBits);
+ if(LOG>4)console.log('READ SIGNATURE ');
+
+ decoder.readEndElement();
+
+};
+
+
+Signature.prototype.to_ccnb= function( encoder){
+
+ if (!this.validate()) {
+ throw new Error("Cannot encode: field values missing.");
+ }
+
+ encoder.writeStartElement(this.getElementLabel());
+
+ if ((null != this.digestAlgorithm) && (!this.digestAlgorithm.equals(CCNDigestHelper.DEFAULT_DIGEST_ALGORITHM))) {
+ encoder.writeElement(CCNProtocolDTags.DigestAlgorithm, OIDLookup.getDigestOID(this.DigestAlgorithm));
+ }
+
+ if (null != this.Witness) {
+ // needs to handle null witness
+ encoder.writeElement(CCNProtocolDTags.Witness, this.Witness);
+ }
+
+ encoder.writeElement(CCNProtocolDTags.SignatureBits, this.signature);
+
+ encoder.writeEndElement();
+};
+
+Signature.prototype.getElementLabel = function() { return CCNProtocolDTags.Signature; };
+
+
+Signature.prototype.validate = function() {
+ return null != this.signature;
+};
+
+
+/**
+ * SignedInfo
+ */
+var ContentType = {DATA:0, ENCR:1, GONE:2, KEY:3, LINK:4, NACK:5};
+var ContentTypeValue = {0:0x0C04C0, 1:0x10D091,2:0x18E344,3:0x28463F,4:0x2C834A,5:0x34008A};
+var ContentTypeValueReverse = {0x0C04C0:0, 0x10D091:1,0x18E344:2,0x28463F:3,0x2C834A:4,0x34008A:5};
+
+var SignedInfo = function SignedInfo(_publisher,_timestamp,_type,_locator,_freshnessSeconds,_finalBlockID){
+
+ //TODO, Check types
+
+ this.publisher = _publisher; //publisherPublicKeyDigest
+ this.timestamp=_timestamp; // CCN Time
+ this.type=_type; // ContentType
+ this.locator =_locator;//KeyLocator
+ this.freshnessSeconds =_freshnessSeconds; // Integer
+ this.finalBlockID=_finalBlockID; //byte array
+
+};
+
+SignedInfo.prototype.setFields = function(){
+ //BASE64 -> RAW STRING
+
+ //this.locator = new KeyLocator( DataUtils.toNumbersFromString(stringCertificate) ,KeyLocatorType.CERTIFICATE );
+
+ var publicKeyHex = globalKeyManager.publicKey;
+
+ if(LOG>4)console.log('PUBLIC KEY TO WRITE TO CONTENT OBJECT IS ');
+ if(LOG>4)console.log(publicKeyHex);
+
+ var publicKeyBytes = DataUtils.toNumbers(globalKeyManager.publicKey) ;
+
+
+
+ //var stringCertificate = DataUtils.base64toString(globalKeyManager.certificate);
+
+ //if(LOG>3)console.log('string Certificate is '+stringCertificate);
+
+ //HEX -> BYTE ARRAY
+ //var publisherkey = DataUtils.toNumbers(hex_sha256(stringCertificate));
+
+ //if(LOG>3)console.log('publisher key is ');
+ //if(LOG>3)console.log(publisherkey);
+
+ var publisherKeyDigest = hex_sha256_from_bytes(publicKeyBytes);
+
+ this.publisher = new PublisherPublicKeyDigest( DataUtils.toNumbers( publisherKeyDigest ) );
+
+ //this.publisher = new PublisherPublicKeyDigest(publisherkey);
+
+ var d = new Date();
+
+ var time = d.getTime();
+
+
+ this.timestamp = new CCNTime( time );
+
+ if(LOG>4)console.log('TIME msec is');
+
+ if(LOG>4)console.log(this.timestamp.msec);
+
+ //DATA
+ this.type = 0;//0x0C04C0;//ContentTypeValue[ContentType.DATA];
+
+ //if(LOG>4)console.log('toNumbersFromString(stringCertificate) '+DataUtils.toNumbersFromString(stringCertificate));
+
+ if(LOG>4)console.log('PUBLIC KEY TO WRITE TO CONTENT OBJECT IS ');
+ if(LOG>4)console.log(publicKeyBytes);
+
+ this.locator = new KeyLocator( publicKeyBytes ,KeyLocatorType.KEY );
+
+ //this.locator = new KeyLocator( DataUtils.toNumbersFromString(stringCertificate) ,KeyLocatorType.CERTIFICATE );
+
+};
+
+SignedInfo.prototype.from_ccnb = function( decoder){
+
+ decoder.readStartElement( this.getElementLabel() );
+
+ if (decoder.peekStartElement(CCNProtocolDTags.PublisherPublicKeyDigest)) {
+ if(LOG>3) console.log('DECODING PUBLISHER KEY');
+ this.publisher = new PublisherPublicKeyDigest();
+ this.publisher.from_ccnb(decoder);
+ }
+
+ if (decoder.peekStartElement(CCNProtocolDTags.Timestamp)) {
+ this.timestamp = decoder.readDateTime(CCNProtocolDTags.Timestamp);
+ if(LOG>4)console.log('TIMESTAMP FOUND IS '+this.timestamp);
+
+ }
+
+ if (decoder.peekStartElement(CCNProtocolDTags.Type)) {
+ binType = decoder.readBinaryElement(CCNProtocolDTags.Type);//byte []
+
+
+ //TODO Implement type of Key Reading
+
+ if(LOG>4)console.log('Binary Type of of Signed Info is '+binType);
+
+ this.type = binType;
+
+
+ //TODO Implement type of Key Reading
+
+
+ if (null == this.type) {
+ throw new Error("Cannot parse signedInfo type: bytes.");
+ }
+
+ } else {
+ this.type = ContentType.DATA; // default
+ }
+
+ if (decoder.peekStartElement(CCNProtocolDTags.FreshnessSeconds)) {
+ this.freshnessSeconds = decoder.readIntegerElement(CCNProtocolDTags.FreshnessSeconds);
+ if(LOG>4) console.log('FRESHNESS IN SECONDS IS '+ this.freshnessSeconds);
+ }
+
+ if (decoder.peekStartElement(CCNProtocolDTags.FinalBlockID)) {
+ this.finalBlockID = decoder.readBinaryElement(CCNProtocolDTags.FinalBlockID);
+ }
+
+ if (decoder.peekStartElement(CCNProtocolDTags.KeyLocator)) {
+ this.locator = new KeyLocator();
+ this.locator.from_ccnb(decoder);
+ }
+
+ decoder.readEndElement();
+};
+
+SignedInfo.prototype.to_ccnb = function( encoder) {
+ if (!this.validate()) {
+ throw new Error("Cannot encode : field values missing.");
+ }
+ encoder.writeStartElement(this.getElementLabel());
+
+ if (null!=this.publisher) {
+ if(LOG>3) console.log('ENCODING PUBLISHER KEY' + this.publisher.publisherPublicKeyDigest);
+
+ this.publisher.to_ccnb(encoder);
+ }
+
+ if (null!=this.timestamp) {
+ encoder.writeDateTime(CCNProtocolDTags.Timestamp, this.timestamp );
+ }
+
+ if (null!=this.type && this.type !=0) {
+
+ encoder.writeElement(CCNProtocolDTags.type, this.type);
+ }
+
+ if (null!=this.freshnessSeconds) {
+ encoder.writeElement(CCNProtocolDTags.FreshnessSeconds, this.freshnessSeconds);
+ }
+
+ if (null!=this.finalBlockID) {
+ encoder.writeElement(CCNProtocolDTags.FinalBlockID, this.finalBlockID);
+ }
+
+ if (null!=this.locator) {
+ this.locator.to_ccnb(encoder);
+ }
+
+ encoder.writeEndElement();
+};
+
+SignedInfo.prototype.valueToType = function(){
+ //for (Entry<byte [], ContentType> entry : ContentValueTypes.entrySet()) {
+ //if (Arrays.equals(value, entry.getKey()))
+ //return entry.getValue();
+ //}
+ return null;
+
+};
+
+SignedInfo.prototype.getElementLabel = function() {
+ return CCNProtocolDTags.SignedInfo;
+};
+
+SignedInfo.prototype.validate = function() {
+ // We don't do partial matches any more, even though encoder/decoder
+ // is still pretty generous.
+ if (null ==this.publisher || null==this.timestamp ||null== this.locator)
+ return false;
+ return true;
+};
diff --git a/js/Exclude.js b/js/Exclude.js
deleted file mode 100644
index 50f8ea7..0000000
--- a/js/Exclude.js
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * @author: ucla-cs
- * This class represents Exclude objects
- */
-
-var Exclude = function Exclude(_Values){
-
- this.OPTIMUM_FILTER_SIZE = 100;
-
-
- this.Values = _Values; //array of elements
-
-}
-
-Exclude.prototype.decode = function(/*XMLDecoder*/ decoder) {
-
-
-
- decoder.readStartElement(this.getElementLabel());
-
- //TODO APPLY FILTERS/EXCLUDE
-
- //TODO
- /*var component;
- var any = false;
- while ((component = decoder.peekStartElement(CCNProtocolDTags.Component)) ||
- (any = decoder.peekStartElement(CCNProtocolDTags.Any)) ||
- decoder.peekStartElement(CCNProtocolDTags.Bloom)) {
- var ee = component?new ExcludeComponent(): any ? new ExcludeAny() : new BloomFilter();
- ee.decode(decoder);
- _values.add(ee);
- }*/
-
- decoder.readEndElement();
-
-};
-
-Exclude.prototype.encode=function(/*XMLEncoder*/ encoder) {
- if (!validate()) {
- throw new ContentEncodingException("Cannot encode " + this.getClass().getName() + ": field values missing.");
- }
-
- if (empty())
- return;
-
- encoder.writeStartElement(getElementLabel());
-
- encoder.writeEndElement();
-
- };
-
-Exclude.prototype.getElementLabel = function() { return CCNProtocolDTags.Exclude; };
-
diff --git a/js/ExcludeAny.js b/js/ExcludeAny.js
deleted file mode 100644
index 25a1a23..0000000
--- a/js/ExcludeAny.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * @author: ucla-cs
- * This class represents ExcludeAny objects
- */
-
-var ExcludeAny = function ExcludeAny() {
-
-};
-
-ExcludeAny.prototype.decode = function(decoder) {
- decoder.readStartElement(this.getElementLabel());
- decoder.readEndElement();
-};
-
-
-ExcludeAny.prototype.encode = function( encoder) {
- encoder.writeStartElement(this.getElementLabel());
- encoder.writeEndElement();
-};
-
-ExcludeAny.prototype.getElementLabel=function() { return CCNProtocolDTags.Any; };
diff --git a/js/ExcludeComponent.js b/js/ExcludeComponent.js
deleted file mode 100644
index ed2bbeb..0000000
--- a/js/ExcludeComponent.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * @author: ucla-cs
- * This class represents Exclude Component OBjects
- */
-
-var ExcludeComponent = function ExcludeComponent(_Body) {
-
- //TODO Check BODY is an Array of componenets.
-
- this.Body = _Body
-};
-
-ExcludeComponent.prototype.decode = function( decoder) {
- body = decoder.readBinaryElement(this.getElementLabel());
-};
-
-ExcludeComponent.prototype.encode = function(encoder) {
- encoder.writeElement(this.getElementLabel(), body);
-};
-
-ExcludeComponent.prototype.getElementLabel = function() { return CCNProtocolDTags.Component; };
-
diff --git a/js/FaceInstance.js b/js/FaceInstance.js
index 9f32ade..f5fdd08 100644
--- a/js/FaceInstance.js
+++ b/js/FaceInstance.js
@@ -1,40 +1,42 @@
/*
* @author: ucla-cs
+ * See COPYING for copyright and distribution information.
* This class represents Face Instances
*/
+var NetworkProtocol = { TCP:6, UDP:17};
var FaceInstance = function FaceInstance(
- _Action,
- _PublisherPublicKeyDigest,
- _FaceID,
- _IPProto,
- _Host,
- _Port,
- _MulticastInterface,
- _MulticastTTL,
- _FreshnessSeconds){
+ _action,
+ _publisherPublicKeyDigest,
+ _faceID,
+ _ipProto,
+ _host,
+ _port,
+ _multicastInterface,
+ _multicastTTL,
+ _freshnessSeconds){
- this.Action = _Action;
- this.PublisherPublicKeyDigest = _PublisherPublicKeyDigest;
- this.FaceID = _FaceID;
- this.IPProto = _IPProto;
- this.Host = _Host;
- this.Port = _Port;
- this.MulticastInterface =_MulticastInterface;
- this.MulticastTTL =_MulticastTTL;
- this.FreshnessSeconds = _FreshnessSeconds;
+ this.action = _action;
+ this.publisherPublicKeyDigest = _publisherPublicKeyDigest;
+ this.faceID = _faceID;
+ this.ipProto = _ipProto;
+ this.host = _host;
+ this.Port = _port;
+ this.multicastInterface =_multicastInterface;
+ this.multicastTTL =_multicastTTL;
+ this.freshnessSeconds = _freshnessSeconds;
- //Action ::= ("newface" | "destroyface" | "queryface")
- //PublisherPublicKeyDigest ::= SHA-256 digest
- //FaceID ::= nonNegativeInteger
- //IPProto ::= nonNegativeInteger [IANA protocol number, 6=TCP, 17=UDP]
+ //action ::= ("newface" | "destroyface" | "queryface")
+ //publisherPublicKeyDigest ::= SHA-256 digest
+ //faceID ::= nonNegativeInteger
+ //ipProto ::= nonNegativeInteger [IANA protocol number, 6=TCP, 17=UDP]
//Host ::= textual representation of numeric IPv4 or IPv6 address
//Port ::= nonNegativeInteger [1..65535]
//MulticastInterface ::= textual representation of numeric IPv4 or IPv6 address
//MulticastTTL ::= nonNegativeInteger [1..255]
- //FreshnessSeconds ::= nonNegativeInteger
+ //freshnessSeconds ::= nonNegativeInteger
};
@@ -42,25 +44,25 @@
* Used by NetworkObject to decode the object from a network stream.
* @see org.ccnx.ccn.impl.encoding.XMLEncodable
*/
-FaceInstance.prototype.decode = function(//XMLDecoder
+FaceInstance.prototype.from_ccnb = function(//XMLDecoder
decoder) {
decoder.readStartElement(this.getElementLabel());
if (decoder.peekStartElement(CCNProtocolDTags.Action)) {
- this.Action = decoder.readUTF8Element(CCNProtocolDTags.Action);
+ this.action = decoder.readUTF8Element(CCNProtocolDTags.Action);
}
if (decoder.peekStartElement(CCNProtocolDTags.PublisherPublicKeyDigest)) {
- this.PublisherPublicKeyDigest = new PublisherPublicKeyDigest();
- this.PublisherPublicKeyDigest.decode(decoder);
+ this.publisherPublicKeyDigest = new PublisherPublicKeyDigest();
+ this.publisherPublicKeyDigest.from_ccnb(decoder);
}
if (decoder.peekStartElement(CCNProtocolDTags.FaceID)) {
- this.FaceID = decoder.readIntegerElement(CCNProtocolDTags.FaceID);
+ this.faceID = decoder.readIntegerElement(CCNProtocolDTags.FaceID);
}
if (decoder.peekStartElement(CCNProtocolDTags.IPProto)) {
@@ -68,19 +70,19 @@
//int
var pI = decoder.readIntegerElement(CCNProtocolDTags.IPProto);
- this.IPProto = null;
+ this.ipProto = null;
- if (NetworkProtocol.TCP.value().intValue() == pI) {
+ if (NetworkProtocol.TCP == pI) {
- this.IPProto = NetworkProtocol.TCP;
+ this.ipProto = NetworkProtocol.TCP;
- } else if (NetworkProtocol.UDP.value().intValue() == pI) {
+ } else if (NetworkProtocol.UDP == pI) {
- this.IPProto = NetworkProtocol.UDP;
+ this.ipProto = NetworkProtocol.UDP;
} else {
- throw new Exception("FaceInstance.decoder. Invalid " +
+ throw new Error("FaceInstance.decoder. Invalid " +
CCNProtocolDTags.tagToString(CCNProtocolDTags.IPProto) + " field: " + pI);
}
@@ -88,7 +90,7 @@
if (decoder.peekStartElement(CCNProtocolDTags.Host)) {
- this.Host = decoder.readUTF8Element(CCNProtocolDTags.Host);
+ this.host = decoder.readUTF8Element(CCNProtocolDTags.Host);
}
@@ -97,17 +99,16 @@
}
if (decoder.peekStartElement(CCNProtocolDTags.MulticastInterface)) {
- this.MulticastInterface = decoder.readUTF8Element(CCNProtocolDTags.MulticastInterface);
+ this.multicastInterface = decoder.readUTF8Element(CCNProtocolDTags.MulticastInterface);
}
if (decoder.peekStartElement(CCNProtocolDTags.MulticastTTL)) {
- this.MulticastTTL = decoder.readIntegerElement(CCNProtocolDTags.MulticastTTL);
+ this.multicastTTL = decoder.readIntegerElement(CCNProtocolDTags.MulticastTTL);
}
if (decoder.peekStartElement(CCNProtocolDTags.FreshnessSeconds)) {
- this.FreshnessSeconds = decoder.readIntegerElement(CCNProtocolDTags.FreshnessSeconds);
+ this.freshnessSeconds = decoder.readIntegerElement(CCNProtocolDTags.FreshnessSeconds);
}
-
decoder.readEndElement();
}
@@ -115,40 +116,42 @@
* Used by NetworkObject to encode the object to a network stream.
* @see org.ccnx.ccn.impl.encoding.XMLEncodable
*/
-FaceInstance.prototype.encode = function(//XMLEncoder
+FaceInstance.prototype.to_ccnb = function(//XMLEncoder
encoder){
//if (!this.validate()) {
- //throw new Exception("Cannot encode : field values missing.");
- //throw new Exception("")
+ //throw new Error("Cannot encode : field values missing.");
+ //throw new Error("")
//}
encoder.writeStartElement(this.getElementLabel());
- if (null != this.Action && this.Action.length != 0)
- encoder.writeElement(CCNProtocolDTags.Action, this.Action);
- if (null != this.PublisherPublicKeyDigest) {
- this.PublisherPublicKeyDigest.encode(encoder);
+
+ if (null != this.action && this.action.length != 0)
+ encoder.writeElement(CCNProtocolDTags.Action, this.action);
+
+ if (null != this.publisherPublicKeyDigest) {
+ this.publisherPublicKeyDigest.to_ccnb(encoder);
}
- if (null != this.FaceID) {
- encoder.writeElement(CCNProtocolDTags.FaceID, this.FaceID);
+ if (null != this.faceID) {
+ encoder.writeElement(CCNProtocolDTags.FaceID, this.faceID);
}
- if (null != this.IPProto) {
+ if (null != this.ipProto) {
//encoder.writeElement(CCNProtocolDTags.IPProto, this.IpProto.value());
- encoder.writeElement(CCNProtocolDTags.IPProto, this.IPProto);
+ encoder.writeElement(CCNProtocolDTags.IPProto, this.ipProto);
}
- if (null != this.Host && this.Host.length != 0) {
- encoder.writeElement(CCNProtocolDTags.Host, this.Host);
+ if (null != this.host && this.host.length != 0) {
+ encoder.writeElement(CCNProtocolDTags.Host, this.host);
}
if (null != this.Port) {
encoder.writeElement(CCNProtocolDTags.Port, this.Port);
}
- if (null != this.MulticastInterface && this.MulticastInterface.length != 0) {
- encoder.writeElement(CCNProtocolDTags.MulticastInterface, this.MulticastInterface);
+ if (null != this.multicastInterface && this.multicastInterface.length != 0) {
+ encoder.writeElement(CCNProtocolDTags.MulticastInterface, this.multicastInterface);
}
- if (null != this.MulticastTTL) {
- encoder.writeElement(CCNProtocolDTags.MulticastTTL, this.MulticastTTL);
+ if (null != this.multicastTTL) {
+ encoder.writeElement(CCNProtocolDTags.MulticastTTL, this.multicastTTL);
}
- if (null != this.FreshnessSeconds) {
- encoder.writeElement(CCNProtocolDTags.FreshnessSeconds, this.FreshnessSeconds);
+ if (null != this.freshnessSeconds) {
+ encoder.writeElement(CCNProtocolDTags.FreshnessSeconds, this.freshnessSeconds);
}
encoder.writeEndElement();
}
diff --git a/js/ForwardingEntry.js b/js/ForwardingEntry.js
index 60fe750..467a0ed 100644
--- a/js/ForwardingEntry.js
+++ b/js/ForwardingEntry.js
@@ -1,12 +1,13 @@
/*
* @author: ucla-cs
+ * See COPYING for copyright and distribution information.
* This class represents Forwarding Entries
*/
var ForwardingEntry = function ForwardingEntry(
//ActionType
_action,
- //ContentName
+ //Name
_prefixName,
//PublisherPublicKeyDigest
_ccndId,
@@ -20,45 +21,45 @@
//String
- this.Action = _action;
- //ContentName\
- this.PrefixName = _prefixName;
+ this.action = _action;
+ //Name\
+ this.prefixName = _prefixName;
//PublisherPublicKeyDigest
- this.CCNID = _ccndId;
+ this.ccndID = _ccndId;
//Integer
- this.FaceID = _faceID;
+ this.faceID = _faceID;
//Integer
- this.Flags = _flags;
+ this.flags = _flags;
//Integer
- this.Lifetime = _lifetime; // in seconds
+ this.lifetime = _lifetime; // in seconds
};
-ForwardingEntry.prototype.decode =function(
+ForwardingEntry.prototype.from_ccnb =function(
//XMLDecoder
decoder)
//throws ContentDecodingException
{
decoder.readStartElement(this.getElementLabel());
if (decoder.peekStartElement(CCNProtocolDTags.Action)) {
- this.Action = decoder.readUTF8Element(CCNProtocolDTags.Action);
+ this.action = decoder.readUTF8Element(CCNProtocolDTags.Action);
}
if (decoder.peekStartElement(CCNProtocolDTags.Name)) {
- this.PrefixName = new ContentName();
- this.PrefixName.decode(decoder) ;
+ this.prefixName = new Name();
+ this.prefixName.from_ccnb(decoder) ;
}
if (decoder.peekStartElement(CCNProtocolDTags.PublisherPublicKeyDigest)) {
this.CcndId = new PublisherPublicKeyDigest();
- this.CcndId.decode(decoder);
+ this.CcndId.from_ccnb(decoder);
}
if (decoder.peekStartElement(CCNProtocolDTags.FaceID)) {
- this.FaceID = decoder.readIntegerElement(CCNProtocolDTags.FaceID);
+ this.faceID = decoder.readIntegerElement(CCNProtocolDTags.FaceID);
}
if (decoder.peekStartElement(CCNProtocolDTags.ForwardingFlags)) {
- this.Flags = decoder.readIntegerElement(CCNProtocolDTags.ForwardingFlags);
+ this.flags = decoder.readIntegerElement(CCNProtocolDTags.ForwardingFlags);
}
if (decoder.peekStartElement(CCNProtocolDTags.FreshnessSeconds)) {
- this.Lifetime = decoder.readIntegerElement(CCNProtocolDTags.FreshnessSeconds);
+ this.lifetime = decoder.readIntegerElement(CCNProtocolDTags.FreshnessSeconds);
}
decoder.readEndElement();
};
@@ -67,7 +68,7 @@
* Used by NetworkObject to encode the object to a network stream.
* @see org.ccnx.ccn.impl.encoding.XMLEncodable
*/
-ForwardingEntry.prototype.encode =function(
+ForwardingEntry.prototype.to_ccnb =function(
//XMLEncoder
encoder)
{
@@ -77,22 +78,22 @@
//throw new ContentEncodingException("Cannot encode " + this.getClass().getName() + ": field values missing.");
//}
encoder.writeStartElement(this.getElementLabel());
- if (null != this.Action && this.Action.length != 0)
- encoder.writeElement(CCNProtocolDTags.Action, this.Action);
- if (null != this.PrefixName) {
- this.PrefixName.encode(encoder);
+ if (null != this.action && this.action.length != 0)
+ encoder.writeElement(CCNProtocolDTags.Action, this.action);
+ if (null != this.prefixName) {
+ this.prefixName.to_ccnb(encoder);
}
if (null != this.CcndId) {
- this.CcndId.encode(encoder);
+ this.CcndId.to_ccnb(encoder);
}
- if (null != this.FaceID) {
- encoder.writeElement(CCNProtocolDTags.FaceID, this.FaceID);
+ if (null != this.faceID) {
+ encoder.writeElement(CCNProtocolDTags.FaceID, this.faceID);
}
- if (null != this.Flags) {
- encoder.writeElement(CCNProtocolDTags.ForwardingFlags, this.Flags);
+ if (null != this.flags) {
+ encoder.writeElement(CCNProtocolDTags.ForwardingFlags, this.flags);
}
- if (null != this.Lifetime) {
- encoder.writeElement(CCNProtocolDTags.FreshnessSeconds, this.Lifetime);
+ if (null != this.lifetime) {
+ encoder.writeElement(CCNProtocolDTags.FreshnessSeconds, this.lifetime);
}
encoder.writeEndElement();
};
diff --git a/js/Helper.js b/js/Helper.js
new file mode 100644
index 0000000..52faac9
--- /dev/null
+++ b/js/Helper.js
@@ -0,0 +1,59 @@
+// Including js files to be used in the web pages
+// Add your js source code reference here, rather than in the HTML files
+
+document.write('<script type="text/javascript" src="../NDN.js"></script>');
+
+document.write('<script type="text/javascript" src="../WebSocketTransport.js"></script>');
+
+document.write('<script type="text/javascript" src="../util/CCNProtocolDTags.js"></script>');
+
+document.write('<script type="text/javascript" src="../util/CCNTime.js"></script>');
+
+document.write('<script type="text/javascript" src="../Name.js"></script>');
+
+document.write('<script type="text/javascript" src="../ContentObject.js"></script>');
+
+document.write('<script type="text/javascript" src="../encoding/DateFormat.js"></script>');
+
+document.write('<script type="text/javascript" src="../Interest.js"></script>');
+
+document.write('<script type="text/javascript" src="../Key.js"></script>');
+
+document.write('<script type="text/javascript" src="../PublisherID.js"></script>');
+
+document.write('<script type="text/javascript" src="../PublisherPublicKeyDigest.js"></script>');
+
+document.write('<script type="text/javascript" src="../FaceInstance.js"></script>');
+
+document.write('<script type="text/javascript" src="../ForwardingEntry.js"></script>');
+
+document.write('<script type="text/javascript" src="../Closure.js"></script>');
+
+document.write('<script type="text/javascript" src="../encoding/BinaryXMLEncoder.js"></script>');
+
+document.write('<script type="text/javascript" src="../encoding/BinaryXMLDecoder.js"></script>');
+
+document.write('<script type="text/javascript" src="../encoding/BinaryXMLStructureDecoder.js"></script>');
+
+document.write('<script type="text/javascript" src="../encoding/DataUtils.js"></script>');
+
+document.write('<script type="text/javascript" src="../encoding/EncodingUtils.js"></script>');
+
+document.write('<script type="text/javascript" src="../security/KeyManager.js"></script>');
+
+document.write('<script type="text/javascript" src="../securityLib/jsbn.js"></script>');
+document.write('<script type="text/javascript" src="../securityLib/jsbn2.js"></script>');
+document.write('<script type="text/javascript" src="../securityLib/rsa.js"></script>');
+document.write('<script type="text/javascript" src="../securityLib/rsa2.js"></script>');
+
+document.write('<script type="text/javascript" src="../securityLib/sha1.js"></script>');
+document.write('<script type="text/javascript" src="../securityLib/sha256.js"></script>');
+document.write('<script type="text/javascript" src="../securityLib/sha512.js"></script>');
+document.write('<script type="text/javascript" src="../securityLib/md5.js"></script>');
+document.write('<script type="text/javascript" src="../securityLib/ripemd160.js"></script>');
+document.write('<script type="text/javascript" src="../securityLib/base64.js"></script>');
+
+document.write('<script type="text/javascript" src="../securityLib/rsapem-1.1.js"></script>');
+document.write('<script type="text/javascript" src="../securityLib/rsasign-1.2.js"></script>');
+document.write('<script type="text/javascript" src="../securityLib/asn1hex-1.1.js"></script>');
+document.write('<script type="text/javascript" src="../securityLib/x509-1.1.js"></script>');
diff --git a/js/Interest.js b/js/Interest.js
index 3c46887..baa7f33 100644
--- a/js/Interest.js
+++ b/js/Interest.js
@@ -1,23 +1,23 @@
/*
* @author: ucla-cs
+ * See COPYING for copyright and distribution information.
* This class represents Interest Objects
*/
-var Interest = function Interest(_Name,_FaceInstance,_MinSuffixComponents,_MaxSuffixComponents,_PublisherPublicKeyDigest, _Exclude, _ChildSelector,_AnswerOriginKind,_Scope,_InterestLifetime,_Nonce){
+var Interest = function Interest(_name,_faceInstance,_minSuffixComponents,_maxSuffixComponents,_publisherPublicKeyDigest, _exclude, _childSelector,_answerOriginKind,_scope,_interestLifetime,_nonce){
+
+ this.name = _name;
+ this.faceInstance = _faceInstance;
+ this.maxSuffixComponents = _maxSuffixComponents;
+ this.minSuffixComponents = _minSuffixComponents;
- //Setting fields
- this.Name = _Name;
- this.FaceInstance = _FaceInstance;
- this.MaxSuffixComponents = _MaxSuffixComponents;
- this.MinSuffixComponents = _MinSuffixComponents;
-
- this.PublisherKeyDigest = _PublisherPublicKeyDigest;
- this.Exclude = _Exclude;
- this.ChildSelector = _ChildSelector;
- this.AnswerOriginKind = _AnswerOriginKind;
- this.Scope = _Scope;
- this.InterestLifetime = null; // For now we don't have the ability to set an interest lifetime
- this.Nonce = _Nonce;
+ this.publisherPublicKeyDigest = _publisherPublicKeyDigest;
+ this.exclude = _exclude;
+ this.childSelector = _childSelector;
+ this.answerOriginKind = _answerOriginKind;
+ this.scope = _scope;
+ this.interestLifetime = null; // For now we don't have the ability to set an interest lifetime
+ this.nonce = _nonce;
this.RECURSIVE_POSTFIX = "*";
@@ -27,101 +27,203 @@
this.ANSWER_CONTENT_STORE = 1;
this.ANSWER_GENERATED = 2;
this.ANSWER_STALE = 4; // Stale answer OK
- this.MARK_STALE = 16; // Must have Scope 0. Michael calls this a "hack"
+ this.MARK_STALE = 16; // Must have scope 0. Michael calls this a "hack"
this.DEFAULT_ANSWER_ORIGIN_KIND = this.ANSWER_CONTENT_STORE | this.ANSWER_GENERATED;
};
-Interest.prototype.decode = function(/*XMLDecoder*/ decoder) {
+Interest.prototype.from_ccnb = function(/*XMLDecoder*/ decoder) {
decoder.readStartElement(CCNProtocolDTags.Interest);
- this.Name = new ContentName();
- this.Name.decode(decoder);
+ this.name = new Name();
+ this.name.from_ccnb(decoder);
if (decoder.peekStartElement(CCNProtocolDTags.MinSuffixComponents)) {
- this.MinSuffixComponents = decoder.readIntegerElement(CCNProtocolDTags.MinSuffixComponents);
+ this.minSuffixComponents = decoder.readIntegerElement(CCNProtocolDTags.MinSuffixComponents);
}
if (decoder.peekStartElement(CCNProtocolDTags.MaxSuffixComponents)) {
- this.MaxSuffixComponents = decoder.readIntegerElement(CCNProtocolDTags.MaxSuffixComponents);
+ this.maxSuffixComponents = decoder.readIntegerElement(CCNProtocolDTags.MaxSuffixComponents);
}
- //TODO decode PublisherID
- /*if (PublisherID.peek(decoder)) {
- this.Publisher = new PublisherID();
- this.Publisher.decode(decoder);
- }*/
+ if (decoder.peekStartElement(CCNProtocolDTags.PublisherPublicKeyDigest)) {
+ this.publisherPublicKeyDigest = new publisherPublicKeyDigest();
+ this.publisherPublicKeyDigest.from_ccnb(decoder);
+ }
if (decoder.peekStartElement(CCNProtocolDTags.Exclude)) {
- this.Exclude = new Exclude();
- this.Exclude.decode(decoder);
+ this.exclude = new Exclude();
+ this.exclude.from_ccnb(decoder);
}
if (decoder.peekStartElement(CCNProtocolDTags.ChildSelector)) {
- this.ChildSelector = decoder.readIntegerElement(CCNProtocolDTags.ChildSelector);
+ this.childSelector = decoder.readIntegerElement(CCNProtocolDTags.ChildSelector);
}
if (decoder.peekStartElement(CCNProtocolDTags.AnswerOriginKind)) {
// call setter to handle defaulting
- this.AnswerOriginKind = decoder.readIntegerElement(CCNProtocolDTags.AnswerOriginKind);
+ this.answerOriginKind = decoder.readIntegerElement(CCNProtocolDTags.AnswerOriginKind);
}
if (decoder.peekStartElement(CCNProtocolDTags.Scope)) {
- this.Scope = decoder.readIntegerElement(CCNProtocolDTags.Scope);
+ this.scope = decoder.readIntegerElement(CCNProtocolDTags.Scope);
}
if (decoder.peekStartElement(CCNProtocolDTags.InterestLifetime)) {
- this.InterestLifetime = decoder.readBinaryElement(CCNProtocolDTags.InterestLifetime);
+ this.interestLifetime = decoder.readBinaryElement(CCNProtocolDTags.InterestLifetime);
}
if (decoder.peekStartElement(CCNProtocolDTags.Nonce)) {
- this.Nonce = decoder.readBinaryElement(CCNProtocolDTags.Nonce);
+ this.nonce = decoder.readBinaryElement(CCNProtocolDTags.Nonce);
}
decoder.readEndElement();
};
-Interest.prototype.encode = function(/*XMLEncoder*/ encoder){
- /*if (!validate()) {
- throw new ContentEncodingException("Cannot encode " + this.getClass().getName() + ": field values missing.");
- }*/
+Interest.prototype.to_ccnb = function(/*XMLEncoder*/ encoder){
+ //Could check if name is present
encoder.writeStartElement(CCNProtocolDTags.Interest);
- this.Name.encode(encoder);
+ this.name.to_ccnb(encoder);
- if (null != this.MinSuffixComponents)
- encoder.writeElement(CCNProtocolDTags.MinSuffixComponents, this.MinSuffixComponents);
+ if (null != this.minSuffixComponents)
+ encoder.writeElement(CCNProtocolDTags.MinSuffixComponents, this.minSuffixComponents);
- if (null != this.MaxSuffixComponents)
- encoder.writeElement(CCNProtocolDTags.MaxSuffixComponents, this.MaxSuffixComponents);
+ if (null != this.maxSuffixComponents)
+ encoder.writeElement(CCNProtocolDTags.MaxSuffixComponents, this.maxSuffixComponents);
- //TODO Encode PublisherID
+ if (null != this.publisherPublicKeyDigest)
+ this.publisherPublicKeyDigest.to_ccnb(encoder);
- /*if (null != this.PublisherID)
- publisherID().encode(encoder);*/
+ if (null != this.exclude)
+ this.exclude.to_ccnb(encoder);
- //TODO Encode Exclude
-
- //if (null != this.Exclude)
- //exclude().encode(encoder);
-
- if (null != this.ChildSelector)
- encoder.writeElement(CCNProtocolDTags.ChildSelector, this.ChildSelector);
+ if (null != this.childSelector)
+ encoder.writeElement(CCNProtocolDTags.ChildSelector, this.childSelector);
//TODO Encode OriginKind
- if (this.DEFAULT_ANSWER_ORIGIN_KIND != this.AnswerOriginKind && this.AnswerOriginKind!=null)
- //encoder.writeElement(CCNProtocolDTags.AnswerOriginKind, this.AnswerOriginKind);
+ if (this.DEFAULT_ANSWER_ORIGIN_KIND != this.answerOriginKind && this.answerOriginKind!=null)
+ encoder.writeElement(CCNProtocolDTags.AnswerOriginKind, this.answerOriginKind);
- if (null != this.Scope)
- encoder.writeElement(CCNProtocolDTags.Scope, this.Scope);
+ if (null != this.scope)
+ encoder.writeElement(CCNProtocolDTags.Scope, this.scope);
- if (null != this.Nonce)
- encoder.writeElement(CCNProtocolDTags.Nonce, this.Nonce);
+ if (null != this.nonce)
+ encoder.writeElement(CCNProtocolDTags.Nonce, this.nonce);
encoder.writeEndElement();
};
+Interest.prototype.matches_name = function(/*Name*/ name){
+ var i_name = this.name.components;
+ var o_name = name.components;
+
+ // The intrest name is longer than the name we are checking it against.
+ if (i_name.length > o_name.length)
+ return false;
+
+ // Check if at least one of given components doesn't match.
+ for (var i = 0; i < i_name.length; ++i) {
+ if (!DataUtils.arraysEqual(i_name[i], o_name[i]))
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Exclude
+ */
+var Exclude = function Exclude(_values){
+
+ this.OPTIMUM_FILTER_SIZE = 100;
+
+
+ this.values = _values; //array of elements
+
+}
+
+Exclude.prototype.from_ccnb = function(/*XMLDecoder*/ decoder) {
+
+
+
+ decoder.readStartElement(this.getElementLabel());
+
+ //TODO APPLY FILTERS/EXCLUDE
+
+ //TODO
+ /*var component;
+ var any = false;
+ while ((component = decoder.peekStartElement(CCNProtocolDTags.Component)) ||
+ (any = decoder.peekStartElement(CCNProtocolDTags.Any)) ||
+ decoder.peekStartElement(CCNProtocolDTags.Bloom)) {
+ var ee = component?new ExcludeComponent(): any ? new ExcludeAny() : new BloomFilter();
+ ee.decode(decoder);
+ _values.add(ee);
+ }*/
+
+ decoder.readEndElement();
+
+};
+
+Exclude.prototype.to_ccnb=function(/*XMLEncoder*/ encoder) {
+ if (!validate()) {
+ throw new ContentEncodingException("Cannot encode " + this.getClass().getName() + ": field values missing.");
+ }
+
+ if (empty())
+ return;
+
+ encoder.writeStartElement(getElementLabel());
+
+ encoder.writeEndElement();
+
+ };
+
+Exclude.prototype.getElementLabel = function() { return CCNProtocolDTags.Exclude; };
+
+
+/**
+ * ExcludeAny
+ */
+var ExcludeAny = function ExcludeAny() {
+
+};
+
+ExcludeAny.prototype.from_ccnb = function(decoder) {
+ decoder.readStartElement(this.getElementLabel());
+ decoder.readEndElement();
+};
+
+
+ExcludeAny.prototype.to_ccnb = function( encoder) {
+ encoder.writeStartElement(this.getElementLabel());
+ encoder.writeEndElement();
+};
+
+ExcludeAny.prototype.getElementLabel=function() { return CCNProtocolDTags.Any; };
+
+
+/**
+ * ExcludeComponent
+ */
+var ExcludeComponent = function ExcludeComponent(_body) {
+
+ //TODO Check BODY is an Array of componenets.
+
+ this.body = _body
+};
+
+ExcludeComponent.prototype.from_ccnb = function( decoder) {
+ this.body = decoder.readBinaryElement(this.getElementLabel());
+};
+
+ExcludeComponent.prototype.to_ccnb = function(encoder) {
+ encoder.writeElement(this.getElementLabel(), this.body);
+};
+
+ExcludeComponent.prototype.getElementLabel = function() { return CCNProtocolDTags.Component; };
diff --git a/js/JavaSocketBridge.jar b/js/JavaSocketBridge.jar
index 0f2deae..5be7655 100644
--- a/js/JavaSocketBridge.jar
+++ b/js/JavaSocketBridge.jar
Binary files differ
diff --git a/js/Key.js b/js/Key.js
new file mode 100644
index 0000000..f5b56e0
--- /dev/null
+++ b/js/Key.js
@@ -0,0 +1,195 @@
+/*
+ * @author: ucla-cs
+ * See COPYING for copyright and distribution information.
+ * This class represents Key Objects
+ */
+
+var Key = function Key(){
+ /* TODO: Port from PyCCN:
+ generateRSA()
+ privateToDER()
+ publicToDER()
+ privateToPEM()
+ publicToPEM()
+ fromDER()
+ fromPEM()
+ */
+}
+
+/**
+ * KeyLocator
+ */
+var KeyLocatorType = {
+ NAME:1,
+ KEY:2,
+ CERTIFICATE:3
+};
+
+var KeyLocator = function KeyLocator(_input,_type){
+
+ this.type=_type;
+
+ if (_type==KeyLocatorType.NAME){
+ this.keyName = _input;
+ }
+ else if(_type==KeyLocatorType.KEY){
+ if(LOG>4)console.log('SET KEY');
+ this.publicKey = _input;
+ }
+ else if(_type==KeyLocatorType.CERTIFICATE){
+ this.certificate = _input;
+ }
+
+};
+
+KeyLocator.prototype.from_ccnb = function(decoder) {
+
+ decoder.readStartElement(this.getElementLabel());
+
+ if (decoder.peekStartElement(CCNProtocolDTags.Key)) {
+ try {
+ encodedKey = decoder.readBinaryElement(CCNProtocolDTags.Key);
+ // This is a DER-encoded SubjectPublicKeyInfo.
+
+ //TODO FIX THIS, This should create a Key Object instead of keeping bytes
+
+ this.publicKey = encodedKey;//CryptoUtil.getPublicKey(encodedKey);
+ this.type = 2;
+
+
+ if(LOG>4) console.log('PUBLIC KEY FOUND: '+ this.publicKey);
+ //this.publicKey = encodedKey;
+
+
+ } catch (e) {
+ throw new Error("Cannot parse key: ", e);
+ }
+
+ if (null == this.publicKey) {
+ throw new Error("Cannot parse key: ");
+ }
+
+ } else if ( decoder.peekStartElement(CCNProtocolDTags.Certificate)) {
+ try {
+ encodedCert = decoder.readBinaryElement(CCNProtocolDTags.Certificate);
+
+ /*
+ * Certificates not yet working
+ */
+
+ //CertificateFactory factory = CertificateFactory.getInstance("X.509");
+ //this.certificate = (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(encodedCert));
+
+
+ this.certificate = encodedCert;
+ this.type = 3;
+
+ if(LOG>4) console.log('CERTIFICATE FOUND: '+ this.certificate);
+
+ } catch ( e) {
+ throw new Error("Cannot decode certificate: " + e);
+ }
+ if (null == this.certificate) {
+ throw new Error("Cannot parse certificate! ");
+ }
+ } else {
+ this.type = 1;
+
+
+ this.keyName = new KeyName();
+ this.keyName.from_ccnb(decoder);
+ }
+ decoder.readEndElement();
+ }
+
+
+ KeyLocator.prototype.to_ccnb = function( encoder) {
+
+ if(LOG>4) console.log('type is is ' + this.type);
+ //TODO Check if Name is missing
+ if (!this.validate()) {
+ throw new ContentEncodingException("Cannot encode " + this.getClass().getName() + ": field values missing.");
+ }
+
+
+ //TODO FIX THIS TOO
+ encoder.writeStartElement(this.getElementLabel());
+
+ if (this.type == KeyLocatorType.KEY) {
+ if(LOG>5)console.log('About to encode a public key' +this.publicKey);
+ encoder.writeElement(CCNProtocolDTags.Key, this.publicKey);
+
+ } else if (this.type == KeyLocatorType.CERTIFICATE) {
+
+ try {
+ encoder.writeElement(CCNProtocolDTags.Certificate, this.certificate);
+ } catch ( e) {
+ throw new Error("CertificateEncodingException attempting to write key locator: " + e);
+ }
+
+ } else if (this.type == KeyLocatorType.NAME) {
+
+ this.keyName.to_ccnb(encoder);
+ }
+ encoder.writeEndElement();
+
+};
+
+KeyLocator.prototype.getElementLabel = function() {
+ return CCNProtocolDTags.KeyLocator;
+};
+
+KeyLocator.prototype.validate = function() {
+ return ( (null != this.keyName) || (null != this.publicKey) || (null != this.certificate) );
+};
+
+/**
+ * KeyName is only used by KeyLocator.
+ */
+var KeyName = function KeyName() {
+
+
+ this.contentName = this.contentName;//contentName
+ this.publisherID =this.publisherID;//publisherID
+
+};
+
+KeyName.prototype.from_ccnb=function( decoder){
+
+
+ decoder.readStartElement(this.getElementLabel());
+
+ this.contentName = new Name();
+ this.contentName.from_ccnb(decoder);
+
+ if(LOG>4) console.log('KEY NAME FOUND: ');
+
+ if ( PublisherID.peek(decoder) ) {
+ this.publisherID = new PublisherID();
+ this.publisherID.from_ccnb(decoder);
+ }
+
+ decoder.readEndElement();
+};
+
+KeyName.prototype.to_ccnb = function( encoder) {
+ if (!this.validate()) {
+ throw new Error("Cannot encode : field values missing.");
+ }
+
+ encoder.writeStartElement(this.getElementLabel());
+
+ this.contentName.to_ccnb(encoder);
+ if (null != this.publisherID)
+ this.publisherID.to_ccnb(encoder);
+
+ encoder.writeEndElement();
+};
+
+KeyName.prototype.getElementLabel = function() { return CCNProtocolDTags.KeyName; };
+
+KeyName.prototype.validate = function() {
+ // DKS -- do we do recursive validation?
+ // null signedInfo ok
+ return (null != this.contentName);
+};
diff --git a/js/KeyLocator.js b/js/KeyLocator.js
deleted file mode 100644
index d61ed12..0000000
--- a/js/KeyLocator.js
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * @author: ucla-cs
- * This class represents KeyLocator Objects
- */
-
-var KeyLocatorType = {
- NAME:1,
- KEY:2,
- CERTIFICATE:3
-};
-
-var KeyLocator = function KeyLocator(_Input,_Type){
-
-
- this.Type=_Type;
-
- if (_Type==KeyLocatorType.NAME){
- this.KeyName = _Input;
- }
- else if(_Type==KeyLocatorType.KEY){
- console.log('SET KEY');
- this.PublicKey = _Input;
- }
- else if(_Type==KeyLocatorType.CERTIFICATE){
- this.Certificate = _Input;
- }
-
-};
-
-KeyLocator.prototype.decode = function(decoder) {
-
- decoder.readStartElement(this.getElementLabel());
-
- if (decoder.peekStartElement(CCNProtocolDTags.Key)) {
- try {
- encodedKey = decoder.readBinaryElement(CCNProtocolDTags.Key);
- // This is a DER-encoded SubjectPublicKeyInfo.
-
- //TODO FIX THIS, This should create a Key Object instead of keeping bytes
-
- this.PublicKey = encodedKey;//CryptoUtil.getPublicKey(encodedKey);
-
-
-
- if(LOG>4) console.log('PUBLIC KEY FOUND: '+ this.PublicKey);
- //this.PublicKey = encodedKey;
-
-
- } catch (e) {
- throw new Exception("Cannot parse key: ", e);
- }
-
- if (null == this.PublicKey) {
- throw new Exception("Cannot parse key: ");
- }
-
- } else if ( decoder.peekStartElement(CCNProtocolDTags.Certificate)) {
- try {
- encodedCert = decoder.readBinaryElement(CCNProtocolDTags.Certificate);
-
- /*
- * Certificates not yet working
- */
-
- //CertificateFactory factory = CertificateFactory.getInstance("X.509");
- //this.Certificate = (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(encodedCert));
-
-
- this.Certificate = encodedCert;
-
- if(LOG>4) console.log('CERTIFICATE FOUND: '+ this.Certificate);
-
- } catch ( e) {
- throw new Exception("Cannot decode certificate: " + e);
- }
- if (null == this.Certificate) {
- throw new Exception("Cannot parse certificate! ");
- }
- } else {
-
-
- this.KeyName = new KeyName();
- this.KeyName.decode(decoder);
- }
- decoder.readEndElement();
- }
-
-
- KeyLocator.prototype.encode = function( encoder) {
-
- if(LOG>2) console.log('type is is ' + this.Type);
- //TODO Check if Name is missing
- if (!this.validate()) {
- throw new ContentEncodingException("Cannot encode " + this.getClass().getName() + ": field values missing.");
- }
-
-
- //TODO FIX THIS TOO
- encoder.writeStartElement(this.getElementLabel());
-
- if (this.Type == KeyLocatorType.KEY) {
- if(LOG>5)console.log('About to encode a public key' +this.PublicKey);
- encoder.writeElement(CCNProtocolDTags.Key, this.PublicKey);
-
- } else if (this.Type == KeyLocatorType.CERTIFICATE) {
-
- try {
- encoder.writeElement(CCNProtocolDTags.Certificate, this.Certificate.getEncoded());
- } catch ( e) {
- throw new Exception("CertificateEncodingException attempting to write key locator: " + e);
- }
-
- } else if (this.Type == KeyLocatorType.NAME) {
-
- this.KeyName.encode(encoder);
- }
- encoder.writeEndElement();
-
-};
-
-KeyLocator.prototype.getElementLabel = function() {
- return CCNProtocolDTags.KeyLocator;
-};
-
-KeyLocator.prototype.validate = function() {
- return ( (null != this.KeyName) || (null != this.PublicKey) || (null != this.Certificate) );
-};
-
\ No newline at end of file
diff --git a/js/KeyName.js b/js/KeyName.js
deleted file mode 100644
index 2c79bfc..0000000
--- a/js/KeyName.js
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * @author: ucla-cs
- * This class represents KeyName Objects
- */
-
-var KeyName = function KeyName() {
-
-
- this.ContentName = this.ContentName;//ContentName
- this.PublisherID =this.PublisherID;//PublisherID
-
-};
-
-
-KeyName.prototype.decode=function( decoder){
-
-
- decoder.readStartElement(this.getElementLabel());
-
- this.ContentName = new ContentName();
- this.ContentName.decode(decoder);
-
- if(LOG>4) console.log('KEY NAME FOUND: ');
-
- if ( peek(decoder) ) {
- this.PublisherID = new PublisherID();
- this.PublisherID.decode(decoder);
- }
-
- decoder.readEndElement();
-};
-
-KeyName.prototype.encode = function( encoder) {
- if (!this.validate()) {
- throw new Exception("Cannot encode : field values missing.");
- }
-
- encoder.writeStartElement(this.getElementLabel());
-
- this.ContentName.encode(encoder);
- if (null != this.PublisherID)
- this.PublisherID.encode(encoder);
-
- encoder.writeEndElement();
-};
-
-KeyName.prototype.getElementLabel = function() { return CCNProtocolDTags.KeyName; };
-
-KeyName.prototype.validate = function() {
- // DKS -- do we do recursive validation?
- // null signedInfo ok
- return (null != this.ContentName);
-};
diff --git a/js/NDN.js b/js/NDN.js
new file mode 100644
index 0000000..8dde5c3
--- /dev/null
+++ b/js/NDN.js
@@ -0,0 +1,206 @@
+/*
+ * @author: Meki Cherkaoui, Jeff Thompson, Wentao Shang
+ * See COPYING for copyright and distribution information.
+ * This class represents the top-level object for communicating with an NDN host.
+ */
+
+var LOG = 3;
+
+/**
+ * settings is an associative array with the following defaults:
+ * {
+ * host: 'localhost',
+ * port: 9696,
+ * getTransport: function() { return new WebSocketTransport(); }
+ * }
+ */
+var NDN = function NDN(settings) {
+ settings = (settings || {});
+ this.host = (settings.host || "localhost");
+ this.port = (settings.port || 9696);
+ var getTransport = (settings.getTransport || function() { return new WebSocketTransport(); });
+ this.transport = getTransport();
+};
+
+
+/* Java Socket Bridge and XPCOM transport */
+
+NDN.prototype.createRoute = function(host,port){
+ this.host=host;
+ this.port=port;
+}
+
+NDN.prototype.get = function(message){
+ if(this.host!=null && this.port!=null){
+ var output ='';
+ message = message.trim();
+ if(message==null || message =="" ){
+ console.log('INVALID INPUT TO GET');
+ return null;
+ }
+
+
+ //var array = Name.createNameArray(message);
+
+ int = new Interest(new Name(message));
+
+ int.InterestLifetime = 4200;
+
+ var hex = encodeToHexInterest(int);
+
+ //var result = get_java_socket_bridge().connectAndStart(ndnurl,ndnport,hex);
+
+ var result = get(this.host,this.port, hex);
+
+
+ if(LOG>0)console.log('BINARY RESPONSE IS ' +result);
+
+ if(result==null || result==undefined || result =="" ){
+ /*if(result[0] != '0'||result[1]!='4') {
+ if(LOG>2)console.log('INVALID ANSWER');
+ }*/
+ return null;
+ }
+
+ else{
+
+ co = decodeHexContentObject(result);
+
+ if(LOG>2) {
+ console.log('DECODED CONTENT OBJECT');
+ console.log(co);
+ }
+ return co;
+ }
+ }
+ else{
+
+ console.log('ERROR URL OR PORT NOT SET');
+
+ return null;
+
+ }
+
+
+}
+
+NDN.prototype.put = function(name,content){
+ if(this.host!=null && this.port!=null){
+
+ var co = this.get("/%C1.M.S.localhost/%C1.M.SRV/ccnd");
+
+ if(!co || !co.signedInfo || !co.signedInfo.publisher || !co.signedInfo.publisher.publisherPublicKeyDigest){
+ alert("Cannot contact router");
+
+ return null;
+ }
+
+ var ccnxnodename = co.signedInfo.publisher.publisherPublicKeyDigest;
+
+ name = name.trim();
+
+ var fe = new ForwardingEntry('selfreg',new Name(name),null, null, 3,2147483647);
+
+ var bytes = encodeForwardingEntry(fe);
+
+
+ var si = new SignedInfo();
+ si.setFields();
+
+ var co = new ContentObject(new Name(),si,bytes,new Signature());
+ co.sign();
+
+ var coBinary = encodeToBinaryContentObject(co);
+
+ //var ccnxnodename = unescape('%E0%A0%1E%099h%F9t%0C%E7%F46%1B%AB%F5%BB%05%A4%E5Z%AC%A5%E5%8Fs%ED%DE%B8%E0%13%AA%8F');
+
+ var interestName = new Name(['ccnx',ccnxnodename,'selfreg',coBinary]);
+
+ int = new Interest(interestName);
+ int.scope = 1;
+
+ var hex = encodeToHexInterest(int);
+
+ console.log('GOING TO PUT INTEREST OBJECT');
+
+ console.log(hex);
+
+ //var result = put(this.host,this.port, hex,name);
+
+
+ //if(LOG>3)console.log('received interest'); //from host'+ host +':'+port+' with name '+name);
+
+ //if(LOG>3)console.log('DATA ');
+
+ //if(LOG>3)console.log(result);
+
+ //interest = decodeHexInterest(result);
+
+ //console.log('SUCCESSFULLY PARSED INTEREST');
+
+ console.log('CREATING ANSWER');
+ var si = new SignedInfo();
+ si.setFields();
+
+ var answer = DataUtils.toNumbersFromString(content);
+
+ var co = new ContentObject(new Name(name),si,answer,new Signature());
+ co.sign();
+
+
+ var outputHex = encodeToHexContentObject(co);
+
+ //console.log('SENDING ANSWER');
+
+ //return get_java_socket_bridge().putAnswer(outputHex,name);
+
+ var result = put(this.host,this.port, hex,name,outputHex);
+
+
+ return result;
+ }
+ else{
+ console.log('ERROR URL OR PORT NOT SET');
+
+ return null;
+ }
+}
+
+/** Encode name as an Interest. If template is not null, use its attributes.
+ * Send the interest to host:port, read the entire response and call
+ * closure.upcall(Closure.UPCALL_CONTENT (or Closure.UPCALL_CONTENT_UNVERIFIED),
+ * new UpcallInfo(this, interest, 0, contentObject)).
+ */
+NDN.prototype.expressInterest = function(
+ // Name
+ name,
+ // Closure
+ closure,
+ // Interest
+ template) {
+ if (this.host == null || this.port == null) {
+ dump('ERROR host OR port NOT SET\n');
+ return;
+ }
+
+ var interest = new Interest(name);
+ if (template != null) {
+ interest.minSuffixComponents = template.minSuffixComponents;
+ interest.maxSuffixComponents = template.maxSuffixComponents;
+ interest.publisherPublicKeyDigest = template.publisherPublicKeyDigest;
+ interest.exclude = template.exclude;
+ interest.childSelector = template.childSelector;
+ interest.answerOriginKind = template.answerOriginKind;
+ interest.scope = template.scope;
+ interest.interestLifetime = template.interestLifetime;
+ }
+ else
+ interest.interestLifetime = 4200;
+
+ this.transport.expressInterest(this, interest, closure);
+};
+
+
+NDN.prototype.registerPrefix = function(name, closure, flag) {
+ return this.transport.registerPrefix(this, name, closure, flag);
+}
diff --git a/js/Name.js b/js/Name.js
new file mode 100644
index 0000000..1d28a81
--- /dev/null
+++ b/js/Name.js
@@ -0,0 +1,182 @@
+/*
+ * @author: ucla-cs
+ * See COPYING for copyright and distribution information.
+ * This class represents a Name as an array of components where each is a byte array.
+ */
+
+
+var Name = function Name(_components){
+
+ if( typeof _components == 'string') {
+
+ if(LOG>3)console.log('Content Name String '+_components);
+ this.components = Name.makeBlob(Name.createNameArray(_components));
+ }
+ else if(typeof _components === 'object' && _components instanceof Array ){
+
+ if(LOG>4)console.log('Content Name Array '+_components);
+ this.components = Name.makeBlob(_components);
+
+ }
+ else if(_components==null){
+ this.components =[];
+ }
+ else{
+
+ if(LOG>1)console.log("NO CONTENT NAME GIVEN");
+
+ }
+};
+
+Name.prototype.getName = function() {
+ return this.to_uri();
+};
+
+Name.makeBlob=function(name){
+
+ var blobArrays = new Array(name.length);
+
+ for(var i=0;i<name.length;i++){
+ if(typeof name[i] == 'string')
+ blobArrays[i]= DataUtils.toNumbersFromString( name[i] );
+ else if(typeof name[i] == 'object')
+ blobArrays[i]= name[i] ;
+ else
+ if(LOG>4)console.log('NAME COMPONENT INVALID');
+ }
+
+ return blobArrays;
+};
+
+Name.createNameArray = function(name) {
+ name = name.trim();
+ if (name.length <= 0)
+ return [];
+
+ var iColon = name.indexOf(':');
+ if (iColon >= 0) {
+ // Make sure the colon came before a '/'.
+ var iFirstSlash = name.indexOf('/');
+ if (iFirstSlash < 0 || iColon < iFirstSlash)
+ // Omit the leading protocol such as ccnx:
+ name = name.substr(iColon + 1, name.length - iColon - 1).trim();
+ }
+
+ if (name[0] == '/') {
+ if (name.length >= 2 && name[1] == '/') {
+ // Strip the authority following "//".
+ var iAfterAuthority = name.indexOf('/', 2);
+ if (iAfterAuthority < 0)
+ // Unusual case: there was only an authority.
+ return [];
+ else
+ name = name.substr(iAfterAuthority + 1, name.length - iAfterAuthority - 1).trim();
+ }
+ else
+ name = name.substr(1, name.length - 1).trim();
+ }
+
+ var array = name.split('/');
+
+ // Unescape the components.
+ for (var i = 0; i < array.length; ++i) {
+ var component = unescape(array[i].trim());
+
+ if (component.match(/[^.]/) == null) {
+ // Special case for component of only periods.
+ if (component.length <= 2) {
+ // Zero, one or two periods is illegal. Ignore this componenent to be
+ // consistent with the C implmentation.
+ // This also gets rid of a trailing '/'.
+ array = array.slice(0, i).concat(array.slice(i + 1, array.length));
+ --i;
+ }
+ else
+ // Remove 3 periods.
+ array[i] = component.substr(3, component.length - 3);
+ }
+ else
+ array[i] = component;
+ }
+
+ return array;
+}
+
+
+Name.prototype.from_ccnb = function(/*XMLDecoder*/ decoder) {
+ decoder.readStartElement(this.getElementLabel());
+
+
+ this.components = new Array(); //new ArrayList<byte []>();
+
+ while (decoder.peekStartElement(CCNProtocolDTags.Component)) {
+ this.add(decoder.readBinaryElement(CCNProtocolDTags.Component));
+ }
+
+ decoder.readEndElement();
+};
+
+Name.prototype.to_ccnb = function(/*XMLEncoder*/ encoder) {
+
+ if( this.components ==null )
+ throw new Error("CANNOT ENCODE EMPTY CONTENT NAME");
+
+ encoder.writeStartElement(this.getElementLabel());
+ var count = this.components.length;
+ for (var i=0; i < count; i++) {
+ encoder.writeElement(CCNProtocolDTags.Component, this.components[i]);
+ }
+ encoder.writeEndElement();
+};
+
+Name.prototype.getElementLabel = function(){
+ return CCNProtocolDTags.Name;
+};
+
+Name.prototype.add = function(param){
+ return this.components.push(param);
+};
+
+// Return the escaped name string according to "CCNx URI Scheme". Does not include "ccnx:".
+Name.prototype.to_uri = function() {
+ var result = "";
+
+ for(var i = 0; i < this.components.length; ++i)
+ result += "/"+ Name.toEscapedString(this.components[i]);
+
+ return result;
+};
+
+/**
+ * Return component as an escaped string according to "CCNx URI Scheme".
+ * We can't use encodeURIComponent because that doesn't encode all the characters we want to.
+ */
+Name.toEscapedString = function(component) {
+ var result = "";
+ var gotNonDot = false;
+ for (var i = 0; i < component.length; ++i) {
+ if (component[i] != 0x2e) {
+ gotNonDot = true;
+ break;
+ }
+ }
+ if (!gotNonDot) {
+ // Special case for component of zero or more periods. Add 3 periods.
+ result = "...";
+ for (var i = 0; i < component.length; ++i)
+ result += ".";
+ }
+ else {
+ for (var i = 0; i < component.length; ++i) {
+ var value = component[i];
+ // Check for 0-9, A-Z, a-z, (+), (-), (.), (_)
+ if (value >= 0x30 && value <= 0x39 || value >= 0x41 && value <= 0x5a ||
+ value >= 0x61 && value <= 0x7a || value == 0x2b || value == 0x2d ||
+ value == 0x2e || value == 0x5f)
+ result += String.fromCharCode(value);
+ else
+ result += "%" + (value < 16 ? "0" : "") + value.toString(16).toUpperCase();
+ }
+ }
+ return result;
+};
diff --git a/js/PublisherID.js b/js/PublisherID.js
index 1e24cc7..29a3add 100644
--- a/js/PublisherID.js
+++ b/js/PublisherID.js
@@ -1,5 +1,6 @@
/*
* @author: ucla-cs
+ * See COPYING for copyright and distribution information.
* This class represents Publisher and PublisherType Objects
*/
@@ -34,46 +35,44 @@
//TODO, implement publisherID creation and key creation
//TODO implement generatePublicKeyDigest
- this.PublisherID =null;//= generatePublicKeyDigest(key);//ByteArray
+ this.publisherID =null;//= generatePublicKeyDigest(key);//ByteArray
//TODO implement generate key
//CryptoUtil.generateKeyID(PUBLISHER_ID_DIGEST_ALGORITHM, key);
- this.PublisherType = null;//isIssuer ? PublisherType.ISSUER_KEY : PublisherType.KEY;//publisher Type
+ this.publisherType = null;//isIssuer ? PublisherType.ISSUER_KEY : PublisherType.KEY;//publisher Type
};
-PublisherID.prototype.decode = function(decoder) {
+PublisherID.prototype.from_ccnb = function(decoder) {
// We have a choice here of one of 4 binary element types.
var nextTag = decoder.peekStartElementAsLong();
if (null == nextTag) {
- throw new Exception("Cannot parse publisher ID.");
+ throw new Error("Cannot parse publisher ID.");
}
- this.PublisherType = new PublisherType(nextTag);
+ this.publisherType = new PublisherType(nextTag);
if (!isTypeTagVal(nextTag)) {
- throw new Exception("Invalid publisher ID, got unexpected type: " + nextTag);
+ throw new Error("Invalid publisher ID, got unexpected type: " + nextTag);
}
- this.PublisherID = decoder.readBinaryElement(nextTag);
- if (null == this.PublisherID) {
- throw new ContentDecodingException("Cannot parse publisher ID of type : " + nextTag + ".");
+ this.publisherID = decoder.readBinaryElement(nextTag);
+ if (null == this.publisherID) {
+ throw new ContentDecodingException(new Error("Cannot parse publisher ID of type : " + nextTag + "."));
}
};
-PublisherID.prototype.encode = function(encoder) {
+PublisherID.prototype.to_ccnb = function(encoder) {
if (!this.validate()) {
- throw new Exception("Cannot encode " + this.getClass().getName() + ": field values missing.");
+ throw new Error("Cannot encode " + this.getClass().getName() + ": field values missing.");
}
- encoder.writeElement(this.getElementLabel(), this.PublisherID);
+ encoder.writeElement(this.getElementLabel(), this.publisherID);
};
-var peek = function(
- //XMLDecoder
- decoder) {
+PublisherID.peek = function(/* XMLDecoder */ decoder) {
//Long
nextTag = decoder.peekStartElementAsLong();
@@ -86,7 +85,7 @@
};
PublisherID.prototype.getElementLabel = function() {
- return this.PublisherType.Tag;
+ return this.publisherType.Tag;
};
PublisherID.prototype.validate = function(){
diff --git a/js/PublisherPublicKeyDigest.js b/js/PublisherPublicKeyDigest.js
index a2a8234..b85e26b 100644
--- a/js/PublisherPublicKeyDigest.js
+++ b/js/PublisherPublicKeyDigest.js
@@ -1,61 +1,51 @@
/*
* @author: ucla-cs
+ * See COPYING for copyright and distribution information.
* This class represents PublisherPublicKeyDigest Objects
*/
var PublisherPublicKeyDigest = function PublisherPublicKeyDigest(_pkd){
-
- this.PUBLISHER_ID_LEN = 256/8;
+ //this.PUBLISHER_ID_LEN = 256/8;
+ this.PUBLISHER_ID_LEN = 512/8;
- this.PublisherPublicKeyDigest = _pkd;
- //if( typeof _pkd == "object") this.PublisherPublicKeyDigest = _pkd; // Byte Array
+
+ this.publisherPublicKeyDigest = _pkd;
+ //if( typeof _pkd == "object") this.publisherPublicKeyDigest = _pkd; // Byte Array
//else if( typeof _pkd == "PublicKey") ;//TODO...
-
-
};
+PublisherPublicKeyDigest.prototype.from_ccnb = function( decoder) {
-
-
-PublisherPublicKeyDigest.prototype.decode = function( decoder) {
-
- this.PublisherPublicKeyDigest = decoder.readBinaryElement(this.getElementLabel());
+ this.publisherPublicKeyDigest = decoder.readBinaryElement(this.getElementLabel());
- if(LOG>4)console.log('Publisher public key digest is ' + this.PublisherPublicKeyDigest);
+ if(LOG>4)console.log('Publisher public key digest is ' + this.publisherPublicKeyDigest);
- if (null == this.PublisherPublicKeyDigest) {
- throw new Exception("Cannot parse publisher key digest.");
+ if (null == this.publisherPublicKeyDigest) {
+ throw new Error("Cannot parse publisher key digest.");
}
//TODO check if the length of the PublisherPublicKeyDigest is correct ( Security reason)
- if(LOG>4){
- console.log('PublisherID.PUBLISHER_ID_LEN = ', PublisherID.PUBLISHER_ID_LEN);
- console.log('PublisherPublicKeyDigest.length = ', PublisherPublicKeyDigest.length);
- }
-
-
- if (this.PublisherPublicKeyDigest.length != PublisherID.PUBLISHER_ID_LEN) {
+ if (this.publisherPublicKeyDigest.length != this.PUBLISHER_ID_LEN) {
+ if (LOG > 0)
+ console.log('LENGTH OF PUBLISHER ID IS WRONG! Expected ' + this.PUBLISHER_ID_LEN + ", got " + this.publisherPublicKeyDigest.length);
- console.log('LENGTH OF PUBLISHER ID IS WRONG!');
-
- //this.PublisherPublicKeyDigest = new PublisherPublicKeyDigest(this.PublisherPublicKeyDigest).PublisherKeyDigest;
-
+ //this.publisherPublicKeyDigest = new PublisherPublicKeyDigest(this.PublisherPublicKeyDigest).PublisherKeyDigest;
}
};
-PublisherPublicKeyDigest.prototype.encode= function( encoder) {
+PublisherPublicKeyDigest.prototype.to_ccnb= function( encoder) {
//TODO Check that the ByteArray for the key is present
- /*if (!this.validate()) {
- throw new Exception("Cannot encode : field values missing.");
- }*/
- if(LOG>3) console.log('PUBLISHER KEY DIGEST IS'+this.PublisherPublicKeyDigest);
- encoder.writeElement(this.getElementLabel(), this.PublisherPublicKeyDigest);
+ if (!this.validate()) {
+ throw new Error("Cannot encode : field values missing.");
+ }
+ if(LOG>3) console.log('PUBLISHER KEY DIGEST IS'+this.publisherPublicKeyDigest);
+ encoder.writeElement(this.getElementLabel(), this.publisherPublicKeyDigest);
};
PublisherPublicKeyDigest.prototype.getElementLabel = function() { return CCNProtocolDTags.PublisherPublicKeyDigest; };
PublisherPublicKeyDigest.prototype.validate =function() {
- return (null != this.PublisherKeyDigest);
+ return (null != this.publisherPublicKeyDigest);
};
diff --git a/js/Signature.js b/js/Signature.js
deleted file mode 100644
index 06badef..0000000
--- a/js/Signature.js
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * @author: ucla-cs
- * This class represents Signature Objects
- */
-
-
-var Signature = function Signature(_Witness,_Signature,_DigestAlgorithm) {
-
- this.Witness = _Witness;//byte [] _witness;
- this.Signature = _Signature;//byte [] _signature;
- this.DigestAlgorithm = _DigestAlgorithm//String _digestAlgorithm;
-};
-
-var generateSignature = function(contentName,content,signedinfo){
-
- var enc = new BinaryXMLEncoder();
- contentName.encode(enc);
- var hex1 = toHex(enc.getReducedOstream());
-
- var enc = new BinaryXMLEncoder();
- content.encode(enc);
- var hex2 = toHex(enc.getReducedOstream());
-
- var enc = new BinaryXMLEncoder();
- signedinfo.encode(enc);
- var hex3 = toHex(enc.getReducedOstream());
-
- var hex = hex1+hex2+hex3;
-
- //globalKeyManager.sig
-
-};
-
-Signature.prototype.decode =function( decoder) {
- decoder.readStartElement(this.getElementLabel());
-
- if(LOG>4)console.log('STARTED DECODING SIGNATURE ');
-
- if (decoder.peekStartElement(CCNProtocolDTags.DigestAlgorithm)) {
-
- if(LOG>4)console.log('DIGEST ALGORITHM FOUND');
- this.DigestAlgorithm = decoder.readUTF8Element(CCNProtocolDTags.DigestAlgorithm);
- }
- if (decoder.peekStartElement(CCNProtocolDTags.Witness)) {
- if(LOG>4)console.log('WITNESS FOUND');
- this.Witness = decoder.readBinaryElement(CCNProtocolDTags.Witness);
- }
-
- //FORCE TO READ A SIGNATURE
-
- //if (decoder.peekStartElement(CCNProtocolDTags.SignatureBits)) {
- //if(LOG>4)console.log('SIGNATURE FOUND ');
- this.Signature = decoder.readBinaryElement(CCNProtocolDTags.SignatureBits);
-
- //}
-
- decoder.readEndElement();
-
-};
-
-
-Signature.prototype.encode= function( encoder){
-
- if (!this.validate()) {
- throw new Exception("Cannot encode: field values missing.");
- }
-
- encoder.writeStartElement(this.getElementLabel());
-
- if ((null != this.DigestAlgorithm) && (!this.DigestAlgorithm.equals(CCNDigestHelper.DEFAULT_DIGEST_ALGORITHM))) {
- encoder.writeElement(CCNProtocolDTags.DigestAlgorithm, OIDLookup.getDigestOID(this.DigestAlgorithm));
- }
-
- if (null != this.Witness) {
- // needs to handle null witness
- encoder.writeElement(CCNProtocolDTags.Witness, this.Witness);
- }
-
- encoder.writeElement(CCNProtocolDTags.SignatureBits, this.Signature);
-
- encoder.writeEndElement();
-};
-
-Signature.prototype.getElementLabel = function() { return CCNProtocolDTags.Signature; };
-
-
-Signature.prototype.validate = function() {
- return null != this.Signature;
-};
-
diff --git a/js/SignedInfo.js b/js/SignedInfo.js
deleted file mode 100644
index 0b81201..0000000
--- a/js/SignedInfo.js
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * @author: ucla-cs
- * This class represents SignedInfo Object
- * This keeps information about the ContentObject Signature
- */
-
-var ContentType = {DATA:0, ENCR:1, GONE:2, KEY:3, LINK:4, NACK:5};
-
-var ContentTypeValue = {0:0x0C04C0, 1:0x10D091,2:0x18E344,3:0x28463F,4:0x2C834A,5:0x34008A};
-var ContentTypeValueReverse = {0x0C04C0:0, 0x10D091:1,0x18E344:2,0x28463F:3,0x2C834A:4,0x34008A:5};
-
-
-var SignedInfo = function SignedInfo(_publisher,_timestamp,_type,_locator,_freshnessSeconds,_finalBlockID){
-
- //TODO, Check types
-
- this.Publisher = _publisher; //PublisherPublicKeyDigest
- this.Timestamp=_timestamp; // CCN Time
- this.Type=_type; // ContentType
- this.Locator =_locator;//KeyLocator
- this.FreshnessSeconds =_freshnessSeconds; // Integer
- this.FinalBlockID=_finalBlockID; //byte array
-
-};
-
-SignedInfo.prototype.setFields = function(){
- //BASE64 -> RAW STRING
-
- var stringCertificate = DataUtils.base64toString(globalKeyManager.certificate);
-
- if(LOG>3)console.log('string Certificate is '+stringCertificate);
-
- //HEX -> BYTE ARRAY
- var publisherkey = toNumbers(hex_sha256(stringCertificate));
-
- if(LOG>3)console.log('publisher key is ');
- if(LOG>3)console.log(publisherkey);
-
- this.Publisher = new PublisherPublicKeyDigest(publisherkey);
-
-
- this.Timestamp = new CCNTime('FD0499602d2000');
-
- this.Type = ContentType.DATA;
-
- console.log('toNumbersFromString(stringCertificate) '+toNumbersFromString(stringCertificate));
- this.Locator = new KeyLocator( toNumbersFromString(stringCertificate) ,KeyLocatorType.KEY );
-
-};
-
-SignedInfo.prototype.decode = function( decoder){
-
- decoder.readStartElement( this.getElementLabel() );
-
- if (decoder.peekStartElement(CCNProtocolDTags.PublisherPublicKeyDigest)) {
- if(LOG>3) console.log('DECODING PUBLISHER KEY');
- this.Publisher = new PublisherPublicKeyDigest();
- this.Publisher.decode(decoder);
- }
-
- if (decoder.peekStartElement(CCNProtocolDTags.Timestamp)) {
- this.Timestamp = decoder.readDateTime(CCNProtocolDTags.Timestamp);
- if(LOG>4)console.log('TIMESTAMP FOUND IS '+this.Timestamp);
-
- }
-
- if (decoder.peekStartElement(CCNProtocolDTags.Type)) {
- binType = decoder.readBinaryElement(CCNProtocolDTags.Type);//byte []
-
-
- //TODO Implement Type of Key Reading
-
- if(LOG>4)console.log('TYPE IS'+bintype);
-
- this.Type = this.valueToType(binType);
-
-
- //TODO Implement Type of Key Reading
-
-
- if (null == this.Type) {
- throw new Exception("Cannot parse signedInfo type: bytes.");
- }
-
- } else {
- this.Type = ContentType.DATA; // default
- }
-
- if (decoder.peekStartElement(CCNProtocolDTags.FreshnessSeconds)) {
- this.FreshnessSeconds = decoder.readIntegerElement(CCNProtocolDTags.FreshnessSeconds);
- if(LOG>4) console.log('FRESHNESS IN SECONDS IS '+ this.FreshnessSeconds);
- }
-
- if (decoder.peekStartElement(CCNProtocolDTags.FinalBlockID)) {
- this.FinalBlockID = decoder.readBinaryElement(CCNProtocolDTags.FinalBlockID);
- }
-
- if (decoder.peekStartElement(CCNProtocolDTags.KeyLocator)) {
- this.Locator = new KeyLocator();
- this.Locator.decode(decoder);
- }
-
- decoder.readEndElement();
-};
-
-SignedInfo.prototype.encode = function( encoder) {
- if (!this.validate()) {
- throw new Exception("Cannot encode : field values missing.");
- }
- encoder.writeStartElement(this.getElementLabel());
-
- if (null!=this.Publisher) {
- if(LOG>3) console.log('ENCODING PUBLISHER KEY' + this.Publisher.PublisherPublicKeyDigest);
-
- this.Publisher.encode(encoder);
- }
-
- if (null!=this.Timestamp) {
- encoder.writeDateTime(CCNProtocolDTags.Timestamp, this.Timestamp);
- }
-
- if (null!=this.Type && this.Type !=0) {
-
- encoder.writeElement(CCNProtocolDTags.Type, this.Type);
- }
-
- if (null!=this.FreshnessSeconds) {
- encoder.writeElement(CCNProtocolDTags.FreshnessSeconds, this.FreshnessSeconds);
- }
-
- if (null!=this.FinalBlockID) {
- encoder.writeElement(CCNProtocolDTags.FinalBlockID, this.FinalBlockID);
- }
-
- if (null!=this.Locator) {
- this.Locator.encode(encoder);
- }
-
- encoder.writeEndElement();
-};
-
-SignedInfo.prototype.valueToType = function(){
- //for (Entry<byte [], ContentType> entry : ContentValueTypes.entrySet()) {
- //if (Arrays.equals(value, entry.getKey()))
- //return entry.getValue();
- //}
- return null;
-
-};
-
-SignedInfo.prototype.getElementLabel = function() {
- return CCNProtocolDTags.SignedInfo;
-};
-
-SignedInfo.prototype.validate = function() {
- // We don't do partial matches any more, even though encoder/decoder
- // is still pretty generous.
- if (null ==this.Publisher || null==this.Timestamp ||null== this.Locator)
- return false;
- return true;
-};
-
diff --git a/js/WebSocketTransport.js b/js/WebSocketTransport.js
new file mode 100644
index 0000000..49c09a4
--- /dev/null
+++ b/js/WebSocketTransport.js
@@ -0,0 +1,255 @@
+/*
+ * @author: Wentao Shang
+ * See COPYING for copyright and distribution information.
+ * Implement getAsync and putAsync used by NDN using nsISocketTransportService.
+ * This is used inside Firefox XPCOM modules.
+ */
+
+var WebSocketTransport = function WebSocketTransport() {
+ this.ws = null;
+ this.ccndid = null;
+ this.maxBufferSize = 10000; // Currently support 10000 bytes data input, consistent with BinaryXMLEncoder
+ this.buffer = new Uint8Array(this.maxBufferSize);
+ this.structureDecoder = new BinaryXMLStructureDecoder();
+};
+
+WebSocketTransport.prototype.expressInterest = function(ndn, interest, closure) {
+ if (this.ws != null) {
+ //TODO: check local content store first
+
+ var binaryInterest = encodeToBinaryInterest(interest);
+ var bytearray = new Uint8Array(binaryInterest.length);
+ bytearray.set(binaryInterest);
+
+ var pitEntry = new PITEntry(interest.name.getName(), closure);
+ PITTable.push(pitEntry);
+
+ this.ws.send(bytearray.buffer);
+ console.log('ws.send() returned.');
+ }
+ else{
+ console.log('WebSocket connection is not established.');
+ return null;
+ }
+};
+
+
+var ccndIdFetcher = '/%C1.M.S.localhost/%C1.M.SRV/ccnd/KEY';
+
+WebSocketTransport.prototype.connectWebSocket = function(ndn) {
+ if (this.ws != null)
+ delete this.ws;
+
+ this.ws = new WebSocket('ws://' + ndn.host + ':' + ndn.port);
+ console.log('ws connection created.');
+
+ this.ws.binaryType = "arraybuffer";
+
+ var self = this;
+ this.ws.onmessage = function(ev) {
+ var result = ev.data;
+ //console.log('RecvHandle called.');
+
+ if(result == null || result == undefined || result == "" ) {
+ console.log('INVALID ANSWER');
+ } else if (result instanceof ArrayBuffer) {
+ var bytearray = new Uint8Array(result);
+
+ if (LOG>3) console.log('BINARY RESPONSE IS ' + bytearray);
+
+ try {
+ if (bytearray.length + self.buffer.byteOffset >= self.buffer.byteLength) {
+ console.log("NDN.ws.onmessage: buffer overflow. Accumulate received length: " + self.buffer.byteOffset
+ + ". Current packet length: " + bytearray.length + ".");
+ // Purge and quit.
+ delete self.structureDecoder;
+ delete self.buffer;
+ self.structureDecoder = new BinaryXMLStructureDecoder();
+ self.buffer = new Uint8Array(self.maxBufferSize);
+ return;
+ }
+
+ /*for (var i = 0; i < bytearray.length; i++) {
+ self.buffer.push(bytearray[i]);
+ }*/
+ self.buffer.set(bytearray, self.buffer.byteOffset);
+
+ if (!self.structureDecoder.findElementEnd(self.buffer)) {
+ // Need more data to decode
+ console.log('Incomplete packet received. Length ' + bytearray.length + '. Wait for more input.');
+ console.log('self.buffer length: ' + self.buffer.length);
+ return;
+ }
+ } catch (ex) {
+ console.log("NDN.ws.onmessage exception: " + ex);
+ return;
+ }
+
+ var decoder = new BinaryXMLDecoder(self.buffer);
+ // Dispatch according to packet type
+ if (decoder.peekStartElement(CCNProtocolDTags.Interest)) { // Interest packet
+ console.log('Interest packet received.');
+
+ var interest = new Interest();
+ interest.from_ccnb(decoder);
+ if (LOG>3) console.log(interest);
+ var nameStr = escape(interest.name.getName());
+ console.log(nameStr);
+
+ var entry = getEntryForRegisteredPrefix(nameStr);
+ if (entry != null) {
+ //console.log(entry);
+ entry.closure.upcall(Closure.UPCALL_INTEREST, new UpcallInfo(ndn, interest, 0, null));
+ }
+
+ } else if (decoder.peekStartElement(CCNProtocolDTags.ContentObject)) { // Content packet
+ console.log('ContentObject packet received.');
+
+ var co = new ContentObject();
+ co.from_ccnb(decoder);
+ if (LOG>3) console.log(co);
+ nameStr = co.name.getName();
+ console.log(nameStr);
+
+ if (self.ccndid == null && nameStr.match(ccndIdFetcher) != null) {
+ // We are in starting phase, record publisherPublicKeyDigest in self.ccndid
+ if(!co.signedInfo || !co.signedInfo.publisher
+ || !co.signedInfo.publisher.publisherPublicKeyDigest) {
+ console.log("Cannot contact router");
+ } else {
+ console.log('Connected to ccnd.');
+ self.ccndid = co.signedInfo.publisher.publisherPublicKeyDigest;
+ if (LOG>3) console.log(self.ccndid);
+ }
+ } else {
+ var pitEntry = getEntryForExpressedInterest(nameStr);
+ if (pitEntry != null) {
+ //console.log(pitEntry);
+ pitEntry.closure.upcall(Closure.UPCALL_CONTENT, new UpcallInfo(ndn, null, 0, co));
+ }
+ }
+ } else {
+ console.log('Incoming packet is not Interest or ContentObject. Discard now.');
+ }
+
+ delete decoder;
+
+ // Renew StrcutureDecoder and buffer after we process a full packet
+ delete self.structureDecoder;
+ delete self.buffer;
+ self.structureDecoder = new BinaryXMLStructureDecoder();
+ self.buffer = new Uint8Array(self.maxBufferSize);
+ }
+ }
+
+ this.ws.onopen = function(ev) {
+ console.log(ev);
+ console.log('ws.onopen: WebSocket connection opened.');
+ console.log('ws.onopen: ReadyState: ' + this.readyState);
+
+ // Fetch ccndid now
+ interest = new Interest(new Name(ccndIdFetcher));
+ interest.InterestLifetime = 4200;
+ //var hex = encodeToHexInterest(interest);
+ var hex = encodeToBinaryInterest(interest);
+
+ /*var bytes = new Uint8Array(hex.length / 2);
+ for (var i = 0; i < hex.length; i = i + 2) {
+ bytes[i / 2] = '0x' + hex.substr(i, 2);
+ }*/
+ var bytes = new Uint8Array(hex.length);
+ bytes.set(hex);
+
+ self.ws.send(bytes.buffer);
+ console.log('ws.onopen: ws.send() returned.');
+ }
+
+ this.ws.onerror = function(ev) {
+ console.log('ws.onerror: ReadyState: ' + this.readyState);
+ console.log(ev);
+ console.log('ws.onerror: WebSocket error: ' + ev.data);
+ }
+
+ this.ws.onclose = function(ev) {
+ console.log('ws.onclose: WebSocket connection closed.');
+ self.ws = null;
+ }
+}
+
+
+// For fetching data
+var PITTable = new Array();
+
+var PITEntry = function PITEntry(interest, closure) {
+ this.interest = interest; // String
+ this.closure = closure; // Closure
+}
+
+function getEntryForExpressedInterest(name) {
+ for (var i = 0; i < PITTable.length; i++) {
+ if (name.match(PITTable[i].interest) != null)
+ return PITTable[i];
+ // TODO: handle multiple matching prefixes
+ }
+ return null;
+}
+
+
+// For publishing data
+var CSTable = new Array();
+
+var CSEntry = function CSEntry(name, closure) {
+ this.name = name; // String
+ this.closure = closure; // Closure
+}
+
+function getEntryForRegisteredPrefix(name) {
+ for (var i = 0; i < CSTable.length; i++) {
+ if (CSTable[i].name.match(name) != null)
+ return CSTable[i];
+ }
+ return null;
+}
+
+WebSocketTransport.prototype.registerPrefix = function(ndn, name, closure, flag) {
+ if (this.ws != null) {
+ if (this.ccndid == null) {
+ console.log('ccnd node ID unkonwn. Cannot register prefix.');
+ return;
+ }
+
+ var fe = new ForwardingEntry('selfreg', name, null, null, 3, 2147483647);
+ var bytes = encodeForwardingEntry(fe);
+
+ var si = new SignedInfo();
+ si.setFields();
+
+ var co = new ContentObject(new Name(), si, bytes, new Signature());
+ co.sign();
+ var coBinary = encodeToBinaryContentObject(co);
+
+ //var ccnxnodename = unescape('%00%88%E2%F4%9C%91%16%16%D6%21%8E%A0c%95%A5%A6r%11%E0%A0%82%89%A6%A9%85%AB%D6%E2%065%DB%AF');
+ var ccnxnodename = this.ccndid;
+ var interestName = new Name(['ccnx', ccnxnodename, 'selfreg', coBinary]);
+
+ var interest = new Interest(interestName);
+ interest.scope = 1;
+ //var hex = encodeToHexInterest(int);
+ var binaryInterest = encodeToBinaryInterest(interest);
+ var bytearray = new Uint8Array(binaryInterest.length);
+ bytearray.set(binaryInterest);
+ console.log('Send Interest registration packet.');
+
+ var csEntry = new CSEntry(name.getName(), closure);
+ CSTable.push(csEntry);
+
+ this.ws.send(bytearray.buffer);
+ console.log('ws.send() returned.');
+
+ return 0;
+ } else {
+ console.log('WebSocket connection is not established.');
+ return -1;
+ }
+}
+
diff --git a/js/XpcomTransport.js b/js/XpcomTransport.js
new file mode 100644
index 0000000..643b918
--- /dev/null
+++ b/js/XpcomTransport.js
@@ -0,0 +1,111 @@
+/*
+ * @author: Jeff Thompson
+ * See COPYING for copyright and distribution information.
+ * Implement getAsync and putAsync used by NDN using nsISocketTransportService.
+ * This is used inside Firefox XPCOM modules.
+ */
+
+// Assume already imported the following:
+// Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+// Components.utils.import("resource://gre/modules/NetUtil.jsm");
+
+var XpcomTransport = function XpcomTransport() {
+};
+
+XpcomTransport.prototype.expressInterest = function(ndn, interest, closure) {
+ var binaryInterest = encodeToBinaryInterest(interest);
+
+ var dataListener = {
+ onReceivedData : function(data) {
+ if (data == null || data == undefined || data.length == 0)
+ dump("NDN.expressInterest: received empty data from socket.\n");
+ else {
+ var decoder = new BinaryXMLDecoder(data);
+ var co = new ContentObject();
+ co.from_ccnb(decoder);
+
+ if(LOG>2) {
+ dump("DECODED CONTENT OBJECT\n");
+ dump(co);
+ dump("\n");
+ }
+
+ // TODO: verify the content object and set kind to UPCALL_CONTENT.
+ var result = closure.upcall(Closure.UPCALL_CONTENT_UNVERIFIED,
+ new UpcallInfo(ndn, interest, 0, co));
+ if (result == Closure.RESULT_OK) {
+ // success
+ }
+ else if (result == Closure.RESULT_ERR)
+ dump("NDN.expressInterest: upcall returned RESULT_ERR.\n");
+ else if (result == Closure.RESULT_REEXPRESS)
+ XpcomTransport.readAllFromSocket(ndn.host, ndn.port, binaryInterest, dataListener);
+ else if (result == Closure.RESULT_VERIFY) {
+ // TODO: force verification of content.
+ }
+ else if (result == Closure.RESULT_FETCHKEY) {
+ // TODO: get the key in the key locator and re-call the interest
+ // with the key available in the local storage.
+ }
+ }
+ }
+ }
+
+ XpcomTransport.readAllFromSocket(ndn.host, ndn.port, binaryInterest, dataListener);
+};
+
+/** Send outputData (Uint8Array) to host:port, read the entire response and call
+ * listener.onReceivedData(data) where data is Uint8Array.
+ * Code derived from http://stackoverflow.com/questions/7816386/why-nsiscriptableinputstream-is-not-working .
+ */
+XpcomTransport.readAllFromSocket = function(host, port, outputData, listener) {
+ var transportService = Components.classes["@mozilla.org/network/socket-transport-service;1"].getService
+ (Components.interfaces.nsISocketTransportService);
+ var pump = Components.classes["@mozilla.org/network/input-stream-pump;1"].createInstance
+ (Components.interfaces.nsIInputStreamPump);
+ var transport = transportService.createTransport(null, 0, host, port, null);
+ var outStream = transport.openOutputStream(1, 0, 0);
+ var rawDataString = DataUtils.toString(outputData);
+ outStream.write(rawDataString, rawDataString.length);
+ outStream.flush();
+ var inStream = transport.openInputStream(0, 0, 0);
+ var dataListener = {
+ data: new Uint8Array(0),
+ structureDecoder: new BinaryXMLStructureDecoder(),
+ calledOnReceivedData: false,
+
+ onStartRequest: function (request, context) {
+ },
+ onStopRequest: function (request, context, status) {
+ inStream.close();
+ outStream.close();
+ if (!this.calledOnReceivedData) {
+ this.calledOnReceivedData = true;
+ listener.onReceivedData(this.data);
+ }
+ },
+ onDataAvailable: function (request, context, _inputStream, offset, count) {
+ if (this.calledOnReceivedData)
+ // Already finished. Ignore extra data.
+ return;
+
+ try {
+ // Ignore _inputStream and use inStream.
+ // Use readInputStreamToString to handle binary data.
+ var rawData = NetUtil.readInputStreamToString(inStream, count);
+ this.data = DataUtils.concatFromString(this.data, rawData);
+
+ // Scan the input to check if a whole ccnb object has been read.
+ if (this.structureDecoder.findElementEnd(this.data))
+ // Finish.
+ this.onStopRequest();
+ } catch (ex) {
+ dump("readAllFromSocket.onDataAvailable exception: " + ex + "\n");
+ }
+ }
+ };
+
+ pump.init(inStream, -1, -1, 0, 0, true);
+ pump.asyncRead(dataListener, null);
+}
+
diff --git a/js/ccnxProtocol.xpi b/js/ccnxProtocol.xpi
new file mode 100644
index 0000000..b8ab92f
--- /dev/null
+++ b/js/ccnxProtocol.xpi
Binary files differ
diff --git a/js/ccnxProtocol/chrome.manifest b/js/ccnxProtocol/chrome.manifest
new file mode 100644
index 0000000..e9cac71
--- /dev/null
+++ b/js/ccnxProtocol/chrome.manifest
@@ -0,0 +1,3 @@
+component {8122e660-1012-11e2-892e-0800200c9a66} components/ccnxProtocolService.js
+contract @mozilla.org/network/protocol;1?name=ccnx {8122e660-1012-11e2-892e-0800200c9a66}
+content modules modules/
diff --git a/js/ccnxProtocol/components/ccnxProtocolService.js b/js/ccnxProtocol/components/ccnxProtocolService.js
new file mode 100644
index 0000000..f5d526d
--- /dev/null
+++ b/js/ccnxProtocol/components/ccnxProtocolService.js
@@ -0,0 +1,226 @@
+/*
+ * @author: Jeff Thompson
+ * See COPYING for copyright and distribution information.
+ * This is the ccnx protocol handler for NDN.
+ * Protocol handling code derived from http://mike.kaply.com/2011/01/18/writing-a-firefox-protocol-handler/
+ */
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cr = Components.results;
+
+const nsIProtocolHandler = Ci.nsIProtocolHandler;
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+Components.utils.import("chrome://modules/content/ndn-js.jsm");
+Components.utils.import("chrome://modules/content/ContentChannel.jsm");
+
+function CcnxProtocol() {
+}
+
+CcnxProtocol.prototype = {
+ scheme: "ccnx",
+ protocolFlags: nsIProtocolHandler.URI_NORELATIVE |
+ nsIProtocolHandler.URI_NOAUTH |
+ nsIProtocolHandler.URI_LOADABLE_BY_ANYONE,
+ transport: new XpcomTransport(),
+
+ newURI: function(aSpec, aOriginCharset, aBaseURI)
+ {
+ var uri = Cc["@mozilla.org/network/simple-uri;1"].createInstance(Ci.nsIURI);
+ uri.spec = aSpec;
+ return uri;
+ },
+
+ newChannel: function(aURI)
+ {
+ var thisCcnxProtocol = this;
+
+ try {
+ var trimmedSpec = aURI.spec.trim();
+
+ var contentChannel;
+ var requestContent = function(contentListener) {
+ // Set nameString to the URI without the protocol.
+ var nameString = trimmedSpec;
+ var colonIndex = nameString.indexOf(':');
+ if (colonIndex >= 0)
+ nameString = nameString.substr
+ (colonIndex + 1, nameString.length - colonIndex - 1).trim();
+
+ var name = new Name(nameString);
+ // TODO: Strip off an ending implicit digest before checking the last component?
+ var uriEndsWithSegmentNumber = endsWithSegmentNumber(name);
+
+ var ndn = new NDN({ host: "lioncub.metwi.ucla.edu", port: 9695,
+ // Use the same transport object each time.
+ getTransport: function() { return thisCcnxProtocol.transport; } });
+ ndn.expressInterest(name, new ContentClosure
+ (ndn, contentListener, uriEndsWithSegmentNumber, aURI.originCharset));
+ };
+
+ contentChannel = new ContentChannel(aURI, requestContent);
+ return contentChannel;
+ } catch (ex) {
+ dump("CcnxProtocol.newChannel exception: " + ex + "\n");
+ }
+ },
+
+ classDescription: "ccnx Protocol Handler",
+ contractID: "@mozilla.org/network/protocol;1?name=" + "ccnx",
+ classID: Components.ID('{8122e660-1012-11e2-892e-0800200c9a66}'),
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIProtocolHandler])
+}
+
+if (XPCOMUtils.generateNSGetFactory)
+ var NSGetFactory = XPCOMUtils.generateNSGetFactory([CcnxProtocol]);
+else
+ var NSGetModule = XPCOMUtils.generateNSGetModule([CcnxProtocol]);
+
+/*
+ * Create a closure for calling expressInterest.
+ * contentListener is from the call to requestContent.
+ * uriEndsWithSegmentNumber is true if the URI passed to newChannel has a segment number
+ * (used to determine whether to request only that segment number and for updating the URL bar).
+ * uriOriginCharset is the charset of the URI passed to newChannel (used for making a new URI)
+ */
+var ContentClosure = function ContentClosure
+ (ndn, contentListener, uriEndsWithSegmentNumber, uriOriginCharset) {
+ // Inherit from Closure.
+ Closure.call(this);
+
+ this.ndn = ndn;
+ this.contentListener = contentListener;
+ this.uriEndsWithSegmentNumber = uriEndsWithSegmentNumber;
+ this.uriOriginCharset = uriOriginCharset;
+ this.firstReceivedSegmentNumber = null;
+ this.firstReceivedContentObject = null;
+}
+
+ContentClosure.prototype.upcall = function(kind, upcallInfo) {
+ if (!(kind == Closure.UPCALL_CONTENT ||
+ kind == Closure.UPCALL_CONTENT_UNVERIFIED))
+ // The upcall is not for us.
+ return Closure.RESULT_ERR;
+
+ var contentObject = upcallInfo.contentObject;
+ if (contentObject.content == null) {
+ dump("CcnxProtocol.ContentClosure: contentObject.content is null\n");
+ return Closure.RESULT_ERR;
+ }
+
+ // If !this.uriEndsWithSegmentNumber, we use the segmentNumber to load multiple segments.
+ var segmentNumber = null;
+ if (!this.uriEndsWithSegmentNumber && endsWithSegmentNumber(contentObject.name)) {
+ segmentNumber = DataUtils.bigEndianToUnsignedInt
+ (contentObject.name.components[contentObject.name.components.length - 1]);
+ if (this.firstReceivedSegmentNumber == null) {
+ // This is the first call.
+ this.firstReceivedSegmentNumber = segmentNumber;
+ if (segmentNumber != 0) {
+ // Special case: Save this content object for later and request segment zero.
+ this.firstReceivedContentObject = contentObject;
+ var componentsForZero = contentObject.name.components.slice
+ (0, contentObject.name.components.length - 1);
+ componentsForZero.push([0]);
+ this.ndn.expressInterest(new Name(componentsForZero), this);
+ return Closure.RESULT_OK;
+ }
+ }
+ }
+
+ if (this.uriEndsWithSegmentNumber || segmentNumber == null || segmentNumber == 0) {
+ // This is the first or only segment, so start.
+ // Get the URI from the ContentObject including the version.
+ var contentUriSpec;
+ if (!this.uriEndsWithSegmentNumber && endsWithSegmentNumber(contentObject.name)) {
+ var nameWithoutSegmentNumber = new Name
+ (contentObject.name.components.slice
+ (0, contentObject.name.components.length - 1));
+ contentUriSpec = "ccnx:" + nameWithoutSegmentNumber.to_uri();
+ }
+ else
+ contentUriSpec = "ccnx:" + contentObject.name.to_uri();
+
+ var contentTypeEtc = getNameContentTypeAndCharset(contentObject.name);
+ var ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
+ this.contentListener.onStart(contentTypeEtc.contentType, contentTypeEtc.contentCharset,
+ ioService.newURI(contentUriSpec, this.uriOriginCharset, null));
+ }
+
+ this.contentListener.onReceivedContent(DataUtils.toString(contentObject.content));
+
+ // Check for the special case if the saved content is for the next segment that we need.
+ if (this.firstReceivedContentObject != null &&
+ this.firstReceivedSegmentNumber == segmentNumber + 1) {
+ // Substitute the saved contentObject send its content and keep going.
+ contentObject = this.firstReceivedContentObject;
+ segmentNumber = segmentNumber + 1;
+ // Clear firstReceivedContentObject to save memory.
+ this.firstReceivedContentObject = null;
+
+ this.contentListener.onReceivedContent(DataUtils.toString(contentObject.content));
+ }
+
+ var finalSegmentNumber = null;
+ if (contentObject.signedInfo != null && contentObject.signedInfo.finalBlockID != null)
+ finalSegmentNumber = DataUtils.bigEndianToUnsignedInt(contentObject.signedInfo.finalBlockID);
+
+ if (!this.uriEndsWithSegmentNumber &&
+ segmentNumber != null &&
+ (finalSegmentNumber == null || segmentNumber != finalSegmentNumber)) {
+ // Make a name for the next segment and get it.
+ var segmentNumberPlus1 = DataUtils.nonNegativeIntToBigEndian(segmentNumber + 1);
+ // Put a 0 byte in front.
+ var nextSegmentNumber = new Uint8Array(segmentNumberPlus1.length + 1);
+ nextSegmentNumber.set(segmentNumberPlus1, 1);
+
+ // TODO: When Name uses Uint8Array, we don't need a byte array.
+ var nextSegmentNumberByteArray = [];
+ for (var i = 0; i < nextSegmentNumber.length; ++i)
+ nextSegmentNumberByteArray.push(nextSegmentNumber[i]);
+
+ var components = contentObject.name.components.slice
+ (0, contentObject.name.components.length - 1);
+ components.push(nextSegmentNumberByteArray);
+ this.ndn.expressInterest(new Name(components), this);
+ }
+ else
+ // Finished.
+ this.contentListener.onStop();
+
+ return Closure.RESULT_OK;
+};
+
+
+/*
+ * Scan the name from the last component to the first (skipping special CCNx components)
+ * for a recognized file name extension, and return an object with properties contentType and charset.
+ */
+function getNameContentTypeAndCharset(name) {
+ var filename = "";
+ for (var i = name.components.length - 1; i >= 0; --i) {
+ var component = name.components[i];
+ if (component.length <= 0)
+ continue;
+
+ // Skip special components which just may have ".gif", etc.
+ if (component[0] == 0 || component[0] == 0xC0 || component[0] == 0xC1 ||
+ (component[0] >= 0xF5 && component[0] <= 0xFF))
+ continue;
+
+ filename = DataUtils.toString(component).toLowerCase();
+ break;
+ }
+
+ return MimeTypes.getContentTypeAndCharset(filename);
+}
+
+/*
+ * Return true if the last component in the name is a segment number..
+ */
+function endsWithSegmentNumber(name) {
+ return name.components != null && name.components.length >= 1 &&
+ name.components[name.components.length - 1].length >= 1 &&
+ name.components[name.components.length - 1][0] == 0;
+}
\ No newline at end of file
diff --git a/js/ccnxProtocol/install.rdf b/js/ccnxProtocol/install.rdf
new file mode 100644
index 0000000..a4edaf7
--- /dev/null
+++ b/js/ccnxProtocol/install.rdf
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>{8122e660-1012-11e2-892e-0800200c9a66}</em:id>
+ <em:type>2</em:type>
+ <em:name>ccnx Protocol</em:name>
+ <em:version>0.1</em:version>
+ <em:creator>ucla-cs</em:creator>
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <!-- Firefox -->
+ <em:minVersion>3.5</em:minVersion>
+ <em:maxVersion>4.0.*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+ </Description>
+</RDF>
diff --git a/js/ccnxProtocol/modules/ContentChannel.jsm b/js/ccnxProtocol/modules/ContentChannel.jsm
new file mode 100644
index 0000000..37d9a2d
--- /dev/null
+++ b/js/ccnxProtocol/modules/ContentChannel.jsm
@@ -0,0 +1,153 @@
+/*
+ * @author: ucla-cs
+ * See COPYING for copyright and distribution information.
+ */
+
+var EXPORTED_SYMBOLS = ["ContentChannel"];
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cr = Components.results;
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+/* Create an nsIChannel for returning content to the caller of asyncOpen.
+ * For requestContent detail, see asyncOpen.
+ */
+function ContentChannel(uri, requestContent) {
+ this.requestContent = requestContent;
+
+ this.done = false;
+
+ this.name = uri.spec;
+ // This is set by the caller of asyncOpen.
+ this.loadFlags = 0;
+ this.loadGroup = null;
+ this.status = 200;
+
+ // We don't know these yet.
+ this.contentLength = -1;
+ this.contentType = null;
+ this.contentCharset = null;
+ this.URI = uri;
+ this.originalURI = uri;
+ this.owner = null;
+ this.notificationCallback = null;
+ this.securityInfo = null;
+
+ // Save the mostRecentWindow from the moment of creating the channel.
+ var wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
+ this.mostRecentWindow = wm.getMostRecentWindow("navigator:browser");
+}
+
+ContentChannel.prototype = {
+ QueryInterface: function(aIID) {
+ if (aIID.equals(Ci.nsISupports))
+ return this;
+
+ if (aIID.equals(Ci.nsIRequest))
+ return this;
+
+ if (aIID.equals(Ci.nsIChannel))
+ return this;
+
+ throw Cr.NS_ERROR_NO_INTERFACE;
+ },
+
+ isPending: function() {
+ return !this.done;
+ },
+
+ cancel: function(aStatus){
+ this.status = aStatus;
+ this.done = true;
+ },
+
+ suspend: function(aStatus){
+ this.status = aStatus;
+ },
+
+ resume: function(aStatus){
+ this.status = aStatus;
+ },
+
+ open: function() {
+ throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+ }
+};
+
+/* Call requestContent(contentListener). When the content is available, you should call
+ * contentListener funtions as follows:
+ * onStart(contentType, contentCharset, uri)
+ * Set the contentType and contentCharset and call aListener.onStartRequest. If uri
+ * is not null, update this.URI and if this.loadFlags LOAD_INITIAL_DOCUMENT_URI bit is set,
+ * then update the URL bar of the mostRecentWindow. (Note that the caller of asyncOpen
+ * sets this.loadFlags.)
+ * onReceivedContent(content)
+ * Call aListener.onDataAvailable.
+ * onStop()
+ * Call aListener.onStopRequest.
+ */
+ContentChannel.prototype.asyncOpen = function(aListener, aContext) {
+ try {
+ var thisContentChannel = this;
+
+ var threadManager = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
+ var callingThread = threadManager.currentThread;
+
+ var contentListener = {
+ onStart : function(contentType, contentCharset, uri) {
+ if (uri)
+ thisContentChannel.URI = uri;
+ thisContentChannel.contentType = contentType;
+ thisContentChannel.contentCharset = contentCharset;
+
+ // nsIChannel requires us to call aListener on its calling thread.
+ callingThread.dispatch({
+ run: function() {
+ aListener.onStartRequest(thisContentChannel, aContext);
+ // Load flags bit 19 "LOAD_INITIAL_DOCUMENT_URI" means this channel is
+ // for the main window with the URL bar.
+ if (uri && thisContentChannel.loadFlags & (1<<19))
+ // aListener.onStartRequest may set the URL bar but now we update it.
+ thisContentChannel.mostRecentWindow.gURLBar.value =
+ thisContentChannel.URI.spec;
+ }
+ }, 0);
+ },
+
+ onReceivedContent : function(content) {
+ var pipe = Cc["@mozilla.org/pipe;1"].createInstance(Ci.nsIPipe);
+ pipe.init(true, true, 0, 0, null);
+ pipe.outputStream.write(content, content.length);
+ pipe.outputStream.close();
+
+ // nsIChannel requires us to call aListener on its calling thread.
+ // Assume calls to dispatch are eventually executed in order.
+ callingThread.dispatch({
+ run: function() {
+ aListener.onDataAvailable(thisContentChannel, aContext,
+ pipe.inputStream, 0, content.length);
+ }
+ }, 0);
+ },
+
+ onStop : function() {
+ thisContentChannel.done = true;
+
+ // nsIChannel requires us to call aListener on its calling thread.
+ callingThread.dispatch({
+ run: function() {
+ aListener.onStopRequest(thisContentChannel, aContext,
+ thisContentChannel.status);
+ }
+ }, 0);
+ }
+ };
+
+ this.requestContent(contentListener);
+ } catch (ex) {
+ dump("ContentChannel.asyncOpen exception: " + ex + "\n");
+ }
+};
+
diff --git a/js/ccnxProtocol/modules/emptyLine.txt b/js/ccnxProtocol/modules/emptyLine.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/js/ccnxProtocol/modules/emptyLine.txt
@@ -0,0 +1 @@
+
diff --git a/js/ccnxProtocol/modules/make-ndn-js.jsm.sh b/js/ccnxProtocol/modules/make-ndn-js.jsm.sh
new file mode 100755
index 0000000..78c52c7
--- /dev/null
+++ b/js/ccnxProtocol/modules/make-ndn-js.jsm.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+cat ndn-js-header.txt \
+ ../../Closure.js emptyLine.txt \
+ ../../NDN.js emptyLine.txt \
+ ../../XpcomTransport.js emptyLine.txt \
+ ../../util/CCNProtocolDTags.js emptyLine.txt \
+ ../../util/CCNTime.js emptyLine.txt \
+ ../../Name.js emptyLine.txt \
+ ../../ContentObject.js emptyLine.txt \
+ ../../encoding/DateFormat.js emptyLine.txt \
+ ../../Interest.js emptyLine.txt \
+ ../../Key.js emptyLine.txt \
+ ../../PublisherID.js emptyLine.txt \
+ ../../PublisherPublicKeyDigest.js emptyLine.txt \
+ ../../FaceInstance.js emptyLine.txt \
+ ../../ForwardingEntry.js emptyLine.txt \
+ ../../encoding/BinaryXMLEncoder.js emptyLine.txt \
+ ../../encoding/BinaryXMLDecoder.js emptyLine.txt \
+ ../../encoding/BinaryXMLStructureDecoder.js emptyLine.txt \
+ ../../encoding/DataUtils.js emptyLine.txt \
+ ../../encoding/MimeTypes.js emptyLine.txt \
+ ../../encoding/EncodingUtils.js emptyLine.txt \
+ ../../security/KeyManager.js emptyLine.txt \
+ ../../securityLib/sha1.js emptyLine.txt \
+ ../../securityLib/sha256.js emptyLine.txt \
+ ../../securityLib/sha512.js emptyLine.txt \
+ ../../securityLib/md5.js emptyLine.txt \
+ ../../securityLib/ripemd160.js emptyLine.txt \
+ ../../securityLib/base64.js emptyLine.txt \
+ ../../securityLib/rsa.js emptyLine.txt \
+ ../../securityLib/rsa2.js emptyLine.txt \
+ ../../securityLib/rsapem-1.1.js emptyLine.txt \
+ ../../securityLib/rsasign-1.2.js emptyLine.txt \
+ ../../securityLib/asn1hex-1.1.js emptyLine.txt \
+ ../../securityLib/x509-1.1.js emptyLine.txt \
+ ../../securityLib/jsbn.js emptyLine.txt \
+ ../../securityLib/jsbn2.js emptyLine.txt \
+ > ndn-js.jsm
diff --git a/js/ccnxProtocol/modules/ndn-js-header.txt b/js/ccnxProtocol/modules/ndn-js-header.txt
new file mode 100644
index 0000000..0660198
--- /dev/null
+++ b/js/ccnxProtocol/modules/ndn-js-header.txt
@@ -0,0 +1,28 @@
+/* This file is created by running make-ndn-js.jsm.sh in this directory.
+ * It concatenates ndn-js-header.txt with all the ndn-js source files to
+ * make ndn-js.jsm .
+ * author: ucla-cs
+ * See COPYING for copyright and distribution information.
+ */
+
+var EXPORTED_SYMBOLS = ["NDN", "Closure", "Name", "Interest", "ContentObject",
+ "DataUtils", "MimeTypes", "XpcomTransport"];
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+Components.utils.import("resource://gre/modules/NetUtil.jsm");
+
+// LOG is used by some of the NDN code.
+var LOG = 0;
+
+// jsbn.js needs the navigator object which isn't defined in XPCOM, so make a local hack.
+var navigator = {
+ appName: "Netscape"
+};
+
+// Some code calls console.log without checking LOG>0. Until this is cleaned up, make a local hack console.
+var console = {
+ log: function(message) {
+ dump(message + "\n");
+ }
+};
+
diff --git a/js/ccnxProtocol/modules/ndn-js.jsm b/js/ccnxProtocol/modules/ndn-js.jsm
new file mode 100644
index 0000000..268435c
--- /dev/null
+++ b/js/ccnxProtocol/modules/ndn-js.jsm
@@ -0,0 +1,9497 @@
+/* This file is created by running make-ndn-js.jsm.sh in this directory.
+ * It concatenates ndn-js-header.txt with all the ndn-js source files to
+ * make ndn-js.jsm .
+ * author: ucla-cs
+ * See COPYING for copyright and distribution information.
+ */
+
+var EXPORTED_SYMBOLS = ["NDN", "Closure", "Name", "Interest", "ContentObject",
+ "DataUtils", "MimeTypes", "XpcomTransport"];
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+Components.utils.import("resource://gre/modules/NetUtil.jsm");
+
+// LOG is used by some of the NDN code.
+var LOG = 0;
+
+// jsbn.js needs the navigator object which isn't defined in XPCOM, so make a local hack.
+var navigator = {
+ appName: "Netscape"
+};
+
+// Some code calls console.log without checking LOG>0. Until this is cleaned up, make a local hack console.
+var console = {
+ log: function(message) {
+ dump(message + "\n");
+ }
+};
+
+/*
+ * @author: ucla-cs
+ * See COPYING for copyright and distribution information.
+ * Provide the callback closure for the async communication methods in the NDN class.
+ * This is a port of Closure.py from PyCCN, written by:
+ * Derek Kulinski <takeda@takeda.tk>
+ * Jeff Burke <jburke@ucla.edu>
+ */
+
+/*
+ * Create a subclass of Closure and pass an object to async calls.
+ */
+var Closure = function Closure() {
+ // I don't think storing NDN's closure is needed
+ // and it creates a reference loop, as of now both
+ // of those variables are never set -- Derek
+ //
+ // Use instance variables to return data to callback
+ this.ndn_data = null; // this holds the ndn_closure
+ this.ndn_data_dirty = false;
+};
+
+// Upcall result
+Closure.RESULT_ERR = -1; // upcall detected an error
+Closure.RESULT_OK = 0; // normal upcall return
+Closure.RESULT_REEXPRESS = 1; // reexpress the same interest again
+Closure.RESULT_INTEREST_CONSUMED = 2; // upcall claims to consume interest
+Closure.RESULT_VERIFY = 3; // force an unverified result to be verified
+Closure.RESULT_FETCHKEY = 4; // get the key in the key locator and re-call the interest
+ // with the key available in the local storage
+
+// Upcall kind
+Closure.UPCALL_FINAL = 0; // handler is about to be deregistered
+Closure.UPCALL_INTEREST = 1; // incoming interest
+Closure.UPCALL_CONSUMED_INTEREST = 2; // incoming interest, someone has answered
+Closure.UPCALL_CONTENT = 3; // incoming verified content
+Closure.UPCALL_INTEREST_TIMED_OUT = 4; // interest timed out
+Closure.UPCALL_CONTENT_UNVERIFIED = 5; // content that has not been verified
+Closure.UPCALL_CONTENT_BAD = 6; // verification failed
+
+/*
+ * Override this in your subclass.
+ * If you're getting strange errors in upcall()
+ * check your code whether you're returning a value.
+ */
+Closure.prototype.upcall = function(kind, upcallInfo) {
+ //dump('upcall ' + this + " " + kind + " " + upcallInfo + "\n");
+ return Closure.RESULT_OK;
+};
+
+var UpcallInfo = function UpcallInfo(ndn, interest, matchedComps, contentObject) {
+ this.ndn = ndn; // NDN object (not used)
+ this.interest = interest; // Interest object
+ this.matchedComps = matchedComps; // int
+ this.contentObject = contentObject; // Content object
+};
+
+UpcallInfo.prototype.toString = function() {
+ var ret = "ndn = " + this.ndn;
+ ret += "\nInterest = " + this.interest;
+ ret += "\nmatchedComps = " + this.matchedComps;
+ ret += "\nContentObject: " + this.contentObject;
+ return ret;
+}
+
+/*
+ * @author: Meki Cherkaoui, Jeff Thompson, Wentao Shang
+ * See COPYING for copyright and distribution information.
+ * This class represents the top-level object for communicating with an NDN host.
+ */
+
+var LOG = 3;
+
+/**
+ * settings is an associative array with the following defaults:
+ * {
+ * host: 'localhost',
+ * port: 9696,
+ * getTransport: function() { return new WebSocketTransport(); }
+ * }
+ */
+var NDN = function NDN(settings) {
+ settings = (settings || {});
+ this.host = (settings.host || "localhost");
+ this.port = (settings.port || 9696);
+ var getTransport = (settings.getTransport || function() { return new WebSocketTransport(); });
+ this.transport = getTransport();
+};
+
+
+/* Java Socket Bridge and XPCOM transport */
+
+NDN.prototype.createRoute = function(host,port){
+ this.host=host;
+ this.port=port;
+}
+
+NDN.prototype.get = function(message){
+ if(this.host!=null && this.port!=null){
+ var output ='';
+ message = message.trim();
+ if(message==null || message =="" ){
+ console.log('INVALID INPUT TO GET');
+ return null;
+ }
+
+
+ //var array = Name.createNameArray(message);
+
+ int = new Interest(new Name(message));
+
+ int.InterestLifetime = 4200;
+
+ var hex = encodeToHexInterest(int);
+
+ //var result = get_java_socket_bridge().connectAndStart(ndnurl,ndnport,hex);
+
+ var result = get(this.host,this.port, hex);
+
+
+ if(LOG>0)console.log('BINARY RESPONSE IS ' +result);
+
+ if(result==null || result==undefined || result =="" ){
+ /*if(result[0] != '0'||result[1]!='4') {
+ if(LOG>2)console.log('INVALID ANSWER');
+ }*/
+ return null;
+ }
+
+ else{
+
+ co = decodeHexContentObject(result);
+
+ if(LOG>2) {
+ console.log('DECODED CONTENT OBJECT');
+ console.log(co);
+ }
+ return co;
+ }
+ }
+ else{
+
+ console.log('ERROR URL OR PORT NOT SET');
+
+ return null;
+
+ }
+
+
+}
+
+NDN.prototype.put = function(name,content){
+ if(this.host!=null && this.port!=null){
+
+ var co = this.get("/%C1.M.S.localhost/%C1.M.SRV/ccnd");
+
+ if(!co || !co.signedInfo || !co.signedInfo.publisher || !co.signedInfo.publisher.publisherPublicKeyDigest){
+ alert("Cannot contact router");
+
+ return null;
+ }
+
+ var ccnxnodename = co.signedInfo.publisher.publisherPublicKeyDigest;
+
+ name = name.trim();
+
+ var fe = new ForwardingEntry('selfreg',new Name(name),null, null, 3,2147483647);
+
+ var bytes = encodeForwardingEntry(fe);
+
+
+ var si = new SignedInfo();
+ si.setFields();
+
+ var co = new ContentObject(new Name(),si,bytes,new Signature());
+ co.sign();
+
+ var coBinary = encodeToBinaryContentObject(co);
+
+ //var ccnxnodename = unescape('%E0%A0%1E%099h%F9t%0C%E7%F46%1B%AB%F5%BB%05%A4%E5Z%AC%A5%E5%8Fs%ED%DE%B8%E0%13%AA%8F');
+
+ var interestName = new Name(['ccnx',ccnxnodename,'selfreg',coBinary]);
+
+ int = new Interest(interestName);
+ int.scope = 1;
+
+ var hex = encodeToHexInterest(int);
+
+ console.log('GOING TO PUT INTEREST OBJECT');
+
+ console.log(hex);
+
+ //var result = put(this.host,this.port, hex,name);
+
+
+ //if(LOG>3)console.log('received interest'); //from host'+ host +':'+port+' with name '+name);
+
+ //if(LOG>3)console.log('DATA ');
+
+ //if(LOG>3)console.log(result);
+
+ //interest = decodeHexInterest(result);
+
+ //console.log('SUCCESSFULLY PARSED INTEREST');
+
+ console.log('CREATING ANSWER');
+ var si = new SignedInfo();
+ si.setFields();
+
+ var answer = DataUtils.toNumbersFromString(content);
+
+ var co = new ContentObject(new Name(name),si,answer,new Signature());
+ co.sign();
+
+
+ var outputHex = encodeToHexContentObject(co);
+
+ //console.log('SENDING ANSWER');
+
+ //return get_java_socket_bridge().putAnswer(outputHex,name);
+
+ var result = put(this.host,this.port, hex,name,outputHex);
+
+
+ return result;
+ }
+ else{
+ console.log('ERROR URL OR PORT NOT SET');
+
+ return null;
+ }
+}
+
+/** Encode name as an Interest. If template is not null, use its attributes.
+ * Send the interest to host:port, read the entire response and call
+ * closure.upcall(Closure.UPCALL_CONTENT (or Closure.UPCALL_CONTENT_UNVERIFIED),
+ * new UpcallInfo(this, interest, 0, contentObject)).
+ */
+NDN.prototype.expressInterest = function(
+ // Name
+ name,
+ // Closure
+ closure,
+ // Interest
+ template) {
+ if (this.host == null || this.port == null) {
+ dump('ERROR host OR port NOT SET\n');
+ return;
+ }
+
+ var interest = new Interest(name);
+ if (template != null) {
+ interest.minSuffixComponents = template.minSuffixComponents;
+ interest.maxSuffixComponents = template.maxSuffixComponents;
+ interest.publisherPublicKeyDigest = template.publisherPublicKeyDigest;
+ interest.exclude = template.exclude;
+ interest.childSelector = template.childSelector;
+ interest.answerOriginKind = template.answerOriginKind;
+ interest.scope = template.scope;
+ interest.interestLifetime = template.interestLifetime;
+ }
+ else
+ interest.interestLifetime = 4200;
+
+ this.transport.expressInterest(this, interest, closure);
+};
+
+
+NDN.prototype.registerPrefix = function(name, closure, flag) {
+ return this.transport.registerPrefix(this, name, closure, flag);
+}
+
+/*
+ * @author: Jeff Thompson
+ * See COPYING for copyright and distribution information.
+ * Implement getAsync and putAsync used by NDN using nsISocketTransportService.
+ * This is used inside Firefox XPCOM modules.
+ */
+
+// Assume already imported the following:
+// Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+// Components.utils.import("resource://gre/modules/NetUtil.jsm");
+
+var XpcomTransport = function XpcomTransport() {
+};
+
+XpcomTransport.prototype.expressInterest = function(ndn, interest, closure) {
+ var binaryInterest = encodeToBinaryInterest(interest);
+
+ var dataListener = {
+ onReceivedData : function(data) {
+ if (data == null || data == undefined || data.length == 0)
+ dump("NDN.expressInterest: received empty data from socket.\n");
+ else {
+ var decoder = new BinaryXMLDecoder(data);
+ var co = new ContentObject();
+ co.from_ccnb(decoder);
+
+ if(LOG>2) {
+ dump("DECODED CONTENT OBJECT\n");
+ dump(co);
+ dump("\n");
+ }
+
+ // TODO: verify the content object and set kind to UPCALL_CONTENT.
+ var result = closure.upcall(Closure.UPCALL_CONTENT_UNVERIFIED,
+ new UpcallInfo(ndn, interest, 0, co));
+ if (result == Closure.RESULT_OK) {
+ // success
+ }
+ else if (result == Closure.RESULT_ERR)
+ dump("NDN.expressInterest: upcall returned RESULT_ERR.\n");
+ else if (result == Closure.RESULT_REEXPRESS)
+ XpcomTransport.readAllFromSocket(ndn.host, ndn.port, binaryInterest, dataListener);
+ else if (result == Closure.RESULT_VERIFY) {
+ // TODO: force verification of content.
+ }
+ else if (result == Closure.RESULT_FETCHKEY) {
+ // TODO: get the key in the key locator and re-call the interest
+ // with the key available in the local storage.
+ }
+ }
+ }
+ }
+
+ XpcomTransport.readAllFromSocket(ndn.host, ndn.port, binaryInterest, dataListener);
+};
+
+/** Send outputData (Uint8Array) to host:port, read the entire response and call
+ * listener.onReceivedData(data) where data is Uint8Array.
+ * Code derived from http://stackoverflow.com/questions/7816386/why-nsiscriptableinputstream-is-not-working .
+ */
+XpcomTransport.readAllFromSocket = function(host, port, outputData, listener) {
+ var transportService = Components.classes["@mozilla.org/network/socket-transport-service;1"].getService
+ (Components.interfaces.nsISocketTransportService);
+ var pump = Components.classes["@mozilla.org/network/input-stream-pump;1"].createInstance
+ (Components.interfaces.nsIInputStreamPump);
+ var transport = transportService.createTransport(null, 0, host, port, null);
+ var outStream = transport.openOutputStream(1, 0, 0);
+ var rawDataString = DataUtils.toString(outputData);
+ outStream.write(rawDataString, rawDataString.length);
+ outStream.flush();
+ var inStream = transport.openInputStream(0, 0, 0);
+ var dataListener = {
+ data: new Uint8Array(0),
+ structureDecoder: new BinaryXMLStructureDecoder(),
+ calledOnReceivedData: false,
+
+ onStartRequest: function (request, context) {
+ },
+ onStopRequest: function (request, context, status) {
+ inStream.close();
+ outStream.close();
+ if (!this.calledOnReceivedData) {
+ this.calledOnReceivedData = true;
+ listener.onReceivedData(this.data);
+ }
+ },
+ onDataAvailable: function (request, context, _inputStream, offset, count) {
+ if (this.calledOnReceivedData)
+ // Already finished. Ignore extra data.
+ return;
+
+ try {
+ // Ignore _inputStream and use inStream.
+ // Use readInputStreamToString to handle binary data.
+ var rawData = NetUtil.readInputStreamToString(inStream, count);
+ this.data = DataUtils.concatFromString(this.data, rawData);
+
+ // Scan the input to check if a whole ccnb object has been read.
+ if (this.structureDecoder.findElementEnd(this.data))
+ // Finish.
+ this.onStopRequest();
+ } catch (ex) {
+ dump("readAllFromSocket.onDataAvailable exception: " + ex + "\n");
+ }
+ }
+ };
+
+ pump.init(inStream, -1, -1, 0, 0, true);
+ pump.asyncRead(dataListener, null);
+}
+
+
+/*
+ * @author: ucla-cs
+ * See COPYING for copyright and distribution information.
+ * This class contains all CCNx tags
+ */
+
+
+var CCNProtocolDTags = {
+
+ /**
+ * Note if you add one of these, add it to the reverse string map as well.
+ * Emphasize getting the work done at compile time over trying to make something
+ * flexible and developer error-proof.
+ */
+
+ Any : 13,
+ Name : 14,
+ Component : 15,
+ Certificate : 16,
+ Collection : 17,
+ CompleteName : 18,
+ Content : 19,
+ SignedInfo : 20,
+ ContentDigest : 21,
+ ContentHash : 22,
+ Count : 24,
+ Header : 25,
+ Interest : 26, /* 20090915 */
+ Key : 27,
+ KeyLocator : 28,
+ KeyName : 29,
+ Length : 30,
+ Link : 31,
+ LinkAuthenticator : 32,
+ NameComponentCount : 33, /* DeprecatedInInterest */
+ RootDigest : 36,
+ Signature : 37,
+ Start : 38,
+ Timestamp : 39,
+ Type : 40,
+ Nonce : 41,
+ Scope : 42,
+ Exclude : 43,
+ Bloom : 44,
+ BloomSeed : 45,
+ AnswerOriginKind : 47,
+ InterestLifetime : 48,
+ Witness : 53,
+ SignatureBits : 54,
+ DigestAlgorithm : 55,
+ BlockSize : 56,
+ FreshnessSeconds : 58,
+ FinalBlockID : 59,
+ PublisherPublicKeyDigest : 60,
+ PublisherCertificateDigest : 61,
+ PublisherIssuerKeyDigest : 62,
+ PublisherIssuerCertificateDigest : 63,
+ ContentObject : 64, /* 20090915 */
+ WrappedKey : 65,
+ WrappingKeyIdentifier : 66,
+ WrapAlgorithm : 67,
+ KeyAlgorithm : 68,
+ Label : 69,
+ EncryptedKey : 70,
+ EncryptedNonceKey : 71,
+ WrappingKeyName : 72,
+ Action : 73,
+ FaceID : 74,
+ IPProto : 75,
+ Host : 76,
+ Port : 77,
+ MulticastInterface : 78,
+ ForwardingFlags : 79,
+ FaceInstance : 80,
+ ForwardingEntry : 81,
+ MulticastTTL : 82,
+ MinSuffixComponents : 83,
+ MaxSuffixComponents : 84,
+ ChildSelector : 85,
+ RepositoryInfo : 86,
+ Version : 87,
+ RepositoryVersion : 88,
+ GlobalPrefix : 89,
+ LocalName : 90,
+ Policy : 91,
+ Namespace : 92,
+ GlobalPrefixName : 93,
+ PolicyVersion : 94,
+ KeyValueSet : 95,
+ KeyValuePair : 96,
+ IntegerValue : 97,
+ DecimalValue : 98,
+ StringValue : 99,
+ BinaryValue : 100,
+ NameValue : 101,
+ Entry : 102,
+ ACL : 103,
+ ParameterizedName : 104,
+ Prefix : 105,
+ Suffix : 106,
+ Root : 107,
+ ProfileName : 108,
+ Parameters : 109,
+ InfoString : 110,
+ // 111 unallocated
+ StatusResponse : 112,
+ StatusCode : 113,
+ StatusText : 114,
+
+ // Sync protocol
+ SyncNode : 115,
+ SyncNodeKind : 116,
+ SyncNodeElement : 117,
+ SyncVersion : 118,
+ SyncNodeElements : 119,
+ SyncContentHash : 120,
+ SyncLeafCount : 121,
+ SyncTreeDepth : 122,
+ SyncByteCount : 123,
+ ConfigSlice : 124,
+ ConfigSliceList : 125,
+ ConfigSliceOp : 126,
+
+ // Remember to keep in sync with schema/tagnames.csvsdict
+ CCNProtocolDataUnit : 17702112,
+ CCNPROTOCOL_DATA_UNIT : "CCNProtocolDataUnit"
+};
+
+var CCNProtocolDTagsStrings = [
+ null, null, null, null, null, null, null, null, null, null, null,
+ null, null,
+ "Any", "Name", "Component", "Certificate", "Collection", "CompleteName",
+ "Content", "SignedInfo", "ContentDigest", "ContentHash", null, "Count", "Header",
+ "Interest", "Key", "KeyLocator", "KeyName", "Length", "Link", "LinkAuthenticator",
+ "NameComponentCount", null, null, "RootDigest", "Signature", "Start", "Timestamp", "Type",
+ "Nonce", "Scope", "Exclude", "Bloom", "BloomSeed", null, "AnswerOriginKind",
+ "InterestLifetime", null, null, null, null, "Witness", "SignatureBits", "DigestAlgorithm", "BlockSize",
+ null, "FreshnessSeconds", "FinalBlockID", "PublisherPublicKeyDigest", "PublisherCertificateDigest",
+ "PublisherIssuerKeyDigest", "PublisherIssuerCertificateDigest", "ContentObject",
+ "WrappedKey", "WrappingKeyIdentifier", "WrapAlgorithm", "KeyAlgorithm", "Label",
+ "EncryptedKey", "EncryptedNonceKey", "WrappingKeyName", "Action", "FaceID", "IPProto",
+ "Host", "Port", "MulticastInterface", "ForwardingFlags", "FaceInstance",
+ "ForwardingEntry", "MulticastTTL", "MinSuffixComponents", "MaxSuffixComponents", "ChildSelector",
+ "RepositoryInfo", "Version", "RepositoryVersion", "GlobalPrefix", "LocalName",
+ "Policy", "Namespace", "GlobalPrefixName", "PolicyVersion", "KeyValueSet", "KeyValuePair",
+ "IntegerValue", "DecimalValue", "StringValue", "BinaryValue", "NameValue", "Entry",
+ "ACL", "ParameterizedName", "Prefix", "Suffix", "Root", "ProfileName", "Parameters",
+ "InfoString", null,
+ "StatusResponse", "StatusCode", "StatusText", "SyncNode", "SyncNodeKind", "SyncNodeElement",
+ "SyncVersion", "SyncNodeElements", "SyncContentHash", "SyncLeafCount", "SyncTreeDepth", "SyncByteCount",
+ "ConfigSlice", "ConfigSliceList", "ConfigSliceOp" ];
+
+
+//TESTING
+//console.log(exports.CCNProtocolDTagsStrings[17]);
+
+
+/*
+ * @author: ucla-cs
+ * See COPYING for copyright and distribution information.
+ * This class represents CCNTime Objects
+ */
+
+var CCNTime = function CCNTime(
+
+ input) {
+
+
+
+
+ this.NANOS_MAX = 999877929;
+
+ /*if(typeof input =='object'){
+ this.longDate = DataUtils.byteArrayToUnsignedLong(input);
+ this.binaryDate = input;
+ }*/
+ if(typeof input =='number'){
+ this.msec = input;
+ //this.binaryDate = DataUtils.unsignedLongToByteArray(input);
+
+ }
+ else{
+ if(LOG>1) console.log('UNRECOGNIZED TYPE FOR TIME');
+ }
+};
+
+
+CCNTime.prototype.getJavascriptDate = function(){
+ var d = new Date();
+ d.setTime( this.msec );
+ return d
+};
+
+ /**
+ * Create a CCNTime
+ * @param timestamp source timestamp to initialize from, some precision will be lost
+ */
+
+
+ /**
+ * Create a CCNTime from its binary encoding
+ * @param binaryTime12 the binary representation of a CCNTime
+ */
+/*CCNTime.prototype.setDateBinary = function(
+ //byte []
+ binaryTime12) {
+
+
+ if ((null == binaryTime12) || (binaryTime12.length == 0)) {
+ throw new IllegalArgumentException("Invalid binary time!");
+ }
+
+
+ value = 0;
+ for(i = 0; i < binaryTime12.length; i++) {
+ value = value << 8;
+ b = (binaryTime12[i]) & 0xFF;
+ value |= b;
+ }
+
+ //this.date = new Date(value);
+
+};
+
+//byte[]
+CCNTime.prototype.toBinaryTime = function() {
+
+ return this.msec; //unsignedLongToByteArray(this.date.getTime());
+
+}*/
+/*
+unsignedLongToByteArray= function( value) {
+ if( 0 == value )
+ return [0];
+
+ if( 0 <= value && value <= 0x00FF ) {
+ //byte []
+ bb = new Array[1];
+ bb[0] = (value & 0x00FF);
+ return bb;
+ }
+
+
+ //byte []
+ out = null;
+ //int
+ offset = -1;
+ for(var i = 7; i >=0; --i) {
+ //byte
+ b = ((value >> (i * 8)) & 0xFF);
+ if( out == null && b != 0 ) {
+ out = new Array(i+1);//byte[i+1];
+ offset = i;
+ }
+ if( out != null )
+ out[ offset - i ] = b;
+ }
+ return out;
+}*/
+
+
+/*
+ * @author: ucla-cs
+ * See COPYING for copyright and distribution information.
+ * This class represents a Name as an array of components where each is a byte array.
+ */
+
+
+var Name = function Name(_components){
+
+ if( typeof _components == 'string') {
+
+ if(LOG>3)console.log('Content Name String '+_components);
+ this.components = Name.makeBlob(Name.createNameArray(_components));
+ }
+ else if(typeof _components === 'object' && _components instanceof Array ){
+
+ if(LOG>4)console.log('Content Name Array '+_components);
+ this.components = Name.makeBlob(_components);
+
+ }
+ else if(_components==null){
+ this.components =[];
+ }
+ else{
+
+ if(LOG>1)console.log("NO CONTENT NAME GIVEN");
+
+ }
+};
+
+Name.prototype.getName = function() {
+ return this.to_uri();
+};
+
+Name.makeBlob=function(name){
+
+ var blobArrays = new Array(name.length);
+
+ for(var i=0;i<name.length;i++){
+ if(typeof name[i] == 'string')
+ blobArrays[i]= DataUtils.toNumbersFromString( name[i] );
+ else if(typeof name[i] == 'object')
+ blobArrays[i]= name[i] ;
+ else
+ if(LOG>4)console.log('NAME COMPONENT INVALID');
+ }
+
+ return blobArrays;
+};
+
+Name.createNameArray = function(name) {
+ name = name.trim();
+ if (name.length <= 0)
+ return [];
+
+ var iColon = name.indexOf(':');
+ if (iColon >= 0) {
+ // Make sure the colon came before a '/'.
+ var iFirstSlash = name.indexOf('/');
+ if (iFirstSlash < 0 || iColon < iFirstSlash)
+ // Omit the leading protocol such as ccnx:
+ name = name.substr(iColon + 1, name.length - iColon - 1).trim();
+ }
+
+ if (name[0] == '/') {
+ if (name.length >= 2 && name[1] == '/') {
+ // Strip the authority following "//".
+ var iAfterAuthority = name.indexOf('/', 2);
+ if (iAfterAuthority < 0)
+ // Unusual case: there was only an authority.
+ return [];
+ else
+ name = name.substr(iAfterAuthority + 1, name.length - iAfterAuthority - 1).trim();
+ }
+ else
+ name = name.substr(1, name.length - 1).trim();
+ }
+
+ var array = name.split('/');
+
+ // Unescape the components.
+ for (var i = 0; i < array.length; ++i) {
+ var component = unescape(array[i].trim());
+
+ if (component.match(/[^.]/) == null) {
+ // Special case for component of only periods.
+ if (component.length <= 2) {
+ // Zero, one or two periods is illegal. Ignore this componenent to be
+ // consistent with the C implmentation.
+ // This also gets rid of a trailing '/'.
+ array = array.slice(0, i).concat(array.slice(i + 1, array.length));
+ --i;
+ }
+ else
+ // Remove 3 periods.
+ array[i] = component.substr(3, component.length - 3);
+ }
+ else
+ array[i] = component;
+ }
+
+ return array;
+}
+
+
+Name.prototype.from_ccnb = function(/*XMLDecoder*/ decoder) {
+ decoder.readStartElement(this.getElementLabel());
+
+
+ this.components = new Array(); //new ArrayList<byte []>();
+
+ while (decoder.peekStartElement(CCNProtocolDTags.Component)) {
+ this.add(decoder.readBinaryElement(CCNProtocolDTags.Component));
+ }
+
+ decoder.readEndElement();
+};
+
+Name.prototype.to_ccnb = function(/*XMLEncoder*/ encoder) {
+
+ if( this.components ==null )
+ throw new Error("CANNOT ENCODE EMPTY CONTENT NAME");
+
+ encoder.writeStartElement(this.getElementLabel());
+ var count = this.components.length;
+ for (var i=0; i < count; i++) {
+ encoder.writeElement(CCNProtocolDTags.Component, this.components[i]);
+ }
+ encoder.writeEndElement();
+};
+
+Name.prototype.getElementLabel = function(){
+ return CCNProtocolDTags.Name;
+};
+
+Name.prototype.add = function(param){
+ return this.components.push(param);
+};
+
+// Return the escaped name string according to "CCNx URI Scheme". Does not include "ccnx:".
+Name.prototype.to_uri = function() {
+ var result = "";
+
+ for(var i = 0; i < this.components.length; ++i)
+ result += "/"+ Name.toEscapedString(this.components[i]);
+
+ return result;
+};
+
+/**
+ * Return component as an escaped string according to "CCNx URI Scheme".
+ * We can't use encodeURIComponent because that doesn't encode all the characters we want to.
+ */
+Name.toEscapedString = function(component) {
+ var result = "";
+ var gotNonDot = false;
+ for (var i = 0; i < component.length; ++i) {
+ if (component[i] != 0x2e) {
+ gotNonDot = true;
+ break;
+ }
+ }
+ if (!gotNonDot) {
+ // Special case for component of zero or more periods. Add 3 periods.
+ result = "...";
+ for (var i = 0; i < component.length; ++i)
+ result += ".";
+ }
+ else {
+ for (var i = 0; i < component.length; ++i) {
+ var value = component[i];
+ // Check for 0-9, A-Z, a-z, (+), (-), (.), (_)
+ if (value >= 0x30 && value <= 0x39 || value >= 0x41 && value <= 0x5a ||
+ value >= 0x61 && value <= 0x7a || value == 0x2b || value == 0x2d ||
+ value == 0x2e || value == 0x5f)
+ result += String.fromCharCode(value);
+ else
+ result += "%" + (value < 16 ? "0" : "") + value.toString(16).toUpperCase();
+ }
+ }
+ return result;
+};
+
+/*
+ * @author: ucla-cs
+ * See COPYING for copyright and distribution information.
+ * This class represents ContentObject Objects
+ */
+var ContentObject = function ContentObject(_name,_signedInfo,_content,_signature){
+
+
+ if (typeof _name === 'string'){
+ this.name = new Name(_name);
+ }
+ else{
+ //TODO Check the class of _name
+ this.name = _name;
+ }
+ this.signedInfo = _signedInfo;
+ this.content=_content;
+ this.signature = _signature;
+
+
+ this.startSIG = null;
+ this.endSIG = null;
+
+ this.startSignedInfo = null;
+ this.endContent = null;
+
+ this.rawSignatureData = null;
+};
+
+ContentObject.prototype.sign = function(){
+
+ var n1 = this.encodeObject(this.name);
+ var n2 = this.encodeObject(this.signedInfo);
+ var n3 = this.encodeContent();
+ /*console.log('sign: ');
+ console.log(n1);
+ console.log(n2);
+ console.log(n3);*/
+
+ //var n = n1.concat(n2,n3);
+ var tempBuf = new ArrayBuffer(n1.length + n2.length + n3.length);
+ var n = new Uint8Array(tempBuf);
+ //console.log(n);
+ n.set(n1, 0);
+ //console.log(n);
+ n.set(n2, n1.length);
+ //console.log(n);
+ n.set(n3, n1.length + n2.length);
+ //console.log(n);
+
+ if(LOG>4)console.log('Signature Data is (binary) '+n);
+
+ if(LOG>4)console.log('Signature Data is (RawString)');
+
+ if(LOG>4)console.log( DataUtils.toString(n) );
+
+ //var sig = DataUtils.toString(n);
+
+
+ var rsa = new RSAKey();
+
+ rsa.readPrivateKeyFromPEMString(globalKeyManager.privateKey);
+
+ //var hSig = rsa.signString(sig, "sha256");
+
+ var hSig = rsa.signByteArrayWithSHA256(n);
+
+
+ if(LOG>4)console.log('SIGNATURE SAVED IS');
+
+ if(LOG>4)console.log(hSig);
+
+ if(LOG>4)console.log( DataUtils.toNumbers(hSig.trim()));
+
+ this.signature.signature = DataUtils.toNumbers(hSig.trim());
+
+
+};
+
+ContentObject.prototype.encodeObject = function encodeObject(obj){
+ var enc = new BinaryXMLEncoder();
+
+ obj.to_ccnb(enc);
+
+ var num = enc.getReducedOstream();
+
+ return num;
+
+
+};
+
+ContentObject.prototype.encodeContent = function encodeContent(obj){
+ var enc = new BinaryXMLEncoder();
+
+ enc.writeElement(CCNProtocolDTags.Content, this.content);
+
+ var num = enc.getReducedOstream();
+
+ return num;
+
+
+};
+
+ContentObject.prototype.saveRawData = function(bytes){
+
+ var sigBits = bytes.subarray(this.startSIG, this.endSIG);
+
+ this.rawSignatureData = sigBits;
+};
+
+ContentObject.prototype.from_ccnb = function(/*XMLDecoder*/ decoder) {
+
+ // TODO VALIDATE THAT ALL FIELDS EXCEPT SIGNATURE ARE PRESENT
+
+ decoder.readStartElement(this.getElementLabel());
+
+
+ if( decoder.peekStartElement(CCNProtocolDTags.Signature) ){
+ this.signature = new Signature();
+ this.signature.from_ccnb(decoder);
+ }
+
+ //this.endSIG = decoder.offset;
+
+ this.startSIG = decoder.offset;
+
+ this.name = new Name();
+ this.name.from_ccnb(decoder);
+
+ //this.startSignedInfo = decoder.offset;
+
+
+ if( decoder.peekStartElement(CCNProtocolDTags.SignedInfo) ){
+ this.signedInfo = new SignedInfo();
+ this.signedInfo.from_ccnb(decoder);
+ }
+
+ this.content = decoder.readBinaryElement(CCNProtocolDTags.Content);
+
+
+ //this.endContent = decoder.offset;
+ this.endSIG = decoder.offset;
+
+
+ decoder.readEndElement();
+
+ this.saveRawData(decoder.istream);
+};
+
+ContentObject.prototype.to_ccnb = function(/*XMLEncoder*/ encoder) {
+
+ //TODO verify name, SignedInfo and Signature is present
+
+
+ encoder.writeStartElement(this.getElementLabel());
+
+
+
+
+ if(null!=this.signature) this.signature.to_ccnb(encoder);
+
+
+ this.startSIG = encoder.offset;
+
+
+ if(null!=this.name) this.name.to_ccnb(encoder);
+
+ //this.endSIG = encoder.offset;
+ //this.startSignedInfo = encoder.offset;
+
+
+ if(null!=this.signedInfo) this.signedInfo.to_ccnb(encoder);
+
+ encoder.writeElement(CCNProtocolDTags.Content, this.content);
+
+
+ this.endSIG = encoder.offset;
+
+ //this.endContent = encoder.offset;
+
+
+ encoder.writeEndElement();
+
+ this.saveRawData(encoder.ostream);
+
+};
+
+ContentObject.prototype.getElementLabel= function(){return CCNProtocolDTags.ContentObject;};
+
+/**
+ * Signature
+ */
+var Signature = function Signature(_witness,_signature,_digestAlgorithm) {
+
+ this.Witness = _witness;//byte [] _witness;
+ this.signature = _signature;//byte [] _signature;
+ this.digestAlgorithm = _digestAlgorithm//String _digestAlgorithm;
+};
+
+var generateSignature = function(contentName,content,signedinfo){
+
+ var enc = new BinaryXMLEncoder();
+ contentName.to_ccnb(enc);
+ var hex1 = toHex(enc.getReducedOstream());
+
+ var enc = new BinaryXMLEncoder();
+ content.to_ccnb(enc);
+ var hex2 = toHex(enc.getReducedOstream());
+
+ var enc = new BinaryXMLEncoder();
+ signedinfo.to_ccnb(enc);
+ var hex3 = toHex(enc.getReducedOstream());
+
+ var hex = hex1+hex2+hex3;
+
+ //globalKeyManager.sig
+
+};
+
+Signature.prototype.from_ccnb =function( decoder) {
+ decoder.readStartElement(this.getElementLabel());
+
+ if(LOG>4)console.log('STARTED DECODING SIGNATURE ');
+
+ if (decoder.peekStartElement(CCNProtocolDTags.DigestAlgorithm)) {
+
+ if(LOG>4)console.log('DIGIEST ALGORITHM FOUND');
+ this.digestAlgorithm = decoder.readUTF8Element(CCNProtocolDTags.DigestAlgorithm);
+ }
+ if (decoder.peekStartElement(CCNProtocolDTags.Witness)) {
+ if(LOG>4)console.log('WITNESS FOUND FOUND');
+ this.Witness = decoder.readBinaryElement(CCNProtocolDTags.Witness);
+ }
+
+ //FORCE TO READ A SIGNATURE
+
+ //if(LOG>4)console.log('SIGNATURE FOUND ');
+ this.signature = decoder.readBinaryElement(CCNProtocolDTags.SignatureBits);
+ if(LOG>4)console.log('READ SIGNATURE ');
+
+ decoder.readEndElement();
+
+};
+
+
+Signature.prototype.to_ccnb= function( encoder){
+
+ if (!this.validate()) {
+ throw new Error("Cannot encode: field values missing.");
+ }
+
+ encoder.writeStartElement(this.getElementLabel());
+
+ if ((null != this.digestAlgorithm) && (!this.digestAlgorithm.equals(CCNDigestHelper.DEFAULT_DIGEST_ALGORITHM))) {
+ encoder.writeElement(CCNProtocolDTags.DigestAlgorithm, OIDLookup.getDigestOID(this.DigestAlgorithm));
+ }
+
+ if (null != this.Witness) {
+ // needs to handle null witness
+ encoder.writeElement(CCNProtocolDTags.Witness, this.Witness);
+ }
+
+ encoder.writeElement(CCNProtocolDTags.SignatureBits, this.signature);
+
+ encoder.writeEndElement();
+};
+
+Signature.prototype.getElementLabel = function() { return CCNProtocolDTags.Signature; };
+
+
+Signature.prototype.validate = function() {
+ return null != this.signature;
+};
+
+
+/**
+ * SignedInfo
+ */
+var ContentType = {DATA:0, ENCR:1, GONE:2, KEY:3, LINK:4, NACK:5};
+var ContentTypeValue = {0:0x0C04C0, 1:0x10D091,2:0x18E344,3:0x28463F,4:0x2C834A,5:0x34008A};
+var ContentTypeValueReverse = {0x0C04C0:0, 0x10D091:1,0x18E344:2,0x28463F:3,0x2C834A:4,0x34008A:5};
+
+var SignedInfo = function SignedInfo(_publisher,_timestamp,_type,_locator,_freshnessSeconds,_finalBlockID){
+
+ //TODO, Check types
+
+ this.publisher = _publisher; //publisherPublicKeyDigest
+ this.timestamp=_timestamp; // CCN Time
+ this.type=_type; // ContentType
+ this.locator =_locator;//KeyLocator
+ this.freshnessSeconds =_freshnessSeconds; // Integer
+ this.finalBlockID=_finalBlockID; //byte array
+
+};
+
+SignedInfo.prototype.setFields = function(){
+ //BASE64 -> RAW STRING
+
+ //this.locator = new KeyLocator( DataUtils.toNumbersFromString(stringCertificate) ,KeyLocatorType.CERTIFICATE );
+
+ var publicKeyHex = globalKeyManager.publicKey;
+
+ if(LOG>4)console.log('PUBLIC KEY TO WRITE TO CONTENT OBJECT IS ');
+ if(LOG>4)console.log(publicKeyHex);
+
+ var publicKeyBytes = DataUtils.toNumbers(globalKeyManager.publicKey) ;
+
+
+
+ //var stringCertificate = DataUtils.base64toString(globalKeyManager.certificate);
+
+ //if(LOG>3)console.log('string Certificate is '+stringCertificate);
+
+ //HEX -> BYTE ARRAY
+ //var publisherkey = DataUtils.toNumbers(hex_sha256(stringCertificate));
+
+ //if(LOG>3)console.log('publisher key is ');
+ //if(LOG>3)console.log(publisherkey);
+
+ var publisherKeyDigest = hex_sha256_from_bytes(publicKeyBytes);
+
+ this.publisher = new PublisherPublicKeyDigest( DataUtils.toNumbers( publisherKeyDigest ) );
+
+ //this.publisher = new PublisherPublicKeyDigest(publisherkey);
+
+ var d = new Date();
+
+ var time = d.getTime();
+
+
+ this.timestamp = new CCNTime( time );
+
+ if(LOG>4)console.log('TIME msec is');
+
+ if(LOG>4)console.log(this.timestamp.msec);
+
+ //DATA
+ this.type = 0;//0x0C04C0;//ContentTypeValue[ContentType.DATA];
+
+ //if(LOG>4)console.log('toNumbersFromString(stringCertificate) '+DataUtils.toNumbersFromString(stringCertificate));
+
+ if(LOG>4)console.log('PUBLIC KEY TO WRITE TO CONTENT OBJECT IS ');
+ if(LOG>4)console.log(publicKeyBytes);
+
+ this.locator = new KeyLocator( publicKeyBytes ,KeyLocatorType.KEY );
+
+ //this.locator = new KeyLocator( DataUtils.toNumbersFromString(stringCertificate) ,KeyLocatorType.CERTIFICATE );
+
+};
+
+SignedInfo.prototype.from_ccnb = function( decoder){
+
+ decoder.readStartElement( this.getElementLabel() );
+
+ if (decoder.peekStartElement(CCNProtocolDTags.PublisherPublicKeyDigest)) {
+ if(LOG>3) console.log('DECODING PUBLISHER KEY');
+ this.publisher = new PublisherPublicKeyDigest();
+ this.publisher.from_ccnb(decoder);
+ }
+
+ if (decoder.peekStartElement(CCNProtocolDTags.Timestamp)) {
+ this.timestamp = decoder.readDateTime(CCNProtocolDTags.Timestamp);
+ if(LOG>4)console.log('TIMESTAMP FOUND IS '+this.timestamp);
+
+ }
+
+ if (decoder.peekStartElement(CCNProtocolDTags.Type)) {
+ binType = decoder.readBinaryElement(CCNProtocolDTags.Type);//byte []
+
+
+ //TODO Implement type of Key Reading
+
+ if(LOG>4)console.log('Binary Type of of Signed Info is '+binType);
+
+ this.type = binType;
+
+
+ //TODO Implement type of Key Reading
+
+
+ if (null == this.type) {
+ throw new Error("Cannot parse signedInfo type: bytes.");
+ }
+
+ } else {
+ this.type = ContentType.DATA; // default
+ }
+
+ if (decoder.peekStartElement(CCNProtocolDTags.FreshnessSeconds)) {
+ this.freshnessSeconds = decoder.readIntegerElement(CCNProtocolDTags.FreshnessSeconds);
+ if(LOG>4) console.log('FRESHNESS IN SECONDS IS '+ this.freshnessSeconds);
+ }
+
+ if (decoder.peekStartElement(CCNProtocolDTags.FinalBlockID)) {
+ this.finalBlockID = decoder.readBinaryElement(CCNProtocolDTags.FinalBlockID);
+ }
+
+ if (decoder.peekStartElement(CCNProtocolDTags.KeyLocator)) {
+ this.locator = new KeyLocator();
+ this.locator.from_ccnb(decoder);
+ }
+
+ decoder.readEndElement();
+};
+
+SignedInfo.prototype.to_ccnb = function( encoder) {
+ if (!this.validate()) {
+ throw new Error("Cannot encode : field values missing.");
+ }
+ encoder.writeStartElement(this.getElementLabel());
+
+ if (null!=this.publisher) {
+ if(LOG>3) console.log('ENCODING PUBLISHER KEY' + this.publisher.publisherPublicKeyDigest);
+
+ this.publisher.to_ccnb(encoder);
+ }
+
+ if (null!=this.timestamp) {
+ encoder.writeDateTime(CCNProtocolDTags.Timestamp, this.timestamp );
+ }
+
+ if (null!=this.type && this.type !=0) {
+
+ encoder.writeElement(CCNProtocolDTags.type, this.type);
+ }
+
+ if (null!=this.freshnessSeconds) {
+ encoder.writeElement(CCNProtocolDTags.FreshnessSeconds, this.freshnessSeconds);
+ }
+
+ if (null!=this.finalBlockID) {
+ encoder.writeElement(CCNProtocolDTags.FinalBlockID, this.finalBlockID);
+ }
+
+ if (null!=this.locator) {
+ this.locator.to_ccnb(encoder);
+ }
+
+ encoder.writeEndElement();
+};
+
+SignedInfo.prototype.valueToType = function(){
+ //for (Entry<byte [], ContentType> entry : ContentValueTypes.entrySet()) {
+ //if (Arrays.equals(value, entry.getKey()))
+ //return entry.getValue();
+ //}
+ return null;
+
+};
+
+SignedInfo.prototype.getElementLabel = function() {
+ return CCNProtocolDTags.SignedInfo;
+};
+
+SignedInfo.prototype.validate = function() {
+ // We don't do partial matches any more, even though encoder/decoder
+ // is still pretty generous.
+ if (null ==this.publisher || null==this.timestamp ||null== this.locator)
+ return false;
+ return true;
+};
+
+/*
+ * Date Format 1.2.3
+ * (c) 2007-2009 Steven Levithan <stevenlevithan.com>
+ * MIT license
+ *
+ * Includes enhancements by Scott Trenda <scott.trenda.net>
+ * and Kris Kowal <cixar.com/~kris.kowal/>
+ *
+ * Accepts a date, a mask, or a date and a mask.
+ * Returns a formatted version of the given date.
+ * The date defaults to the current date/time.
+ * The mask defaults to dateFormat.masks.default.
+ */
+
+var DateFormat = function () {
+ var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g,
+ timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
+ timezoneClip = /[^-+\dA-Z]/g,
+ pad = function (val, len) {
+ val = String(val);
+ len = len || 2;
+ while (val.length < len) val = "0" + val;
+ return val;
+ };
+
+ // Regexes and supporting functions are cached through closure
+ return function (date, mask, utc) {
+ var dF = dateFormat;
+
+ // You can't provide utc if you skip other args (use the "UTC:" mask prefix)
+ if (arguments.length == 1 && Object.prototype.toString.call(date) == "[object String]" && !/\d/.test(date)) {
+ mask = date;
+ date = undefined;
+ }
+
+ // Passing date through Date applies Date.parse, if necessary
+ date = date ? new Date(date) : new Date;
+ if (isNaN(date)) throw SyntaxError("invalid date");
+
+ mask = String(dF.masks[mask] || mask || dF.masks["default"]);
+
+ // Allow setting the utc argument via the mask
+ if (mask.slice(0, 4) == "UTC:") {
+ mask = mask.slice(4);
+ utc = true;
+ }
+
+ var _ = utc ? "getUTC" : "get",
+ d = date[_ + "Date"](),
+ D = date[_ + "Day"](),
+ m = date[_ + "Month"](),
+ y = date[_ + "FullYear"](),
+ H = date[_ + "Hours"](),
+ M = date[_ + "Minutes"](),
+ s = date[_ + "Seconds"](),
+ L = date[_ + "Milliseconds"](),
+ o = utc ? 0 : date.getTimezoneOffset(),
+ flags = {
+ d: d,
+ dd: pad(d),
+ ddd: dF.i18n.dayNames[D],
+ dddd: dF.i18n.dayNames[D + 7],
+ m: m + 1,
+ mm: pad(m + 1),
+ mmm: dF.i18n.monthNames[m],
+ mmmm: dF.i18n.monthNames[m + 12],
+ yy: String(y).slice(2),
+ yyyy: y,
+ h: H % 12 || 12,
+ hh: pad(H % 12 || 12),
+ H: H,
+ HH: pad(H),
+ M: M,
+ MM: pad(M),
+ s: s,
+ ss: pad(s),
+ l: pad(L, 3),
+ L: pad(L > 99 ? Math.round(L / 10) : L),
+ t: H < 12 ? "a" : "p",
+ tt: H < 12 ? "am" : "pm",
+ T: H < 12 ? "A" : "P",
+ TT: H < 12 ? "AM" : "PM",
+ Z: utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""),
+ o: (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),
+ S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]
+ };
+
+ return mask.replace(token, function ($0) {
+ return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
+ });
+ };
+}();
+
+// Some common format strings
+DateFormat.masks = {
+ "default": "ddd mmm dd yyyy HH:MM:ss",
+ shortDate: "m/d/yy",
+ mediumDate: "mmm d, yyyy",
+ longDate: "mmmm d, yyyy",
+ fullDate: "dddd, mmmm d, yyyy",
+ shortTime: "h:MM TT",
+ mediumTime: "h:MM:ss TT",
+ longTime: "h:MM:ss TT Z",
+ isoDate: "yyyy-mm-dd",
+ isoTime: "HH:MM:ss",
+ isoDateTime: "yyyy-mm-dd'T'HH:MM:ss",
+ isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'"
+};
+
+// Internationalization strings
+DateFormat.i18n = {
+ dayNames: [
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
+ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
+ ],
+ monthNames: [
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
+ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
+ ]
+};
+
+// For convenience...
+Date.prototype.format = function (mask, utc) {
+ return dateFormat(this, mask, utc);
+};
+
+ /*
+ * @author: ucla-cs
+ * See COPYING for copyright and distribution information.
+ * This class represents Interest Objects
+ */
+
+var Interest = function Interest(_name,_faceInstance,_minSuffixComponents,_maxSuffixComponents,_publisherPublicKeyDigest, _exclude, _childSelector,_answerOriginKind,_scope,_interestLifetime,_nonce){
+
+ this.name = _name;
+ this.faceInstance = _faceInstance;
+ this.maxSuffixComponents = _maxSuffixComponents;
+ this.minSuffixComponents = _minSuffixComponents;
+
+ this.publisherPublicKeyDigest = _publisherPublicKeyDigest;
+ this.exclude = _exclude;
+ this.childSelector = _childSelector;
+ this.answerOriginKind = _answerOriginKind;
+ this.scope = _scope;
+ this.interestLifetime = null; // For now we don't have the ability to set an interest lifetime
+ this.nonce = _nonce;
+
+
+ this.RECURSIVE_POSTFIX = "*";
+
+ this.CHILD_SELECTOR_LEFT = 0;
+ this.CHILD_SELECTOR_RIGHT = 1;
+ this.ANSWER_CONTENT_STORE = 1;
+ this.ANSWER_GENERATED = 2;
+ this.ANSWER_STALE = 4; // Stale answer OK
+ this.MARK_STALE = 16; // Must have scope 0. Michael calls this a "hack"
+
+ this.DEFAULT_ANSWER_ORIGIN_KIND = this.ANSWER_CONTENT_STORE | this.ANSWER_GENERATED;
+
+};
+
+Interest.prototype.from_ccnb = function(/*XMLDecoder*/ decoder) {
+
+ decoder.readStartElement(CCNProtocolDTags.Interest);
+
+ this.name = new Name();
+ this.name.from_ccnb(decoder);
+
+ if (decoder.peekStartElement(CCNProtocolDTags.MinSuffixComponents)) {
+ this.minSuffixComponents = decoder.readIntegerElement(CCNProtocolDTags.MinSuffixComponents);
+ }
+
+ if (decoder.peekStartElement(CCNProtocolDTags.MaxSuffixComponents)) {
+ this.maxSuffixComponents = decoder.readIntegerElement(CCNProtocolDTags.MaxSuffixComponents);
+ }
+
+ if (decoder.peekStartElement(CCNProtocolDTags.PublisherPublicKeyDigest)) {
+ this.publisherPublicKeyDigest = new publisherPublicKeyDigest();
+ this.publisherPublicKeyDigest.from_ccnb(decoder);
+ }
+
+ if (decoder.peekStartElement(CCNProtocolDTags.Exclude)) {
+ this.exclude = new Exclude();
+ this.exclude.from_ccnb(decoder);
+ }
+
+ if (decoder.peekStartElement(CCNProtocolDTags.ChildSelector)) {
+ this.childSelector = decoder.readIntegerElement(CCNProtocolDTags.ChildSelector);
+ }
+
+ if (decoder.peekStartElement(CCNProtocolDTags.AnswerOriginKind)) {
+ // call setter to handle defaulting
+ this.answerOriginKind = decoder.readIntegerElement(CCNProtocolDTags.AnswerOriginKind);
+ }
+
+ if (decoder.peekStartElement(CCNProtocolDTags.Scope)) {
+ this.scope = decoder.readIntegerElement(CCNProtocolDTags.Scope);
+ }
+
+ if (decoder.peekStartElement(CCNProtocolDTags.InterestLifetime)) {
+ this.interestLifetime = decoder.readBinaryElement(CCNProtocolDTags.InterestLifetime);
+ }
+
+ if (decoder.peekStartElement(CCNProtocolDTags.Nonce)) {
+ this.nonce = decoder.readBinaryElement(CCNProtocolDTags.Nonce);
+ }
+
+ decoder.readEndElement();
+};
+
+Interest.prototype.to_ccnb = function(/*XMLEncoder*/ encoder){
+ //Could check if name is present
+
+ encoder.writeStartElement(CCNProtocolDTags.Interest);
+
+ this.name.to_ccnb(encoder);
+
+ if (null != this.minSuffixComponents)
+ encoder.writeElement(CCNProtocolDTags.MinSuffixComponents, this.minSuffixComponents);
+
+ if (null != this.maxSuffixComponents)
+ encoder.writeElement(CCNProtocolDTags.MaxSuffixComponents, this.maxSuffixComponents);
+
+ if (null != this.publisherPublicKeyDigest)
+ this.publisherPublicKeyDigest.to_ccnb(encoder);
+
+ if (null != this.exclude)
+ this.exclude.to_ccnb(encoder);
+
+ if (null != this.childSelector)
+ encoder.writeElement(CCNProtocolDTags.ChildSelector, this.childSelector);
+
+ //TODO Encode OriginKind
+ if (this.DEFAULT_ANSWER_ORIGIN_KIND != this.answerOriginKind && this.answerOriginKind!=null)
+ encoder.writeElement(CCNProtocolDTags.AnswerOriginKind, this.answerOriginKind);
+
+ if (null != this.scope)
+ encoder.writeElement(CCNProtocolDTags.Scope, this.scope);
+
+ if (null != this.nonce)
+ encoder.writeElement(CCNProtocolDTags.Nonce, this.nonce);
+
+ encoder.writeEndElement();
+
+};
+
+Interest.prototype.matches_name = function(/*Name*/ name){
+ var i_name = this.name.components;
+ var o_name = name.components;
+
+ // The intrest name is longer than the name we are checking it against.
+ if (i_name.length > o_name.length)
+ return false;
+
+ // Check if at least one of given components doesn't match.
+ for (var i = 0; i < i_name.length; ++i) {
+ if (!DataUtils.arraysEqual(i_name[i], o_name[i]))
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Exclude
+ */
+var Exclude = function Exclude(_values){
+
+ this.OPTIMUM_FILTER_SIZE = 100;
+
+
+ this.values = _values; //array of elements
+
+}
+
+Exclude.prototype.from_ccnb = function(/*XMLDecoder*/ decoder) {
+
+
+
+ decoder.readStartElement(this.getElementLabel());
+
+ //TODO APPLY FILTERS/EXCLUDE
+
+ //TODO
+ /*var component;
+ var any = false;
+ while ((component = decoder.peekStartElement(CCNProtocolDTags.Component)) ||
+ (any = decoder.peekStartElement(CCNProtocolDTags.Any)) ||
+ decoder.peekStartElement(CCNProtocolDTags.Bloom)) {
+ var ee = component?new ExcludeComponent(): any ? new ExcludeAny() : new BloomFilter();
+ ee.decode(decoder);
+ _values.add(ee);
+ }*/
+
+ decoder.readEndElement();
+
+};
+
+Exclude.prototype.to_ccnb=function(/*XMLEncoder*/ encoder) {
+ if (!validate()) {
+ throw new ContentEncodingException("Cannot encode " + this.getClass().getName() + ": field values missing.");
+ }
+
+ if (empty())
+ return;
+
+ encoder.writeStartElement(getElementLabel());
+
+ encoder.writeEndElement();
+
+ };
+
+Exclude.prototype.getElementLabel = function() { return CCNProtocolDTags.Exclude; };
+
+
+/**
+ * ExcludeAny
+ */
+var ExcludeAny = function ExcludeAny() {
+
+};
+
+ExcludeAny.prototype.from_ccnb = function(decoder) {
+ decoder.readStartElement(this.getElementLabel());
+ decoder.readEndElement();
+};
+
+
+ExcludeAny.prototype.to_ccnb = function( encoder) {
+ encoder.writeStartElement(this.getElementLabel());
+ encoder.writeEndElement();
+};
+
+ExcludeAny.prototype.getElementLabel=function() { return CCNProtocolDTags.Any; };
+
+
+/**
+ * ExcludeComponent
+ */
+var ExcludeComponent = function ExcludeComponent(_body) {
+
+ //TODO Check BODY is an Array of componenets.
+
+ this.body = _body
+};
+
+ExcludeComponent.prototype.from_ccnb = function( decoder) {
+ this.body = decoder.readBinaryElement(this.getElementLabel());
+};
+
+ExcludeComponent.prototype.to_ccnb = function(encoder) {
+ encoder.writeElement(this.getElementLabel(), this.body);
+};
+
+ExcludeComponent.prototype.getElementLabel = function() { return CCNProtocolDTags.Component; };
+
+/*
+ * @author: ucla-cs
+ * See COPYING for copyright and distribution information.
+ * This class represents Key Objects
+ */
+
+var Key = function Key(){
+ /* TODO: Port from PyCCN:
+ generateRSA()
+ privateToDER()
+ publicToDER()
+ privateToPEM()
+ publicToPEM()
+ fromDER()
+ fromPEM()
+ */
+}
+
+/**
+ * KeyLocator
+ */
+var KeyLocatorType = {
+ NAME:1,
+ KEY:2,
+ CERTIFICATE:3
+};
+
+var KeyLocator = function KeyLocator(_input,_type){
+
+ this.type=_type;
+
+ if (_type==KeyLocatorType.NAME){
+ this.keyName = _input;
+ }
+ else if(_type==KeyLocatorType.KEY){
+ if(LOG>4)console.log('SET KEY');
+ this.publicKey = _input;
+ }
+ else if(_type==KeyLocatorType.CERTIFICATE){
+ this.certificate = _input;
+ }
+
+};
+
+KeyLocator.prototype.from_ccnb = function(decoder) {
+
+ decoder.readStartElement(this.getElementLabel());
+
+ if (decoder.peekStartElement(CCNProtocolDTags.Key)) {
+ try {
+ encodedKey = decoder.readBinaryElement(CCNProtocolDTags.Key);
+ // This is a DER-encoded SubjectPublicKeyInfo.
+
+ //TODO FIX THIS, This should create a Key Object instead of keeping bytes
+
+ this.publicKey = encodedKey;//CryptoUtil.getPublicKey(encodedKey);
+ this.type = 2;
+
+
+ if(LOG>4) console.log('PUBLIC KEY FOUND: '+ this.publicKey);
+ //this.publicKey = encodedKey;
+
+
+ } catch (e) {
+ throw new Error("Cannot parse key: ", e);
+ }
+
+ if (null == this.publicKey) {
+ throw new Error("Cannot parse key: ");
+ }
+
+ } else if ( decoder.peekStartElement(CCNProtocolDTags.Certificate)) {
+ try {
+ encodedCert = decoder.readBinaryElement(CCNProtocolDTags.Certificate);
+
+ /*
+ * Certificates not yet working
+ */
+
+ //CertificateFactory factory = CertificateFactory.getInstance("X.509");
+ //this.certificate = (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(encodedCert));
+
+
+ this.certificate = encodedCert;
+ this.type = 3;
+
+ if(LOG>4) console.log('CERTIFICATE FOUND: '+ this.certificate);
+
+ } catch ( e) {
+ throw new Error("Cannot decode certificate: " + e);
+ }
+ if (null == this.certificate) {
+ throw new Error("Cannot parse certificate! ");
+ }
+ } else {
+ this.type = 1;
+
+
+ this.keyName = new KeyName();
+ this.keyName.from_ccnb(decoder);
+ }
+ decoder.readEndElement();
+ }
+
+
+ KeyLocator.prototype.to_ccnb = function( encoder) {
+
+ if(LOG>4) console.log('type is is ' + this.type);
+ //TODO Check if Name is missing
+ if (!this.validate()) {
+ throw new ContentEncodingException("Cannot encode " + this.getClass().getName() + ": field values missing.");
+ }
+
+
+ //TODO FIX THIS TOO
+ encoder.writeStartElement(this.getElementLabel());
+
+ if (this.type == KeyLocatorType.KEY) {
+ if(LOG>5)console.log('About to encode a public key' +this.publicKey);
+ encoder.writeElement(CCNProtocolDTags.Key, this.publicKey);
+
+ } else if (this.type == KeyLocatorType.CERTIFICATE) {
+
+ try {
+ encoder.writeElement(CCNProtocolDTags.Certificate, this.certificate);
+ } catch ( e) {
+ throw new Error("CertificateEncodingException attempting to write key locator: " + e);
+ }
+
+ } else if (this.type == KeyLocatorType.NAME) {
+
+ this.keyName.to_ccnb(encoder);
+ }
+ encoder.writeEndElement();
+
+};
+
+KeyLocator.prototype.getElementLabel = function() {
+ return CCNProtocolDTags.KeyLocator;
+};
+
+KeyLocator.prototype.validate = function() {
+ return ( (null != this.keyName) || (null != this.publicKey) || (null != this.certificate) );
+};
+
+/**
+ * KeyName is only used by KeyLocator.
+ */
+var KeyName = function KeyName() {
+
+
+ this.contentName = this.contentName;//contentName
+ this.publisherID =this.publisherID;//publisherID
+
+};
+
+KeyName.prototype.from_ccnb=function( decoder){
+
+
+ decoder.readStartElement(this.getElementLabel());
+
+ this.contentName = new Name();
+ this.contentName.from_ccnb(decoder);
+
+ if(LOG>4) console.log('KEY NAME FOUND: ');
+
+ if ( PublisherID.peek(decoder) ) {
+ this.publisherID = new PublisherID();
+ this.publisherID.from_ccnb(decoder);
+ }
+
+ decoder.readEndElement();
+};
+
+KeyName.prototype.to_ccnb = function( encoder) {
+ if (!this.validate()) {
+ throw new Error("Cannot encode : field values missing.");
+ }
+
+ encoder.writeStartElement(this.getElementLabel());
+
+ this.contentName.to_ccnb(encoder);
+ if (null != this.publisherID)
+ this.publisherID.to_ccnb(encoder);
+
+ encoder.writeEndElement();
+};
+
+KeyName.prototype.getElementLabel = function() { return CCNProtocolDTags.KeyName; };
+
+KeyName.prototype.validate = function() {
+ // DKS -- do we do recursive validation?
+ // null signedInfo ok
+ return (null != this.contentName);
+};
+
+/*
+ * @author: ucla-cs
+ * See COPYING for copyright and distribution information.
+ * This class represents Publisher and PublisherType Objects
+ */
+
+
+var PublisherType = function PublisherType(_tag){
+ this.KEY =(CCNProtocolDTags.PublisherPublicKeyDigest);
+ this.CERTIFICATE= (CCNProtocolDTags.PublisherCertificateDigest);
+ this.ISSUER_KEY= (CCNProtocolDTags.PublisherIssuerKeyDigest);
+ this.ISSUER_CERTIFICATE =(CCNProtocolDTags.PublisherIssuerCertificateDigest);
+
+ this.Tag = _tag;
+};
+
+var isTypeTagVal = function(tagVal) {
+ if ((tagVal == CCNProtocolDTags.PublisherPublicKeyDigest) ||
+ (tagVal == CCNProtocolDTags.PublisherCertificateDigest) ||
+ (tagVal == CCNProtocolDTags.PublisherIssuerKeyDigest) ||
+ (tagVal == CCNProtocolDTags.PublisherIssuerCertificateDigest)) {
+ return true;
+ }
+ return false;
+};
+
+
+
+
+var PublisherID = function PublisherID() {
+
+ this.PUBLISHER_ID_DIGEST_ALGORITHM = "SHA-256";
+ this.PUBLISHER_ID_LEN = 256/8;
+
+ //TODO, implement publisherID creation and key creation
+
+ //TODO implement generatePublicKeyDigest
+ this.publisherID =null;//= generatePublicKeyDigest(key);//ByteArray
+
+ //TODO implement generate key
+ //CryptoUtil.generateKeyID(PUBLISHER_ID_DIGEST_ALGORITHM, key);
+ this.publisherType = null;//isIssuer ? PublisherType.ISSUER_KEY : PublisherType.KEY;//publisher Type
+
+};
+
+
+PublisherID.prototype.from_ccnb = function(decoder) {
+
+ // We have a choice here of one of 4 binary element types.
+ var nextTag = decoder.peekStartElementAsLong();
+
+ if (null == nextTag) {
+ throw new Error("Cannot parse publisher ID.");
+ }
+
+ this.publisherType = new PublisherType(nextTag);
+
+ if (!isTypeTagVal(nextTag)) {
+ throw new Error("Invalid publisher ID, got unexpected type: " + nextTag);
+ }
+ this.publisherID = decoder.readBinaryElement(nextTag);
+ if (null == this.publisherID) {
+ throw new ContentDecodingException(new Error("Cannot parse publisher ID of type : " + nextTag + "."));
+ }
+};
+
+PublisherID.prototype.to_ccnb = function(encoder) {
+ if (!this.validate()) {
+ throw new Error("Cannot encode " + this.getClass().getName() + ": field values missing.");
+ }
+
+ encoder.writeElement(this.getElementLabel(), this.publisherID);
+};
+
+PublisherID.peek = function(/* XMLDecoder */ decoder) {
+
+ //Long
+ nextTag = decoder.peekStartElementAsLong();
+
+ if (null == nextTag) {
+ // on end element
+ return false;
+ }
+ return (isTypeTagVal(nextTag));
+ };
+
+PublisherID.prototype.getElementLabel = function() {
+ return this.publisherType.Tag;
+};
+
+PublisherID.prototype.validate = function(){
+ return ((null != id() && (null != type())));
+};
+
+
+
+
+/*
+ * @author: ucla-cs
+ * See COPYING for copyright and distribution information.
+ * This class represents PublisherPublicKeyDigest Objects
+ */
+var PublisherPublicKeyDigest = function PublisherPublicKeyDigest(_pkd){
+
+ //this.PUBLISHER_ID_LEN = 256/8;
+ this.PUBLISHER_ID_LEN = 512/8;
+
+
+ this.publisherPublicKeyDigest = _pkd;
+ //if( typeof _pkd == "object") this.publisherPublicKeyDigest = _pkd; // Byte Array
+ //else if( typeof _pkd == "PublicKey") ;//TODO...
+
+};
+
+PublisherPublicKeyDigest.prototype.from_ccnb = function( decoder) {
+
+ this.publisherPublicKeyDigest = decoder.readBinaryElement(this.getElementLabel());
+
+ if(LOG>4)console.log('Publisher public key digest is ' + this.publisherPublicKeyDigest);
+
+ if (null == this.publisherPublicKeyDigest) {
+ throw new Error("Cannot parse publisher key digest.");
+ }
+
+ //TODO check if the length of the PublisherPublicKeyDigest is correct ( Security reason)
+
+ if (this.publisherPublicKeyDigest.length != this.PUBLISHER_ID_LEN) {
+ if (LOG > 0)
+ console.log('LENGTH OF PUBLISHER ID IS WRONG! Expected ' + this.PUBLISHER_ID_LEN + ", got " + this.publisherPublicKeyDigest.length);
+
+ //this.publisherPublicKeyDigest = new PublisherPublicKeyDigest(this.PublisherPublicKeyDigest).PublisherKeyDigest;
+ }
+ };
+
+PublisherPublicKeyDigest.prototype.to_ccnb= function( encoder) {
+ //TODO Check that the ByteArray for the key is present
+ if (!this.validate()) {
+ throw new Error("Cannot encode : field values missing.");
+ }
+ if(LOG>3) console.log('PUBLISHER KEY DIGEST IS'+this.publisherPublicKeyDigest);
+ encoder.writeElement(this.getElementLabel(), this.publisherPublicKeyDigest);
+};
+
+PublisherPublicKeyDigest.prototype.getElementLabel = function() { return CCNProtocolDTags.PublisherPublicKeyDigest; };
+
+PublisherPublicKeyDigest.prototype.validate =function() {
+ return (null != this.publisherPublicKeyDigest);
+};
+
+/*
+ * @author: ucla-cs
+ * See COPYING for copyright and distribution information.
+ * This class represents Face Instances
+ */
+
+var NetworkProtocol = { TCP:6, UDP:17};
+
+var FaceInstance = function FaceInstance(
+ _action,
+ _publisherPublicKeyDigest,
+ _faceID,
+ _ipProto,
+ _host,
+ _port,
+ _multicastInterface,
+ _multicastTTL,
+ _freshnessSeconds){
+
+
+ this.action = _action;
+ this.publisherPublicKeyDigest = _publisherPublicKeyDigest;
+ this.faceID = _faceID;
+ this.ipProto = _ipProto;
+ this.host = _host;
+ this.Port = _port;
+ this.multicastInterface =_multicastInterface;
+ this.multicastTTL =_multicastTTL;
+ this.freshnessSeconds = _freshnessSeconds;
+
+ //action ::= ("newface" | "destroyface" | "queryface")
+ //publisherPublicKeyDigest ::= SHA-256 digest
+ //faceID ::= nonNegativeInteger
+ //ipProto ::= nonNegativeInteger [IANA protocol number, 6=TCP, 17=UDP]
+ //Host ::= textual representation of numeric IPv4 or IPv6 address
+ //Port ::= nonNegativeInteger [1..65535]
+ //MulticastInterface ::= textual representation of numeric IPv4 or IPv6 address
+ //MulticastTTL ::= nonNegativeInteger [1..255]
+ //freshnessSeconds ::= nonNegativeInteger
+
+};
+
+/**
+ * Used by NetworkObject to decode the object from a network stream.
+ * @see org.ccnx.ccn.impl.encoding.XMLEncodable
+ */
+FaceInstance.prototype.from_ccnb = function(//XMLDecoder
+ decoder) {
+
+ decoder.readStartElement(this.getElementLabel());
+
+ if (decoder.peekStartElement(CCNProtocolDTags.Action)) {
+
+ this.action = decoder.readUTF8Element(CCNProtocolDTags.Action);
+
+ }
+ if (decoder.peekStartElement(CCNProtocolDTags.PublisherPublicKeyDigest)) {
+
+ this.publisherPublicKeyDigest = new PublisherPublicKeyDigest();
+ this.publisherPublicKeyDigest.from_ccnb(decoder);
+
+ }
+ if (decoder.peekStartElement(CCNProtocolDTags.FaceID)) {
+
+ this.faceID = decoder.readIntegerElement(CCNProtocolDTags.FaceID);
+
+ }
+ if (decoder.peekStartElement(CCNProtocolDTags.IPProto)) {
+
+ //int
+ var pI = decoder.readIntegerElement(CCNProtocolDTags.IPProto);
+
+ this.ipProto = null;
+
+ if (NetworkProtocol.TCP == pI) {
+
+ this.ipProto = NetworkProtocol.TCP;
+
+ } else if (NetworkProtocol.UDP == pI) {
+
+ this.ipProto = NetworkProtocol.UDP;
+
+ } else {
+
+ throw new Error("FaceInstance.decoder. Invalid " +
+ CCNProtocolDTags.tagToString(CCNProtocolDTags.IPProto) + " field: " + pI);
+
+ }
+ }
+
+ if (decoder.peekStartElement(CCNProtocolDTags.Host)) {
+
+ this.host = decoder.readUTF8Element(CCNProtocolDTags.Host);
+
+ }
+
+ if (decoder.peekStartElement(CCNProtocolDTags.Port)) {
+ this.Port = decoder.readIntegerElement(CCNProtocolDTags.Port);
+ }
+
+ if (decoder.peekStartElement(CCNProtocolDTags.MulticastInterface)) {
+ this.multicastInterface = decoder.readUTF8Element(CCNProtocolDTags.MulticastInterface);
+ }
+
+ if (decoder.peekStartElement(CCNProtocolDTags.MulticastTTL)) {
+ this.multicastTTL = decoder.readIntegerElement(CCNProtocolDTags.MulticastTTL);
+ }
+
+ if (decoder.peekStartElement(CCNProtocolDTags.FreshnessSeconds)) {
+ this.freshnessSeconds = decoder.readIntegerElement(CCNProtocolDTags.FreshnessSeconds);
+ }
+ decoder.readEndElement();
+}
+
+/**
+ * Used by NetworkObject to encode the object to a network stream.
+ * @see org.ccnx.ccn.impl.encoding.XMLEncodable
+ */
+FaceInstance.prototype.to_ccnb = function(//XMLEncoder
+ encoder){
+
+ //if (!this.validate()) {
+ //throw new Error("Cannot encode : field values missing.");
+ //throw new Error("")
+ //}
+ encoder.writeStartElement(this.getElementLabel());
+
+ if (null != this.action && this.action.length != 0)
+ encoder.writeElement(CCNProtocolDTags.Action, this.action);
+
+ if (null != this.publisherPublicKeyDigest) {
+ this.publisherPublicKeyDigest.to_ccnb(encoder);
+ }
+ if (null != this.faceID) {
+ encoder.writeElement(CCNProtocolDTags.FaceID, this.faceID);
+ }
+ if (null != this.ipProto) {
+ //encoder.writeElement(CCNProtocolDTags.IPProto, this.IpProto.value());
+ encoder.writeElement(CCNProtocolDTags.IPProto, this.ipProto);
+ }
+ if (null != this.host && this.host.length != 0) {
+ encoder.writeElement(CCNProtocolDTags.Host, this.host);
+ }
+ if (null != this.Port) {
+ encoder.writeElement(CCNProtocolDTags.Port, this.Port);
+ }
+ if (null != this.multicastInterface && this.multicastInterface.length != 0) {
+ encoder.writeElement(CCNProtocolDTags.MulticastInterface, this.multicastInterface);
+ }
+ if (null != this.multicastTTL) {
+ encoder.writeElement(CCNProtocolDTags.MulticastTTL, this.multicastTTL);
+ }
+ if (null != this.freshnessSeconds) {
+ encoder.writeElement(CCNProtocolDTags.FreshnessSeconds, this.freshnessSeconds);
+ }
+ encoder.writeEndElement();
+}
+
+
+FaceInstance.prototype.getElementLabel= function(){return CCNProtocolDTags.FaceInstance;};
+
+
+/*
+ * @author: ucla-cs
+ * See COPYING for copyright and distribution information.
+ * This class represents Forwarding Entries
+ */
+
+var ForwardingEntry = function ForwardingEntry(
+ //ActionType
+ _action,
+ //Name
+ _prefixName,
+ //PublisherPublicKeyDigest
+ _ccndId,
+ //Integer
+ _faceID,
+ //Integer
+ _flags,
+ //Integer
+ _lifetime){
+
+
+
+ //String
+ this.action = _action;
+ //Name\
+ this.prefixName = _prefixName;
+ //PublisherPublicKeyDigest
+ this.ccndID = _ccndId;
+ //Integer
+ this.faceID = _faceID;
+ //Integer
+ this.flags = _flags;
+ //Integer
+ this.lifetime = _lifetime; // in seconds
+
+};
+
+ForwardingEntry.prototype.from_ccnb =function(
+ //XMLDecoder
+ decoder)
+ //throws ContentDecodingException
+ {
+ decoder.readStartElement(this.getElementLabel());
+ if (decoder.peekStartElement(CCNProtocolDTags.Action)) {
+ this.action = decoder.readUTF8Element(CCNProtocolDTags.Action);
+ }
+ if (decoder.peekStartElement(CCNProtocolDTags.Name)) {
+ this.prefixName = new Name();
+ this.prefixName.from_ccnb(decoder) ;
+ }
+ if (decoder.peekStartElement(CCNProtocolDTags.PublisherPublicKeyDigest)) {
+ this.CcndId = new PublisherPublicKeyDigest();
+ this.CcndId.from_ccnb(decoder);
+ }
+ if (decoder.peekStartElement(CCNProtocolDTags.FaceID)) {
+ this.faceID = decoder.readIntegerElement(CCNProtocolDTags.FaceID);
+ }
+ if (decoder.peekStartElement(CCNProtocolDTags.ForwardingFlags)) {
+ this.flags = decoder.readIntegerElement(CCNProtocolDTags.ForwardingFlags);
+ }
+ if (decoder.peekStartElement(CCNProtocolDTags.FreshnessSeconds)) {
+ this.lifetime = decoder.readIntegerElement(CCNProtocolDTags.FreshnessSeconds);
+ }
+ decoder.readEndElement();
+ };
+
+ /**
+ * Used by NetworkObject to encode the object to a network stream.
+ * @see org.ccnx.ccn.impl.encoding.XMLEncodable
+ */
+ForwardingEntry.prototype.to_ccnb =function(
+ //XMLEncoder
+encoder)
+{
+
+
+ //if (!validate()) {
+ //throw new ContentEncodingException("Cannot encode " + this.getClass().getName() + ": field values missing.");
+ //}
+ encoder.writeStartElement(this.getElementLabel());
+ if (null != this.action && this.action.length != 0)
+ encoder.writeElement(CCNProtocolDTags.Action, this.action);
+ if (null != this.prefixName) {
+ this.prefixName.to_ccnb(encoder);
+ }
+ if (null != this.CcndId) {
+ this.CcndId.to_ccnb(encoder);
+ }
+ if (null != this.faceID) {
+ encoder.writeElement(CCNProtocolDTags.FaceID, this.faceID);
+ }
+ if (null != this.flags) {
+ encoder.writeElement(CCNProtocolDTags.ForwardingFlags, this.flags);
+ }
+ if (null != this.lifetime) {
+ encoder.writeElement(CCNProtocolDTags.FreshnessSeconds, this.lifetime);
+ }
+ encoder.writeEndElement();
+ };
+
+ForwardingEntry.prototype.getElementLabel = function() { return CCNProtocolDTags.ForwardingEntry; }
+
+/*
+ * This class is used to encode ccnb binary elements (blob, type/value pairs).
+ *
+ * @author: ucla-cs
+ * See COPYING for copyright and distribution information.
+ */
+
+var XML_EXT = 0x00;
+
+var XML_TAG = 0x01;
+
+var XML_DTAG = 0x02;
+
+var XML_ATTR = 0x03;
+
+var XML_DATTR = 0x04;
+
+var XML_BLOB = 0x05;
+
+var XML_UDATA = 0x06;
+
+var XML_CLOSE = 0x0;
+
+var XML_SUBTYPE_PROCESSING_INSTRUCTIONS = 16;
+
+
+var XML_TT_BITS = 3;
+var XML_TT_MASK = ((1 << XML_TT_BITS) - 1);
+var XML_TT_VAL_BITS = XML_TT_BITS + 1;
+var XML_TT_VAL_MASK = ((1 << (XML_TT_VAL_BITS)) - 1);
+var XML_REG_VAL_BITS = 7;
+var XML_REG_VAL_MASK = ((1 << XML_REG_VAL_BITS) - 1);
+var XML_TT_NO_MORE = (1 << XML_REG_VAL_BITS); // 0x80
+var BYTE_MASK = 0xFF;
+var LONG_BYTES = 8;
+var LONG_BITS = 64;
+
+var bits_11 = 0x0000007FF;
+var bits_18 = 0x00003FFFF;
+var bits_32 = 0x0FFFFFFFF;
+
+
+var BinaryXMLEncoder = function BinaryXMLEncoder(){
+ this.ostream = new Uint8Array(10000);
+ this.offset =0;
+ this.CODEC_NAME = "Binary";
+};
+
+
+BinaryXMLEncoder.prototype.writeUString = function(/*String*/ utf8Content) {
+ this.encodeUString(this.ostream, utf8Content, XML_UDATA);
+};
+
+
+BinaryXMLEncoder.prototype.writeBlob = function(
+ /*Uint8Array*/ binaryContent
+ //, /*int*/ offset, /*int*/ length
+ ) {
+
+ if(LOG >3) console.log(binaryContent);
+
+ this.encodeBlob(this.ostream, binaryContent, this.offset, binaryContent.length);
+};
+
+
+BinaryXMLEncoder.prototype.writeStartElement = function(
+ /*String*/ tag,
+ /*TreeMap<String,String>*/ attributes
+ ) {
+
+ /*Long*/ dictionaryVal = tag; //stringToTag(tag);
+
+ if (null == dictionaryVal) {
+ this.encodeUString(this.ostream, tag, XML_TAG);
+ } else {
+ this.encodeTypeAndVal(XML_DTAG, dictionaryVal, this.ostream);
+ }
+
+ if (null != attributes) {
+ this.writeAttributes(attributes);
+ }
+};
+
+
+BinaryXMLEncoder.prototype.writeEndElement = function() {
+ this.ostream[this.offset] = XML_CLOSE;
+ this.offset += 1;
+}
+
+
+BinaryXMLEncoder.prototype.writeAttributes = function(/*TreeMap<String,String>*/ attributes) {
+ if (null == attributes) {
+ return;
+ }
+
+ // the keySet of a TreeMap is sorted.
+
+ for(var i=0; i<attributes.length;i++){
+ var strAttr = attributes[i].k;
+ var strValue = attributes[i].v;
+
+ var dictionaryAttr = stringToTag(strAttr);
+ if (null == dictionaryAttr) {
+ // not in dictionary, encode as attr
+ // compressed format wants length of tag represented as length-1
+ // to save that extra bit, as tag cannot be 0 length.
+ // encodeUString knows to do that.
+ this.encodeUString(this.ostream, strAttr, XML_ATTR);
+ } else {
+ this.encodeTypeAndVal(XML_DATTR, dictionaryAttr, this.ostream);
+ }
+ // Write value
+ this.encodeUString(this.ostream, strValue);
+
+ }
+}
+
+
+//returns a string
+stringToTag = function(/*long*/ tagVal) {
+ if ((tagVal >= 0) && (tagVal < CCNProtocolDTagsStrings.length)) {
+ return CCNProtocolDTagsStrings[tagVal];
+ } else if (tagVal == CCNProtocolDTags.CCNProtocolDataUnit) {
+ return CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT;
+ }
+ return null;
+};
+
+//returns a Long
+tagToString = function(/*String*/ tagName) {
+ // the slow way, but right now we don't care.... want a static lookup for the forward direction
+ for (var i=0; i < CCNProtocolDTagsStrings.length; ++i) {
+ if ((null != CCNProtocolDTagsStrings[i]) && (CCNProtocolDTagsStrings[i] == tagName)) {
+ return i;
+ }
+ }
+ if (CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT == tagName) {
+ return CCNProtocolDTags.CCNProtocolDataUnit;
+ }
+ return null;
+};
+
+
+BinaryXMLEncoder.prototype.writeElement = function(
+ //long
+ tag,
+ //byte[]
+ Content,
+ //TreeMap<String, String>
+ attributes
+ ) {
+ this.writeStartElement(tag, attributes);
+ // Will omit if 0-length
+
+ if(typeof Content === 'number') {
+ if(LOG>4) console.log('GOING TO WRITE THE NUMBER .charCodeAt(0) ' + Content.toString().charCodeAt(0) );
+ if(LOG>4) console.log('GOING TO WRITE THE NUMBER ' + Content.toString() );
+ if(LOG>4) console.log('type of number is ' + typeof Content.toString() );
+
+ this.writeUString(Content.toString());
+ //whatever
+ }
+ else if(typeof Content === 'string'){
+ if(LOG>4) console.log('GOING TO WRITE THE STRING ' + Content );
+ if(LOG>4) console.log('type of STRING is ' + typeof Content );
+
+ this.writeUString(Content);
+ }
+ else{
+ if(LOG>4) console.log('GOING TO WRITE A BLOB ' + Content );
+
+ this.writeBlob(Content);
+ }
+
+ this.writeEndElement();
+}
+
+
+
+var TypeAndVal = function TypeAndVal(_type,_val) {
+ this.type = _type;
+ this.val = _val;
+
+};
+
+
+BinaryXMLEncoder.prototype.encodeTypeAndVal = function(
+ //int
+ type,
+ //long
+ val,
+ //ArrayBufferView
+ ostream
+ ) {
+
+ if(LOG>4) console.log('Encoding type '+ type+ ' and value '+ val);
+
+ if(LOG>4) console.log('OFFSET IS ' + this.offset);
+
+ if ((type > XML_UDATA) || (type < 0) || (val < 0)) {
+ throw new Error("Tag and value must be positive, and tag valid.");
+ }
+
+ // Encode backwards. Calculate how many bytes we need:
+ var numEncodingBytes = this.numEncodingBytes(val);
+
+ if ((this.offset + numEncodingBytes) > ostream.length) {
+ throw new Error("Buffer space of " + (ostream.length - this.offset) +
+ " bytes insufficient to hold " +
+ numEncodingBytes + " of encoded type and value.");
+ }
+
+ // Bottom 4 bits of val go in last byte with tag.
+ ostream[this.offset + numEncodingBytes - 1] =
+ //(byte)
+ (BYTE_MASK &
+ (((XML_TT_MASK & type) |
+ ((XML_TT_VAL_MASK & val) << XML_TT_BITS))) |
+ XML_TT_NO_MORE); // set top bit for last byte
+ val = val >>> XML_TT_VAL_BITS;;
+
+ // Rest of val goes into preceding bytes, 7 bits per byte, top bit
+ // is "more" flag.
+ var i = this.offset + numEncodingBytes - 2;
+ while ((0 != val) && (i >= this.offset)) {
+ ostream[i] = //(byte)
+ (BYTE_MASK & (val & XML_REG_VAL_MASK)); // leave top bit unset
+ val = val >>> XML_REG_VAL_BITS;
+ --i;
+ }
+ if (val != 0) {
+ throw new Error( "This should not happen: miscalculated encoding");
+ //Log.warning(Log.FAC_ENCODING, "This should not happen: miscalculated encoding length, have " + val + " left.");
+ }
+ this.offset+= numEncodingBytes;
+
+ return numEncodingBytes;
+};
+
+
+BinaryXMLEncoder.prototype.encodeUString = function(
+ //OutputStream
+ ostream,
+ //String
+ ustring,
+ //byte
+ type) {
+
+ if ((null == ustring) || (ustring.length == 0)) {
+ return;
+ }
+
+ if(LOG>3) console.log("The string to write is ");
+ if(LOG>3) console.log(ustring);
+
+ //COPY THE STRING TO AVOID PROBLEMS
+ strBytes = new Array(ustring.length);
+
+ for (i = 0; i < ustring.length; i++) //in InStr.ToCharArray())
+ {
+ if(LOG>3) console.log('ustring[' + i + '] = ' + ustring[i]);
+ strBytes[i] = ustring.charCodeAt(i);
+ }
+
+ //strBytes = DataUtils.getBytesFromUTF8String(ustring);
+
+ this.encodeTypeAndVal(type,
+ (((type == XML_TAG) || (type == XML_ATTR)) ?
+ (strBytes.length-1) :
+ strBytes.length), ostream);
+
+ if(LOG>3) console.log("THE string to write is ");
+
+ if(LOG>3) console.log(strBytes);
+
+ this.writeString(strBytes,this.offset);
+ this.offset+= strBytes.length;
+};
+
+
+
+BinaryXMLEncoder.prototype.encodeBlob = function(
+ //OutputStream
+ ostream,
+ //Uint8Array
+ blob,
+ //int
+ offset,
+ //int
+ length) {
+
+
+ if (null == blob)
+ return;
+
+ if(LOG>4) console.log('LENGTH OF XML_BLOB IS '+length);
+
+ /*blobCopy = new Array(blob.Length);
+
+ for (i = 0; i < blob.length; i++) //in InStr.ToCharArray())
+ {
+ blobCopy[i] = blob[i];
+ }*/
+
+ this.encodeTypeAndVal(XML_BLOB, length, ostream, offset);
+
+ this.writeBlobArray(blob, this.offset);
+ this.offset += length;
+};
+
+var ENCODING_LIMIT_1_BYTE = ((1 << (XML_TT_VAL_BITS)) - 1);
+var ENCODING_LIMIT_2_BYTES = ((1 << (XML_TT_VAL_BITS + XML_REG_VAL_BITS)) - 1);
+var ENCODING_LIMIT_3_BYTES = ((1 << (XML_TT_VAL_BITS + 2 * XML_REG_VAL_BITS)) - 1);
+
+BinaryXMLEncoder.prototype.numEncodingBytes = function(
+ //long
+ x) {
+ if (x <= ENCODING_LIMIT_1_BYTE) return (1);
+ if (x <= ENCODING_LIMIT_2_BYTES) return (2);
+ if (x <= ENCODING_LIMIT_3_BYTES) return (3);
+
+ var numbytes = 1;
+
+ // Last byte gives you XML_TT_VAL_BITS
+ // Remainder each give you XML_REG_VAL_BITS
+ x = x >>> XML_TT_VAL_BITS;
+ while (x != 0) {
+ numbytes++;
+ x = x >>> XML_REG_VAL_BITS;
+ }
+ return (numbytes);
+};
+
+BinaryXMLEncoder.prototype.writeDateTime = function(
+ //String
+ tag,
+ //CCNTime
+ dateTime) {
+
+ if(LOG>4)console.log('ENCODING DATE with LONG VALUE');
+ if(LOG>4)console.log(dateTime.msec);
+
+ //var binarydate = DataUtils.unsignedLongToByteArray( Math.round((dateTime.msec/1000) * 4096) );
+
+
+ //parse to hex
+ var binarydate = Math.round((dateTime.msec/1000) * 4096).toString(16) ;
+
+ //HACK
+ var binarydate = DataUtils.toNumbers( '0'.concat(binarydate,'0')) ;
+
+
+ if(LOG>4)console.log('ENCODING DATE with BINARY VALUE');
+ if(LOG>4)console.log(binarydate);
+ if(LOG>4)console.log('ENCODING DATE with BINARY VALUE(HEX)');
+ if(LOG>4)console.log(DataUtils.toHex(binarydate));
+
+ this.writeElement(tag, binarydate);
+};
+
+BinaryXMLEncoder.prototype.writeString = function(
+ //String
+ input,
+ //CCNTime
+ offset) {
+
+ if(typeof input === 'string'){
+ //console.log('went here');
+ if(LOG>4) console.log('GOING TO WRITE A STRING');
+ if(LOG>4) console.log(input);
+
+ for (i = 0; i < input.length; i++) {
+ if(LOG>4) console.log('input.charCodeAt(i)=' + input.charCodeAt(i));
+ this.ostream[this.offset+i] = (input.charCodeAt(i));
+ }
+ }
+ else{
+ if(LOG>4) console.log('GOING TO WRITE A STRING IN BINARY FORM');
+ if(LOG>4) console.log(input);
+
+ this.writeBlobArray(input);
+ }
+ /*
+ else if(typeof input === 'object'){
+
+ }
+ */
+};
+
+
+BinaryXMLEncoder.prototype.writeBlobArray = function(
+ //Uint8Array
+ blob,
+ //int
+ offset) {
+
+ if(LOG>4) console.log('GOING TO WRITE A BLOB');
+
+ /*for (var i = 0; i < Blob.length; i++) {
+ this.ostream[this.offset+i] = Blob[i];
+ }*/
+ this.ostream.set(blob, this.offset);
+};
+
+
+BinaryXMLEncoder.prototype.getReducedOstream = function() {
+ return this.ostream.subarray(0, this.offset);
+};
+
+
+/*
+ * This class is used to decode ccnb binary elements (blob, type/value pairs).
+ *
+ * @author: ucla-cs
+ * See COPYING for copyright and distribution information.
+ */
+
+var XML_EXT = 0x00;
+
+var XML_TAG = 0x01;
+
+var XML_DTAG = 0x02;
+
+var XML_ATTR = 0x03;
+
+var XML_DATTR = 0x04;
+
+var XML_BLOB = 0x05;
+
+var XML_UDATA = 0x06;
+
+var XML_CLOSE = 0x0;
+
+var XML_SUBTYPE_PROCESSING_INSTRUCTIONS = 16;
+
+
+var XML_TT_BITS = 3;
+var XML_TT_MASK = ((1 << XML_TT_BITS) - 1);
+var XML_TT_VAL_BITS = XML_TT_BITS + 1;
+var XML_TT_VAL_MASK = ((1 << (XML_TT_VAL_BITS)) - 1);
+var XML_REG_VAL_BITS = 7;
+var XML_REG_VAL_MASK = ((1 << XML_REG_VAL_BITS) - 1);
+var XML_TT_NO_MORE = (1 << XML_REG_VAL_BITS); // 0x80
+var BYTE_MASK = 0xFF;
+var LONG_BYTES = 8;
+var LONG_BITS = 64;
+
+var bits_11 = 0x0000007FF;
+var bits_18 = 0x00003FFFF;
+var bits_32 = 0x0FFFFFFFF;
+
+
+
+//returns a string
+tagToString = function(/*long*/ tagVal) {
+ if ((tagVal >= 0) && (tagVal < CCNProtocolDTagsStrings.length)) {
+ return CCNProtocolDTagsStrings[tagVal];
+ } else if (tagVal == CCNProtocolDTags.CCNProtocolDataUnit) {
+ return CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT;
+ }
+ return null;
+};
+
+//returns a Long
+stringToTag = function(/*String*/ tagName) {
+ // the slow way, but right now we don't care.... want a static lookup for the forward direction
+ for (var i=0; i < CCNProtocolDTagsStrings.length; ++i) {
+ if ((null != CCNProtocolDTagsStrings[i]) && (CCNProtocolDTagsStrings[i] == tagName)) {
+ return i;
+ }
+ }
+ if (CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT == tagName) {
+ return CCNProtocolDTags.CCNProtocolDataUnit;
+ }
+ return null;
+};
+
+//console.log(stringToTag(64));
+var BinaryXMLDecoder = function BinaryXMLDecoder(istream){
+ var MARK_LEN=512;
+ var DEBUG_MAX_LEN = 32768;
+
+ this.istream = istream;
+ this.offset = 0;
+};
+
+BinaryXMLDecoder.prototype.readAttributes = function(
+ //TreeMap<String,String>
+ attributes){
+
+ if (null == attributes) {
+ return;
+ }
+
+ try {
+
+ //this.TypeAndVal
+ nextTV = this.peekTypeAndVal();
+
+ while ((null != nextTV) && ((XML_ATTR == nextTV.type()) ||
+ (XML_DATTR == nextTV.type()))) {
+
+ //this.TypeAndVal
+ thisTV = this.decodeTypeAndVal();
+
+ var attributeName = null;
+ if (XML_ATTR == thisTV.type()) {
+
+ attributeName = this.decodeUString(thisTV.val()+1);
+
+ } else if (XML_DATTR == thisTV.type()) {
+ // DKS TODO are attributes same or different dictionary?
+ attributeName = tagToString(thisTV.val());
+ if (null == attributeName) {
+ throw new ContentDecodingException(new Error("Unknown DATTR value" + thisTV.val()));
+ }
+ }
+
+ var attributeValue = this.decodeUString();
+
+ attributes.put(attributeName, attributeValue);
+
+ nextTV = this.peekTypeAndVal();
+ }
+
+ } catch ( e) {
+
+ throw new ContentDecodingException(new Error("readStartElement", e));
+ }
+};
+
+
+BinaryXMLDecoder.prototype.initializeDecoding = function() {
+ //if (!this.istream.markSupported()) {
+ //throw new IllegalArgumentException(this.getClass().getName() + ": input stream must support marking!");
+ //}
+}
+
+BinaryXMLDecoder.prototype.readStartDocument = function(){
+ // Currently no start document in binary encoding.
+ }
+
+BinaryXMLDecoder.prototype.readEndDocument = function() {
+ // Currently no end document in binary encoding.
+ };
+
+BinaryXMLDecoder.prototype.readStartElement = function(
+ //String
+ startTag,
+ //TreeMap<String, String>
+ attributes) {
+
+
+ //NOT SURE
+ //if(typeof startTag == 'number')
+ //startTag = tagToString(startTag);
+
+ //TypeAndVal
+ tv = this.decodeTypeAndVal();
+
+ if (null == tv) {
+ throw new ContentDecodingException(new Error("Expected start element: " + startTag + " got something not a tag."));
+ }
+
+ //String
+ decodedTag = null;
+ //console.log(tv);
+ //console.log(typeof tv);
+
+ //console.log(XML_TAG);
+ if (tv.type() == XML_TAG) {
+ //console.log('got here');
+ //Log.info(Log.FAC_ENCODING, "Unexpected: got tag in readStartElement; looking for tag " + startTag + " got length: " + (int)tv.val()+1);
+ // Tag value represents length-1 as tags can never be empty.
+ var valval ;
+ if(typeof tv.val() == 'string'){
+ valval = (parseInt(tv.val())) + 1;
+ }
+ else
+ valval = (tv.val())+ 1;
+
+ //console.log('valval is ' +valval);
+
+ decodedTag = this.decodeUString(valval);
+
+ } else if (tv.type() == XML_DTAG) {
+ //console.log('gothere');
+ //console.log(tv.val());
+ //decodedTag = tagToString(tv.val());
+ //console.log()
+ decodedTag = tv.val();
+ }
+
+ //console.log(decodedTag);
+ //console.log('startTag is '+startTag);
+
+
+ if ((null == decodedTag) || decodedTag != startTag ) {
+ console.log('expecting '+ startag + ' but got '+ decodedTag);
+ throw new ContentDecodingException(new Error("Expected start element: " + startTag + " got: " + decodedTag + "(" + tv.val() + ")"));
+ }
+
+ // DKS: does not read attributes out of stream if caller doesn't
+ // ask for them. Should possibly peek and skip over them regardless.
+ // TODO: fix this
+ if (null != attributes) {
+ readAttributes(attributes);
+ }
+ }
+
+
+BinaryXMLDecoder.prototype.readAttributes = function(
+ //TreeMap<String,String>
+ attributes) {
+
+ if (null == attributes) {
+ return;
+ }
+
+ try {
+ // Now need to get attributes.
+ //TypeAndVal
+ nextTV = this.peekTypeAndVal();
+
+ while ((null != nextTV) && ((XML_ATTR == nextTV.type()) ||
+ (XML_DATTR == nextTV.type()))) {
+
+ // Decode this attribute. First, really read the type and value.
+ //this.TypeAndVal
+ thisTV = this.decodeTypeAndVal();
+
+ //String
+ attributeName = null;
+ if (XML_ATTR == thisTV.type()) {
+ // Tag value represents length-1 as attribute names cannot be empty.
+ var valval ;
+ if(typeof tv.val() == 'string'){
+ valval = (parseInt(tv.val())) + 1;
+ }
+ else
+ valval = (tv.val())+ 1;
+
+ attributeName = this.decodeUString(valval);
+
+ } else if (XML_DATTR == thisTV.type()) {
+ // DKS TODO are attributes same or different dictionary?
+ attributeName = tagToString(thisTV.val());
+ if (null == attributeName) {
+ throw new ContentDecodingException(new Error("Unknown DATTR value" + thisTV.val()));
+ }
+ }
+ // Attribute values are always UDATA
+ //String
+ attributeValue = this.decodeUString();
+
+ //
+ attributes.push([attributeName, attributeValue]);
+
+ nextTV = this.peekTypeAndVal();
+ }
+ } catch ( e) {
+ throw new ContentDecodingException(new Error("readStartElement", e));
+ }
+};
+
+//returns a string
+BinaryXMLDecoder.prototype.peekStartElementAsString = function() {
+ //this.istream.mark(MARK_LEN);
+
+ //String
+ decodedTag = null;
+ var previousOffset = this.offset;
+ try {
+ // Have to distinguish genuine errors from wrong tags. Could either use
+ // a special exception subtype, or redo the work here.
+ //this.TypeAndVal
+ tv = this.decodeTypeAndVal();
+
+ if (null != tv) {
+
+ if (tv.type() == XML_TAG) {
+ /*if (tv.val()+1 > DEBUG_MAX_LEN) {
+ throw new ContentDecodingException(new Error("Decoding error: length " + tv.val()+1 + " longer than expected maximum length!")(;
+ }*/
+
+ // Tag value represents length-1 as tags can never be empty.
+ var valval ;
+ if(typeof tv.val() == 'string'){
+ valval = (parseInt(tv.val())) + 1;
+ }
+ else
+ valval = (tv.val())+ 1;
+
+ decodedTag = this.decodeUString(valval);
+
+ //Log.info(Log.FAC_ENCODING, "Unexpected: got text tag in peekStartElement; length: " + valval + " decoded tag = " + decodedTag);
+
+ } else if (tv.type() == XML_DTAG) {
+ decodedTag = tagToString(tv.val());
+ }
+
+ } // else, not a type and val, probably an end element. rewind and return false.
+
+ } catch ( e) {
+
+ } finally {
+ try {
+ this.offset = previousOffset;
+ } catch ( e) {
+ Log.logStackTrace(Log.FAC_ENCODING, Level.WARNING, e);
+ throw new ContentDecodingException(new Error("Cannot reset stream! " + e.getMessage(), e));
+ }
+ }
+ return decodedTag;
+};
+
+BinaryXMLDecoder.prototype.peekStartElement = function(
+ //String
+ startTag) {
+ //String
+ if(typeof startTag == 'string'){
+ decodedTag = this.peekStartElementAsString();
+
+ if ((null != decodedTag) && decodedTag == startTag) {
+ return true;
+ }
+ return false;
+ }
+ else if(typeof startTag == 'number'){
+ decodedTag = this.peekStartElementAsLong();
+ if ((null != decodedTag) && decodedTag == startTag) {
+ return true;
+ }
+ return false;
+ }
+ else{
+ throw new ContentDecodingException(new Error("SHOULD BE STRING OR NUMBER"));
+ }
+}
+//returns Long
+BinaryXMLDecoder.prototype.peekStartElementAsLong = function() {
+ //this.istream.mark(MARK_LEN);
+
+ //Long
+ decodedTag = null;
+
+ var previousOffset = this.offset;
+
+ try {
+ // Have to distinguish genuine errors from wrong tags. Could either use
+ // a special exception subtype, or redo the work here.
+ //this.TypeAndVal
+ tv = this.decodeTypeAndVal();
+
+ if (null != tv) {
+
+ if (tv.type() == XML_TAG) {
+ if (tv.val()+1 > DEBUG_MAX_LEN) {
+ throw new ContentDecodingException(new Error("Decoding error: length " + tv.val()+1 + " longer than expected maximum length!"));
+ }
+
+ var valval ;
+ if(typeof tv.val() == 'string'){
+ valval = (parseInt(tv.val())) + 1;
+ }
+ else
+ valval = (tv.val())+ 1;
+
+ // Tag value represents length-1 as tags can never be empty.
+ //String
+ strTag = this.decodeUString(valval);
+
+ decodedTag = stringToTag(strTag);
+
+ //Log.info(Log.FAC_ENCODING, "Unexpected: got text tag in peekStartElement; length: " + valval + " decoded tag = " + decodedTag);
+
+ } else if (tv.type() == XML_DTAG) {
+ decodedTag = tv.val();
+ }
+
+ } // else, not a type and val, probably an end element. rewind and return false.
+
+ } catch ( e) {
+
+ } finally {
+ try {
+ //this.istream.reset();
+ this.offset = previousOffset;
+ } catch ( e) {
+ Log.logStackTrace(Log.FAC_ENCODING, Level.WARNING, e);
+ throw new Error("Cannot reset stream! " + e.getMessage(), e);
+ }
+ }
+ return decodedTag;
+ };
+
+
+// returns a byte[]
+BinaryXMLDecoder.prototype.readBinaryElement = function(
+ //long
+ startTag,
+ //TreeMap<String, String>
+ attributes){
+ //byte []
+ blob = null;
+
+ this.readStartElement(startTag, attributes);
+ blob = this.readBlob();
+
+
+ return blob;
+
+};
+
+
+BinaryXMLDecoder.prototype.readEndElement = function(){
+ if(LOG>4)console.log('this.offset is '+this.offset);
+
+ var next = this.istream[this.offset];
+
+ this.offset++;
+ //read();
+
+ if(LOG>4)console.log('XML_CLOSE IS '+XML_CLOSE);
+ if(LOG>4)console.log('next is '+next);
+
+ if (next != XML_CLOSE) {
+ console.log("Expected end element, got: " + next);
+ throw new ContentDecodingException(new Error("Expected end element, got: " + next));
+ }
+ };
+
+
+//String
+BinaryXMLDecoder.prototype.readUString = function(){
+ //String
+ ustring = this.decodeUString();
+ this.readEndElement();
+ return ustring;
+
+ };
+
+
+//returns a byte[]
+BinaryXMLDecoder.prototype.readBlob = function() {
+ //byte []
+
+ blob = this.decodeBlob();
+ this.readEndElement();
+ return blob;
+
+ };
+
+
+//CCNTime
+BinaryXMLDecoder.prototype.readDateTime = function(
+ //long
+ startTag) {
+ //byte []
+
+ var byteTimestamp = this.readBinaryElement(startTag);
+
+ //var lontimestamp = DataUtils.byteArrayToUnsignedLong(byteTimestamp);
+
+ var byteTimestamp = DataUtils.toHex(byteTimestamp);
+
+
+ var byteTimestamp = parseInt(byteTimestamp, 16);
+
+ lontimestamp = (byteTimestamp/ 4096) * 1000;
+
+ //if(lontimestamp<0) lontimestamp = - lontimestamp;
+
+ if(LOG>3) console.log('DECODED DATE WITH VALUE');
+ if(LOG>3) console.log(lontimestamp);
+
+
+ //CCNTime
+ timestamp = new CCNTime(lontimestamp);
+ //timestamp.setDateBinary(byteTimestamp);
+
+ if (null == timestamp) {
+ throw new ContentDecodingException(new Error("Cannot parse timestamp: " + DataUtils.printHexBytes(byteTimestamp)));
+ }
+ return timestamp;
+};
+
+BinaryXMLDecoder.prototype.decodeTypeAndVal = function() {
+
+ /*int*/var type = -1;
+ /*long*/var val = 0;
+ /*boolean*/var more = true;
+
+ do {
+
+ var next = this.istream[this.offset ];
+
+
+ if (next < 0) {
+ return null;
+ }
+
+ if ((0 == next) && (0 == val)) {
+ return null;
+ }
+
+ more = (0 == (next & XML_TT_NO_MORE));
+
+ if (more) {
+ val = val << XML_REG_VAL_BITS;
+ val |= (next & XML_REG_VAL_MASK);
+ } else {
+
+ type = next & XML_TT_MASK;
+ val = val << XML_TT_VAL_BITS;
+ val |= ((next >>> XML_TT_BITS) & XML_TT_VAL_MASK);
+ }
+
+ this.offset++;
+
+ } while (more);
+
+ if(LOG>3)console.log('TYPE is '+ type + ' VAL is '+ val);
+
+ return new TypeAndVal(type, val);
+};
+
+
+
+//TypeAndVal
+BinaryXMLDecoder.peekTypeAndVal = function() {
+ //TypeAndVal
+ tv = null;
+
+ //this.istream.mark(LONG_BYTES*2);
+
+ var previousOffset = this.offset;
+
+ try {
+ tv = this.decodeTypeAndVal();
+ } finally {
+ //this.istream.reset();
+ this.offset = previousOffset;
+ }
+
+ return tv;
+};
+
+
+//Uint8Array
+BinaryXMLDecoder.prototype.decodeBlob = function(
+ //int
+ blobLength) {
+
+ if(null == blobLength){
+ //TypeAndVal
+ tv = this.decodeTypeAndVal();
+
+ var valval ;
+
+ if(typeof tv.val() == 'string'){
+ valval = (parseInt(tv.val()));
+ }
+ else
+ valval = (tv.val());
+
+ //console.log('valval here is ' + valval);
+ return this.decodeBlob(valval);
+ }
+
+ //
+ //Uint8Array
+ var bytes = this.istream.subarray(this.offset, this.offset+ blobLength);
+ this.offset += blobLength;
+
+ return bytes;
+};
+
+var count =0;
+
+//String
+BinaryXMLDecoder.prototype.decodeUString = function(
+ //int
+ byteLength) {
+
+ /*
+ console.log('COUNT IS '+count);
+ console.log('INPUT BYTELENGTH IS '+byteLength);
+ count++;
+ if(null == byteLength|| undefined == byteLength){
+ console.log("!!!!");
+ tv = this.decodeTypeAndVal();
+ var valval ;
+ if(typeof tv.val() == 'string'){
+ valval = (parseInt(tv.val()));
+ }
+ else
+ valval = (tv.val());
+
+ if(LOG>4) console.log('valval is ' + valval);
+ byteLength= this.decodeUString(valval);
+
+ //if(LOG>4) console.log('byte Length found in type val is '+ byteLength.charCodeAt(0));
+ byteLength = parseInt(byteLength);
+
+
+ //byteLength = byteLength.charCodeAt(0);
+ //if(LOG>4) console.log('byte Length found in type val is '+ byteLength);
+ }
+ if(LOG>4)console.log('byteLength is '+byteLength);
+ if(LOG>4)console.log('type of byteLength is '+typeof byteLength);
+
+ stringBytes = this.decodeBlob(byteLength);
+
+ //console.log('String bytes are '+ stringBytes);
+ //console.log('stringBytes);
+
+ if(LOG>4)console.log('byteLength is '+byteLength);
+ if(LOG>4)console.log('this.offset is '+this.offset);
+
+ tempBuffer = this.istream.slice(this.offset, this.offset+byteLength);
+ if(LOG>4)console.log('TEMPBUFFER IS' + tempBuffer);
+ if(LOG>4)console.log( tempBuffer);
+
+ if(LOG>4)console.log('ADDING to offset value' + byteLength);
+ this.offset+= byteLength;
+ //if(LOG>3)console.log('read the String' + tempBuffer.toString('ascii'));
+ //return tempBuffer.toString('ascii');//
+
+
+ //if(LOG>3)console.log( 'STRING READ IS '+ DataUtils.getUTF8StringFromBytes(stringBytes) ) ;
+ //if(LOG>3)console.log( 'STRING READ IS '+ DataUtils.getUTF8StringFromBytes(tempBuffer) ) ;
+ //if(LOG>3)console.log(DataUtils.getUTF8StringFromBytes(tempBuffer) ) ;
+ //return DataUtils.getUTF8StringFromBytes(tempBuffer);
+
+ if(LOG>3)console.log( 'STRING READ IS '+ DataUtils.toString(stringBytes) ) ;
+ if(LOG>3)console.log( 'TYPE OF STRING READ IS '+ typeof DataUtils.toString(stringBytes) ) ;
+
+ return DataUtils.toString(stringBytes);*/
+
+ if(null == byteLength ){
+ var tempStreamPosition = this.offset;
+
+ //TypeAndVal
+ tv = this.decodeTypeAndVal();
+
+ if(LOG>3)console.log('TV is '+tv);
+ if(LOG>3)console.log(tv);
+
+ if(LOG>3)console.log('Type of TV is '+typeof tv);
+
+ if ((null == tv) || (XML_UDATA != tv.type())) { // if we just have closers left, will get back null
+ //if (Log.isLoggable(Log.FAC_ENCODING, Level.FINEST))
+ //Log.finest(Log.FAC_ENCODING, "Expected UDATA, got " + ((null == tv) ? " not a tag " : tv.type()) + ", assuming elided 0-length blob.");
+
+ this.offset = tempStreamPosition;
+
+ return "";
+ }
+
+ return this.decodeUString(tv.val());
+ }
+ else{
+ //byte []
+ stringBytes = this.decodeBlob(byteLength);
+
+ //return DataUtils.getUTF8StringFromBytes(stringBytes);
+ return DataUtils.toString(stringBytes);
+
+ }
+};
+
+
+
+
+//OBject containg a pair of type and value
+var TypeAndVal = function TypeAndVal(_type,_val) {
+ this.t = _type;
+ this.v = _val;
+};
+
+TypeAndVal.prototype.type = function(){
+ return this.t;
+};
+
+TypeAndVal.prototype.val = function(){
+ return this.v;
+};
+
+
+
+
+BinaryXMLDecoder.prototype.readIntegerElement =function(
+ //String
+ startTag) {
+
+ //String
+ if(LOG>4) console.log('READING INTEGER '+ startTag);
+ if(LOG>4) console.log('TYPE OF '+ typeof startTag);
+
+ strVal = this.readUTF8Element(startTag);
+
+ return parseInt(strVal);
+};
+
+
+BinaryXMLDecoder.prototype.readUTF8Element =function(
+ //String
+ startTag,
+ //TreeMap<String, String>
+ attributes) {
+ //throws Error where name == "ContentDecodingException"
+
+ this.readStartElement(startTag, attributes); // can't use getElementText, can't get attributes
+ //String
+ strElementText = this.readUString();
+ return strElementText;
+};
+
+
+/*
+ * Set the offset into the input, used for the next read.
+ */
+BinaryXMLDecoder.prototype.seek = function(
+ //int
+ offset) {
+ this.offset = offset;
+}
+
+/*
+ * Call with: throw new ContentDecodingException(new Error("message")).
+ */
+function ContentDecodingException(error) {
+ this.message = error.message;
+ // Copy lineNumber, etc. from where new Error was called.
+ for (var prop in error)
+ this[prop] = error[prop];
+}
+ContentDecodingException.prototype = new Error();
+ContentDecodingException.prototype.name = "ContentDecodingException";
+
+
+/*
+ * This class uses BinaryXMLDecoder to follow the structure of a ccnb binary element to
+ * determine its end.
+ *
+ * @author: ucla-cs
+ * See COPYING for copyright and distribution information.
+ */
+
+var BinaryXMLStructureDecoder = function BinaryXMLDecoder() {
+ this.gotElementEnd = false;
+ this.offset = 0;
+ this.level = 0;
+ this.state = BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE;
+ this.headerStartOffset = 0;
+ this.readBytesEndOffset = 0;
+};
+
+BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE = 0;
+BinaryXMLStructureDecoder.READ_BYTES = 1;
+
+/*
+ * Continue scanning input starting from this.offset. If found the end of the element
+ * which started at offset 0 then return true, else false.
+ * If this returns false, you should read more into input and call again.
+ * You have to pass in input each time because the array could be reallocated.
+ * This throws an exception for badly formed ccnb.
+ */
+BinaryXMLStructureDecoder.prototype.findElementEnd = function(
+ // byte array
+ input)
+{
+ if (this.gotElementEnd)
+ // Someone is calling when we already got the end.
+ return true;
+
+ var decoder = new BinaryXMLDecoder(input);
+
+ while (true) {
+ if (this.offset >= input.length)
+ // All the cases assume we have some input.
+ return false;
+
+ switch (this.state) {
+ case BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE:
+ // First check for XML_CLOSE.
+ if (this.offset == this.headerStartOffset && input[this.offset] == XML_CLOSE) {
+ ++this.offset;
+ // Close the level.
+ --this.level;
+ if (this.level == 0)
+ // Finished.
+ return true;
+ if (this.level < 0)
+ throw new Error("BinaryXMLStructureDecoder: Unexepected close tag at offset " +
+ (this.offset - 1));
+
+ // Get ready for the next header.
+ this.headerStartOffset = this.offset;
+ break;
+ }
+
+ while (true) {
+ if (this.offset >= input.length)
+ return false;
+ if (input[this.offset++] & XML_TT_NO_MORE)
+ // Break and read the header.
+ break;
+ }
+
+ decoder.seek(this.headerStartOffset);
+ var typeAndVal = decoder.decodeTypeAndVal();
+ if (typeAndVal == null)
+ throw new Error("BinaryXMLStructureDecoder: Can't read header starting at offset " +
+ this.headerStartOffset);
+
+ // Set the next state based on the type.
+ var type = typeAndVal.t;
+ if (type == XML_DATTR)
+ // We already consumed the item. READ_HEADER_OR_CLOSE again.
+ // ccnb has rules about what must follow an attribute, but we are just scanning.
+ this.headerStartOffset = this.offset;
+ else if (type == XML_DTAG || type == XML_EXT) {
+ // Start a new level and READ_HEADER_OR_CLOSE again.
+ ++this.level;
+ this.headerStartOffset = this.offset;
+ }
+ else if (type == XML_TAG || type == XML_ATTR) {
+ if (type == XML_TAG)
+ // Start a new level and read the tag.
+ ++this.level;
+ // Minimum tag or attribute length is 1.
+ this.readBytesEndOffset = this.offset + typeAndVal.v + 1;
+ this.state = BinaryXMLStructureDecoder.READ_BYTES;
+ // ccnb has rules about what must follow an attribute, but we are just scanning.
+ }
+ else if (type == XML_BLOB || type == XML_UDATA) {
+ this.readBytesEndOffset = this.offset + typeAndVal.v;
+ this.state = BinaryXMLStructureDecoder.READ_BYTES;
+ }
+ else
+ throw new Error("BinaryXMLStructureDecoder: Unrecognized header type " + type);
+ break;
+
+ case BinaryXMLStructureDecoder.READ_BYTES:
+ if (input.length < this.readBytesEndOffset) {
+ // Need more.
+ this.offset = input.length;
+ return false;
+ }
+ // Got the bytes. Read a new header or close.
+ this.offset = this.readBytesEndOffset;
+ this.headerStartOffset = this.offset;
+ this.state = BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE;
+ break;
+
+ default:
+ // We don't expect this to happen.
+ throw new Error("BinaryXMLStructureDecoder: Unrecognized state " + this.state);
+ }
+ }
+};
+
+/*
+ * This class contains utilities to help parse the data
+ * author: ucla-cs
+ * See COPYING for copyright and distribution information.
+ */
+
+var DataUtils = function DataUtils(){
+
+
+};
+
+
+/*
+ * NOTE THIS IS CURRENTLY NOT BEHING USED
+ *
+ */
+
+DataUtils.keyStr = "ABCDEFGHIJKLMNOP" +
+ "QRSTUVWXYZabcdef" +
+ "ghijklmnopqrstuv" +
+ "wxyz0123456789+/" +
+ "=";
+
+
+/**
+ * Raw String to Base 64
+ */
+DataUtils.stringtoBase64=function stringtoBase64(input) {
+ input = escape(input);
+ var output = "";
+ var chr1, chr2, chr3 = "";
+ var enc1, enc2, enc3, enc4 = "";
+ var i = 0;
+
+ do {
+ chr1 = input.charCodeAt(i++);
+ chr2 = input.charCodeAt(i++);
+ chr3 = input.charCodeAt(i++);
+
+ enc1 = chr1 >> 2;
+ enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
+ enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
+ enc4 = chr3 & 63;
+
+ if (isNaN(chr2)) {
+ enc3 = enc4 = 64;
+ } else if (isNaN(chr3)) {
+ enc4 = 64;
+ }
+
+ output = output +
+ DataUtils.keyStr.charAt(enc1) +
+ DataUtils.keyStr.charAt(enc2) +
+ DataUtils.keyStr.charAt(enc3) +
+ DataUtils.keyStr.charAt(enc4);
+ chr1 = chr2 = chr3 = "";
+ enc1 = enc2 = enc3 = enc4 = "";
+ } while (i < input.length);
+
+ return output;
+ }
+
+/**
+ * Base 64 to Raw String
+ */
+DataUtils.base64toString = function base64toString(input) {
+ var output = "";
+ var chr1, chr2, chr3 = "";
+ var enc1, enc2, enc3, enc4 = "";
+ var i = 0;
+
+ // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
+ var base64test = /[^A-Za-z0-9\+\/\=]/g;
+ /* Test for invalid characters. */
+ if (base64test.exec(input)) {
+ alert("There were invalid base64 characters in the input text.\n" +
+ "Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\n" +
+ "Expect errors in decoding.");
+ }
+
+ input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
+
+ do {
+ enc1 = DataUtils.keyStr.indexOf(input.charAt(i++));
+ enc2 = DataUtils.keyStr.indexOf(input.charAt(i++));
+ enc3 = DataUtils.keyStr.indexOf(input.charAt(i++));
+ enc4 = DataUtils.keyStr.indexOf(input.charAt(i++));
+
+ chr1 = (enc1 << 2) | (enc2 >> 4);
+ chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
+ chr3 = ((enc3 & 3) << 6) | enc4;
+
+ output = output + String.fromCharCode(chr1);
+
+ if (enc3 != 64) {
+ output = output + String.fromCharCode(chr2);
+ }
+ if (enc4 != 64) {
+ output = output + String.fromCharCode(chr3);
+ }
+
+ chr1 = chr2 = chr3 = "";
+ enc1 = enc2 = enc3 = enc4 = "";
+
+ } while (i < input.length);
+
+ return unescape(output);
+ };
+
+//byte []
+
+/**
+ * NOT WORKING!!!!!
+ *
+ * Unsiged Long Number to Byte Array
+ */
+
+ /*
+DataUtils.unsignedLongToByteArray= function( value) {
+
+ if(LOG>4)console.log('INPUT IS '+value);
+
+ if( 0 == value )
+ return [0];
+
+ if( 0 <= value && value <= 0x00FF ) {
+ //byte []
+ var bb = new Array(1);
+ bb[0] = (value & 0x00FF);
+ return bb;
+ }
+
+ if(LOG>4) console.log('type of value is '+typeof value);
+ if(LOG>4) console.log('value is '+value);
+ //byte []
+ var out = null;
+ //int
+ var offset = -1;
+ for(var i = 7; i >=0; --i) {
+ //byte
+ console.log(i);
+ console.log('value is '+value);
+ console.log('(value >> (i * 8)) '+ (value >> (i * 8)) );
+ console.log(' ((value >> (i * 8)) & 0xFF) '+ ((value >> (i * 8)) & 0xFF) );
+
+ var b = ((value >> (i * 8)) & 0xFF) ;
+
+ if(LOG>4) console.log('b is '+b);
+
+ if( out == null && b != 0 ) {
+ //out = new byte[i+1];
+ out = new Array(i+1);
+ offset = i;
+ }
+
+ if( out != null )
+ out[ offset - i ] = b;
+ }
+ if(LOG>4)console.log('OUTPUT IS ');
+ if(LOG>4)console.log(out);
+ return out;
+}
+*/
+
+/**
+ * NOT WORKING!!!!!
+ *
+ * Unsiged Long Number to Byte Array
+ *//*
+DataUtils.byteArrayToUnsignedLong = function(//final byte []
+ src) {
+ if(LOG>4) console.log('INPUT IS ');
+ if(LOG>4) console.log(src);
+
+ var value = 0;
+ for(var i = 0; i < src.length; i++) {
+ value = value << 8;
+ // Java will assume the byte is signed, so extend it and trim it.
+
+
+ var b = ((src[i]) & 0xFF );
+ value |= b;
+ }
+
+ if(LOG>4) console.log('OUTPUT IS ');
+
+ if(LOG>4) console.log(value);
+
+ return value;
+ }*/
+
+
+/**
+ * Hex String to Byte Array
+ */
+ //THIS IS NOT WORKING
+/*
+DataUtils.HexStringtoByteArray = function(str) {
+ var byteArray = [];
+ for (var i = 0; i < str.length; i++)
+ if (str.charCodeAt(i) <= 0x7F)
+ byteArray.push(str.charCodeAt(i));
+ else {
+ var h = encodeURIComponent(str.charAt(i)).substr(1).split('%');
+ for (var j = 0; j < h.length; j++)
+ byteArray.push(parseInt(h[j], 16));
+ }
+ return byteArray;
+};
+*/
+
+/**
+ * Uint8Array to Hex String
+ */
+//http://ejohn.org/blog/numbers-hex-and-colors/
+DataUtils.toHex = function(arguments){
+ if (LOG>4) console.log('ABOUT TO CONVERT '+ arguments);
+ //console.log(arguments);
+ var ret = "";
+ for ( var i = 0; i < arguments.length; i++ )
+ ret += (arguments[i] < 16 ? "0" : "") + arguments[i].toString(16);
+ if (LOG>4) console.log('Converted to: ' + ret);
+ return ret; //.toUpperCase();
+}
+
+/**
+ * Raw string to hex string.
+ */
+DataUtils.stringToHex = function(arguments){
+ var ret = "";
+ for (var i = 0; i < arguments.length; ++i) {
+ var value = arguments.charCodeAt(i);
+ ret += (value < 16 ? "0" : "") + value.toString(16);
+ }
+ return ret;
+}
+
+/**
+ * Uint8Array to raw string.
+ */
+DataUtils.toString = function(arguments){
+ //console.log(arguments);
+ var ret = "";
+ for ( var i = 0; i < arguments.length; i++ )
+ ret += String.fromCharCode(arguments[i]);
+ return ret;
+}
+
+/**
+ * Hex String to Uint8Array.
+ */
+DataUtils.toNumbers = function(str) {
+ if (typeof str == 'string') {
+ var ret = new Uint8Array(Math.floor(str.length / 2));
+ var i = 0;
+ str.replace(/(..)/g, function(str) {
+ ret[i++] = parseInt(str, 16);
+ });
+ return ret;
+ }
+}
+
+/**
+ * Hex String to raw string.
+ */
+DataUtils.hexToRawString = function(str) {
+ if(typeof str =='string') {
+ var ret = "";
+ str.replace(/(..)/g, function(s) {
+ ret += String.fromCharCode(parseInt(s, 16));
+ });
+ return ret;
+ }
+}
+
+/**
+ * Raw String to Uint8Array.
+ */
+DataUtils.toNumbersFromString = function( str ){
+ var bytes = new Uint8Array(str.length);
+ for(var i=0;i<str.length;i++)
+ bytes[i] = str.charCodeAt(i);
+ return bytes;
+}
+
+/*
+ * Return a new Uint8Array which is the Uint8Array concatenated with raw String str.
+ */
+DataUtils.concatFromString = function(array, str) {
+ var bytes = new Uint8Array(array.length + str.length);
+ bytes.set(array);
+ for (var i = 0; i < str.length; ++i)
+ bytes[array.length + i] = str.charCodeAt(i);
+ return bytes;
+}
+
+// TODO: Use TextEncoder and return Uint8Array.
+DataUtils.encodeUtf8 = function (string) {
+ string = string.replace(/\r\n/g,"\n");
+ var utftext = "";
+
+ for (var n = 0; n < string.length; n++) {
+
+ var c = string.charCodeAt(n);
+
+ if (c < 128) {
+ utftext += String.fromCharCode(c);
+ }
+ else if((c > 127) && (c < 2048)) {
+ utftext += String.fromCharCode((c >> 6) | 192);
+ utftext += String.fromCharCode((c & 63) | 128);
+ }
+ else {
+ utftext += String.fromCharCode((c >> 12) | 224);
+ utftext += String.fromCharCode(((c >> 6) & 63) | 128);
+ utftext += String.fromCharCode((c & 63) | 128);
+ }
+
+ }
+
+ return utftext;
+ };
+
+// TODO: Take Uint8Array and use TextDecoder.
+DataUtils.decodeUtf8 = function (utftext) {
+ var string = "";
+ var i = 0;
+ var c = 0;
+ var c1 = 0;
+ var c2 = 0;
+
+ while ( i < utftext.length ) {
+
+ c = utftext.charCodeAt(i);
+
+ if (c < 128) {
+ string += String.fromCharCode(c);
+ i++;
+ }
+ else if((c > 191) && (c < 224)) {
+ c2 = utftext.charCodeAt(i+1);
+ string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
+ i += 2;
+ }
+ else {
+ c2 = utftext.charCodeAt(i+1);
+ var c3 = utftext.charCodeAt(i+2);
+ string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
+ i += 3;
+ }
+
+ }
+
+ return string;
+ };
+
+//NOT WORKING
+/*
+DataUtils.getUTF8StringFromBytes = function(bytes) {
+
+ bytes = toString(bytes);
+
+ var ix = 0;
+
+ if( bytes.slice(0,3) == "\xEF\xBB\xBF") {
+ ix = 3;
+ }
+
+ var string = "";
+ for( ; ix < bytes.length; ix++ ) {
+ var byte1 = bytes[ix].charCodeAt(0);
+ if( byte1 < 0x80 ) {
+ string += String.fromCharCode(byte1);
+ } else if( byte1 >= 0xC2 && byte1 < 0xE0 ) {
+ var byte2 = bytes[++ix].charCodeAt(0);
+ string += String.fromCharCode(((byte1&0x1F)<<6) + (byte2&0x3F));
+ } else if( byte1 >= 0xE0 && byte1 < 0xF0 ) {
+ var byte2 = bytes[++ix].charCodeAt(0);
+ var byte3 = bytes[++ix].charCodeAt(0);
+ string += String.fromCharCode(((byte1&0xFF)<<12) + ((byte2&0x3F)<<6) + (byte3&0x3F));
+ } else if( byte1 >= 0xF0 && byte1 < 0xF5) {
+ var byte2 = bytes[++ix].charCodeAt(0);
+ var byte3 = bytes[++ix].charCodeAt(0);
+ var byte4 = bytes[++ix].charCodeAt(0);
+ var codepoint = ((byte1&0x07)<<18) + ((byte2&0x3F)<<12)+ ((byte3&0x3F)<<6) + (byte4&0x3F);
+ codepoint -= 0x10000;
+ string += String.fromCharCode(
+ (codepoint>>10) + 0xD800,
+ (codepoint&0x3FF) + 0xDC00
+ );
+ }
+ }
+
+ return string;
+}*/
+
+/**
+ * Return true if a1 and a2 are the same length with equal elements.
+ */
+DataUtils.arraysEqual = function(a1, a2){
+ if (a1.length != a2.length)
+ return false;
+
+ for (var i = 0; i < a1.length; ++i) {
+ if (a1[i] != a2[i])
+ return false;
+ }
+
+ return true;
+};
+
+/*
+ * Convert the big endian Uint8Array to an unsigned int.
+ * Don't check for overflow.
+ */
+DataUtils.bigEndianToUnsignedInt = function(bytes) {
+ var result = 0;
+ for (var i = 0; i < bytes.length; ++i) {
+ result <<= 8;
+ result += bytes[i];
+ }
+ return result;
+};
+
+/*
+ * Convert the int value to a new big endian Uint8Array and return.
+ * If value is 0 or negative, return Uint8Array(0).
+ */
+DataUtils.nonNegativeIntToBigEndian = function(value) {
+ if (value <= 0)
+ return new Uint8Array(0);
+
+ // Assume value is not over 64 bits.
+ var result = new Uint8Array(8);
+ var i = 0;
+ while (value != 0) {
+ result[i++] = value & 0xff;
+ value >>= 8;
+ }
+ return result.subarray(0, i);
+};
+
+var MimeTypes = {
+ /*
+ * Based on filename, return an object with properties contentType and charset.
+ */
+ getContentTypeAndCharset: function(filename) {
+ var iDot = filename.lastIndexOf('.');
+ if (iDot >= 0) {
+ var extension = filename.substr(iDot + 1, filename.length - iDot - 1);
+ var contentType = MimeTypes[extension];
+ if (contentType != null) {
+ var charset = "ISO-8859-1";
+ if (contentType.split('/')[0] == "text")
+ charset = "utf-8";
+ return { contentType: contentType, charset: charset };
+ }
+ }
+
+ // Use a default.
+ return { contentType: "text/html", charset: "utf-8" };
+ },
+
+ /* For each file extension, define the MIME type.
+ */
+ "323": "text/h323",
+ "%": "application/x-trash",
+ "~": "application/x-trash",
+ "3gp": "video/3gpp",
+ "7z": "application/x-7z-compressed",
+ "abw": "application/x-abiword",
+ "ai": "application/postscript",
+ "aif": "audio/x-aiff",
+ "aifc": "audio/x-aiff",
+ "aiff": "audio/x-aiff",
+ "alc": "chemical/x-alchemy",
+ "amr": "audio/amr",
+ "anx": "application/annodex",
+ "apk": "application/vnd.android.package-archive",
+ "art": "image/x-jg",
+ "asc": "text/plain",
+ "asf": "video/x-ms-asf",
+ "asx": "video/x-ms-asf",
+ "asn": "chemical/x-ncbi-asn1",
+ "atom": "application/atom+xml",
+ "atomcat": "application/atomcat+xml",
+ "atomsrv": "application/atomserv+xml",
+ "au": "audio/basic",
+ "snd": "audio/basic",
+ "avi": "video/x-msvideo",
+ "awb": "audio/amr-wb",
+ "axa": "audio/annodex",
+ "axv": "video/annodex",
+ "b": "chemical/x-molconn-Z",
+ "bak": "application/x-trash",
+ "bat": "application/x-msdos-program",
+ "bcpio": "application/x-bcpio",
+ "bib": "text/x-bibtex",
+ "bin": "application/octet-stream",
+ "bmp": "image/x-ms-bmp",
+ "boo": "text/x-boo",
+ "book": "application/x-maker",
+ "brf": "text/plain",
+ "bsd": "chemical/x-crossfire",
+ "c": "text/x-csrc",
+ "c++": "text/x-c++src",
+ "c3d": "chemical/x-chem3d",
+ "cab": "application/x-cab",
+ "cac": "chemical/x-cache",
+ "cache": "chemical/x-cache",
+ "cap": "application/cap",
+ "cascii": "chemical/x-cactvs-binary",
+ "cat": "application/vnd.ms-pki.seccat",
+ "cbin": "chemical/x-cactvs-binary",
+ "cbr": "application/x-cbr",
+ "cbz": "application/x-cbz",
+ "cc": "text/x-c++src",
+ "cda": "application/x-cdf",
+ "cdf": "application/x-cdf",
+ "cdr": "image/x-coreldraw",
+ "cdt": "image/x-coreldrawtemplate",
+ "cdx": "chemical/x-cdx",
+ "cdy": "application/vnd.cinderella",
+ "cer": "chemical/x-cerius",
+ "chm": "chemical/x-chemdraw",
+ "chrt": "application/x-kchart",
+ "cif": "chemical/x-cif",
+ "class": "application/java-vm",
+ "cls": "text/x-tex",
+ "cmdf": "chemical/x-cmdf",
+ "cml": "chemical/x-cml",
+ "cod": "application/vnd.rim.cod",
+ "com": "application/x-msdos-program",
+ "cpa": "chemical/x-compass",
+ "cpio": "application/x-cpio",
+ "cpp": "text/x-c++src",
+ "cpt": "image/x-corelphotopaint",
+ "cr2": "image/x-canon-cr2",
+ "crl": "application/x-pkcs7-crl",
+ "crt": "application/x-x509-ca-cert",
+ "crw": "image/x-canon-crw",
+ "csd": "audio/csound",
+ "csf": "chemical/x-cache-csf",
+ "csh": "application/x-csh",
+ "csml": "chemical/x-csml",
+ "csm": "chemical/x-csml",
+ "css": "text/css",
+ "csv": "text/csv",
+ "ctab": "chemical/x-cactvs-binary",
+ "ctx": "chemical/x-ctx",
+ "cu": "application/cu-seeme",
+ "cub": "chemical/x-gaussian-cube",
+ "cxf": "chemical/x-cxf",
+ "cef": "chemical/x-cxf",
+ "cxx": "text/x-c++src",
+ "d": "text/x-dsrc",
+ "dat": "application/x-ns-proxy-autoconfig",
+ "davmount": "application/davmount+xml",
+ "dcr": "application/x-director",
+ "deb": "application/x-debian-package",
+ "dif": "video/dv",
+ "dv": "video/dv",
+ "diff": "text/x-diff",
+ "patch": "text/x-diff",
+ "dir": "application/x-director",
+ "djvu": "image/vnd.djvu",
+ "djv": "image/vnd.djvu",
+ "dl": "video/dl",
+ "dll": "application/x-msdos-program",
+ "dmg": "application/x-apple-diskimage",
+ "dms": "application/x-dms",
+ "doc": "application/msword",
+ "docm": "application/vnd.ms-word.document.macroEnabled.12",
+ "docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
+ "dot": "application/msword",
+ "dotm": "application/vnd.ms-word.template.macroEnabled.12",
+ "dotx": "application/vnd.openxmlformats-officedocument.wordprocessingml.template",
+ "dvi": "application/x-dvi",
+ "dxr": "application/x-director",
+ "emb": "chemical/x-embl-dl-nucleotide",
+ "embl": "chemical/x-embl-dl-nucleotide",
+ "eml": "message/rfc822",
+ "eps": "application/postscript",
+ "eps2": "application/postscript",
+ "eps3": "application/postscript",
+ "epsf": "application/postscript",
+ "epsi": "application/postscript",
+ "erf": "image/x-epson-erf",
+ "es": "application/ecmascript",
+ "etx": "text/x-setext",
+ "exe": "application/x-msdos-program",
+ "ez": "application/andrew-inset",
+ "fb": "application/x-maker",
+ "fbdoc": "application/x-maker",
+ "fch": "chemical/x-gaussian-checkpoint",
+ "fchk": "chemical/x-gaussian-checkpoint",
+ "fig": "application/x-xfig",
+ "flac": "audio/flac",
+ "fli": "video/fli",
+ "flv": "video/x-flv",
+ "fm": "application/x-maker",
+ "frame": "application/x-maker",
+ "frm": "application/x-maker",
+ "gal": "chemical/x-gaussian-log",
+ "gam": "chemical/x-gamess-input",
+ "gamin": "chemical/x-gamess-input",
+ "gan": "application/x-ganttproject",
+ "gau": "chemical/x-gaussian-input",
+ "gcd": "text/x-pcs-gcd",
+ "gcf": "application/x-graphing-calculator",
+ "gcg": "chemical/x-gcg8-sequence",
+ "gen": "chemical/x-genbank",
+ "gf": "application/x-tex-gf",
+ "gif": "image/gif",
+ "gjc": "chemical/x-gaussian-input",
+ "gjf": "chemical/x-gaussian-input",
+ "gl": "video/gl",
+ "gnumeric": "application/x-gnumeric",
+ "gpt": "chemical/x-mopac-graph",
+ "gsf": "application/x-font",
+ "gsm": "audio/x-gsm",
+ "gtar": "application/x-gtar",
+ "h": "text/x-chdr",
+ "h++": "text/x-c++hdr",
+ "hdf": "application/x-hdf",
+ "hh": "text/x-c++hdr",
+ "hin": "chemical/x-hin",
+ "hpp": "text/x-c++hdr",
+ "hqx": "application/mac-binhex40",
+ "hs": "text/x-haskell",
+ "hta": "application/hta",
+ "htc": "text/x-component",
+ "htm": "text/html",
+ "html": "text/html",
+ "hxx": "text/x-c++hdr",
+ "ica": "application/x-ica",
+ "ice": "x-conference/x-cooltalk",
+ "ico": "image/x-icon",
+ "ics": "text/calendar",
+ "icz": "text/calendar",
+ "ief": "image/ief",
+ "igs": "model/iges",
+ "iges": "model/iges",
+ "iii": "application/x-iphone",
+ "info": "application/x-info",
+ "inp": "chemical/x-gamess-input",
+ "ins": "application/x-internet-signup",
+ "iso": "application/x-iso9660-image",
+ "isp": "application/x-internet-signup",
+ "istr": "chemical/x-isostar",
+ "ist": "chemical/x-isostar",
+ "jad": "text/vnd.sun.j2me.app-descriptor",
+ "jam": "application/x-jam",
+ "jar": "application/java-archive",
+ "java": "text/x-java",
+ "jdx": "chemical/x-jcamp-dx",
+ "dx": "chemical/x-jcamp-dx",
+ "jmz": "application/x-jmol",
+ "jng": "image/x-jng",
+ "jnlp": "application/x-java-jnlp-file",
+ "jpe": "image/jpeg",
+ "jpeg": "image/jpeg",
+ "jpg": "image/jpeg",
+ "js": "application/javascript",
+ "json": "application/json",
+ "kar": "audio/midi",
+ "key": "application/pgp-keys",
+ "kil": "application/x-killustrator",
+ "kin": "chemical/x-kinemage",
+ "kml": "application/vnd.google-earth.kml+xml",
+ "kmz": "application/vnd.google-earth.kmz",
+ "kpr": "application/x-kpresenter",
+ "kpt": "application/x-kpresenter",
+ "ksp": "application/x-kspread",
+ "kwd": "application/x-kword",
+ "kwt": "application/x-kword",
+ "latex": "application/x-latex",
+ "lha": "application/x-lha",
+ "lhs": "text/x-literate-haskell",
+ "lin": "application/bbolin",
+ "lsf": "video/x-la-asf",
+ "lsx": "video/x-la-asf",
+ "ltx": "text/x-tex",
+ "lyx": "application/x-lyx",
+ "lzh": "application/x-lzh",
+ "lzx": "application/x-lzx",
+ "m3g": "application/m3g",
+ "m3u": "audio/mpegurl",
+ "m3u8": "application/x-mpegURL",
+ "m4a": "audio/mpeg",
+ "maker": "application/x-maker",
+ "man": "application/x-troff-man",
+ "manifest": "text/cache-manifest",
+ "mcif": "chemical/x-mmcif",
+ "mcm": "chemical/x-macmolecule",
+ "mdb": "application/msaccess",
+ "me": "application/x-troff-me",
+ "mesh": "model/mesh",
+ "mid": "audio/midi",
+ "midi": "audio/midi",
+ "mif": "application/x-mif",
+ "mm": "application/x-freemind",
+ "mmd": "chemical/x-macromodel-input",
+ "mmod": "chemical/x-macromodel-input",
+ "mmf": "application/vnd.smaf",
+ "mml": "text/mathml",
+ "mng": "video/x-mng",
+ "moc": "text/x-moc",
+ "mol": "chemical/x-mdl-molfile",
+ "mol2": "chemical/x-mol2",
+ "moo": "chemical/x-mopac-out",
+ "mop": "chemical/x-mopac-input",
+ "mopcrt": "chemical/x-mopac-input",
+ "movie": "video/x-sgi-movie",
+ "mp2": "audio/mpeg",
+ "mp3": "audio/mpeg",
+ "mp4": "video/mp4",
+ "mpc": "chemical/x-mopac-input",
+ "mpe": "video/mpeg",
+ "mpeg": "video/mpeg",
+ "mpega": "audio/mpeg",
+ "mpg": "video/mpeg",
+ "mpga": "audio/mpeg",
+ "mph": "application/x-comsol",
+ "mpv": "video/x-matroska",
+ "mkv": "video/x-matroska",
+ "ms": "application/x-troff-ms",
+ "msh": "model/mesh",
+ "msi": "application/x-msi",
+ "mvb": "chemical/x-mopac-vib",
+ "mxf": "application/mxf",
+ "mxu": "video/vnd.mpegurl",
+ "nb": "application/mathematica",
+ "nbp": "application/mathematica",
+ "nc": "application/x-netcdf",
+ "nef": "image/x-nikon-nef",
+ "nwc": "application/x-nwc",
+ "o": "application/x-object",
+ "oda": "application/oda",
+ "odb": "application/vnd.oasis.opendocument.database",
+ "odc": "application/vnd.oasis.opendocument.chart",
+ "odf": "application/vnd.oasis.opendocument.formula",
+ "odg": "application/vnd.oasis.opendocument.graphics",
+ "odi": "application/vnd.oasis.opendocument.image",
+ "odm": "application/vnd.oasis.opendocument.text-master",
+ "odp": "application/vnd.oasis.opendocument.presentation",
+ "ods": "application/vnd.oasis.opendocument.spreadsheet",
+ "odt": "application/vnd.oasis.opendocument.text",
+ "oga": "audio/ogg",
+ "ogg": "audio/ogg",
+ "ogv": "video/ogg",
+ "ogx": "application/ogg",
+ "old": "application/x-trash",
+ "one": "application/onenote",
+ "onepkg": "application/onenote",
+ "onetmp": "application/onenote",
+ "onetoc2": "application/onenote",
+ "orc": "audio/csound",
+ "orf": "image/x-olympus-orf",
+ "otg": "application/vnd.oasis.opendocument.graphics-template",
+ "oth": "application/vnd.oasis.opendocument.text-web",
+ "otp": "application/vnd.oasis.opendocument.presentation-template",
+ "ots": "application/vnd.oasis.opendocument.spreadsheet-template",
+ "ott": "application/vnd.oasis.opendocument.text-template",
+ "oza": "application/x-oz-application",
+ "p": "text/x-pascal",
+ "pas": "text/x-pascal",
+ "p7r": "application/x-pkcs7-certreqresp",
+ "pac": "application/x-ns-proxy-autoconfig",
+ "pat": "image/x-coreldrawpattern",
+ "pbm": "image/x-portable-bitmap",
+ "pcap": "application/cap",
+ "pcf": "application/x-font",
+ "pcx": "image/pcx",
+ "pdb": "chemical/x-pdb",
+ "ent": "chemical/x-pdb",
+ "pdf": "application/pdf",
+ "pfa": "application/x-font",
+ "pfb": "application/x-font",
+ "pgm": "image/x-portable-graymap",
+ "pgn": "application/x-chess-pgn",
+ "pgp": "application/pgp-signature",
+ "php": "application/x-httpd-php",
+ "php3": "application/x-httpd-php3",
+ "php3p": "application/x-httpd-php3-preprocessed",
+ "php4": "application/x-httpd-php4",
+ "php5": "application/x-httpd-php5",
+ "phps": "application/x-httpd-php-source",
+ "pht": "application/x-httpd-php",
+ "phtml": "application/x-httpd-php",
+ "pk": "application/x-tex-pk",
+ "pl": "text/x-perl",
+ "pm": "text/x-perl",
+ "pls": "audio/x-scpls",
+ "png": "image/png",
+ "pnm": "image/x-portable-anymap",
+ "pot": "text/plain",
+ "potm": "application/vnd.ms-powerpoint.template.macroEnabled.12",
+ "potx": "application/vnd.openxmlformats-officedocument.presentationml.template",
+ "ppam": "application/vnd.ms-powerpoint.addin.macroEnabled.12",
+ "ppm": "image/x-portable-pixmap",
+ "pps": "application/vnd.ms-powerpoint",
+ "ppsm": "application/vnd.ms-powerpoint.slideshow.macroEnabled.12",
+ "ppsx": "application/vnd.openxmlformats-officedocument.presentationml.slideshow",
+ "ppt": "application/vnd.ms-powerpoint",
+ "pptm": "application/vnd.ms-powerpoint.presentation.macroEnabled.12",
+ "pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
+ "prf": "application/pics-rules",
+ "prt": "chemical/x-ncbi-asn1-ascii",
+ "ps": "application/postscript",
+ "psd": "image/x-photoshop",
+ "py": "text/x-python",
+ "pyc": "application/x-python-code",
+ "pyo": "application/x-python-code",
+ "qgs": "application/x-qgis",
+ "qt": "video/quicktime",
+ "mov": "video/quicktime",
+ "qtl": "application/x-quicktimeplayer",
+ "ra": "audio/x-realaudio",
+ "ram": "audio/x-pn-realaudio",
+ "rar": "application/rar",
+ "ras": "image/x-cmu-raster",
+ "rb": "application/x-ruby",
+ "rd": "chemical/x-mdl-rdfile",
+ "rdf": "application/rdf+xml",
+ "rdp": "application/x-rdp",
+ "rgb": "image/x-rgb",
+ "rhtml": "application/x-httpd-eruby",
+ "rm": "audio/x-pn-realaudio",
+ "roff": "application/x-troff",
+ "ros": "chemical/x-rosdal",
+ "rpm": "application/x-redhat-package-manager",
+ "rss": "application/rss+xml",
+ "rtf": "application/rtf",
+ "rtx": "text/richtext",
+ "rxn": "chemical/x-mdl-rxnfile",
+ "scala": "text/x-scala",
+ "sci": "application/x-scilab",
+ "sce": "application/x-scilab",
+ "sco": "audio/csound",
+ "scr": "application/x-silverlight",
+ "sct": "text/scriptlet",
+ "wsc": "text/scriptlet",
+ "sd": "chemical/x-mdl-sdfile",
+ "sdf": "chemical/x-mdl-sdfile",
+ "sd2": "audio/x-sd2",
+ "sda": "application/vnd.stardivision.draw",
+ "sdc": "application/vnd.stardivision.calc",
+ "sdd": "application/vnd.stardivision.impress",
+ "sds": "application/vnd.stardivision.chart",
+ "sdw": "application/vnd.stardivision.writer",
+ "ser": "application/java-serialized-object",
+ "sfv": "text/x-sfv",
+ "sgf": "application/x-go-sgf",
+ "sgl": "application/vnd.stardivision.writer-global",
+ "sh": "application/x-sh",
+ "shar": "application/x-shar",
+ "shp": "application/x-qgis",
+ "shtml": "text/html",
+ "shx": "application/x-qgis",
+ "sid": "audio/prs.sid",
+ "sik": "application/x-trash",
+ "silo": "model/mesh",
+ "sis": "application/vnd.symbian.install",
+ "sisx": "x-epoc/x-sisx-app",
+ "sit": "application/x-stuffit",
+ "sitx": "application/x-stuffit",
+ "skd": "application/x-koan",
+ "skm": "application/x-koan",
+ "skp": "application/x-koan",
+ "skt": "application/x-koan",
+ "sldm": "application/vnd.ms-powerpoint.slide.macroEnabled.12",
+ "sldx": "application/vnd.openxmlformats-officedocument.presentationml.slide",
+ "smi": "application/smil",
+ "smil": "application/smil",
+ "spc": "chemical/x-galactic-spc",
+ "spl": "application/futuresplash",
+ "spx": "audio/ogg",
+ "sql": "application/x-sql",
+ "src": "application/x-wais-source",
+ "stc": "application/vnd.sun.xml.calc.template",
+ "std": "application/vnd.sun.xml.draw.template",
+ "sti": "application/vnd.sun.xml.impress.template",
+ "stl": "application/sla",
+ "stw": "application/vnd.sun.xml.writer.template",
+ "sty": "text/x-tex",
+ "sv4cpio": "application/x-sv4cpio",
+ "sv4crc": "application/x-sv4crc",
+ "svg": "image/svg+xml",
+ "svgz": "image/svg+xml",
+ "sw": "chemical/x-swissprot",
+ "swf": "application/x-shockwave-flash",
+ "swfl": "application/x-shockwave-flash",
+ "sxc": "application/vnd.sun.xml.calc",
+ "sxd": "application/vnd.sun.xml.draw",
+ "sxg": "application/vnd.sun.xml.writer.global",
+ "sxi": "application/vnd.sun.xml.impress",
+ "sxm": "application/vnd.sun.xml.math",
+ "sxw": "application/vnd.sun.xml.writer",
+ "t": "application/x-troff",
+ "tar": "application/x-tar",
+ "taz": "application/x-gtar-compressed",
+ "tcl": "application/x-tcl",
+ "tk": "text/x-tcl",
+ "tex": "text/x-tex",
+ "texinfo": "application/x-texinfo",
+ "texi": "application/x-texinfo",
+ "text": "text/plain",
+ "tgf": "chemical/x-mdl-tgf",
+ "tgz": "application/x-gtar-compressed",
+ "thmx": "application/vnd.ms-officetheme",
+ "tiff": "image/tiff",
+ "tif": "image/tiff",
+ "tm": "text/texmacs",
+ "torrent": "application/x-bittorrent",
+ "tr": "application/x-troff",
+ "ts": "video/MP2T",
+ "tsp": "application/dsptype",
+ "tsv": "text/tab-separated-values",
+ "txt": "text/plain",
+ "udeb": "application/x-debian-package",
+ "uls": "text/iuls",
+ "ustar": "application/x-ustar",
+ "val": "chemical/x-ncbi-asn1-binary",
+ "aso": "chemical/x-ncbi-asn1-binary",
+ "vcd": "application/x-cdlink",
+ "vcf": "text/x-vcard",
+ "vcs": "text/x-vcalendar",
+ "vmd": "chemical/x-vmd",
+ "vms": "chemical/x-vamas-iso14976",
+ "vrm": "x-world/x-vrml",
+ "vsd": "application/vnd.visio",
+ "wad": "application/x-doom",
+ "wav": "audio/x-wav",
+ "wax": "audio/x-ms-wax",
+ "wbmp": "image/vnd.wap.wbmp",
+ "wbxml": "application/vnd.wap.wbxml",
+ "webm": "video/webm",
+ "wk": "application/x-123",
+ "wm": "video/x-ms-wm",
+ "wma": "audio/x-ms-wma",
+ "wmd": "application/x-ms-wmd",
+ "wml": "text/vnd.wap.wml",
+ "wmlc": "application/vnd.wap.wmlc",
+ "wmls": "text/vnd.wap.wmlscript",
+ "wmlsc": "application/vnd.wap.wmlscriptc",
+ "wmv": "video/x-ms-wmv",
+ "wmx": "video/x-ms-wmx",
+ "wmz": "application/x-ms-wmz",
+ "wp5": "application/vnd.wordperfect5.1",
+ "wpd": "application/vnd.wordperfect",
+ "wrl": "model/vrml",
+ "vrml": "model/vrml",
+ "wvx": "video/x-ms-wvx",
+ "wz": "application/x-wingz",
+ "x3d": "model/x3d+xml",
+ "x3db": "model/x3d+binary",
+ "x3dv": "model/x3d+vrml",
+ "xbm": "image/x-xbitmap",
+ "xcf": "application/x-xcf",
+ "xht": "application/xhtml+xml",
+ "xhtml": "application/xhtml+xml",
+ "xlam": "application/vnd.ms-excel.addin.macroEnabled.12",
+ "xlb": "application/vnd.ms-excel",
+ "xls": "application/vnd.ms-excel",
+ "xlsb": "application/vnd.ms-excel.sheet.binary.macroEnabled.12",
+ "xlsm": "application/vnd.ms-excel.sheet.macroEnabled.12",
+ "xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+ "xlt": "application/vnd.ms-excel",
+ "xltm": "application/vnd.ms-excel.template.macroEnabled.12",
+ "xltx": "application/vnd.openxmlformats-officedocument.spreadsheetml.template",
+ "xml": "application/xml",
+ "xpi": "application/x-xpinstall",
+ "xpm": "image/x-xpixmap",
+ "xsd": "application/xml",
+ "xsl": "application/xml",
+ "xspf": "application/xspf+xml",
+ "xtel": "chemical/x-xtel",
+ "xul": "application/vnd.mozilla.xul+xml",
+ "xwd": "image/x-xwindowdump",
+ "xyz": "chemical/x-xyz",
+ "zip": "application/zip",
+ "zmt": "chemical/x-mopac-input"
+};
+
+/*
+ * This file contains utilities to help encode and decode NDN objects.
+ * author: ucla-cs
+ * See COPYING for copyright and distribution information.
+ */
+
+function encodeToHexInterest(interest){
+ var enc = new BinaryXMLEncoder();
+
+ interest.to_ccnb(enc);
+
+ var hex = DataUtils.toHex(enc.getReducedOstream());
+
+ return hex;
+
+}
+
+
+function encodeToBinaryInterest(interest){
+ var enc = new BinaryXMLEncoder();
+
+ interest.to_ccnb(enc);
+
+ var hex = enc.getReducedOstream();
+
+ return hex;
+}
+
+
+function encodeToHexContentObject(co){
+ var enc = new BinaryXMLEncoder();
+
+ co.to_ccnb(enc);
+
+ var hex = DataUtils.toHex(enc.getReducedOstream());
+
+ return hex;
+
+
+}
+
+function encodeToBinaryContentObject(co){
+ var enc = new BinaryXMLEncoder();
+
+ co.to_ccnb(enc);
+
+ var hex = enc.getReducedOstream();
+
+ return hex;
+}
+
+function encodeForwardingEntry(co){
+ var enc = new BinaryXMLEncoder();
+
+ co.to_ccnb(enc);
+
+ var bytes = enc.getReducedOstream();
+
+ return bytes;
+
+
+}
+
+
+
+function decodeHexFaceInstance(result){
+
+ var numbers = DataUtils.toNumbers(result);
+
+
+ decoder = new BinaryXMLDecoder(numbers);
+
+ if(LOG>3)console.log('DECODING HEX FACE INSTANCE \n'+numbers);
+
+ var faceInstance = new FaceInstance();
+
+ faceInstance.from_ccnb(decoder);
+
+ return faceInstance;
+
+}
+
+
+
+function decodeHexInterest(result){
+ var numbers = DataUtils.toNumbers(result);
+
+ decoder = new BinaryXMLDecoder(numbers);
+
+ if(LOG>3)console.log('DECODING HEX INTERST \n'+numbers);
+
+ var interest = new Interest();
+
+ interest.from_ccnb(decoder);
+
+ return interest;
+
+}
+
+
+
+function decodeHexContentObject(result){
+ var numbers = DataUtils.toNumbers(result);
+
+ decoder = new BinaryXMLDecoder(numbers);
+
+ if(LOG>3)console.log('DECODED HEX CONTENT OBJECT \n'+numbers);
+
+ co = new ContentObject();
+
+ co.from_ccnb(decoder);
+
+ return co;
+
+}
+
+
+
+function decodeHexForwardingEntry(result){
+ var numbers = DataUtils.toNumbers(result);
+
+ decoder = new BinaryXMLDecoder(numbers);
+
+ if(LOG>3)console.log('DECODED HEX FORWARDING ENTRY \n'+numbers);
+
+ forwardingEntry = new ForwardingEntry();
+
+ forwardingEntry.from_ccnb(decoder);
+
+ return forwardingEntry;
+
+}
+
+/* Return a user friendly HTML string with the contents of co.
+ This also outputs to console.log.
+ */
+function contentObjectToHtml(/* ContentObject */ co) {
+ var output ="";
+
+ if(co==-1)
+ output+= "NO CONTENT FOUND"
+ else if (co==-2)
+ output+= "CONTENT NAME IS EMPTY"
+ else{
+ if(co.name!=null && co.name.components!=null){
+ output+= "NAME: ";
+
+ for(var i=0;i<co.name.components.length;i++){
+ output+= "/"+ escape(DataUtils.toString(co.name.components[i]));
+ }
+ output+= "<br />";
+ output+= "<br />";
+ }
+
+ if(co.content !=null){
+ output += "CONTENT(ASCII): "+ DataUtils.toString(co.content);
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+ if(co.content !=null){
+ output += "CONTENT(hex): "+ DataUtils.toHex(co.content);
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+ if(co.signature !=null && co.signature.signature!=null){
+ output += "SIGNATURE(hex): "+ DataUtils.toHex(co.signature.signature);
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+ if(co.signedInfo !=null && co.signedInfo.publisher!=null && co.signedInfo.publisher.publisherPublicKeyDigest!=null){
+ output += "Publisher Public Key Digest(hex): "+ DataUtils.toHex(co.signedInfo.publisher.publisherPublicKeyDigest);
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+ if(co.signedInfo !=null && co.signedInfo.timestamp!=null){
+ var d = new Date();
+ d.setTime( co.signedInfo.timestamp.msec );
+
+ var bytes = [217, 185, 12, 225, 217, 185, 12, 225];
+
+ output += "TimeStamp: "+d;
+ output+= "<br />";
+ output += "TimeStamp(number): "+ co.signedInfo.timestamp.msec;
+
+ output+= "<br />";
+ }
+ if(co.signedInfo !=null && co.signedInfo.finalBlockID!=null){
+ output += "FinalBlockID: "+ DataUtils.toHex(co.signedInfo.finalBlockID);
+ output+= "<br />";
+ }
+ if(co.signedInfo!=null && co.signedInfo.locator!=null && co.signedInfo.locator.certificate!=null){
+ var tmp = DataUtils.toString(co.signedInfo.locator.certificate);
+ var publickey = rstr2b64(tmp);
+ var publickeyHex = DataUtils.toHex(co.signedInfo.locator.certificate).toLowerCase();
+ var publickeyString = DataUtils.toString(co.signedInfo.locator.certificate);
+ var signature = DataUtils.toHex(co.signature.signature).toLowerCase();
+ var input = DataUtils.toString(co.rawSignatureData);
+
+ output += "DER Certificate: "+publickey ;
+
+ output+= "<br />";
+ output+= "<br />";
+
+ if(LOG>2) console.log(" ContentName + SignedInfo + Content = "+input);
+
+ if(LOG>2) console.log("HEX OF ContentName + SignedInfo + Content = ");
+ if(LOG>2) console.log(DataUtils.stringtoBase64(input));
+
+ if(LOG>2) console.log(" PublicKey = "+publickey );
+ if(LOG>2) console.log(" PublicKeyHex = "+publickeyHex );
+ if(LOG>2) console.log(" PublicKeyString = "+publickeyString );
+
+ if(LOG>2) console.log(" Signature is");
+ if(LOG>2) console.log( signature );
+ //if(LOG>2) console.log(" Signature NOW IS" );
+ //if(LOG>2) console.log(co.signature.signature);
+
+ var x509 = new X509();
+ x509.readCertPEM(publickey);
+
+ //x509.readCertPEMWithoutRSAInit(publickey);
+
+ var result = x509.subjectPublicKeyRSA.verifyByteArray(co.rawSignatureData, signature);
+ if(LOG>2) console.log('result is '+result);
+
+ var n = x509.subjectPublicKeyRSA.n;
+ var e = x509.subjectPublicKeyRSA.e;
+
+ if(LOG>2) console.log('PUBLIC KEY n after is ');
+ if(LOG>2) console.log(n);
+
+ if(LOG>2) console.log('EXPONENT e after is ');
+ if(LOG>2) console.log(e);
+
+ /*var rsakey = new RSAKey();
+
+ var kp = publickeyHex.slice(56,314);
+
+ output += "PUBLISHER KEY(hex): "+kp ;
+
+ output+= "<br />";
+ output+= "<br />";
+
+ console.log('kp is '+kp);
+
+ var exp = publickeyHex.slice(318,324);
+
+ console.log('kp size is '+kp.length );
+ output += "exponent: "+exp ;
+
+ output+= "<br />";
+ output+= "<br />";
+
+ console.log('exp is '+exp);
+
+ rsakey.setPublic(kp,exp);
+
+ var result = rsakey.verifyString(input, signature);*/
+
+ if(result)
+ output += 'SIGNATURE VALID';
+ else
+ output += 'SIGNATURE INVALID';
+
+ //output += "VALID: "+ toHex(co.signedInfo.locator.publicKey);
+
+ output+= "<br />";
+ output+= "<br />";
+
+ //if(LOG>4) console.log('str'[1]);
+ }
+ if(co.signedInfo!=null && co.signedInfo.locator!=null && co.signedInfo.locator.publicKey!=null){
+ var publickey = rstr2b64(DataUtils.toString(co.signedInfo.locator.publicKey));
+ var publickeyHex = DataUtils.toHex(co.signedInfo.locator.publicKey).toLowerCase();
+ var publickeyString = DataUtils.toString(co.signedInfo.locator.publicKey);
+ var signature = DataUtils.toHex(co.signature.signature).toLowerCase();
+ var input = DataUtils.toString(co.rawSignatureData);
+
+ output += "DER Certificate: "+publickey ;
+
+ output+= "<br />";
+ output+= "<br />";
+
+ if(LOG>2) console.log(" ContentName + SignedInfo + Content = "+input);
+ if(LOG>2) console.log(" PublicKey = "+publickey );
+ if(LOG>2) console.log(" PublicKeyHex = "+publickeyHex );
+ if(LOG>2) console.log(" PublicKeyString = "+publickeyString );
+
+ if(LOG>2) console.log(" Signature "+signature );
+
+ if(LOG>2) console.log(" Signature NOW IS" );
+
+ if(LOG>2) console.log(co.signature.signature);
+
+ /*var x509 = new X509();
+
+ x509.readCertPEM(publickey);
+
+
+ //x509.readCertPEMWithoutRSAInit(publickey);
+
+ var result = x509.subjectPublicKeyRSA.verifyString(input, signature);*/
+ //console.log('result is '+result);
+
+ var kp = publickeyHex.slice(56,314);
+
+ output += "PUBLISHER KEY(hex): "+kp ;
+
+ output+= "<br />";
+ output+= "<br />";
+
+ console.log('PUBLIC KEY IN HEX is ');
+ console.log(kp);
+
+ var exp = publickeyHex.slice(318,324);
+
+ console.log('kp size is '+kp.length );
+ output += "exponent: "+exp ;
+
+ output+= "<br />";
+ output+= "<br />";
+
+ console.log('EXPONENT is ');
+ console.log(exp);
+
+ /*var c1 = hex_sha256(input);
+ var c2 = signature;
+
+ if(LOG>4)console.log('input is ');
+ if(LOG>4)console.log(input);
+ if(LOG>4)console.log('C1 is ');
+ if(LOG>4)console.log(c1);
+ if(LOG>4)console.log('C2 is ');
+ if(LOG>4)console.log(c2);
+ var result = c1 == c2;*/
+
+ var rsakey = new RSAKey();
+
+ rsakey.setPublic(kp,exp);
+
+ var result = rsakey.verifyByteArray(co.rawSignatureData,signature);
+ // var result = rsakey.verifyString(input, signature);
+
+ console.log('PUBLIC KEY n after is ');
+ console.log(rsakey.n);
+
+ console.log('EXPONENT e after is ');
+ console.log(rsakey.e);
+
+ if(result)
+ output += 'SIGNATURE VALID';
+ else
+ output += 'SIGNATURE INVALID';
+
+ //output += "VALID: "+ toHex(co.signedInfo.locator.publicKey);
+
+ output+= "<br />";
+ output+= "<br />";
+
+ //if(LOG>4) console.log('str'[1]);
+ }
+ }
+
+ return output;
+}
+
+/*
+ * @author: ucla-cs
+ * See COPYING for copyright and distribution information.
+ */
+
+var KeyManager = function KeyManager(){
+
+
+//Certificate from CCNx
+
+this.certificate = 'MIIBmzCCAQQCCQC32FyQa61S7jANBgkqhkiG9w0BAQUFADASMRAwDgYDVQQDEwd'+
+
+'heGVsY2R2MB4XDTEyMDQyODIzNDQzN1oXDTEyMDUyODIzNDQzN1owEjEQMA4GA1'+
+
+'UEAxMHYXhlbGNkdjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4X0wp9goq'+
+
+'xuECxdULcr2IHr9Ih4Iaypg0Wy39URIup8/CLzQmdsh3RYqd55hqonu5VTTpH3i'+
+
+'MLx6xZDVJAZ8OJi7pvXcQ2C4Re2kjL2c8SanI0RfDhlS1zJadfr1VhRPmpivcYa'+
+
+'wJ4aFuOLAi+qHFxtN7lhcGCgpW1OV60oXd58CAwEAATANBgkqhkiG9w0BAQUFAA'+
+
+'OBgQDLOrA1fXzSrpftUB5Ro6DigX1Bjkf7F5Bkd69hSVp+jYeJFBBlsILQAfSxU'+
+
+'ZPQtD+2Yc3iCmSYNyxqu9PcufDRJlnvB7PG29+L3y9lR37tetzUV9eTscJ7rdp8'+
+
+'Wt6AzpW32IJ/54yKNfP7S6ZIoIG+LP6EIxq6s8K1MXRt8uBJKw==';
+
+
+//this.publicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDhfTCn2CirG4QLF1QtyvYgev0iHghrKmDRbLf1REi6nz8IvNCZ2yHdFip3nmGqie7lVNOkfeIwvHrFkNUkBnw4mLum9dxDYLhF7aSMvZzxJqcjRF8OGVLXMlp1+vVWFE+amK9xhrAnhoW44sCL6ocXG03uWFwYKClbU5XrShd3nwIDAQAB';
+this.publicKey ='30819F300D06092A864886F70D010101050003818D0030818902818100E17D30A7D828AB1B840B17542DCAF6207AFD221E086B2A60D16CB7F54448BA9F3F08BCD099DB21DD162A779E61AA89EEE554D3A47DE230BC7AC590D524067C3898BBA6F5DC4360B845EDA48CBD9CF126A723445F0E1952D7325A75FAF556144F9A98AF7186B0278685B8E2C08BEA87171B4DEE585C1828295B5395EB4A17779F0203010001';
+//Private Key from CCNx
+
+this.privateKey ='MIICXQIBAAKBgQDhfTCn2CirG4QLF1QtyvYgev0iHghrKmDRbLf1REi6nz8IvNCZ2yHdFip3nmGqie7lVNOkfeIwvHrFkNUkBnw4mLum9dxDYLhF7aSMvZzxJqcjRF8OGVLXMlp1+vVWFE+amK9xhrAnhoW44sCL6ocXG03uWFwYKClbU5XrShd3nwIDAQABAoGAGkv6T6jC3WmhFZYL6CdCWvlc6gysmKrhjarrLTxgavtFY6R5g2ft5BXAsCCVbUkWxkIFSKqxpVNl0gKZCNGEzPDN6mHJOQI/h0rlxNIHAuGfoAbCzALnqmyZivhJAPGijAyKuU9tczsst5+Kpn+bn7ehzHQuj7iwJonS5WbojqECQQD851K8TpW2GrRizNgG4dx6orZxAaon/Jnl8lS7soXhllQty7qG+oDfzznmdMsiznCqEABzHUUKOVGE9RWPN3aRAkEA5D/w9N55d0ibnChFJlc8cUAoaqH+w+U3oQP2Lb6AZHJpLptN4y4b/uf5d4wYU5/i/gC7SSBH3wFhh9bjRLUDLwJAVOx8vN0Kqt7myfKNbCo19jxjVSlA8TKCn1Oznl/BU1I+rC4oUaEW25DjmX6IpAR8kq7S59ThVSCQPjxqY/A08QJBAIRaF2zGPITQk3r/VumemCvLWiRK/yG0noc9dtibqHOWbCtcXtOm/xDWjq+lis2i3ssOvYrvrv0/HcDY+Dv1An0CQQCLJtMsfSg4kvG/FRY5UMhtMuwo8ovYcMXt4Xv/LWaMhndD67b2UGawQCRqr5ghRTABWdDD/HuuMBjrkPsX0861';
+
+
+/*
+ this.certificate =
+ 'MIIBvTCCASYCCQD55fNzc0WF7TANBgkqhkiG9w0BAQUFADAjMQswCQYDVQQGEwJK'+
+ 'UDEUMBIGA1UEChMLMDAtVEVTVC1SU0EwHhcNMTAwNTI4MDIwODUxWhcNMjAwNTI1'+
+ 'MDIwODUxWjAjMQswCQYDVQQGEwJKUDEUMBIGA1UEChMLMDAtVEVTVC1SU0EwgZ8w'+
+ 'DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANGEYXtfgDRlWUSDn3haY4NVVQiKI9Cz'+
+ 'Thoua9+DxJuiseyzmBBe7Roh1RPqdvmtOHmEPbJ+kXZYhbozzPRbFGHCJyBfCLzQ'+
+ 'fVos9/qUQ88u83b0SFA2MGmQWQAlRtLy66EkR4rDRwTj2DzR4EEXgEKpIvo8VBs/'+
+ '3+sHLF3ESgAhAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAEZ6mXFFq3AzfaqWHmCy1'+
+ 'ARjlauYAa8ZmUFnLm0emg9dkVBJ63aEqARhtok6bDQDzSJxiLpCEF6G4b/Nv/M/M'+
+ 'LyhP+OoOTmETMegAVQMq71choVJyOFE5BtQa6M/lCHEOya5QUfoRF2HF9EjRF44K'+
+ '3OK+u3ivTSj3zwjtpudY5Xo=';
+
+ this.privateKey =
+ 'MIICWwIBAAKBgQDRhGF7X4A0ZVlEg594WmODVVUIiiPQs04aLmvfg8SborHss5gQ'+
+ 'Xu0aIdUT6nb5rTh5hD2yfpF2WIW6M8z0WxRhwicgXwi80H1aLPf6lEPPLvN29EhQ'+
+ 'NjBpkFkAJUbS8uuhJEeKw0cE49g80eBBF4BCqSL6PFQbP9/rByxdxEoAIQIDAQAB'+
+ 'AoGAA9/q3Zk6ib2GFRpKDLO/O2KMnAfR+b4XJ6zMGeoZ7Lbpi3MW0Nawk9ckVaX0'+
+ 'ZVGqxbSIX5Cvp/yjHHpww+QbUFrw/gCjLiiYjM9E8C3uAF5AKJ0r4GBPl4u8K4bp'+
+ 'bXeSxSB60/wPQFiQAJVcA5xhZVzqNuF3EjuKdHsw+dk+dPECQQDubX/lVGFgD/xY'+
+ 'uchz56Yc7VHX+58BUkNSewSzwJRbcueqknXRWwj97SXqpnYfKqZq78dnEF10SWsr'+
+ '/NMKi+7XAkEA4PVqDv/OZAbWr4syXZNv/Mpl4r5suzYMMUD9U8B2JIRnrhmGZPzL'+
+ 'x23N9J4hEJ+Xh8tSKVc80jOkrvGlSv+BxwJAaTOtjA3YTV+gU7Hdza53sCnSw/8F'+
+ 'YLrgc6NOJtYhX9xqdevbyn1lkU0zPr8mPYg/F84m6MXixm2iuSz8HZoyzwJARi2p'+
+ 'aYZ5/5B2lwroqnKdZBJMGKFpUDn7Mb5hiSgocxnvMkv6NjT66Xsi3iYakJII9q8C'+
+ 'Ma1qZvT/cigmdbAh7wJAQNXyoizuGEltiSaBXx4H29EdXNYWDJ9SS5f070BRbAIl'+
+ 'dqRh3rcNvpY6BKJqFapda1DjdcncZECMizT/GMrc1w==';
+
+ */
+};
+
+
+KeyManager.prototype.verify = function verify(message,signature){
+
+ var input = message;
+
+ var _PEM_X509CERT_STRING_ = this.certificate;
+
+ var x509 = new X509();
+
+ x509.readCertPEM(_PEM_X509CERT_STRING_);
+
+ var result = x509.subjectPublicKeyRSA.verifyString(input, signature);
+
+ return result;
+};
+
+KeyManager.prototype.sign= function sign(message){
+
+ var input = message;
+
+ var _PEM_PRIVATE_KEY_STRING_ = this.privateKey;
+
+ var rsa = new RSAKey();
+
+ rsa.readPrivateKeyFromPEMString(_PEM_PRIVATE_KEY_STRING_);
+
+ var hSig = rsa.signString(input, "sha256");
+
+ return hSig;
+
+};
+
+
+
+var globalKeyManager = new KeyManager();
+//var KeyPair = { "public" : "PUBLIC KEY" , "private" : "PRIVATE KEY" };
+
+
+
+/*
+ * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
+ * in FIPS 180-1
+ * Version 2.2 Copyright Paul Johnston 2000 - 2009.
+ * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
+ * Distributed under the BSD License
+ * See http://pajhome.org.uk/crypt/md5 for details.
+ */
+
+/*
+ * Configurable variables. You may need to tweak these to be compatible with
+ * the server-side, but the defaults work in most cases.
+ */
+var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
+var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
+
+/**
+ * These are the functions you'll usually want to call
+ * They take string arguments and return either hex or base-64 encoded strings
+ */
+function hex_sha1(s) { return rstr2hex(rstr_sha1(str2rstr_utf8(s))); }
+function b64_sha1(s) { return rstr2b64(rstr_sha1(str2rstr_utf8(s))); }
+function any_sha1(s, e) { return rstr2any(rstr_sha1(str2rstr_utf8(s)), e); }
+function hex_hmac_sha1(k, d)
+ { return rstr2hex(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d))); }
+function b64_hmac_sha1(k, d)
+ { return rstr2b64(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d))); }
+function any_hmac_sha1(k, d, e)
+ { return rstr2any(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d)), e); }
+
+/**
+ * Perform a simple self-test to see if the VM is working
+ */
+function sha1_vm_test()
+{
+ return hex_sha1("abc").toLowerCase() == "a9993e364706816aba3e25717850c26c9cd0d89d";
+}
+
+/**
+ * Calculate the SHA1 of a raw string
+ */
+function rstr_sha1(s)
+{
+ return binb2rstr(binb_sha1(rstr2binb(s), s.length * 8));
+}
+
+/**
+ * Calculate the HMAC-SHA1 of a key and some data (raw strings)
+ */
+function rstr_hmac_sha1(key, data)
+{
+ var bkey = rstr2binb(key);
+ if(bkey.length > 16) bkey = binb_sha1(bkey, key.length * 8);
+
+ var ipad = Array(16), opad = Array(16);
+ for(var i = 0; i < 16; i++)
+ {
+ ipad[i] = bkey[i] ^ 0x36363636;
+ opad[i] = bkey[i] ^ 0x5C5C5C5C;
+ }
+
+ var hash = binb_sha1(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
+ return binb2rstr(binb_sha1(opad.concat(hash), 512 + 160));
+}
+
+/**
+ * Convert a raw string to a hex string
+ */
+function rstr2hex(input)
+{
+ try { hexcase } catch(e) { hexcase=0; }
+ var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
+ var output = "";
+ var x;
+ for(var i = 0; i < input.length; i++)
+ {
+ x = input.charCodeAt(i);
+ output += hex_tab.charAt((x >>> 4) & 0x0F)
+ + hex_tab.charAt( x & 0x0F);
+ }
+ return output;
+}
+
+/**
+ * Convert a raw string to a base-64 string
+ */
+function rstr2b64(input)
+{
+ try { b64pad } catch(e) { b64pad=''; }
+ var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ var output = "";
+ var len = input.length;
+ for(var i = 0; i < len; i += 3)
+ {
+ var triplet = (input.charCodeAt(i) << 16)
+ | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
+ | (i + 2 < len ? input.charCodeAt(i+2) : 0);
+ for(var j = 0; j < 4; j++)
+ {
+ if(i * 8 + j * 6 > input.length * 8) output += b64pad;
+ else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
+ }
+ }
+ return output;
+}
+
+/**
+ * Convert a raw string to an arbitrary string encoding
+ */
+function rstr2any(input, encoding)
+{
+ var divisor = encoding.length;
+ var remainders = Array();
+ var i, q, x, quotient;
+
+ /* Convert to an array of 16-bit big-endian values, forming the dividend */
+ var dividend = Array(Math.ceil(input.length / 2));
+ for(i = 0; i < dividend.length; i++)
+ {
+ dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
+ }
+
+ /*
+ * Repeatedly perform a long division. The binary array forms the dividend,
+ * the length of the encoding is the divisor. Once computed, the quotient
+ * forms the dividend for the next step. We stop when the dividend is zero.
+ * All remainders are stored for later use.
+ */
+ while(dividend.length > 0)
+ {
+ quotient = Array();
+ x = 0;
+ for(i = 0; i < dividend.length; i++)
+ {
+ x = (x << 16) + dividend[i];
+ q = Math.floor(x / divisor);
+ x -= q * divisor;
+ if(quotient.length > 0 || q > 0)
+ quotient[quotient.length] = q;
+ }
+ remainders[remainders.length] = x;
+ dividend = quotient;
+ }
+
+ /* Convert the remainders to the output string */
+ var output = "";
+ for(i = remainders.length - 1; i >= 0; i--)
+ output += encoding.charAt(remainders[i]);
+
+ /* Append leading zero equivalents */
+ var full_length = Math.ceil(input.length * 8 /
+ (Math.log(encoding.length) / Math.log(2)));
+ for(i = output.length; i < full_length; i++)
+ output = encoding[0] + output;
+
+ return output;
+}
+
+/**
+ * Encode a string as utf-8.
+ * For efficiency, this assumes the input is valid utf-16.
+ */
+function str2rstr_utf8(input)
+{
+ var output = "";
+ var i = -1;
+ var x, y;
+
+ while(++i < input.length)
+ {
+ /* Decode utf-16 surrogate pairs */
+ x = input.charCodeAt(i);
+ y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
+ if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
+ {
+ x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
+ i++;
+ }
+
+ /* Encode output as utf-8 */
+ if(x <= 0x7F)
+ output += String.fromCharCode(x);
+ else if(x <= 0x7FF)
+ output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
+ 0x80 | ( x & 0x3F));
+ else if(x <= 0xFFFF)
+ output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
+ 0x80 | ((x >>> 6 ) & 0x3F),
+ 0x80 | ( x & 0x3F));
+ else if(x <= 0x1FFFFF)
+ output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
+ 0x80 | ((x >>> 12) & 0x3F),
+ 0x80 | ((x >>> 6 ) & 0x3F),
+ 0x80 | ( x & 0x3F));
+ }
+ return output;
+}
+
+/**
+ * Encode a string as utf-16
+ */
+function str2rstr_utf16le(input)
+{
+ var output = "";
+ for(var i = 0; i < input.length; i++)
+ output += String.fromCharCode( input.charCodeAt(i) & 0xFF,
+ (input.charCodeAt(i) >>> 8) & 0xFF);
+ return output;
+}
+
+function str2rstr_utf16be(input)
+{
+ var output = "";
+ for(var i = 0; i < input.length; i++)
+ output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
+ input.charCodeAt(i) & 0xFF);
+ return output;
+}
+
+/**
+ * Convert a raw string to an array of big-endian words
+ * Characters >255 have their high-byte silently ignored.
+ */
+function rstr2binb(input)
+{
+ var output = Array(input.length >> 2);
+ for(var i = 0; i < output.length; i++)
+ output[i] = 0;
+ for(var i = 0; i < input.length * 8; i += 8)
+ output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32);
+ return output;
+}
+
+/**
+ * Convert an array of big-endian words to a string
+ */
+function binb2rstr(input)
+{
+ var output = "";
+ for(var i = 0; i < input.length * 32; i += 8)
+ output += String.fromCharCode((input[i>>5] >>> (24 - i % 32)) & 0xFF);
+ return output;
+}
+
+/**
+ * Calculate the SHA-1 of an array of big-endian words, and a bit length
+ */
+function binb_sha1(x, len)
+{
+ /* append padding */
+ x[len >> 5] |= 0x80 << (24 - len % 32);
+ x[((len + 64 >> 9) << 4) + 15] = len;
+
+ var w = Array(80);
+ var a = 1732584193;
+ var b = -271733879;
+ var c = -1732584194;
+ var d = 271733878;
+ var e = -1009589776;
+
+ for(var i = 0; i < x.length; i += 16)
+ {
+ var olda = a;
+ var oldb = b;
+ var oldc = c;
+ var oldd = d;
+ var olde = e;
+
+ for(var j = 0; j < 80; j++)
+ {
+ if(j < 16) w[j] = x[i + j];
+ else w[j] = bit_rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
+ var t = safe_add(safe_add(bit_rol(a, 5), sha1_ft(j, b, c, d)),
+ safe_add(safe_add(e, w[j]), sha1_kt(j)));
+ e = d;
+ d = c;
+ c = bit_rol(b, 30);
+ b = a;
+ a = t;
+ }
+
+ a = safe_add(a, olda);
+ b = safe_add(b, oldb);
+ c = safe_add(c, oldc);
+ d = safe_add(d, oldd);
+ e = safe_add(e, olde);
+ }
+ return Array(a, b, c, d, e);
+
+}
+
+/**
+ * Perform the appropriate triplet combination function for the current
+ * iteration
+ */
+function sha1_ft(t, b, c, d)
+{
+ if(t < 20) return (b & c) | ((~b) & d);
+ if(t < 40) return b ^ c ^ d;
+ if(t < 60) return (b & c) | (b & d) | (c & d);
+ return b ^ c ^ d;
+}
+
+/**
+ * Determine the appropriate additive constant for the current iteration
+ */
+function sha1_kt(t)
+{
+ return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 :
+ (t < 60) ? -1894007588 : -899497514;
+}
+
+/**
+ * Add integers, wrapping at 2^32. This uses 16-bit operations internally
+ * to work around bugs in some JS interpreters.
+ */
+function safe_add(x, y)
+{
+ var lsw = (x & 0xFFFF) + (y & 0xFFFF);
+ var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
+ return (msw << 16) | (lsw & 0xFFFF);
+}
+
+/**
+ * Bitwise rotate a 32-bit number to the left.
+ */
+function bit_rol(num, cnt)
+{
+ return (num << cnt) | (num >>> (32 - cnt));
+}
+
+/*
+ * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined
+ * in FIPS 180-2
+ * Version 2.2 Copyright Angel Marin, Paul Johnston 2000 - 2009.
+ * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
+ * Distributed under the BSD License
+ * See http://pajhome.org.uk/crypt/md5 for details.
+ * Also http://anmar.eu.org/projects/jssha2/
+ */
+
+/*
+ * Configurable variables. You may need to tweak these to be compatible with
+ * the server-side, but the defaults work in most cases.
+ */
+var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
+var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
+
+/*
+ * These are the functions you'll usually want to call
+ * They take string arguments and return either hex or base-64 encoded strings
+ */
+
+//@author axelcdv
+/**
+ * Computes the Sha-256 hash of the given byte array
+ * @param {byte[]}
+ * @return the hex string corresponding to the Sha-256 hash of the byte array
+ */
+function hex_sha256_from_bytes(byteArray){
+ return rstr2hex(binb2rstr(binb_sha256( byteArray2binb(byteArray), byteArray.length * 8)));
+}
+
+function hex_sha256(s) { return rstr2hex(rstr_sha256(str2rstr_utf8(s))); }
+function b64_sha256(s) { return rstr2b64(rstr_sha256(str2rstr_utf8(s))); }
+function any_sha256(s, e) { return rstr2any(rstr_sha256(str2rstr_utf8(s)), e); }
+function hex_hmac_sha256(k, d)
+ { return rstr2hex(rstr_hmac_sha256(str2rstr_utf8(k), str2rstr_utf8(d))); }
+function b64_hmac_sha256(k, d)
+ { return rstr2b64(rstr_hmac_sha256(str2rstr_utf8(k), str2rstr_utf8(d))); }
+function any_hmac_sha256(k, d, e)
+ { return rstr2any(rstr_hmac_sha256(str2rstr_utf8(k), str2rstr_utf8(d)), e); }
+
+
+/*
+ function hex_sha256(s) { return rstr2hex(rstr_sha256(s)); }
+function b64_sha256(s) { return rstr2b64(rstr_sha256(s)); }
+function any_sha256(s, e) { return rstr2any(rstr_sha256(s), e); }
+function hex_hmac_sha256(k, d)
+ { return rstr2hex(rstr_hmac_sha256(str2rstr_utf8(k), d)); }
+function b64_hmac_sha256(k, d)
+ { return rstr2b64(rstr_hmac_sha256(str2rstr_utf8(k), d)); }
+function any_hmac_sha256(k, d, e)
+ { return rstr2any(rstr_hmac_sha256(str2rstr_utf8(k), d), e); }
+*/
+
+/*
+ * Perform a simple self-test to see if the VM is working
+ */
+function sha256_vm_test()
+{
+ return hex_sha256("abc").toLowerCase() ==
+ "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad";
+}
+
+/**
+ * Calculate the sha256 of a raw string
+ * @param s: the raw string
+ */
+function rstr_sha256(s)
+{
+ return binb2rstr(binb_sha256(rstr2binb(s), s.length * 8));
+}
+
+/**
+ * Calculate the HMAC-sha256 of a key and some data (raw strings)
+ */
+function rstr_hmac_sha256(key, data)
+{
+ var bkey = rstr2binb(key);
+ if(bkey.length > 16) bkey = binb_sha256(bkey, key.length * 8);
+
+ var ipad = Array(16), opad = Array(16);
+ for(var i = 0; i < 16; i++)
+ {
+ ipad[i] = bkey[i] ^ 0x36363636;
+ opad[i] = bkey[i] ^ 0x5C5C5C5C;
+ }
+
+ var hash = binb_sha256(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
+ return binb2rstr(binb_sha256(opad.concat(hash), 512 + 256));
+}
+
+/**
+ * Convert a raw string to a hex string
+ */
+function rstr2hex(input)
+{
+ try { hexcase } catch(e) { hexcase=0; }
+ var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
+ var output = "";
+ var x;
+ for(var i = 0; i < input.length; i++)
+ {
+ x = input.charCodeAt(i);
+ output += hex_tab.charAt((x >>> 4) & 0x0F)
+ + hex_tab.charAt( x & 0x0F);
+ }
+ return output;
+}
+
+/*
+ * Convert a raw string to a base-64 string
+ */
+function rstr2b64(input)
+{
+ try { b64pad } catch(e) { b64pad=''; }
+ var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ var output = "";
+ var len = input.length;
+ for(var i = 0; i < len; i += 3)
+ {
+ var triplet = (input.charCodeAt(i) << 16)
+ | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
+ | (i + 2 < len ? input.charCodeAt(i+2) : 0);
+ for(var j = 0; j < 4; j++)
+ {
+ if(i * 8 + j * 6 > input.length * 8) output += b64pad;
+ else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
+ }
+ }
+ return output;
+}
+
+/*
+ * Convert a raw string to an arbitrary string encoding
+ */
+function rstr2any(input, encoding)
+{
+ var divisor = encoding.length;
+ var remainders = Array();
+ var i, q, x, quotient;
+
+ /* Convert to an array of 16-bit big-endian values, forming the dividend */
+ var dividend = Array(Math.ceil(input.length / 2));
+ for(i = 0; i < dividend.length; i++)
+ {
+ dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
+ }
+
+ /*
+ * Repeatedly perform a long division. The binary array forms the dividend,
+ * the length of the encoding is the divisor. Once computed, the quotient
+ * forms the dividend for the next step. We stop when the dividend is zero.
+ * All remainders are stored for later use.
+ */
+ while(dividend.length > 0)
+ {
+ quotient = Array();
+ x = 0;
+ for(i = 0; i < dividend.length; i++)
+ {
+ x = (x << 16) + dividend[i];
+ q = Math.floor(x / divisor);
+ x -= q * divisor;
+ if(quotient.length > 0 || q > 0)
+ quotient[quotient.length] = q;
+ }
+ remainders[remainders.length] = x;
+ dividend = quotient;
+ }
+
+ /* Convert the remainders to the output string */
+ var output = "";
+ for(i = remainders.length - 1; i >= 0; i--)
+ output += encoding.charAt(remainders[i]);
+
+ /* Append leading zero equivalents */
+ var full_length = Math.ceil(input.length * 8 /
+ (Math.log(encoding.length) / Math.log(2)))
+ for(i = output.length; i < full_length; i++)
+ output = encoding[0] + output;
+
+ return output;
+}
+
+/*
+ * Encode a string as utf-8.
+ * For efficiency, this assumes the input is valid utf-16.
+ */
+function str2rstr_utf8(input)
+{
+ var output = "";
+ var i = -1;
+ var x, y;
+
+ while(++i < input.length)
+ {
+ /* Decode utf-16 surrogate pairs */
+ x = input.charCodeAt(i);
+ y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
+ if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
+ {
+ x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
+ i++;
+ }
+
+ /* Encode output as utf-8 */
+ if(x <= 0x7F)
+ output += String.fromCharCode(x);
+ else if(x <= 0x7FF)
+ output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
+ 0x80 | ( x & 0x3F));
+ else if(x <= 0xFFFF)
+ output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
+ 0x80 | ((x >>> 6 ) & 0x3F),
+ 0x80 | ( x & 0x3F));
+ else if(x <= 0x1FFFFF)
+ output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
+ 0x80 | ((x >>> 12) & 0x3F),
+ 0x80 | ((x >>> 6 ) & 0x3F),
+ 0x80 | ( x & 0x3F));
+ }
+ return output;
+}
+
+/*
+ * Encode a string as utf-16
+ */
+function str2rstr_utf16le(input)
+{
+ var output = "";
+ for(var i = 0; i < input.length; i++)
+ output += String.fromCharCode( input.charCodeAt(i) & 0xFF,
+ (input.charCodeAt(i) >>> 8) & 0xFF);
+ return output;
+}
+
+function str2rstr_utf16be(input)
+{
+ var output = "";
+ for(var i = 0; i < input.length; i++)
+ output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
+ input.charCodeAt(i) & 0xFF);
+ return output;
+}
+
+/**
+ * Convert a raw string to an array of big-endian words
+ * Characters >255 have their high-byte silently ignored.
+ */
+function rstr2binb(input)
+{
+ //console.log('Raw string comming is '+input);
+ var output = Array(input.length >> 2);
+ for(var i = 0; i < output.length; i++)
+ output[i] = 0;
+ for(var i = 0; i < input.length * 8; i += 8)
+ output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32);
+ return output;
+}
+
+/**
+ * @author axelcdv
+ * Convert a byte array to an array of big-endian words
+ * @param {byte[]} input
+ * @return the array of big-endian words
+ */
+function byteArray2binb(input){
+ //console.log("Byte array coming is " + input);
+ var output = Array(input.length >> 2);
+ for(var i = 0; i < output.length; i++)
+ output[i] = 0;
+ for(var i = 0; i < input.length * 8; i += 8)
+ output[i>>5] |= (input[i / 8] & 0xFF) << (24 - i % 32);
+ return output;
+}
+
+/*
+ * Convert an array of big-endian words to a string
+ */
+function binb2rstr(input)
+{
+ var output = "";
+ for(var i = 0; i < input.length * 32; i += 8)
+ output += String.fromCharCode((input[i>>5] >>> (24 - i % 32)) & 0xFF);
+ return output;
+}
+
+/*
+ * Main sha256 function, with its support functions
+ */
+function sha256_S (X, n) {return ( X >>> n ) | (X << (32 - n));}
+function sha256_R (X, n) {return ( X >>> n );}
+function sha256_Ch(x, y, z) {return ((x & y) ^ ((~x) & z));}
+function sha256_Maj(x, y, z) {return ((x & y) ^ (x & z) ^ (y & z));}
+function sha256_Sigma0256(x) {return (sha256_S(x, 2) ^ sha256_S(x, 13) ^ sha256_S(x, 22));}
+function sha256_Sigma1256(x) {return (sha256_S(x, 6) ^ sha256_S(x, 11) ^ sha256_S(x, 25));}
+function sha256_Gamma0256(x) {return (sha256_S(x, 7) ^ sha256_S(x, 18) ^ sha256_R(x, 3));}
+function sha256_Gamma1256(x) {return (sha256_S(x, 17) ^ sha256_S(x, 19) ^ sha256_R(x, 10));}
+function sha256_Sigma0512(x) {return (sha256_S(x, 28) ^ sha256_S(x, 34) ^ sha256_S(x, 39));}
+function sha256_Sigma1512(x) {return (sha256_S(x, 14) ^ sha256_S(x, 18) ^ sha256_S(x, 41));}
+function sha256_Gamma0512(x) {return (sha256_S(x, 1) ^ sha256_S(x, 8) ^ sha256_R(x, 7));}
+function sha256_Gamma1512(x) {return (sha256_S(x, 19) ^ sha256_S(x, 61) ^ sha256_R(x, 6));}
+
+var sha256_K = new Array
+(
+ 1116352408, 1899447441, -1245643825, -373957723, 961987163, 1508970993,
+ -1841331548, -1424204075, -670586216, 310598401, 607225278, 1426881987,
+ 1925078388, -2132889090, -1680079193, -1046744716, -459576895, -272742522,
+ 264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986,
+ -1740746414, -1473132947, -1341970488, -1084653625, -958395405, -710438585,
+ 113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291,
+ 1695183700, 1986661051, -2117940946, -1838011259, -1564481375, -1474664885,
+ -1035236496, -949202525, -778901479, -694614492, -200395387, 275423344,
+ 430227734, 506948616, 659060556, 883997877, 958139571, 1322822218,
+ 1537002063, 1747873779, 1955562222, 2024104815, -2067236844, -1933114872,
+ -1866530822, -1538233109, -1090935817, -965641998
+);
+
+function binb_sha256(m, l)
+{
+ var HASH = new Array(1779033703, -1150833019, 1013904242, -1521486534,
+ 1359893119, -1694144372, 528734635, 1541459225);
+ var W = new Array(64);
+ var a, b, c, d, e, f, g, h;
+ var i, j, T1, T2;
+
+ /* append padding */
+ m[l >> 5] |= 0x80 << (24 - l % 32);
+ m[((l + 64 >> 9) << 4) + 15] = l;
+
+ for(i = 0; i < m.length; i += 16)
+ {
+ a = HASH[0];
+ b = HASH[1];
+ c = HASH[2];
+ d = HASH[3];
+ e = HASH[4];
+ f = HASH[5];
+ g = HASH[6];
+ h = HASH[7];
+
+ for(j = 0; j < 64; j++)
+ {
+ if (j < 16) W[j] = m[j + i];
+ else W[j] = safe_add(safe_add(safe_add(sha256_Gamma1256(W[j - 2]), W[j - 7]),
+ sha256_Gamma0256(W[j - 15])), W[j - 16]);
+
+ T1 = safe_add(safe_add(safe_add(safe_add(h, sha256_Sigma1256(e)), sha256_Ch(e, f, g)),
+ sha256_K[j]), W[j]);
+ T2 = safe_add(sha256_Sigma0256(a), sha256_Maj(a, b, c));
+ h = g;
+ g = f;
+ f = e;
+ e = safe_add(d, T1);
+ d = c;
+ c = b;
+ b = a;
+ a = safe_add(T1, T2);
+ }
+
+ HASH[0] = safe_add(a, HASH[0]);
+ HASH[1] = safe_add(b, HASH[1]);
+ HASH[2] = safe_add(c, HASH[2]);
+ HASH[3] = safe_add(d, HASH[3]);
+ HASH[4] = safe_add(e, HASH[4]);
+ HASH[5] = safe_add(f, HASH[5]);
+ HASH[6] = safe_add(g, HASH[6]);
+ HASH[7] = safe_add(h, HASH[7]);
+ }
+ return HASH;
+}
+
+function safe_add (x, y)
+{
+ var lsw = (x & 0xFFFF) + (y & 0xFFFF);
+ var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
+ return (msw << 16) | (lsw & 0xFFFF);
+}
+
+/*
+ * A JavaScript implementation of the Secure Hash Algorithm, SHA-512, as defined
+ * in FIPS 180-2
+ * Version 2.2 Copyright Anonymous Contributor, Paul Johnston 2000 - 2009.
+ * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
+ * Distributed under the BSD License
+ * See http://pajhome.org.uk/crypt/md5 for details.
+ */
+
+/*
+ * Configurable variables. You may need to tweak these to be compatible with
+ * the server-side, but the defaults work in most cases.
+ */
+var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
+var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
+
+/*
+ * These are the functions you'll usually want to call
+ * They take string arguments and return either hex or base-64 encoded strings
+ */
+function hex_sha512(s) { return rstr2hex(rstr_sha512(str2rstr_utf8(s))); }
+function b64_sha512(s) { return rstr2b64(rstr_sha512(str2rstr_utf8(s))); }
+function any_sha512(s, e) { return rstr2any(rstr_sha512(str2rstr_utf8(s)), e);}
+function hex_hmac_sha512(k, d)
+ { return rstr2hex(rstr_hmac_sha512(str2rstr_utf8(k), str2rstr_utf8(d))); }
+function b64_hmac_sha512(k, d)
+ { return rstr2b64(rstr_hmac_sha512(str2rstr_utf8(k), str2rstr_utf8(d))); }
+function any_hmac_sha512(k, d, e)
+ { return rstr2any(rstr_hmac_sha512(str2rstr_utf8(k), str2rstr_utf8(d)), e);}
+
+/*
+ * Perform a simple self-test to see if the VM is working
+ */
+function sha512_vm_test()
+{
+ return hex_sha512("abc").toLowerCase() ==
+ "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" +
+ "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f";
+}
+
+/*
+ * Calculate the SHA-512 of a raw string
+ */
+function rstr_sha512(s)
+{
+ return binb2rstr(binb_sha512(rstr2binb(s), s.length * 8));
+}
+
+/*
+ * Calculate the HMAC-SHA-512 of a key and some data (raw strings)
+ */
+function rstr_hmac_sha512(key, data)
+{
+ var bkey = rstr2binb(key);
+ if(bkey.length > 32) bkey = binb_sha512(bkey, key.length * 8);
+
+ var ipad = Array(32), opad = Array(32);
+ for(var i = 0; i < 32; i++)
+ {
+ ipad[i] = bkey[i] ^ 0x36363636;
+ opad[i] = bkey[i] ^ 0x5C5C5C5C;
+ }
+
+ var hash = binb_sha512(ipad.concat(rstr2binb(data)), 1024 + data.length * 8);
+ return binb2rstr(binb_sha512(opad.concat(hash), 1024 + 512));
+}
+
+/*
+ * Convert a raw string to a hex string
+ */
+function rstr2hex(input)
+{
+ try { hexcase } catch(e) { hexcase=0; }
+ var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
+ var output = "";
+ var x;
+ for(var i = 0; i < input.length; i++)
+ {
+ x = input.charCodeAt(i);
+ output += hex_tab.charAt((x >>> 4) & 0x0F)
+ + hex_tab.charAt( x & 0x0F);
+ }
+ return output;
+}
+
+/*
+ * Convert a raw string to a base-64 string
+ */
+function rstr2b64(input)
+{
+ try { b64pad } catch(e) { b64pad=''; }
+ var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ var output = "";
+ var len = input.length;
+ for(var i = 0; i < len; i += 3)
+ {
+ var triplet = (input.charCodeAt(i) << 16)
+ | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
+ | (i + 2 < len ? input.charCodeAt(i+2) : 0);
+ for(var j = 0; j < 4; j++)
+ {
+ if(i * 8 + j * 6 > input.length * 8) output += b64pad;
+ else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
+ }
+ }
+ return output;
+}
+
+/*
+ * Convert a raw string to an arbitrary string encoding
+ */
+function rstr2any(input, encoding)
+{
+ var divisor = encoding.length;
+ var i, j, q, x, quotient;
+
+ /* Convert to an array of 16-bit big-endian values, forming the dividend */
+ var dividend = Array(Math.ceil(input.length / 2));
+ for(i = 0; i < dividend.length; i++)
+ {
+ dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
+ }
+
+ /*
+ * Repeatedly perform a long division. The binary array forms the dividend,
+ * the length of the encoding is the divisor. Once computed, the quotient
+ * forms the dividend for the next step. All remainders are stored for later
+ * use.
+ */
+ var full_length = Math.ceil(input.length * 8 /
+ (Math.log(encoding.length) / Math.log(2)));
+ var remainders = Array(full_length);
+ for(j = 0; j < full_length; j++)
+ {
+ quotient = Array();
+ x = 0;
+ for(i = 0; i < dividend.length; i++)
+ {
+ x = (x << 16) + dividend[i];
+ q = Math.floor(x / divisor);
+ x -= q * divisor;
+ if(quotient.length > 0 || q > 0)
+ quotient[quotient.length] = q;
+ }
+ remainders[j] = x;
+ dividend = quotient;
+ }
+
+ /* Convert the remainders to the output string */
+ var output = "";
+ for(i = remainders.length - 1; i >= 0; i--)
+ output += encoding.charAt(remainders[i]);
+
+ return output;
+}
+
+/*
+ * Encode a string as utf-8.
+ * For efficiency, this assumes the input is valid utf-16.
+ */
+function str2rstr_utf8(input)
+{
+ var output = "";
+ var i = -1;
+ var x, y;
+
+ while(++i < input.length)
+ {
+ /* Decode utf-16 surrogate pairs */
+ x = input.charCodeAt(i);
+ y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
+ if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
+ {
+ x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
+ i++;
+ }
+
+ /* Encode output as utf-8 */
+ if(x <= 0x7F)
+ output += String.fromCharCode(x);
+ else if(x <= 0x7FF)
+ output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
+ 0x80 | ( x & 0x3F));
+ else if(x <= 0xFFFF)
+ output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
+ 0x80 | ((x >>> 6 ) & 0x3F),
+ 0x80 | ( x & 0x3F));
+ else if(x <= 0x1FFFFF)
+ output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
+ 0x80 | ((x >>> 12) & 0x3F),
+ 0x80 | ((x >>> 6 ) & 0x3F),
+ 0x80 | ( x & 0x3F));
+ }
+ return output;
+}
+
+/*
+ * Encode a string as utf-16
+ */
+function str2rstr_utf16le(input)
+{
+ var output = "";
+ for(var i = 0; i < input.length; i++)
+ output += String.fromCharCode( input.charCodeAt(i) & 0xFF,
+ (input.charCodeAt(i) >>> 8) & 0xFF);
+ return output;
+}
+
+function str2rstr_utf16be(input)
+{
+ var output = "";
+ for(var i = 0; i < input.length; i++)
+ output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
+ input.charCodeAt(i) & 0xFF);
+ return output;
+}
+
+/*
+ * Convert a raw string to an array of big-endian words
+ * Characters >255 have their high-byte silently ignored.
+ */
+function rstr2binb(input)
+{
+ var output = Array(input.length >> 2);
+ for(var i = 0; i < output.length; i++)
+ output[i] = 0;
+ for(var i = 0; i < input.length * 8; i += 8)
+ output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32);
+ return output;
+}
+
+/*
+ * Convert an array of big-endian words to a string
+ */
+function binb2rstr(input)
+{
+ var output = "";
+ for(var i = 0; i < input.length * 32; i += 8)
+ output += String.fromCharCode((input[i>>5] >>> (24 - i % 32)) & 0xFF);
+ return output;
+}
+
+/*
+ * Calculate the SHA-512 of an array of big-endian dwords, and a bit length
+ */
+var sha512_k;
+function binb_sha512(x, len)
+{
+ if(sha512_k == undefined)
+ {
+ //SHA512 constants
+ sha512_k = new Array(
+new int64(0x428a2f98, -685199838), new int64(0x71374491, 0x23ef65cd),
+new int64(-1245643825, -330482897), new int64(-373957723, -2121671748),
+new int64(0x3956c25b, -213338824), new int64(0x59f111f1, -1241133031),
+new int64(-1841331548, -1357295717), new int64(-1424204075, -630357736),
+new int64(-670586216, -1560083902), new int64(0x12835b01, 0x45706fbe),
+new int64(0x243185be, 0x4ee4b28c), new int64(0x550c7dc3, -704662302),
+new int64(0x72be5d74, -226784913), new int64(-2132889090, 0x3b1696b1),
+new int64(-1680079193, 0x25c71235), new int64(-1046744716, -815192428),
+new int64(-459576895, -1628353838), new int64(-272742522, 0x384f25e3),
+new int64(0xfc19dc6, -1953704523), new int64(0x240ca1cc, 0x77ac9c65),
+new int64(0x2de92c6f, 0x592b0275), new int64(0x4a7484aa, 0x6ea6e483),
+new int64(0x5cb0a9dc, -1119749164), new int64(0x76f988da, -2096016459),
+new int64(-1740746414, -295247957), new int64(-1473132947, 0x2db43210),
+new int64(-1341970488, -1728372417), new int64(-1084653625, -1091629340),
+new int64(-958395405, 0x3da88fc2), new int64(-710438585, -1828018395),
+new int64(0x6ca6351, -536640913), new int64(0x14292967, 0xa0e6e70),
+new int64(0x27b70a85, 0x46d22ffc), new int64(0x2e1b2138, 0x5c26c926),
+new int64(0x4d2c6dfc, 0x5ac42aed), new int64(0x53380d13, -1651133473),
+new int64(0x650a7354, -1951439906), new int64(0x766a0abb, 0x3c77b2a8),
+new int64(-2117940946, 0x47edaee6), new int64(-1838011259, 0x1482353b),
+new int64(-1564481375, 0x4cf10364), new int64(-1474664885, -1136513023),
+new int64(-1035236496, -789014639), new int64(-949202525, 0x654be30),
+new int64(-778901479, -688958952), new int64(-694614492, 0x5565a910),
+new int64(-200395387, 0x5771202a), new int64(0x106aa070, 0x32bbd1b8),
+new int64(0x19a4c116, -1194143544), new int64(0x1e376c08, 0x5141ab53),
+new int64(0x2748774c, -544281703), new int64(0x34b0bcb5, -509917016),
+new int64(0x391c0cb3, -976659869), new int64(0x4ed8aa4a, -482243893),
+new int64(0x5b9cca4f, 0x7763e373), new int64(0x682e6ff3, -692930397),
+new int64(0x748f82ee, 0x5defb2fc), new int64(0x78a5636f, 0x43172f60),
+new int64(-2067236844, -1578062990), new int64(-1933114872, 0x1a6439ec),
+new int64(-1866530822, 0x23631e28), new int64(-1538233109, -561857047),
+new int64(-1090935817, -1295615723), new int64(-965641998, -479046869),
+new int64(-903397682, -366583396), new int64(-779700025, 0x21c0c207),
+new int64(-354779690, -840897762), new int64(-176337025, -294727304),
+new int64(0x6f067aa, 0x72176fba), new int64(0xa637dc5, -1563912026),
+new int64(0x113f9804, -1090974290), new int64(0x1b710b35, 0x131c471b),
+new int64(0x28db77f5, 0x23047d84), new int64(0x32caab7b, 0x40c72493),
+new int64(0x3c9ebe0a, 0x15c9bebc), new int64(0x431d67c4, -1676669620),
+new int64(0x4cc5d4be, -885112138), new int64(0x597f299c, -60457430),
+new int64(0x5fcb6fab, 0x3ad6faec), new int64(0x6c44198c, 0x4a475817));
+ }
+
+ //Initial hash values
+ var H = new Array(
+new int64(0x6a09e667, -205731576),
+new int64(-1150833019, -2067093701),
+new int64(0x3c6ef372, -23791573),
+new int64(-1521486534, 0x5f1d36f1),
+new int64(0x510e527f, -1377402159),
+new int64(-1694144372, 0x2b3e6c1f),
+new int64(0x1f83d9ab, -79577749),
+new int64(0x5be0cd19, 0x137e2179));
+
+ var T1 = new int64(0, 0),
+ T2 = new int64(0, 0),
+ a = new int64(0,0),
+ b = new int64(0,0),
+ c = new int64(0,0),
+ d = new int64(0,0),
+ e = new int64(0,0),
+ f = new int64(0,0),
+ g = new int64(0,0),
+ h = new int64(0,0),
+ //Temporary variables not specified by the document
+ s0 = new int64(0, 0),
+ s1 = new int64(0, 0),
+ Ch = new int64(0, 0),
+ Maj = new int64(0, 0),
+ r1 = new int64(0, 0),
+ r2 = new int64(0, 0),
+ r3 = new int64(0, 0);
+ var j, i;
+ var W = new Array(80);
+ for(i=0; i<80; i++)
+ W[i] = new int64(0, 0);
+
+ // append padding to the source string. The format is described in the FIPS.
+ x[len >> 5] |= 0x80 << (24 - (len & 0x1f));
+ x[((len + 128 >> 10)<< 5) + 31] = len;
+
+ for(i = 0; i<x.length; i+=32) //32 dwords is the block size
+ {
+ int64copy(a, H[0]);
+ int64copy(b, H[1]);
+ int64copy(c, H[2]);
+ int64copy(d, H[3]);
+ int64copy(e, H[4]);
+ int64copy(f, H[5]);
+ int64copy(g, H[6]);
+ int64copy(h, H[7]);
+
+ for(j=0; j<16; j++)
+ {
+ W[j].h = x[i + 2*j];
+ W[j].l = x[i + 2*j + 1];
+ }
+
+ for(j=16; j<80; j++)
+ {
+ //sigma1
+ int64rrot(r1, W[j-2], 19);
+ int64revrrot(r2, W[j-2], 29);
+ int64shr(r3, W[j-2], 6);
+ s1.l = r1.l ^ r2.l ^ r3.l;
+ s1.h = r1.h ^ r2.h ^ r3.h;
+ //sigma0
+ int64rrot(r1, W[j-15], 1);
+ int64rrot(r2, W[j-15], 8);
+ int64shr(r3, W[j-15], 7);
+ s0.l = r1.l ^ r2.l ^ r3.l;
+ s0.h = r1.h ^ r2.h ^ r3.h;
+
+ int64add4(W[j], s1, W[j-7], s0, W[j-16]);
+ }
+
+ for(j = 0; j < 80; j++)
+ {
+ //Ch
+ Ch.l = (e.l & f.l) ^ (~e.l & g.l);
+ Ch.h = (e.h & f.h) ^ (~e.h & g.h);
+
+ //Sigma1
+ int64rrot(r1, e, 14);
+ int64rrot(r2, e, 18);
+ int64revrrot(r3, e, 9);
+ s1.l = r1.l ^ r2.l ^ r3.l;
+ s1.h = r1.h ^ r2.h ^ r3.h;
+
+ //Sigma0
+ int64rrot(r1, a, 28);
+ int64revrrot(r2, a, 2);
+ int64revrrot(r3, a, 7);
+ s0.l = r1.l ^ r2.l ^ r3.l;
+ s0.h = r1.h ^ r2.h ^ r3.h;
+
+ //Maj
+ Maj.l = (a.l & b.l) ^ (a.l & c.l) ^ (b.l & c.l);
+ Maj.h = (a.h & b.h) ^ (a.h & c.h) ^ (b.h & c.h);
+
+ int64add5(T1, h, s1, Ch, sha512_k[j], W[j]);
+ int64add(T2, s0, Maj);
+
+ int64copy(h, g);
+ int64copy(g, f);
+ int64copy(f, e);
+ int64add(e, d, T1);
+ int64copy(d, c);
+ int64copy(c, b);
+ int64copy(b, a);
+ int64add(a, T1, T2);
+ }
+ int64add(H[0], H[0], a);
+ int64add(H[1], H[1], b);
+ int64add(H[2], H[2], c);
+ int64add(H[3], H[3], d);
+ int64add(H[4], H[4], e);
+ int64add(H[5], H[5], f);
+ int64add(H[6], H[6], g);
+ int64add(H[7], H[7], h);
+ }
+
+ //represent the hash as an array of 32-bit dwords
+ var hash = new Array(16);
+ for(i=0; i<8; i++)
+ {
+ hash[2*i] = H[i].h;
+ hash[2*i + 1] = H[i].l;
+ }
+ return hash;
+}
+
+//A constructor for 64-bit numbers
+function int64(h, l)
+{
+ this.h = h;
+ this.l = l;
+ //this.toString = int64toString;
+}
+
+//Copies src into dst, assuming both are 64-bit numbers
+function int64copy(dst, src)
+{
+ dst.h = src.h;
+ dst.l = src.l;
+}
+
+//Right-rotates a 64-bit number by shift
+//Won't handle cases of shift>=32
+//The function revrrot() is for that
+function int64rrot(dst, x, shift)
+{
+ dst.l = (x.l >>> shift) | (x.h << (32-shift));
+ dst.h = (x.h >>> shift) | (x.l << (32-shift));
+}
+
+//Reverses the dwords of the source and then rotates right by shift.
+//This is equivalent to rotation by 32+shift
+function int64revrrot(dst, x, shift)
+{
+ dst.l = (x.h >>> shift) | (x.l << (32-shift));
+ dst.h = (x.l >>> shift) | (x.h << (32-shift));
+}
+
+//Bitwise-shifts right a 64-bit number by shift
+//Won't handle shift>=32, but it's never needed in SHA512
+function int64shr(dst, x, shift)
+{
+ dst.l = (x.l >>> shift) | (x.h << (32-shift));
+ dst.h = (x.h >>> shift);
+}
+
+//Adds two 64-bit numbers
+//Like the original implementation, does not rely on 32-bit operations
+function int64add(dst, x, y)
+{
+ var w0 = (x.l & 0xffff) + (y.l & 0xffff);
+ var w1 = (x.l >>> 16) + (y.l >>> 16) + (w0 >>> 16);
+ var w2 = (x.h & 0xffff) + (y.h & 0xffff) + (w1 >>> 16);
+ var w3 = (x.h >>> 16) + (y.h >>> 16) + (w2 >>> 16);
+ dst.l = (w0 & 0xffff) | (w1 << 16);
+ dst.h = (w2 & 0xffff) | (w3 << 16);
+}
+
+//Same, except with 4 addends. Works faster than adding them one by one.
+function int64add4(dst, a, b, c, d)
+{
+ var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff);
+ var w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (w0 >>> 16);
+ var w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (w1 >>> 16);
+ var w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (w2 >>> 16);
+ dst.l = (w0 & 0xffff) | (w1 << 16);
+ dst.h = (w2 & 0xffff) | (w3 << 16);
+}
+
+//Same, except with 5 addends
+function int64add5(dst, a, b, c, d, e)
+{
+ var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff) + (e.l & 0xffff);
+ var w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (e.l >>> 16) + (w0 >>> 16);
+ var w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (e.h & 0xffff) + (w1 >>> 16);
+ var w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (e.h >>> 16) + (w2 >>> 16);
+ dst.l = (w0 & 0xffff) | (w1 << 16);
+ dst.h = (w2 & 0xffff) | (w3 << 16);
+}
+
+/*
+ * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
+ * Digest Algorithm, as defined in RFC 1321.
+ * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
+ * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
+ * Distributed under the BSD License
+ * See http://pajhome.org.uk/crypt/md5 for more info.
+ */
+
+/*
+ * Configurable variables. You may need to tweak these to be compatible with
+ * the server-side, but the defaults work in most cases.
+ */
+var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
+var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
+
+/*
+ * These are the functions you'll usually want to call
+ * They take string arguments and return either hex or base-64 encoded strings
+ */
+function hex_md5(s) { return rstr2hex(rstr_md5(str2rstr_utf8(s))); }
+function b64_md5(s) { return rstr2b64(rstr_md5(str2rstr_utf8(s))); }
+function any_md5(s, e) { return rstr2any(rstr_md5(str2rstr_utf8(s)), e); }
+function hex_hmac_md5(k, d)
+ { return rstr2hex(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); }
+function b64_hmac_md5(k, d)
+ { return rstr2b64(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); }
+function any_hmac_md5(k, d, e)
+ { return rstr2any(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d)), e); }
+
+/*
+ * Perform a simple self-test to see if the VM is working
+ */
+function md5_vm_test()
+{
+ return hex_md5("abc").toLowerCase() == "900150983cd24fb0d6963f7d28e17f72";
+}
+
+/*
+ * Calculate the MD5 of a raw string
+ */
+function rstr_md5(s)
+{
+ return binl2rstr(binl_md5(rstr2binl(s), s.length * 8));
+}
+
+/*
+ * Calculate the HMAC-MD5, of a key and some data (raw strings)
+ */
+function rstr_hmac_md5(key, data)
+{
+ var bkey = rstr2binl(key);
+ if(bkey.length > 16) bkey = binl_md5(bkey, key.length * 8);
+
+ var ipad = Array(16), opad = Array(16);
+ for(var i = 0; i < 16; i++)
+ {
+ ipad[i] = bkey[i] ^ 0x36363636;
+ opad[i] = bkey[i] ^ 0x5C5C5C5C;
+ }
+
+ var hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
+ return binl2rstr(binl_md5(opad.concat(hash), 512 + 128));
+}
+
+/*
+ * Convert a raw string to a hex string
+ */
+function rstr2hex(input)
+{
+ try { hexcase } catch(e) { hexcase=0; }
+ var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
+ var output = "";
+ var x;
+ for(var i = 0; i < input.length; i++)
+ {
+ x = input.charCodeAt(i);
+ output += hex_tab.charAt((x >>> 4) & 0x0F)
+ + hex_tab.charAt( x & 0x0F);
+ }
+ return output;
+}
+
+/*
+ * Convert a raw string to a base-64 string
+ */
+function rstr2b64(input)
+{
+ try { b64pad } catch(e) { b64pad=''; }
+ var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ var output = "";
+ var len = input.length;
+ for(var i = 0; i < len; i += 3)
+ {
+ var triplet = (input.charCodeAt(i) << 16)
+ | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
+ | (i + 2 < len ? input.charCodeAt(i+2) : 0);
+ for(var j = 0; j < 4; j++)
+ {
+ if(i * 8 + j * 6 > input.length * 8) output += b64pad;
+ else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
+ }
+ }
+ return output;
+}
+
+/*
+ * Convert a raw string to an arbitrary string encoding
+ */
+function rstr2any(input, encoding)
+{
+ var divisor = encoding.length;
+ var i, j, q, x, quotient;
+
+ /* Convert to an array of 16-bit big-endian values, forming the dividend */
+ var dividend = Array(Math.ceil(input.length / 2));
+ for(i = 0; i < dividend.length; i++)
+ {
+ dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
+ }
+
+ /*
+ * Repeatedly perform a long division. The binary array forms the dividend,
+ * the length of the encoding is the divisor. Once computed, the quotient
+ * forms the dividend for the next step. All remainders are stored for later
+ * use.
+ */
+ var full_length = Math.ceil(input.length * 8 /
+ (Math.log(encoding.length) / Math.log(2)));
+ var remainders = Array(full_length);
+ for(j = 0; j < full_length; j++)
+ {
+ quotient = Array();
+ x = 0;
+ for(i = 0; i < dividend.length; i++)
+ {
+ x = (x << 16) + dividend[i];
+ q = Math.floor(x / divisor);
+ x -= q * divisor;
+ if(quotient.length > 0 || q > 0)
+ quotient[quotient.length] = q;
+ }
+ remainders[j] = x;
+ dividend = quotient;
+ }
+
+ /* Convert the remainders to the output string */
+ var output = "";
+ for(i = remainders.length - 1; i >= 0; i--)
+ output += encoding.charAt(remainders[i]);
+
+ return output;
+}
+
+/*
+ * Encode a string as utf-8.
+ * For efficiency, this assumes the input is valid utf-16.
+ */
+function str2rstr_utf8(input)
+{
+ var output = "";
+ var i = -1;
+ var x, y;
+
+ while(++i < input.length)
+ {
+ /* Decode utf-16 surrogate pairs */
+ x = input.charCodeAt(i);
+ y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
+ if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
+ {
+ x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
+ i++;
+ }
+
+ /* Encode output as utf-8 */
+ if(x <= 0x7F)
+ output += String.fromCharCode(x);
+ else if(x <= 0x7FF)
+ output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
+ 0x80 | ( x & 0x3F));
+ else if(x <= 0xFFFF)
+ output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
+ 0x80 | ((x >>> 6 ) & 0x3F),
+ 0x80 | ( x & 0x3F));
+ else if(x <= 0x1FFFFF)
+ output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
+ 0x80 | ((x >>> 12) & 0x3F),
+ 0x80 | ((x >>> 6 ) & 0x3F),
+ 0x80 | ( x & 0x3F));
+ }
+ return output;
+}
+
+/*
+ * Encode a string as utf-16
+ */
+function str2rstr_utf16le(input)
+{
+ var output = "";
+ for(var i = 0; i < input.length; i++)
+ output += String.fromCharCode( input.charCodeAt(i) & 0xFF,
+ (input.charCodeAt(i) >>> 8) & 0xFF);
+ return output;
+}
+
+function str2rstr_utf16be(input)
+{
+ var output = "";
+ for(var i = 0; i < input.length; i++)
+ output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
+ input.charCodeAt(i) & 0xFF);
+ return output;
+}
+
+/*
+ * Convert a raw string to an array of little-endian words
+ * Characters >255 have their high-byte silently ignored.
+ */
+function rstr2binl(input)
+{
+ var output = Array(input.length >> 2);
+ for(var i = 0; i < output.length; i++)
+ output[i] = 0;
+ for(var i = 0; i < input.length * 8; i += 8)
+ output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32);
+ return output;
+}
+
+/*
+ * Convert an array of little-endian words to a string
+ */
+function binl2rstr(input)
+{
+ var output = "";
+ for(var i = 0; i < input.length * 32; i += 8)
+ output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF);
+ return output;
+}
+
+/*
+ * Calculate the MD5 of an array of little-endian words, and a bit length.
+ */
+function binl_md5(x, len)
+{
+ /* append padding */
+ x[len >> 5] |= 0x80 << ((len) % 32);
+ x[(((len + 64) >>> 9) << 4) + 14] = len;
+
+ var a = 1732584193;
+ var b = -271733879;
+ var c = -1732584194;
+ var d = 271733878;
+
+ for(var i = 0; i < x.length; i += 16)
+ {
+ var olda = a;
+ var oldb = b;
+ var oldc = c;
+ var oldd = d;
+
+ a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
+ d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
+ c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);
+ b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
+ a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
+ d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);
+ c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
+ b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
+ a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);
+ d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
+ c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
+ b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
+ a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);
+ d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
+ c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
+ b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);
+
+ a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
+ d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
+ c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);
+ b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
+ a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
+ d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);
+ c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
+ b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
+ a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);
+ d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
+ c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
+ b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);
+ a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
+ d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
+ c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);
+ b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
+
+ a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
+ d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
+ c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);
+ b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
+ a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
+ d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);
+ c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
+ b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
+ a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);
+ d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
+ c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
+ b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);
+ a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
+ d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
+ c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);
+ b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
+
+ a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
+ d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);
+ c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
+ b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
+ a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);
+ d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
+ c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
+ b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
+ a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);
+ d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
+ c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
+ b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);
+ a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
+ d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
+ c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);
+ b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
+
+ a = safe_add(a, olda);
+ b = safe_add(b, oldb);
+ c = safe_add(c, oldc);
+ d = safe_add(d, oldd);
+ }
+ return Array(a, b, c, d);
+}
+
+/*
+ * These functions implement the four basic operations the algorithm uses.
+ */
+function md5_cmn(q, a, b, x, s, t)
+{
+ return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
+}
+function md5_ff(a, b, c, d, x, s, t)
+{
+ return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
+}
+function md5_gg(a, b, c, d, x, s, t)
+{
+ return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
+}
+function md5_hh(a, b, c, d, x, s, t)
+{
+ return md5_cmn(b ^ c ^ d, a, b, x, s, t);
+}
+function md5_ii(a, b, c, d, x, s, t)
+{
+ return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
+}
+
+/*
+ * Add integers, wrapping at 2^32. This uses 16-bit operations internally
+ * to work around bugs in some JS interpreters.
+ */
+function safe_add(x, y)
+{
+ var lsw = (x & 0xFFFF) + (y & 0xFFFF);
+ var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
+ return (msw << 16) | (lsw & 0xFFFF);
+}
+
+/*
+ * Bitwise rotate a 32-bit number to the left.
+ */
+function bit_rol(num, cnt)
+{
+ return (num << cnt) | (num >>> (32 - cnt));
+}
+
+/*
+ * A JavaScript implementation of the RIPEMD-160 Algorithm
+ * Version 2.2 Copyright Jeremy Lin, Paul Johnston 2000 - 2009.
+ * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
+ * Distributed under the BSD License
+ * See http://pajhome.org.uk/crypt/md5 for details.
+ * Also http://www.ocf.berkeley.edu/~jjlin/jsotp/
+ */
+
+/*
+ * Configurable variables. You may need to tweak these to be compatible with
+ * the server-side, but the defaults work in most cases.
+ */
+var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
+var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
+
+/*
+ * These are the functions you'll usually want to call
+ * They take string arguments and return either hex or base-64 encoded strings
+ */
+function hex_rmd160(s) { return rstr2hex(rstr_rmd160(str2rstr_utf8(s))); }
+function b64_rmd160(s) { return rstr2b64(rstr_rmd160(str2rstr_utf8(s))); }
+function any_rmd160(s, e) { return rstr2any(rstr_rmd160(str2rstr_utf8(s)), e); }
+function hex_hmac_rmd160(k, d)
+ { return rstr2hex(rstr_hmac_rmd160(str2rstr_utf8(k), str2rstr_utf8(d))); }
+function b64_hmac_rmd160(k, d)
+ { return rstr2b64(rstr_hmac_rmd160(str2rstr_utf8(k), str2rstr_utf8(d))); }
+function any_hmac_rmd160(k, d, e)
+ { return rstr2any(rstr_hmac_rmd160(str2rstr_utf8(k), str2rstr_utf8(d)), e); }
+
+/*
+ * Perform a simple self-test to see if the VM is working
+ */
+function rmd160_vm_test()
+{
+ return hex_rmd160("abc").toLowerCase() == "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc";
+}
+
+/*
+ * Calculate the rmd160 of a raw string
+ */
+function rstr_rmd160(s)
+{
+ return binl2rstr(binl_rmd160(rstr2binl(s), s.length * 8));
+}
+
+/*
+ * Calculate the HMAC-rmd160 of a key and some data (raw strings)
+ */
+function rstr_hmac_rmd160(key, data)
+{
+ var bkey = rstr2binl(key);
+ if(bkey.length > 16) bkey = binl_rmd160(bkey, key.length * 8);
+
+ var ipad = Array(16), opad = Array(16);
+ for(var i = 0; i < 16; i++)
+ {
+ ipad[i] = bkey[i] ^ 0x36363636;
+ opad[i] = bkey[i] ^ 0x5C5C5C5C;
+ }
+
+ var hash = binl_rmd160(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
+ return binl2rstr(binl_rmd160(opad.concat(hash), 512 + 160));
+}
+
+/*
+ * Convert a raw string to a hex string
+ */
+function rstr2hex(input)
+{
+ try { hexcase } catch(e) { hexcase=0; }
+ var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
+ var output = "";
+ var x;
+ for(var i = 0; i < input.length; i++)
+ {
+ x = input.charCodeAt(i);
+ output += hex_tab.charAt((x >>> 4) & 0x0F)
+ + hex_tab.charAt( x & 0x0F);
+ }
+ return output;
+}
+
+/*
+ * Convert a raw string to a base-64 string
+ */
+function rstr2b64(input)
+{
+ try { b64pad } catch(e) { b64pad=''; }
+ var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ var output = "";
+ var len = input.length;
+ for(var i = 0; i < len; i += 3)
+ {
+ var triplet = (input.charCodeAt(i) << 16)
+ | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
+ | (i + 2 < len ? input.charCodeAt(i+2) : 0);
+ for(var j = 0; j < 4; j++)
+ {
+ if(i * 8 + j * 6 > input.length * 8) output += b64pad;
+ else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
+ }
+ }
+ return output;
+}
+
+/*
+ * Convert a raw string to an arbitrary string encoding
+ */
+function rstr2any(input, encoding)
+{
+ var divisor = encoding.length;
+ var remainders = Array();
+ var i, q, x, quotient;
+
+ /* Convert to an array of 16-bit big-endian values, forming the dividend */
+ var dividend = Array(Math.ceil(input.length / 2));
+ for(i = 0; i < dividend.length; i++)
+ {
+ dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
+ }
+
+ /*
+ * Repeatedly perform a long division. The binary array forms the dividend,
+ * the length of the encoding is the divisor. Once computed, the quotient
+ * forms the dividend for the next step. We stop when the dividend is zero.
+ * All remainders are stored for later use.
+ */
+ while(dividend.length > 0)
+ {
+ quotient = Array();
+ x = 0;
+ for(i = 0; i < dividend.length; i++)
+ {
+ x = (x << 16) + dividend[i];
+ q = Math.floor(x / divisor);
+ x -= q * divisor;
+ if(quotient.length > 0 || q > 0)
+ quotient[quotient.length] = q;
+ }
+ remainders[remainders.length] = x;
+ dividend = quotient;
+ }
+
+ /* Convert the remainders to the output string */
+ var output = "";
+ for(i = remainders.length - 1; i >= 0; i--)
+ output += encoding.charAt(remainders[i]);
+
+ /* Append leading zero equivalents */
+ var full_length = Math.ceil(input.length * 8 /
+ (Math.log(encoding.length) / Math.log(2)))
+ for(i = output.length; i < full_length; i++)
+ output = encoding[0] + output;
+
+ return output;
+}
+
+/*
+ * Encode a string as utf-8.
+ * For efficiency, this assumes the input is valid utf-16.
+ */
+function str2rstr_utf8(input)
+{
+ var output = "";
+ var i = -1;
+ var x, y;
+
+ while(++i < input.length)
+ {
+ /* Decode utf-16 surrogate pairs */
+ x = input.charCodeAt(i);
+ y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
+ if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
+ {
+ x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
+ i++;
+ }
+
+ /* Encode output as utf-8 */
+ if(x <= 0x7F)
+ output += String.fromCharCode(x);
+ else if(x <= 0x7FF)
+ output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
+ 0x80 | ( x & 0x3F));
+ else if(x <= 0xFFFF)
+ output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
+ 0x80 | ((x >>> 6 ) & 0x3F),
+ 0x80 | ( x & 0x3F));
+ else if(x <= 0x1FFFFF)
+ output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
+ 0x80 | ((x >>> 12) & 0x3F),
+ 0x80 | ((x >>> 6 ) & 0x3F),
+ 0x80 | ( x & 0x3F));
+ }
+ return output;
+}
+
+/*
+ * Encode a string as utf-16
+ */
+function str2rstr_utf16le(input)
+{
+ var output = "";
+ for(var i = 0; i < input.length; i++)
+ output += String.fromCharCode( input.charCodeAt(i) & 0xFF,
+ (input.charCodeAt(i) >>> 8) & 0xFF);
+ return output;
+}
+
+function str2rstr_utf16be(input)
+{
+ var output = "";
+ for(var i = 0; i < input.length; i++)
+ output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
+ input.charCodeAt(i) & 0xFF);
+ return output;
+}
+
+/*
+ * Convert a raw string to an array of little-endian words
+ * Characters >255 have their high-byte silently ignored.
+ */
+function rstr2binl(input)
+{
+ var output = Array(input.length >> 2);
+ for(var i = 0; i < output.length; i++)
+ output[i] = 0;
+ for(var i = 0; i < input.length * 8; i += 8)
+ output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32);
+ return output;
+}
+
+/*
+ * Convert an array of little-endian words to a string
+ */
+function binl2rstr(input)
+{
+ var output = "";
+ for(var i = 0; i < input.length * 32; i += 8)
+ output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF);
+ return output;
+}
+
+/*
+ * Calculate the RIPE-MD160 of an array of little-endian words, and a bit length.
+ */
+function binl_rmd160(x, len)
+{
+ /* append padding */
+ x[len >> 5] |= 0x80 << (len % 32);
+ x[(((len + 64) >>> 9) << 4) + 14] = len;
+
+ var h0 = 0x67452301;
+ var h1 = 0xefcdab89;
+ var h2 = 0x98badcfe;
+ var h3 = 0x10325476;
+ var h4 = 0xc3d2e1f0;
+
+ for (var i = 0; i < x.length; i += 16) {
+ var T;
+ var A1 = h0, B1 = h1, C1 = h2, D1 = h3, E1 = h4;
+ var A2 = h0, B2 = h1, C2 = h2, D2 = h3, E2 = h4;
+ for (var j = 0; j <= 79; ++j) {
+ T = safe_add(A1, rmd160_f(j, B1, C1, D1));
+ T = safe_add(T, x[i + rmd160_r1[j]]);
+ T = safe_add(T, rmd160_K1(j));
+ T = safe_add(bit_rol(T, rmd160_s1[j]), E1);
+ A1 = E1; E1 = D1; D1 = bit_rol(C1, 10); C1 = B1; B1 = T;
+ T = safe_add(A2, rmd160_f(79-j, B2, C2, D2));
+ T = safe_add(T, x[i + rmd160_r2[j]]);
+ T = safe_add(T, rmd160_K2(j));
+ T = safe_add(bit_rol(T, rmd160_s2[j]), E2);
+ A2 = E2; E2 = D2; D2 = bit_rol(C2, 10); C2 = B2; B2 = T;
+ }
+ T = safe_add(h1, safe_add(C1, D2));
+ h1 = safe_add(h2, safe_add(D1, E2));
+ h2 = safe_add(h3, safe_add(E1, A2));
+ h3 = safe_add(h4, safe_add(A1, B2));
+ h4 = safe_add(h0, safe_add(B1, C2));
+ h0 = T;
+ }
+ return [h0, h1, h2, h3, h4];
+}
+
+function rmd160_f(j, x, y, z)
+{
+ return ( 0 <= j && j <= 15) ? (x ^ y ^ z) :
+ (16 <= j && j <= 31) ? (x & y) | (~x & z) :
+ (32 <= j && j <= 47) ? (x | ~y) ^ z :
+ (48 <= j && j <= 63) ? (x & z) | (y & ~z) :
+ (64 <= j && j <= 79) ? x ^ (y | ~z) :
+ "rmd160_f: j out of range";
+}
+function rmd160_K1(j)
+{
+ return ( 0 <= j && j <= 15) ? 0x00000000 :
+ (16 <= j && j <= 31) ? 0x5a827999 :
+ (32 <= j && j <= 47) ? 0x6ed9eba1 :
+ (48 <= j && j <= 63) ? 0x8f1bbcdc :
+ (64 <= j && j <= 79) ? 0xa953fd4e :
+ "rmd160_K1: j out of range";
+}
+function rmd160_K2(j)
+{
+ return ( 0 <= j && j <= 15) ? 0x50a28be6 :
+ (16 <= j && j <= 31) ? 0x5c4dd124 :
+ (32 <= j && j <= 47) ? 0x6d703ef3 :
+ (48 <= j && j <= 63) ? 0x7a6d76e9 :
+ (64 <= j && j <= 79) ? 0x00000000 :
+ "rmd160_K2: j out of range";
+}
+var rmd160_r1 = [
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
+ 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
+ 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
+ 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
+];
+var rmd160_r2 = [
+ 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
+ 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
+ 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
+ 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
+ 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
+];
+var rmd160_s1 = [
+ 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
+ 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
+ 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
+ 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
+ 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
+];
+var rmd160_s2 = [
+ 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
+ 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
+ 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
+ 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
+ 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
+];
+
+/*
+ * Add integers, wrapping at 2^32. This uses 16-bit operations internally
+ * to work around bugs in some JS interpreters.
+ */
+function safe_add(x, y)
+{
+ var lsw = (x & 0xFFFF) + (y & 0xFFFF);
+ var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
+ return (msw << 16) | (lsw & 0xFFFF);
+}
+
+/*
+ * Bitwise rotate a 32-bit number to the left.
+ */
+function bit_rol(num, cnt)
+{
+ return (num << cnt) | (num >>> (32 - cnt));
+}
+
+var b64map="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+var b64pad="=";
+
+function hex2b64(h) {
+ var i;
+ var c;
+ var ret = "";
+ for(i = 0; i+3 <= h.length; i+=3) {
+ c = parseInt(h.substring(i,i+3),16);
+ ret += b64map.charAt(c >> 6) + b64map.charAt(c & 63);
+ }
+ if(i+1 == h.length) {
+ c = parseInt(h.substring(i,i+1),16);
+ ret += b64map.charAt(c << 2);
+ }
+ else if(i+2 == h.length) {
+ c = parseInt(h.substring(i,i+2),16);
+ ret += b64map.charAt(c >> 2) + b64map.charAt((c & 3) << 4);
+ }
+ while((ret.length & 3) > 0) ret += b64pad;
+ return ret;
+}
+
+// convert a base64 string to hex
+function b64tohex(s) {
+ var ret = ""
+ var i;
+ var k = 0; // b64 state, 0-3
+ var slop;
+ for(i = 0; i < s.length; ++i) {
+ if(s.charAt(i) == b64pad) break;
+ v = b64map.indexOf(s.charAt(i));
+ if(v < 0) continue;
+ if(k == 0) {
+ ret += int2char(v >> 2);
+ slop = v & 3;
+ k = 1;
+ }
+ else if(k == 1) {
+ ret += int2char((slop << 2) | (v >> 4));
+ slop = v & 0xf;
+ k = 2;
+ }
+ else if(k == 2) {
+ ret += int2char(slop);
+ ret += int2char(v >> 2);
+ slop = v & 3;
+ k = 3;
+ }
+ else {
+ ret += int2char((slop << 2) | (v >> 4));
+ ret += int2char(v & 0xf);
+ k = 0;
+ }
+ }
+ if(k == 1)
+ ret += int2char(slop << 2);
+ return ret;
+}
+
+// convert a base64 string to a byte/number array
+function b64toBA(s) {
+ //piggyback on b64tohex for now, optimize later
+ var h = b64tohex(s);
+ var i;
+ var a = new Array();
+ for(i = 0; 2*i < h.length; ++i) {
+ a[i] = parseInt(h.substring(2*i,2*i+2),16);
+ }
+ return a;
+}
+
+// Depends on jsbn.js and rng.js
+
+// Version 1.1: support utf-8 encoding in pkcs1pad2
+
+// convert a (hex) string to a bignum object
+function parseBigInt(str,r) {
+ return new BigInteger(str,r);
+}
+
+function linebrk(s,n) {
+ var ret = "";
+ var i = 0;
+ while(i + n < s.length) {
+ ret += s.substring(i,i+n) + "\n";
+ i += n;
+ }
+ return ret + s.substring(i,s.length);
+}
+
+function byte2Hex(b) {
+ if(b < 0x10)
+ return "0" + b.toString(16);
+ else
+ return b.toString(16);
+}
+
+/**
+ * PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint
+ * @param s: the string to encode
+ * @param n: the size in byte
+ */
+function pkcs1pad2(s,n) {
+ if(n < s.length + 11) { // TODO: fix for utf-8
+ alert("Message too long for RSA");
+ return null;
+ }
+ var ba = new Array();
+ var i = s.length - 1;
+ while(i >= 0 && n > 0) {
+ var c = s.charCodeAt(i--);
+ if(c < 128) { // encode using utf-8
+ ba[--n] = c;
+ }
+ else if((c > 127) && (c < 2048)) {
+ ba[--n] = (c & 63) | 128;
+ ba[--n] = (c >> 6) | 192;
+ }
+ else {
+ ba[--n] = (c & 63) | 128;
+ ba[--n] = ((c >> 6) & 63) | 128;
+ ba[--n] = (c >> 12) | 224;
+ }
+ }
+ ba[--n] = 0;
+ var rng = new SecureRandom();
+ var x = new Array();
+ while(n > 2) { // random non-zero pad
+ x[0] = 0;
+ while(x[0] == 0) rng.nextBytes(x);
+ ba[--n] = x[0];
+ }
+ ba[--n] = 2;
+ ba[--n] = 0;
+ return new BigInteger(ba);
+}
+
+/**
+ * "empty" RSA key constructor
+ * @returns {RSAKey}
+ */
+function RSAKey() {
+ this.n = null;
+ this.e = 0;
+ this.d = null;
+ this.p = null;
+ this.q = null;
+ this.dmp1 = null;
+ this.dmq1 = null;
+ this.coeff = null;
+}
+
+/**
+ * Set the public key fields N and e from hex strings
+ * @param N
+ * @param E
+ * @returns {RSASetPublic}
+ */
+function RSASetPublic(N,E) {
+ if(N != null && E != null && N.length > 0 && E.length > 0) {
+ this.n = parseBigInt(N,16);
+ this.e = parseInt(E,16);
+ }
+ else
+ alert("Invalid RSA public key");
+}
+
+/**
+ * Perform raw public operation on "x": return x^e (mod n)
+ * @param x
+ * @returns x^e (mod n)
+ */
+function RSADoPublic(x) {
+ return x.modPowInt(this.e, this.n);
+}
+
+/**
+ * Return the PKCS#1 RSA encryption of "text" as an even-length hex string
+ */
+function RSAEncrypt(text) {
+ var m = pkcs1pad2(text,(this.n.bitLength()+7)>>3);
+ if(m == null) return null;
+ var c = this.doPublic(m);
+ if(c == null) return null;
+ var h = c.toString(16);
+ if((h.length & 1) == 0) return h; else return "0" + h;
+}
+
+// Return the PKCS#1 RSA encryption of "text" as a Base64-encoded string
+//function RSAEncryptB64(text) {
+// var h = this.encrypt(text);
+// if(h) return hex2b64(h); else return null;
+//}
+
+// protected
+RSAKey.prototype.doPublic = RSADoPublic;
+
+// public
+RSAKey.prototype.setPublic = RSASetPublic;
+RSAKey.prototype.encrypt = RSAEncrypt;
+//RSAKey.prototype.encrypt_b64 = RSAEncryptB64;
+
+// Depends on rsa.js and jsbn2.js
+
+// Version 1.1: support utf-8 decoding in pkcs1unpad2
+
+// Undo PKCS#1 (type 2, random) padding and, if valid, return the plaintext
+function pkcs1unpad2(d,n) {
+ var b = d.toByteArray();
+ var i = 0;
+ while(i < b.length && b[i] == 0) ++i;
+ if(b.length-i != n-1 || b[i] != 2)
+ return null;
+ ++i;
+ while(b[i] != 0)
+ if(++i >= b.length) return null;
+ var ret = "";
+ while(++i < b.length) {
+ var c = b[i] & 255;
+ if(c < 128) { // utf-8 decode
+ ret += String.fromCharCode(c);
+ }
+ else if((c > 191) && (c < 224)) {
+ ret += String.fromCharCode(((c & 31) << 6) | (b[i+1] & 63));
+ ++i;
+ }
+ else {
+ ret += String.fromCharCode(((c & 15) << 12) | ((b[i+1] & 63) << 6) | (b[i+2] & 63));
+ i += 2;
+ }
+ }
+ return ret;
+}
+
+// Set the private key fields N, e, and d from hex strings
+function RSASetPrivate(N,E,D) {
+ if(N != null && E != null && N.length > 0 && E.length > 0) {
+ this.n = parseBigInt(N,16);
+ this.e = parseInt(E,16);
+ this.d = parseBigInt(D,16);
+ }
+ else
+ alert("Invalid RSA private key");
+}
+
+// Set the private key fields N, e, d and CRT params from hex strings
+function RSASetPrivateEx(N,E,D,P,Q,DP,DQ,C) {
+ if(N != null && E != null && N.length > 0 && E.length > 0) {
+ this.n = parseBigInt(N,16);
+ this.e = parseInt(E,16);
+ this.d = parseBigInt(D,16);
+ this.p = parseBigInt(P,16);
+ this.q = parseBigInt(Q,16);
+ this.dmp1 = parseBigInt(DP,16);
+ this.dmq1 = parseBigInt(DQ,16);
+ this.coeff = parseBigInt(C,16);
+ }
+ else
+ alert("Invalid RSA private key");
+}
+
+/**
+ * Generate a new random private key B bits long, using public expt E
+ */
+function RSAGenerate(B,E) {
+ var rng = new SecureRandom();
+ var qs = B>>1;
+ this.e = parseInt(E,16);
+ var ee = new BigInteger(E,16);
+ for(;;) {
+ for(;;) {
+ this.p = new BigInteger(B-qs,1,rng);
+ if(this.p.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.p.isProbablePrime(10)) break;
+ }
+ for(;;) {
+ this.q = new BigInteger(qs,1,rng);
+ if(this.q.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.q.isProbablePrime(10)) break;
+ }
+ if(this.p.compareTo(this.q) <= 0) {
+ var t = this.p;
+ this.p = this.q;
+ this.q = t;
+ }
+ var p1 = this.p.subtract(BigInteger.ONE); // p1 = p - 1
+ var q1 = this.q.subtract(BigInteger.ONE); // q1 = q - 1
+ var phi = p1.multiply(q1);
+ if(phi.gcd(ee).compareTo(BigInteger.ONE) == 0) {
+ this.n = this.p.multiply(this.q); // this.n = p * q
+ this.d = ee.modInverse(phi); // this.d =
+ this.dmp1 = this.d.mod(p1); // this.dmp1 = d mod (p - 1)
+ this.dmq1 = this.d.mod(q1); // this.dmq1 = d mod (q - 1)
+ this.coeff = this.q.modInverse(this.p); // this.coeff = (q ^ -1) mod p
+ break;
+ }
+ }
+}
+
+/**
+ * Perform raw private operation on "x": return x^d (mod n)
+ * @return x^d (mod n)
+ */
+function RSADoPrivate(x) {
+ if(this.p == null || this.q == null)
+ return x.modPow(this.d, this.n);
+
+ // TODO: re-calculate any missing CRT params
+ var xp = x.mod(this.p).modPow(this.dmp1, this.p); // xp=cp?
+ var xq = x.mod(this.q).modPow(this.dmq1, this.q); // xq=cq?
+
+ while(xp.compareTo(xq) < 0)
+ xp = xp.add(this.p);
+ // NOTE:
+ // xp.subtract(xq) => cp -cq
+ // xp.subtract(xq).multiply(this.coeff).mod(this.p) => (cp - cq) * u mod p = h
+ // xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq) => cq + (h * q) = M
+ return xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq);
+}
+
+// Return the PKCS#1 RSA decryption of "ctext".
+// "ctext" is an even-length hex string and the output is a plain string.
+function RSADecrypt(ctext) {
+ var c = parseBigInt(ctext, 16);
+ var m = this.doPrivate(c);
+ if(m == null) return null;
+ return pkcs1unpad2(m, (this.n.bitLength()+7)>>3);
+}
+
+// Return the PKCS#1 RSA decryption of "ctext".
+// "ctext" is a Base64-encoded string and the output is a plain string.
+//function RSAB64Decrypt(ctext) {
+// var h = b64tohex(ctext);
+// if(h) return this.decrypt(h); else return null;
+//}
+
+// protected
+RSAKey.prototype.doPrivate = RSADoPrivate;
+
+// public
+RSAKey.prototype.setPrivate = RSASetPrivate;
+RSAKey.prototype.setPrivateEx = RSASetPrivateEx;
+RSAKey.prototype.generate = RSAGenerate;
+RSAKey.prototype.decrypt = RSADecrypt;
+//RSAKey.prototype.b64_decrypt = RSAB64Decrypt;
+
+/*! rsapem-1.1.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
+ */
+//
+// rsa-pem.js - adding function for reading/writing PKCS#1 PEM private key
+// to RSAKey class.
+//
+// version: 1.1 (2012-May-10)
+//
+// Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com)
+//
+// This software is licensed under the terms of the MIT License.
+// http://kjur.github.com/jsrsasign/license/
+//
+// The above copyright and license notice shall be
+// included in all copies or substantial portions of the Software.
+//
+//
+// Depends on:
+//
+//
+//
+// _RSApem_pemToBase64(sPEM)
+//
+// removing PEM header, PEM footer and space characters including
+// new lines from PEM formatted RSA private key string.
+//
+
+function _rsapem_pemToBase64(sPEMPrivateKey) {
+ var s = sPEMPrivateKey;
+ s = s.replace("-----BEGIN RSA PRIVATE KEY-----", "");
+ s = s.replace("-----END RSA PRIVATE KEY-----", "");
+ s = s.replace(/[ \n]+/g, "");
+ return s;
+}
+
+function _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey) {
+ var a = new Array();
+ var v1 = ASN1HEX.getStartPosOfV_AtObj(hPrivateKey, 0);
+ var n1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, v1);
+ var e1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, n1);
+ var d1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, e1);
+ var p1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, d1);
+ var q1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, p1);
+ var dp1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, q1);
+ var dq1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, dp1);
+ var co1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, dq1);
+ a.push(v1, n1, e1, d1, p1, q1, dp1, dq1, co1);
+ return a;
+}
+
+function _rsapem_getHexValueArrayOfChildrenFromHex(hPrivateKey) {
+ var posArray = _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey);
+ var v = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[0]);
+ var n = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[1]);
+ var e = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[2]);
+ var d = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[3]);
+ var p = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[4]);
+ var q = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[5]);
+ var dp = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[6]);
+ var dq = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[7]);
+ var co = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[8]);
+ var a = new Array();
+ a.push(v, n, e, d, p, q, dp, dq, co);
+ return a;
+}
+
+/**
+ * read PKCS#1 private key from a string
+ * @name readPrivateKeyFromPEMString
+ * @memberOf RSAKey#
+ * @function
+ * @param {String} keyPEM string of PKCS#1 private key.
+ */
+function _rsapem_readPrivateKeyFromPEMString(keyPEM) {
+ var keyB64 = _rsapem_pemToBase64(keyPEM);
+ var keyHex = b64tohex(keyB64) // depends base64.js
+ var a = _rsapem_getHexValueArrayOfChildrenFromHex(keyHex);
+ this.setPrivateEx(a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8]);
+}
+
+RSAKey.prototype.readPrivateKeyFromPEMString = _rsapem_readPrivateKeyFromPEMString;
+
+/*! rsasign-1.2.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
+ */
+//
+// rsa-sign.js - adding signing functions to RSAKey class.
+//
+//
+// version: 1.2.1 (08 May 2012)
+//
+// Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com)
+//
+// This software is licensed under the terms of the MIT License.
+// http://kjur.github.com/jsrsasign/license/
+//
+// The above copyright and license notice shall be
+// included in all copies or substantial portions of the Software.
+
+//
+// Depends on:
+// function sha1.hex(s) of sha1.js
+// jsbn.js
+// jsbn2.js
+// rsa.js
+// rsa2.js
+//
+
+// keysize / pmstrlen
+// 512 / 128
+// 1024 / 256
+// 2048 / 512
+// 4096 / 1024
+
+/**
+ * @property {Dictionary} _RSASIGN_DIHEAD
+ * @description Array of head part of hexadecimal DigestInfo value for hash algorithms.
+ * You can add any DigestInfo hash algorith for signing.
+ * See PKCS#1 v2.1 spec (p38).
+ */
+var _RSASIGN_DIHEAD = [];
+_RSASIGN_DIHEAD['sha1'] = "3021300906052b0e03021a05000414";
+_RSASIGN_DIHEAD['sha256'] = "3031300d060960864801650304020105000420";
+_RSASIGN_DIHEAD['sha384'] = "3041300d060960864801650304020205000430";
+_RSASIGN_DIHEAD['sha512'] = "3051300d060960864801650304020305000440";
+_RSASIGN_DIHEAD['md2'] = "3020300c06082a864886f70d020205000410";
+_RSASIGN_DIHEAD['md5'] = "3020300c06082a864886f70d020505000410";
+_RSASIGN_DIHEAD['ripemd160'] = "3021300906052b2403020105000414";
+
+/**
+ * @property {Dictionary} _RSASIGN_HASHHEXFUNC
+ * @description Array of functions which calculate hash and returns it as hexadecimal.
+ * You can add any hash algorithm implementations.
+ */
+var _RSASIGN_HASHHEXFUNC = [];
+_RSASIGN_HASHHEXFUNC['sha1'] = function(s){return hex_sha1(s);}; // http://pajhome.org.uk/crypt/md5/md5.html
+_RSASIGN_HASHHEXFUNC['sha256'] = function(s){return hex_sha256(s);} // http://pajhome.org.uk/crypt/md5/md5.html
+_RSASIGN_HASHHEXFUNC['sha512'] = function(s){return hex_sha512(s);} // http://pajhome.org.uk/crypt/md5/md5.html
+_RSASIGN_HASHHEXFUNC['md5'] = function(s){return hex_md5(s);}; // http://pajhome.org.uk/crypt/md5/md5.html
+_RSASIGN_HASHHEXFUNC['ripemd160'] = function(s){return hex_rmd160(s);}; // http://pajhome.org.uk/crypt/md5/md5.html
+
+//@author axelcdv
+var _RSASIGN_HASHBYTEFUNC = [];
+_RSASIGN_HASHBYTEFUNC['sha256'] = function(byteArray){return hex_sha256_from_bytes(byteArray);};
+
+//_RSASIGN_HASHHEXFUNC['sha1'] = function(s){return sha1.hex(s);} // http://user1.matsumoto.ne.jp/~goma/js/hash.html
+//_RSASIGN_HASHHEXFUNC['sha256'] = function(s){return sha256.hex;} // http://user1.matsumoto.ne.jp/~goma/js/hash.html
+
+var _RE_HEXDECONLY = new RegExp("");
+_RE_HEXDECONLY.compile("[^0-9a-f]", "gi");
+
+// ========================================================================
+// Signature Generation
+// ========================================================================
+
+function _rsasign_getHexPaddedDigestInfoForString(s, keySize, hashAlg) {
+ var pmStrLen = keySize / 4;
+ var hashFunc = _RSASIGN_HASHHEXFUNC[hashAlg];
+ var sHashHex = hashFunc(s);
+
+ var sHead = "0001";
+ var sTail = "00" + _RSASIGN_DIHEAD[hashAlg] + sHashHex;
+ var sMid = "";
+ var fLen = pmStrLen - sHead.length - sTail.length;
+ for (var i = 0; i < fLen; i += 2) {
+ sMid += "ff";
+ }
+ sPaddedMessageHex = sHead + sMid + sTail;
+ return sPaddedMessageHex;
+}
+
+
+//@author: ucla-cs
+function _rsasign_getHexPaddedDigestInfoForStringHEX(s, keySize, hashAlg) {
+ var pmStrLen = keySize / 4;
+ var hashFunc = _RSASIGN_HASHHEXFUNC[hashAlg];
+ var sHashHex = hashFunc(s);
+
+ var sHead = "0001";
+ var sTail = "00" + _RSASIGN_DIHEAD[hashAlg] + sHashHex;
+ var sMid = "";
+ var fLen = pmStrLen - sHead.length - sTail.length;
+ for (var i = 0; i < fLen; i += 2) {
+ sMid += "ff";
+ }
+ sPaddedMessageHex = sHead + sMid + sTail;
+ return sPaddedMessageHex;
+}
+
+/**
+ * Apply padding, then computes the hash of the given byte array, according to the key size and with the hash algorithm
+ * @param byteArray (byte[])
+ * @param keySize (int)
+ * @param hashAlg the hash algorithm to apply (string)
+ * @return the hash of byteArray
+ */
+function _rsasign_getHexPaddedDigestInfoForByteArray(byteArray, keySize, hashAlg){
+ var pmStrLen = keySize / 4;
+ var hashFunc = _RSASIGN_HASHBYTEFUNC[hashAlg];
+ var sHashHex = hashFunc(byteArray); //returns hex hash
+
+ var sHead = "0001";
+ var sTail = "00" + _RSASIGN_DIHEAD[hashAlg] + sHashHex;
+ var sMid = "";
+ var fLen = pmStrLen - sHead.length - sTail.length;
+ for (var i = 0; i < fLen; i += 2) {
+ sMid += "ff";
+ }
+ sPaddedMessageHex = sHead + sMid + sTail;
+ return sPaddedMessageHex;
+}
+
+function _zeroPaddingOfSignature(hex, bitLength) {
+ var s = "";
+ var nZero = bitLength / 4 - hex.length;
+ for (var i = 0; i < nZero; i++) {
+ s = s + "0";
+ }
+ return s + hex;
+}
+
+/**
+ * sign for a message string with RSA private key.<br/>
+ * @name signString
+ * @memberOf RSAKey#
+ * @function
+ * @param {String} s message string to be signed.
+ * @param {String} hashAlg hash algorithm name for signing.<br/>
+ * @return returns hexadecimal string of signature value.
+ */
+function _rsasign_signString(s, hashAlg) {
+ //alert("this.n.bitLength() = " + this.n.bitLength());
+ var hPM = _rsasign_getHexPaddedDigestInfoForString(s, this.n.bitLength(), hashAlg);
+ var biPaddedMessage = parseBigInt(hPM, 16);
+ var biSign = this.doPrivate(biPaddedMessage);
+ var hexSign = biSign.toString(16);
+ return _zeroPaddingOfSignature(hexSign, this.n.bitLength());
+}
+
+//@author: ucla-cs
+function _rsasign_signStringHEX(s, hashAlg) {
+ //alert("this.n.bitLength() = " + this.n.bitLength());
+ var hPM = _rsasign_getHexPaddedDigestInfoForString(s, this.n.bitLength(), hashAlg);
+ var biPaddedMessage = parseBigInt(hPM, 16);
+ var biSign = this.doPrivate(biPaddedMessage);
+ var hexSign = biSign.toString(16);
+ return _zeroPaddingOfSignature(hexSign, this.n.bitLength());
+}
+
+
+/**
+ * Sign a message byteArray with an RSA private key
+ * @name signByteArray
+ * @memberOf RSAKey#
+ * @function
+ * @param {byte[]} byteArray
+ * @param {Sring} hashAlg the hash algorithm to apply
+ * @param {RSAKey} rsa key to sign with: hack because the context is lost here
+ * @return hexadecimal string of signature value
+ */
+function _rsasign_signByteArray(byteArray, hashAlg, rsaKey) {
+ var hPM = _rsasign_getHexPaddedDigestInfoForByteArray(byteArray, rsaKey.n.bitLength(), hashAlg); ///hack because the context is lost here
+ var biPaddedMessage = parseBigInt(hPM, 16);
+ var biSign = rsaKey.doPrivate(biPaddedMessage); //hack because the context is lost here
+ var hexSign = biSign.toString(16);
+ return _zeroPaddingOfSignature(hexSign, rsaKey.n.bitLength()); //hack because the context is lost here
+}
+
+/**
+ * Sign a byte array with the Sha-256 algorithm
+ * @param {byte[]} byteArray
+ * @return hexadecimal string of signature value
+ */
+function _rsasign_signByteArrayWithSHA256(byteArray){
+ return _rsasign_signByteArray(byteArray, 'sha256', this); //Hack because the context is lost in the next function
+}
+
+
+function _rsasign_signStringWithSHA1(s) {
+ return _rsasign_signString(s, 'sha1');
+}
+
+function _rsasign_signStringWithSHA256(s) {
+ return _rsasign_signString(s, 'sha256');
+}
+
+// ========================================================================
+// Signature Verification
+// ========================================================================
+
+function _rsasign_getDecryptSignatureBI(biSig, hN, hE) {
+ var rsa = new RSAKey();
+ rsa.setPublic(hN, hE);
+ var biDecryptedSig = rsa.doPublic(biSig);
+ return biDecryptedSig;
+}
+
+function _rsasign_getHexDigestInfoFromSig(biSig, hN, hE) {
+ var biDecryptedSig = _rsasign_getDecryptSignatureBI(biSig, hN, hE);
+ var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, '');
+ return hDigestInfo;
+}
+
+function _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo) {
+ for (var algName in _RSASIGN_DIHEAD) {
+ var head = _RSASIGN_DIHEAD[algName];
+ var len = head.length;
+ if (hDigestInfo.substring(0, len) == head) {
+ var a = [algName, hDigestInfo.substring(len)];
+ return a;
+ }
+ }
+ return [];
+}
+
+function _rsasign_verifySignatureWithArgs(sMsg, biSig, hN, hE) {
+ var hDigestInfo = _rsasign_getHexDigestInfoFromSig(biSig, hN, hE);
+ var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo);
+ if (digestInfoAry.length == 0) return false;
+ var algName = digestInfoAry[0];
+ var diHashValue = digestInfoAry[1];
+ var ff = _RSASIGN_HASHHEXFUNC[algName];
+ var msgHashValue = ff(sMsg);
+ return (diHashValue == msgHashValue);
+}
+
+function _rsasign_verifyHexSignatureForMessage(hSig, sMsg) {
+ var biSig = parseBigInt(hSig, 16);
+ var result = _rsasign_verifySignatureWithArgs(sMsg, biSig,
+ this.n.toString(16),
+ this.e.toString(16));
+ return result;
+}
+
+/**
+ * verifies a sigature for a message string with RSA public key.<br/>
+ * @name verifyString
+ * @memberOf RSAKey#
+ * @function
+ * @param {String} sMsg message string to be verified.
+ * @param {String} hSig hexadecimal string of siganture.<br/>
+ * non-hexadecimal charactors including new lines will be ignored.
+ * @return returns 1 if valid, otherwise 0
+ */
+function _rsasign_verifyString(sMsg, hSig) {
+ hSig = hSig.replace(_RE_HEXDECONLY, '');
+
+ if(LOG>3)console.log('n is '+this.n);
+ if(LOG>3)console.log('e is '+this.e);
+
+ if (hSig.length != this.n.bitLength() / 4) return 0;
+ hSig = hSig.replace(/[ \n]+/g, "");
+ var biSig = parseBigInt(hSig, 16);
+ var biDecryptedSig = this.doPublic(biSig);
+ var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, '');
+ var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo);
+
+ if (digestInfoAry.length == 0) return false;
+ var algName = digestInfoAry[0];
+ var diHashValue = digestInfoAry[1];
+ var ff = _RSASIGN_HASHHEXFUNC[algName];
+ var msgHashValue = ff(sMsg);
+ return (diHashValue == msgHashValue);
+}
+
+/**
+ * verifies a sigature for a message byte array with RSA public key.<br/>
+ * @name verifyByteArray
+ * @memberOf RSAKey#
+ * @function
+ * @param {byte[]} byteArray message byte array to be verified.
+ * @param {String} hSig hexadecimal string of signature.<br/>
+ * non-hexadecimal charactors including new lines will be ignored.
+ * @return returns 1 if valid, otherwise 0
+ */
+function _rsasign_verifyByteArray(byteArray, hSig) {
+ hSig = hSig.replace(_RE_HEXDECONLY, '');
+
+ if(LOG>3)console.log('n is '+this.n);
+ if(LOG>3)console.log('e is '+this.e);
+
+ if (hSig.length != this.n.bitLength() / 4) return 0;
+ hSig = hSig.replace(/[ \n]+/g, "");
+ var biSig = parseBigInt(hSig, 16);
+ var biDecryptedSig = this.doPublic(biSig);
+ var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, '');
+ var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo);
+
+ if (digestInfoAry.length == 0) return false;
+ var algName = digestInfoAry[0];
+ var diHashValue = digestInfoAry[1];
+ var ff = _RSASIGN_HASHBYTEFUNC[algName];
+ var msgHashValue = ff(byteArray);
+ return (diHashValue == msgHashValue);
+}
+
+RSAKey.prototype.signString = _rsasign_signString;
+
+RSAKey.prototype.signByteArray = _rsasign_signByteArray; //@author axelcdv
+RSAKey.prototype.signByteArrayWithSHA256 = _rsasign_signByteArrayWithSHA256; //@author axelcdv
+
+RSAKey.prototype.signStringWithSHA1 = _rsasign_signStringWithSHA1;
+RSAKey.prototype.signStringWithSHA256 = _rsasign_signStringWithSHA256;
+RSAKey.prototype.sign = _rsasign_signString;
+RSAKey.prototype.signWithSHA1 = _rsasign_signStringWithSHA1;
+RSAKey.prototype.signWithSHA256 = _rsasign_signStringWithSHA256;
+
+
+/*RSAKey.prototype.signStringHEX = _rsasign_signStringHEX;
+RSAKey.prototype.signStringWithSHA1HEX = _rsasign_signStringWithSHA1HEX;
+RSAKey.prototype.signStringWithSHA256HEX = _rsasign_signStringWithSHA256HEX;
+RSAKey.prototype.signHEX = _rsasign_signStringHEX;
+RSAKey.prototype.signWithSHA1HEX = _rsasign_signStringWithSHA1HEX;
+RSAKey.prototype.signWithSHA256HEX = _rsasign_signStringWithSHA256HEX;
+*/
+
+RSAKey.prototype.verifyByteArray = _rsasign_verifyByteArray;
+RSAKey.prototype.verifyString = _rsasign_verifyString;
+RSAKey.prototype.verifyHexSignatureForMessage = _rsasign_verifyHexSignatureForMessage;
+RSAKey.prototype.verify = _rsasign_verifyString;
+RSAKey.prototype.verifyHexSignatureForByteArrayMessage = _rsasign_verifyHexSignatureForMessage;
+
+/*
+RSAKey.prototype.verifyStringHEX = _rsasign_verifyStringHEX;
+RSAKey.prototype.verifyHexSignatureForMessageHEX = _rsasign_verifyHexSignatureForMessageHEX;
+RSAKey.prototype.verifyHEX = _rsasign_verifyStringHEX;
+RSAKey.prototype.verifyHexSignatureForByteArrayMessageHEX = _rsasign_verifyHexSignatureForMessageHEX;
+*/
+
+
+/**
+ * @name RSAKey
+ * @class
+ * @description Tom Wu's RSA Key class and extension
+ */
+
+/*! asn1hex-1.1.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
+ */
+//
+// asn1hex.js - Hexadecimal represented ASN.1 string library
+//
+// version: 1.1 (09-May-2012)
+//
+// Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com)
+//
+// This software is licensed under the terms of the MIT License.
+// http://kjur.github.com/jsrsasign/license/
+//
+// The above copyright and license notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// Depends on:
+//
+
+// MEMO:
+// f('3082025b02...', 2) ... 82025b ... 3bytes
+// f('020100', 2) ... 01 ... 1byte
+// f('0203001...', 2) ... 03 ... 1byte
+// f('02818003...', 2) ... 8180 ... 2bytes
+// f('3080....0000', 2) ... 80 ... -1
+//
+// Requirements:
+// - ASN.1 type octet length MUST be 1.
+// (i.e. ASN.1 primitives like SET, SEQUENCE, INTEGER, OCTETSTRING ...)
+// -
+/**
+ * get byte length for ASN.1 L(length) bytes
+ * @name getByteLengthOfL_AtObj
+ * @memberOf ASN1HEX
+ * @function
+ * @param {String} s hexadecimal string of ASN.1 DER encoded data
+ * @param {Number} pos string index
+ * @return byte length for ASN.1 L(length) bytes
+ */
+function _asnhex_getByteLengthOfL_AtObj(s, pos) {
+ if (s.substring(pos + 2, pos + 3) != '8') return 1;
+ var i = parseInt(s.substring(pos + 3, pos + 4));
+ if (i == 0) return -1; // length octet '80' indefinite length
+ if (0 < i && i < 10) return i + 1; // including '8?' octet;
+ return -2; // malformed format
+}
+
+
+/**
+ * get hexadecimal string for ASN.1 L(length) bytes
+ * @name getHexOfL_AtObj
+ * @memberOf ASN1HEX
+ * @function
+ * @param {String} s hexadecimal string of ASN.1 DER encoded data
+ * @param {Number} pos string index
+ * @return {String} hexadecimal string for ASN.1 L(length) bytes
+ */
+function _asnhex_getHexOfL_AtObj(s, pos) {
+ var len = _asnhex_getByteLengthOfL_AtObj(s, pos);
+ if (len < 1) return '';
+ return s.substring(pos + 2, pos + 2 + len * 2);
+}
+
+//
+// getting ASN.1 length value at the position 'idx' of
+// hexa decimal string 's'.
+//
+// f('3082025b02...', 0) ... 82025b ... ???
+// f('020100', 0) ... 01 ... 1
+// f('0203001...', 0) ... 03 ... 3
+// f('02818003...', 0) ... 8180 ... 128
+/**
+ * get integer value of ASN.1 length for ASN.1 data
+ * @name getIntOfL_AtObj
+ * @memberOf ASN1HEX
+ * @function
+ * @param {String} s hexadecimal string of ASN.1 DER encoded data
+ * @param {Number} pos string index
+ * @return ASN.1 L(length) integer value
+ */
+function _asnhex_getIntOfL_AtObj(s, pos) {
+ var hLength = _asnhex_getHexOfL_AtObj(s, pos);
+ if (hLength == '') return -1;
+ var bi;
+ if (parseInt(hLength.substring(0, 1)) < 8) {
+ bi = parseBigInt(hLength, 16);
+ } else {
+ bi = parseBigInt(hLength.substring(2), 16);
+ }
+ return bi.intValue();
+}
+
+/**
+ * get ASN.1 value starting string position for ASN.1 object refered by index 'idx'.
+ * @name getStartPosOfV_AtObj
+ * @memberOf ASN1HEX
+ * @function
+ * @param {String} s hexadecimal string of ASN.1 DER encoded data
+ * @param {Number} pos string index
+ */
+function _asnhex_getStartPosOfV_AtObj(s, pos) {
+ var l_len = _asnhex_getByteLengthOfL_AtObj(s, pos);
+ if (l_len < 0) return l_len;
+ return pos + (l_len + 1) * 2;
+}
+
+/**
+ * get hexadecimal string of ASN.1 V(value)
+ * @name getHexOfV_AtObj
+ * @memberOf ASN1HEX
+ * @function
+ * @param {String} s hexadecimal string of ASN.1 DER encoded data
+ * @param {Number} pos string index
+ * @return {String} hexadecimal string of ASN.1 value.
+ */
+function _asnhex_getHexOfV_AtObj(s, pos) {
+ var pos1 = _asnhex_getStartPosOfV_AtObj(s, pos);
+ var len = _asnhex_getIntOfL_AtObj(s, pos);
+ return s.substring(pos1, pos1 + len * 2);
+}
+
+/**
+ * get hexadecimal string of ASN.1 TLV at
+ * @name getHexOfTLV_AtObj
+ * @memberOf ASN1HEX
+ * @function
+ * @param {String} s hexadecimal string of ASN.1 DER encoded data
+ * @param {Number} pos string index
+ * @return {String} hexadecimal string of ASN.1 TLV.
+ * @since 1.1
+ */
+function _asnhex_getHexOfTLV_AtObj(s, pos) {
+ var hT = s.substr(pos, 2);
+ var hL = _asnhex_getHexOfL_AtObj(s, pos);
+ var hV = _asnhex_getHexOfV_AtObj(s, pos);
+ return hT + hL + hV;
+}
+
+/**
+ * get next sibling starting index for ASN.1 object string
+ * @name getPosOfNextSibling_AtObj
+ * @memberOf ASN1HEX
+ * @function
+ * @param {String} s hexadecimal string of ASN.1 DER encoded data
+ * @param {Number} pos string index
+ * @return next sibling starting index for ASN.1 object string
+ */
+function _asnhex_getPosOfNextSibling_AtObj(s, pos) {
+ var pos1 = _asnhex_getStartPosOfV_AtObj(s, pos);
+ var len = _asnhex_getIntOfL_AtObj(s, pos);
+ return pos1 + len * 2;
+}
+
+/**
+ * get array of indexes of child ASN.1 objects
+ * @name getPosArrayOfChildren_AtObj
+ * @memberOf ASN1HEX
+ * @function
+ * @param {String} s hexadecimal string of ASN.1 DER encoded data
+ * @param {Number} start string index of ASN.1 object
+ * @return {Array of Number} array of indexes for childen of ASN.1 objects
+ */
+function _asnhex_getPosArrayOfChildren_AtObj(h, pos) {
+ var a = new Array();
+ var p0 = _asnhex_getStartPosOfV_AtObj(h, pos);
+ a.push(p0);
+
+ var len = _asnhex_getIntOfL_AtObj(h, pos);
+ var p = p0;
+ var k = 0;
+ while (1) {
+ var pNext = _asnhex_getPosOfNextSibling_AtObj(h, p);
+ if (pNext == null || (pNext - p0 >= (len * 2))) break;
+ if (k >= 200) break;
+
+ a.push(pNext);
+ p = pNext;
+
+ k++;
+ }
+
+ return a;
+}
+
+/**
+ * get string index of nth child object of ASN.1 object refered by h, idx
+ * @name getNthChildIndex_AtObj
+ * @memberOf ASN1HEX
+ * @function
+ * @param {String} h hexadecimal string of ASN.1 DER encoded data
+ * @param {Number} idx start string index of ASN.1 object
+ * @param {Number} nth for child
+ * @return {Number} string index of nth child.
+ * @since 1.1
+ */
+function _asnhex_getNthChildIndex_AtObj(h, idx, nth) {
+ var a = _asnhex_getPosArrayOfChildren_AtObj(h, idx);
+ return a[nth];
+}
+
+// ========== decendant methods ==============================
+
+/**
+ * get string index of nth child object of ASN.1 object refered by h, idx
+ * @name getDecendantIndexByNthList
+ * @memberOf ASN1HEX
+ * @function
+ * @param {String} h hexadecimal string of ASN.1 DER encoded data
+ * @param {Number} currentIndex start string index of ASN.1 object
+ * @param {Array of Number} nthList array list of nth
+ * @return {Number} string index refered by nthList
+ * @since 1.1
+ */
+function _asnhex_getDecendantIndexByNthList(h, currentIndex, nthList) {
+ if (nthList.length == 0) {
+ return currentIndex;
+ }
+ var firstNth = nthList.shift();
+ var a = _asnhex_getPosArrayOfChildren_AtObj(h, currentIndex);
+ return _asnhex_getDecendantIndexByNthList(h, a[firstNth], nthList);
+}
+
+/**
+ * get hexadecimal string of ASN.1 TLV refered by current index and nth index list.
+ * @name getDecendantHexTLVByNthList
+ * @memberOf ASN1HEX
+ * @function
+ * @param {String} h hexadecimal string of ASN.1 DER encoded data
+ * @param {Number} currentIndex start string index of ASN.1 object
+ * @param {Array of Number} nthList array list of nth
+ * @return {Number} hexadecimal string of ASN.1 TLV refered by nthList
+ * @since 1.1
+ */
+function _asnhex_getDecendantHexTLVByNthList(h, currentIndex, nthList) {
+ var idx = _asnhex_getDecendantIndexByNthList(h, currentIndex, nthList);
+ return _asnhex_getHexOfTLV_AtObj(h, idx);
+}
+
+/**
+ * get hexadecimal string of ASN.1 V refered by current index and nth index list.
+ * @name getDecendantHexVByNthList
+ * @memberOf ASN1HEX
+ * @function
+ * @param {String} h hexadecimal string of ASN.1 DER encoded data
+ * @param {Number} currentIndex start string index of ASN.1 object
+ * @param {Array of Number} nthList array list of nth
+ * @return {Number} hexadecimal string of ASN.1 V refered by nthList
+ * @since 1.1
+ */
+function _asnhex_getDecendantHexVByNthList(h, currentIndex, nthList) {
+ var idx = _asnhex_getDecendantIndexByNthList(h, currentIndex, nthList);
+ return _asnhex_getHexOfV_AtObj(h, idx);
+}
+
+// ========== class definition ==============================
+
+/**
+ * ASN.1 DER encoded hexadecimal string utility class
+ * @class ASN.1 DER encoded hexadecimal string utility class
+ * @author Kenji Urushima
+ * @version 1.1 (09 May 2012)
+ * @see <a href="http://kjur.github.com/jsrsasigns/">'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/</a>
+ * @since 1.1
+ */
+function ASN1HEX() {
+ return ASN1HEX;
+}
+
+ASN1HEX.getByteLengthOfL_AtObj = _asnhex_getByteLengthOfL_AtObj;
+ASN1HEX.getHexOfL_AtObj = _asnhex_getHexOfL_AtObj;
+ASN1HEX.getIntOfL_AtObj = _asnhex_getIntOfL_AtObj;
+ASN1HEX.getStartPosOfV_AtObj = _asnhex_getStartPosOfV_AtObj;
+ASN1HEX.getHexOfV_AtObj = _asnhex_getHexOfV_AtObj;
+ASN1HEX.getHexOfTLV_AtObj = _asnhex_getHexOfTLV_AtObj;
+ASN1HEX.getPosOfNextSibling_AtObj = _asnhex_getPosOfNextSibling_AtObj;
+ASN1HEX.getPosArrayOfChildren_AtObj = _asnhex_getPosArrayOfChildren_AtObj;
+ASN1HEX.getNthChildIndex_AtObj = _asnhex_getNthChildIndex_AtObj;
+ASN1HEX.getDecendantIndexByNthList = _asnhex_getDecendantIndexByNthList;
+ASN1HEX.getDecendantHexVByNthList = _asnhex_getDecendantHexVByNthList;
+ASN1HEX.getDecendantHexTLVByNthList = _asnhex_getDecendantHexTLVByNthList;
+
+/*! x509-1.1.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
+ */
+//
+// x509.js - X509 class to read subject public key from certificate.
+//
+// version: 1.1 (10-May-2012)
+//
+// Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com)
+//
+// This software is licensed under the terms of the MIT License.
+// http://kjur.github.com/jsrsasign/license
+//
+// The above copyright and license notice shall be
+// included in all copies or substantial portions of the Software.
+//
+
+// Depends:
+// base64.js
+// rsa.js
+// asn1hex.js
+
+function _x509_pemToBase64(sCertPEM) {
+ var s = sCertPEM;
+ s = s.replace("-----BEGIN CERTIFICATE-----", "");
+ s = s.replace("-----END CERTIFICATE-----", "");
+ s = s.replace(/[ \n]+/g, "");
+ return s;
+}
+
+function _x509_pemToHex(sCertPEM) {
+ var b64Cert = _x509_pemToBase64(sCertPEM);
+ var hCert = b64tohex(b64Cert);
+ return hCert;
+}
+
+function _x509_getHexTbsCertificateFromCert(hCert) {
+ var pTbsCert = ASN1HEX.getStartPosOfV_AtObj(hCert, 0);
+ return pTbsCert;
+}
+
+// NOTE: privateKeyUsagePeriod field of X509v2 not supported.
+// NOTE: v1 and v3 supported
+function _x509_getSubjectPublicKeyInfoPosFromCertHex(hCert) {
+ var pTbsCert = ASN1HEX.getStartPosOfV_AtObj(hCert, 0);
+ var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pTbsCert);
+ if (a.length < 1) return -1;
+ if (hCert.substring(a[0], a[0] + 10) == "a003020102") { // v3
+ if (a.length < 6) return -1;
+ return a[6];
+ } else {
+ if (a.length < 5) return -1;
+ return a[5];
+ }
+}
+
+// NOTE: Without BITSTRING encapsulation.
+function _x509_getSubjectPublicKeyPosFromCertHex(hCert) {
+ var pInfo = _x509_getSubjectPublicKeyInfoPosFromCertHex(hCert);
+ if (pInfo == -1) return -1;
+ var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pInfo);
+
+ if (a.length != 2) return -1;
+ var pBitString = a[1];
+ if (hCert.substring(pBitString, pBitString + 2) != '03') return -1;
+ var pBitStringV = ASN1HEX.getStartPosOfV_AtObj(hCert, pBitString);
+
+ if (hCert.substring(pBitStringV, pBitStringV + 2) != '00') return -1;
+ return pBitStringV + 2;
+}
+
+function _x509_getPublicKeyHexArrayFromCertHex(hCert) {
+ var p = _x509_getSubjectPublicKeyPosFromCertHex(hCert);
+ var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, p);
+ //var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a[3]);
+ if(LOG>4){
+ console.log('a is now');
+ console.log(a);
+ }
+
+ //if (a.length != 2) return [];
+ if (a.length < 2) return [];
+
+ var hN = ASN1HEX.getHexOfV_AtObj(hCert, a[0]);
+ var hE = ASN1HEX.getHexOfV_AtObj(hCert, a[1]);
+ if (hN != null && hE != null) {
+ return [hN, hE];
+ } else {
+ return [];
+ }
+}
+
+function _x509_getPublicKeyHexArrayFromCertPEM(sCertPEM) {
+ var hCert = _x509_pemToHex(sCertPEM);
+ var a = _x509_getPublicKeyHexArrayFromCertHex(hCert);
+ return a;
+}
+
+// ===== get basic fields from hex =====================================
+/**
+ * get hexadecimal string of serialNumber field of certificate.<br/>
+ * @name getSerialNumberHex
+ * @memberOf X509#
+ * @function
+ */
+function _x509_getSerialNumberHex() {
+ return ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 1]);
+}
+
+/**
+ * get hexadecimal string of issuer field of certificate.<br/>
+ * @name getIssuerHex
+ * @memberOf X509#
+ * @function
+ */
+function _x509_getIssuerHex() {
+ return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3]);
+}
+
+/**
+ * get string of issuer field of certificate.<br/>
+ * @name getIssuerString
+ * @memberOf X509#
+ * @function
+ */
+function _x509_getIssuerString() {
+ return _x509_hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3]));
+}
+
+/**
+ * get hexadecimal string of subject field of certificate.<br/>
+ * @name getSubjectHex
+ * @memberOf X509#
+ * @function
+ */
+function _x509_getSubjectHex() {
+ return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5]);
+}
+
+/**
+ * get string of subject field of certificate.<br/>
+ * @name getSubjectString
+ * @memberOf X509#
+ * @function
+ */
+function _x509_getSubjectString() {
+ return _x509_hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5]));
+}
+
+/**
+ * get notBefore field string of certificate.<br/>
+ * @name getNotBefore
+ * @memberOf X509#
+ * @function
+ */
+function _x509_getNotBefore() {
+ var s = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 4, 0]);
+ s = s.replace(/(..)/g, "%$1");
+ s = decodeURIComponent(s);
+ return s;
+}
+
+/**
+ * get notAfter field string of certificate.<br/>
+ * @name getNotAfter
+ * @memberOf X509#
+ * @function
+ */
+function _x509_getNotAfter() {
+ var s = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 4, 1]);
+ s = s.replace(/(..)/g, "%$1");
+ s = decodeURIComponent(s);
+ return s;
+}
+
+// ===== read certificate =====================================
+
+_x509_DN_ATTRHEX = {
+ "0603550406": "C",
+ "060355040a": "O",
+ "060355040b": "OU",
+ "0603550403": "CN",
+ "0603550405": "SN",
+ "0603550408": "ST",
+ "0603550407": "L" };
+
+function _x509_hex2dn(hDN) {
+ var s = "";
+ var a = ASN1HEX.getPosArrayOfChildren_AtObj(hDN, 0);
+ for (var i = 0; i < a.length; i++) {
+ var hRDN = ASN1HEX.getHexOfTLV_AtObj(hDN, a[i]);
+ s = s + "/" + _x509_hex2rdn(hRDN);
+ }
+ return s;
+}
+
+function _x509_hex2rdn(hRDN) {
+ var hType = ASN1HEX.getDecendantHexTLVByNthList(hRDN, 0, [0, 0]);
+ var hValue = ASN1HEX.getDecendantHexVByNthList(hRDN, 0, [0, 1]);
+ var type = "";
+ try { type = _x509_DN_ATTRHEX[hType]; } catch (ex) { type = hType; }
+ hValue = hValue.replace(/(..)/g, "%$1");
+ var value = decodeURIComponent(hValue);
+ return type + "=" + value;
+}
+
+// ===== read certificate =====================================
+
+
+/**
+ * read PEM formatted X.509 certificate from string.<br/>
+ * @name readCertPEM
+ * @memberOf X509#
+ * @function
+ * @param {String} sCertPEM string for PEM formatted X.509 certificate
+ */
+function _x509_readCertPEM(sCertPEM) {
+ var hCert = _x509_pemToHex(sCertPEM);
+ var a = _x509_getPublicKeyHexArrayFromCertHex(hCert);
+ if(LOG>4){
+ console.log('HEX VALUE IS ' + hCert);
+ console.log('type of a' + typeof a);
+ console.log('a VALUE IS ');
+ console.log(a);
+ console.log('a[0] VALUE IS ' + a[0]);
+ console.log('a[1] VALUE IS ' + a[1]);
+ }
+ var rsa = new RSAKey();
+ rsa.setPublic(a[0], a[1]);
+ this.subjectPublicKeyRSA = rsa;
+ this.subjectPublicKeyRSA_hN = a[0];
+ this.subjectPublicKeyRSA_hE = a[1];
+ this.hex = hCert;
+}
+
+function _x509_readCertPEMWithoutRSAInit(sCertPEM) {
+ var hCert = _x509_pemToHex(sCertPEM);
+ var a = _x509_getPublicKeyHexArrayFromCertHex(hCert);
+ this.subjectPublicKeyRSA.setPublic(a[0], a[1]);
+ this.subjectPublicKeyRSA_hN = a[0];
+ this.subjectPublicKeyRSA_hE = a[1];
+ this.hex = hCert;
+}
+
+/**
+ * X.509 certificate class.<br/>
+ * @class X.509 certificate class
+ * @property {RSAKey} subjectPublicKeyRSA Tom Wu's RSAKey object
+ * @property {String} subjectPublicKeyRSA_hN hexadecimal string for modulus of RSA public key
+ * @property {String} subjectPublicKeyRSA_hE hexadecimal string for public exponent of RSA public key
+ * @property {String} hex hexacedimal string for X.509 certificate.
+ * @author Kenji Urushima
+ * @version 1.0.1 (08 May 2012)
+ * @see <a href="http://kjur.github.com/jsrsasigns/">'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/</a>
+ */
+function X509() {
+ this.subjectPublicKeyRSA = null;
+ this.subjectPublicKeyRSA_hN = null;
+ this.subjectPublicKeyRSA_hE = null;
+ this.hex = null;
+}
+
+X509.prototype.readCertPEM = _x509_readCertPEM;
+X509.prototype.readCertPEMWithoutRSAInit = _x509_readCertPEMWithoutRSAInit;
+X509.prototype.getSerialNumberHex = _x509_getSerialNumberHex;
+X509.prototype.getIssuerHex = _x509_getIssuerHex;
+X509.prototype.getSubjectHex = _x509_getSubjectHex;
+X509.prototype.getIssuerString = _x509_getIssuerString;
+X509.prototype.getSubjectString = _x509_getSubjectString;
+X509.prototype.getNotBefore = _x509_getNotBefore;
+X509.prototype.getNotAfter = _x509_getNotAfter;
+
+
+// Copyright (c) 2005 Tom Wu
+// All Rights Reserved.
+// See "LICENSE" for details.
+
+// Basic JavaScript BN library - subset useful for RSA encryption.
+
+// Bits per digit
+var dbits;
+
+// JavaScript engine analysis
+var canary = 0xdeadbeefcafe;
+var j_lm = ((canary&0xffffff)==0xefcafe);
+
+// (public) Constructor
+function BigInteger(a,b,c) {
+ if(a != null)
+ if("number" == typeof a) this.fromNumber(a,b,c);
+ else if(b == null && "string" != typeof a) this.fromString(a,256);
+ else this.fromString(a,b);
+}
+
+// return new, unset BigInteger
+function nbi() { return new BigInteger(null); }
+
+// am: Compute w_j += (x*this_i), propagate carries,
+// c is initial carry, returns final carry.
+// c < 3*dvalue, x < 2*dvalue, this_i < dvalue
+// We need to select the fastest one that works in this environment.
+
+// am1: use a single mult and divide to get the high bits,
+// max digit bits should be 26 because
+// max internal value = 2*dvalue^2-2*dvalue (< 2^53)
+function am1(i,x,w,j,c,n) {
+ while(--n >= 0) {
+ var v = x*this[i++]+w[j]+c;
+ c = Math.floor(v/0x4000000);
+ w[j++] = v&0x3ffffff;
+ }
+ return c;
+}
+// am2 avoids a big mult-and-extract completely.
+// Max digit bits should be <= 30 because we do bitwise ops
+// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
+function am2(i,x,w,j,c,n) {
+ var xl = x&0x7fff, xh = x>>15;
+ while(--n >= 0) {
+ var l = this[i]&0x7fff;
+ var h = this[i++]>>15;
+ var m = xh*l+h*xl;
+ l = xl*l+((m&0x7fff)<<15)+w[j]+(c&0x3fffffff);
+ c = (l>>>30)+(m>>>15)+xh*h+(c>>>30);
+ w[j++] = l&0x3fffffff;
+ }
+ return c;
+}
+// Alternately, set max digit bits to 28 since some
+// browsers slow down when dealing with 32-bit numbers.
+function am3(i,x,w,j,c,n) {
+ var xl = x&0x3fff, xh = x>>14;
+ while(--n >= 0) {
+ var l = this[i]&0x3fff;
+ var h = this[i++]>>14;
+ var m = xh*l+h*xl;
+ l = xl*l+((m&0x3fff)<<14)+w[j]+c;
+ c = (l>>28)+(m>>14)+xh*h;
+ w[j++] = l&0xfffffff;
+ }
+ return c;
+}
+if(j_lm && (navigator.appName == "Microsoft Internet Explorer")) {
+ BigInteger.prototype.am = am2;
+ dbits = 30;
+}
+else if(j_lm && (navigator.appName != "Netscape")) {
+ BigInteger.prototype.am = am1;
+ dbits = 26;
+}
+else { // Mozilla/Netscape seems to prefer am3
+ BigInteger.prototype.am = am3;
+ dbits = 28;
+}
+
+BigInteger.prototype.DB = dbits;
+BigInteger.prototype.DM = ((1<<dbits)-1);
+BigInteger.prototype.DV = (1<<dbits);
+
+var BI_FP = 52;
+BigInteger.prototype.FV = Math.pow(2,BI_FP);
+BigInteger.prototype.F1 = BI_FP-dbits;
+BigInteger.prototype.F2 = 2*dbits-BI_FP;
+
+// Digit conversions
+var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
+var BI_RC = new Array();
+var rr,vv;
+rr = "0".charCodeAt(0);
+for(vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv;
+rr = "a".charCodeAt(0);
+for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
+rr = "A".charCodeAt(0);
+for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
+
+function int2char(n) { return BI_RM.charAt(n); }
+function intAt(s,i) {
+ var c = BI_RC[s.charCodeAt(i)];
+ return (c==null)?-1:c;
+}
+
+// (protected) copy this to r
+function bnpCopyTo(r) {
+ for(var i = this.t-1; i >= 0; --i) r[i] = this[i];
+ r.t = this.t;
+ r.s = this.s;
+}
+
+// (protected) set from integer value x, -DV <= x < DV
+function bnpFromInt(x) {
+ this.t = 1;
+ this.s = (x<0)?-1:0;
+ if(x > 0) this[0] = x;
+ else if(x < -1) this[0] = x+DV;
+ else this.t = 0;
+}
+
+// return bigint initialized to value
+function nbv(i) { var r = nbi(); r.fromInt(i); return r; }
+
+// (protected) set from string and radix
+function bnpFromString(s,b) {
+ var k;
+ if(b == 16) k = 4;
+ else if(b == 8) k = 3;
+ else if(b == 256) k = 8; // byte array
+ else if(b == 2) k = 1;
+ else if(b == 32) k = 5;
+ else if(b == 4) k = 2;
+ else { this.fromRadix(s,b); return; }
+ this.t = 0;
+ this.s = 0;
+ var i = s.length, mi = false, sh = 0;
+ while(--i >= 0) {
+ var x = (k==8)?s[i]&0xff:intAt(s,i);
+ if(x < 0) {
+ if(s.charAt(i) == "-") mi = true;
+ continue;
+ }
+ mi = false;
+ if(sh == 0)
+ this[this.t++] = x;
+ else if(sh+k > this.DB) {
+ this[this.t-1] |= (x&((1<<(this.DB-sh))-1))<<sh;
+ this[this.t++] = (x>>(this.DB-sh));
+ }
+ else
+ this[this.t-1] |= x<<sh;
+ sh += k;
+ if(sh >= this.DB) sh -= this.DB;
+ }
+ if(k == 8 && (s[0]&0x80) != 0) {
+ this.s = -1;
+ if(sh > 0) this[this.t-1] |= ((1<<(this.DB-sh))-1)<<sh;
+ }
+ this.clamp();
+ if(mi) BigInteger.ZERO.subTo(this,this);
+}
+
+// (protected) clamp off excess high words
+function bnpClamp() {
+ var c = this.s&this.DM;
+ while(this.t > 0 && this[this.t-1] == c) --this.t;
+}
+
+// (public) return string representation in given radix
+function bnToString(b) {
+ if(this.s < 0) return "-"+this.negate().toString(b);
+ var k;
+ if(b == 16) k = 4;
+ else if(b == 8) k = 3;
+ else if(b == 2) k = 1;
+ else if(b == 32) k = 5;
+ else if(b == 4) k = 2;
+ else return this.toRadix(b);
+ var km = (1<<k)-1, d, m = false, r = "", i = this.t;
+ var p = this.DB-(i*this.DB)%k;
+ if(i-- > 0) {
+ if(p < this.DB && (d = this[i]>>p) > 0) { m = true; r = int2char(d); }
+ while(i >= 0) {
+ if(p < k) {
+ d = (this[i]&((1<<p)-1))<<(k-p);
+ d |= this[--i]>>(p+=this.DB-k);
+ }
+ else {
+ d = (this[i]>>(p-=k))&km;
+ if(p <= 0) { p += this.DB; --i; }
+ }
+ if(d > 0) m = true;
+ if(m) r += int2char(d);
+ }
+ }
+ return m?r:"0";
+}
+
+// (public) -this
+function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; }
+
+// (public) |this|
+function bnAbs() { return (this.s<0)?this.negate():this; }
+
+// (public) return + if this > a, - if this < a, 0 if equal
+function bnCompareTo(a) {
+ var r = this.s-a.s;
+ if(r != 0) return r;
+ var i = this.t;
+ r = i-a.t;
+ if(r != 0) return r;
+ while(--i >= 0) if((r=this[i]-a[i]) != 0) return r;
+ return 0;
+}
+
+// returns bit length of the integer x
+function nbits(x) {
+ var r = 1, t;
+ if((t=x>>>16) != 0) { x = t; r += 16; }
+ if((t=x>>8) != 0) { x = t; r += 8; }
+ if((t=x>>4) != 0) { x = t; r += 4; }
+ if((t=x>>2) != 0) { x = t; r += 2; }
+ if((t=x>>1) != 0) { x = t; r += 1; }
+ return r;
+}
+
+// (public) return the number of bits in "this"
+function bnBitLength() {
+ if(this.t <= 0) return 0;
+ return this.DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this.DM));
+}
+
+// (protected) r = this << n*DB
+function bnpDLShiftTo(n,r) {
+ var i;
+ for(i = this.t-1; i >= 0; --i) r[i+n] = this[i];
+ for(i = n-1; i >= 0; --i) r[i] = 0;
+ r.t = this.t+n;
+ r.s = this.s;
+}
+
+// (protected) r = this >> n*DB
+function bnpDRShiftTo(n,r) {
+ for(var i = n; i < this.t; ++i) r[i-n] = this[i];
+ r.t = Math.max(this.t-n,0);
+ r.s = this.s;
+}
+
+// (protected) r = this << n
+function bnpLShiftTo(n,r) {
+ var bs = n%this.DB;
+ var cbs = this.DB-bs;
+ var bm = (1<<cbs)-1;
+ var ds = Math.floor(n/this.DB), c = (this.s<<bs)&this.DM, i;
+ for(i = this.t-1; i >= 0; --i) {
+ r[i+ds+1] = (this[i]>>cbs)|c;
+ c = (this[i]&bm)<<bs;
+ }
+ for(i = ds-1; i >= 0; --i) r[i] = 0;
+ r[ds] = c;
+ r.t = this.t+ds+1;
+ r.s = this.s;
+ r.clamp();
+}
+
+// (protected) r = this >> n
+function bnpRShiftTo(n,r) {
+ r.s = this.s;
+ var ds = Math.floor(n/this.DB);
+ if(ds >= this.t) { r.t = 0; return; }
+ var bs = n%this.DB;
+ var cbs = this.DB-bs;
+ var bm = (1<<bs)-1;
+ r[0] = this[ds]>>bs;
+ for(var i = ds+1; i < this.t; ++i) {
+ r[i-ds-1] |= (this[i]&bm)<<cbs;
+ r[i-ds] = this[i]>>bs;
+ }
+ if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<<cbs;
+ r.t = this.t-ds;
+ r.clamp();
+}
+
+// (protected) r = this - a
+function bnpSubTo(a,r) {
+ var i = 0, c = 0, m = Math.min(a.t,this.t);
+ while(i < m) {
+ c += this[i]-a[i];
+ r[i++] = c&this.DM;
+ c >>= this.DB;
+ }
+ if(a.t < this.t) {
+ c -= a.s;
+ while(i < this.t) {
+ c += this[i];
+ r[i++] = c&this.DM;
+ c >>= this.DB;
+ }
+ c += this.s;
+ }
+ else {
+ c += this.s;
+ while(i < a.t) {
+ c -= a[i];
+ r[i++] = c&this.DM;
+ c >>= this.DB;
+ }
+ c -= a.s;
+ }
+ r.s = (c<0)?-1:0;
+ if(c < -1) r[i++] = this.DV+c;
+ else if(c > 0) r[i++] = c;
+ r.t = i;
+ r.clamp();
+}
+
+// (protected) r = this * a, r != this,a (HAC 14.12)
+// "this" should be the larger one if appropriate.
+function bnpMultiplyTo(a,r) {
+ var x = this.abs(), y = a.abs();
+ var i = x.t;
+ r.t = i+y.t;
+ while(--i >= 0) r[i] = 0;
+ for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t);
+ r.s = 0;
+ r.clamp();
+ if(this.s != a.s) BigInteger.ZERO.subTo(r,r);
+}
+
+// (protected) r = this^2, r != this (HAC 14.16)
+function bnpSquareTo(r) {
+ var x = this.abs();
+ var i = r.t = 2*x.t;
+ while(--i >= 0) r[i] = 0;
+ for(i = 0; i < x.t-1; ++i) {
+ var c = x.am(i,x[i],r,2*i,0,1);
+ if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1)) >= x.DV) {
+ r[i+x.t] -= x.DV;
+ r[i+x.t+1] = 1;
+ }
+ }
+ if(r.t > 0) r[r.t-1] += x.am(i,x[i],r,2*i,0,1);
+ r.s = 0;
+ r.clamp();
+}
+
+// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
+// r != q, this != m. q or r may be null.
+function bnpDivRemTo(m,q,r) {
+ var pm = m.abs();
+ if(pm.t <= 0) return;
+ var pt = this.abs();
+ if(pt.t < pm.t) {
+ if(q != null) q.fromInt(0);
+ if(r != null) this.copyTo(r);
+ return;
+ }
+ if(r == null) r = nbi();
+ var y = nbi(), ts = this.s, ms = m.s;
+ var nsh = this.DB-nbits(pm[pm.t-1]); // normalize modulus
+ if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); }
+ else { pm.copyTo(y); pt.copyTo(r); }
+ var ys = y.t;
+ var y0 = y[ys-1];
+ if(y0 == 0) return;
+ var yt = y0*(1<<this.F1)+((ys>1)?y[ys-2]>>this.F2:0);
+ var d1 = this.FV/yt, d2 = (1<<this.F1)/yt, e = 1<<this.F2;
+ var i = r.t, j = i-ys, t = (q==null)?nbi():q;
+ y.dlShiftTo(j,t);
+ if(r.compareTo(t) >= 0) {
+ r[r.t++] = 1;
+ r.subTo(t,r);
+ }
+ BigInteger.ONE.dlShiftTo(ys,t);
+ t.subTo(y,y); // "negative" y so we can replace sub with am later
+ while(y.t < ys) y[y.t++] = 0;
+ while(--j >= 0) {
+ // Estimate quotient digit
+ var qd = (r[--i]==y0)?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2);
+ if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out
+ y.dlShiftTo(j,t);
+ r.subTo(t,r);
+ while(r[i] < --qd) r.subTo(t,r);
+ }
+ }
+ if(q != null) {
+ r.drShiftTo(ys,q);
+ if(ts != ms) BigInteger.ZERO.subTo(q,q);
+ }
+ r.t = ys;
+ r.clamp();
+ if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder
+ if(ts < 0) BigInteger.ZERO.subTo(r,r);
+}
+
+// (public) this mod a
+function bnMod(a) {
+ var r = nbi();
+ this.abs().divRemTo(a,null,r);
+ if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r);
+ return r;
+}
+
+// Modular reduction using "classic" algorithm
+function Classic(m) { this.m = m; }
+function cConvert(x) {
+ if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
+ else return x;
+}
+function cRevert(x) { return x; }
+function cReduce(x) { x.divRemTo(this.m,null,x); }
+function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
+function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
+
+Classic.prototype.convert = cConvert;
+Classic.prototype.revert = cRevert;
+Classic.prototype.reduce = cReduce;
+Classic.prototype.mulTo = cMulTo;
+Classic.prototype.sqrTo = cSqrTo;
+
+// (protected) return "-1/this % 2^DB"; useful for Mont. reduction
+// justification:
+// xy == 1 (mod m)
+// xy = 1+km
+// xy(2-xy) = (1+km)(1-km)
+// x[y(2-xy)] = 1-k^2m^2
+// x[y(2-xy)] == 1 (mod m^2)
+// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
+// should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
+// JS multiply "overflows" differently from C/C++, so care is needed here.
+function bnpInvDigit() {
+ if(this.t < 1) return 0;
+ var x = this[0];
+ if((x&1) == 0) return 0;
+ var y = x&3; // y == 1/x mod 2^2
+ y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4
+ y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8
+ y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16
+ // last step - calculate inverse mod DV directly;
+ // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
+ y = (y*(2-x*y%this.DV))%this.DV; // y == 1/x mod 2^dbits
+ // we really want the negative inverse, and -DV < y < DV
+ return (y>0)?this.DV-y:-y;
+}
+
+// Montgomery reduction
+function Montgomery(m) {
+ this.m = m;
+ this.mp = m.invDigit();
+ this.mpl = this.mp&0x7fff;
+ this.mph = this.mp>>15;
+ this.um = (1<<(m.DB-15))-1;
+ this.mt2 = 2*m.t;
+}
+
+// xR mod m
+function montConvert(x) {
+ var r = nbi();
+ x.abs().dlShiftTo(this.m.t,r);
+ r.divRemTo(this.m,null,r);
+ if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r);
+ return r;
+}
+
+// x/R mod m
+function montRevert(x) {
+ var r = nbi();
+ x.copyTo(r);
+ this.reduce(r);
+ return r;
+}
+
+// x = x/R mod m (HAC 14.32)
+function montReduce(x) {
+ while(x.t <= this.mt2) // pad x so am has enough room later
+ x[x.t++] = 0;
+ for(var i = 0; i < this.m.t; ++i) {
+ // faster way of calculating u0 = x[i]*mp mod DV
+ var j = x[i]&0x7fff;
+ var u0 = (j*this.mpl+(((j*this.mph+(x[i]>>15)*this.mpl)&this.um)<<15))&x.DM;
+ // use am to combine the multiply-shift-add into one call
+ j = i+this.m.t;
+ x[j] += this.m.am(0,u0,x,i,0,this.m.t);
+ // propagate carry
+ while(x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; }
+ }
+ x.clamp();
+ x.drShiftTo(this.m.t,x);
+ if(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
+}
+
+// r = "x^2/R mod m"; x != r
+function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
+
+// r = "xy/R mod m"; x,y != r
+function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
+
+Montgomery.prototype.convert = montConvert;
+Montgomery.prototype.revert = montRevert;
+Montgomery.prototype.reduce = montReduce;
+Montgomery.prototype.mulTo = montMulTo;
+Montgomery.prototype.sqrTo = montSqrTo;
+
+// (protected) true iff this is even
+function bnpIsEven() { return ((this.t>0)?(this[0]&1):this.s) == 0; }
+
+// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
+function bnpExp(e,z) {
+ if(e > 0xffffffff || e < 1) return BigInteger.ONE;
+ var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1;
+ g.copyTo(r);
+ while(--i >= 0) {
+ z.sqrTo(r,r2);
+ if((e&(1<<i)) > 0) z.mulTo(r2,g,r);
+ else { var t = r; r = r2; r2 = t; }
+ }
+ return z.revert(r);
+}
+
+// (public) this^e % m, 0 <= e < 2^32
+function bnModPowInt(e,m) {
+ var z;
+ if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m);
+ return this.exp(e,z);
+}
+
+// protected
+BigInteger.prototype.copyTo = bnpCopyTo;
+BigInteger.prototype.fromInt = bnpFromInt;
+BigInteger.prototype.fromString = bnpFromString;
+BigInteger.prototype.clamp = bnpClamp;
+BigInteger.prototype.dlShiftTo = bnpDLShiftTo;
+BigInteger.prototype.drShiftTo = bnpDRShiftTo;
+BigInteger.prototype.lShiftTo = bnpLShiftTo;
+BigInteger.prototype.rShiftTo = bnpRShiftTo;
+BigInteger.prototype.subTo = bnpSubTo;
+BigInteger.prototype.multiplyTo = bnpMultiplyTo;
+BigInteger.prototype.squareTo = bnpSquareTo;
+BigInteger.prototype.divRemTo = bnpDivRemTo;
+BigInteger.prototype.invDigit = bnpInvDigit;
+BigInteger.prototype.isEven = bnpIsEven;
+BigInteger.prototype.exp = bnpExp;
+
+// public
+BigInteger.prototype.toString = bnToString;
+BigInteger.prototype.negate = bnNegate;
+BigInteger.prototype.abs = bnAbs;
+BigInteger.prototype.compareTo = bnCompareTo;
+BigInteger.prototype.bitLength = bnBitLength;
+BigInteger.prototype.mod = bnMod;
+BigInteger.prototype.modPowInt = bnModPowInt;
+
+// "constants"
+BigInteger.ZERO = nbv(0);
+BigInteger.ONE = nbv(1);
+
+// Copyright (c) 2005-2009 Tom Wu
+// All Rights Reserved.
+// See "LICENSE" for details.
+
+// Extended JavaScript BN functions, required for RSA private ops.
+
+// Version 1.1: new BigInteger("0", 10) returns "proper" zero
+
+// (public)
+function bnClone() { var r = nbi(); this.copyTo(r); return r; }
+
+// (public) return value as integer
+function bnIntValue() {
+ if(this.s < 0) {
+ if(this.t == 1) return this[0]-this.DV;
+ else if(this.t == 0) return -1;
+ }
+ else if(this.t == 1) return this[0];
+ else if(this.t == 0) return 0;
+ // assumes 16 < DB < 32
+ return ((this[1]&((1<<(32-this.DB))-1))<<this.DB)|this[0];
+}
+
+// (public) return value as byte
+function bnByteValue() { return (this.t==0)?this.s:(this[0]<<24)>>24; }
+
+// (public) return value as short (assumes DB>=16)
+function bnShortValue() { return (this.t==0)?this.s:(this[0]<<16)>>16; }
+
+// (protected) return x s.t. r^x < DV
+function bnpChunkSize(r) { return Math.floor(Math.LN2*this.DB/Math.log(r)); }
+
+// (public) 0 if this == 0, 1 if this > 0
+function bnSigNum() {
+ if(this.s < 0) return -1;
+ else if(this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0;
+ else return 1;
+}
+
+// (protected) convert to radix string
+function bnpToRadix(b) {
+ if(b == null) b = 10;
+ if(this.signum() == 0 || b < 2 || b > 36) return "0";
+ var cs = this.chunkSize(b);
+ var a = Math.pow(b,cs);
+ var d = nbv(a), y = nbi(), z = nbi(), r = "";
+ this.divRemTo(d,y,z);
+ while(y.signum() > 0) {
+ r = (a+z.intValue()).toString(b).substr(1) + r;
+ y.divRemTo(d,y,z);
+ }
+ return z.intValue().toString(b) + r;
+}
+
+// (protected) convert from radix string
+function bnpFromRadix(s,b) {
+ this.fromInt(0);
+ if(b == null) b = 10;
+ var cs = this.chunkSize(b);
+ var d = Math.pow(b,cs), mi = false, j = 0, w = 0;
+ for(var i = 0; i < s.length; ++i) {
+ var x = intAt(s,i);
+ if(x < 0) {
+ if(s.charAt(i) == "-" && this.signum() == 0) mi = true;
+ continue;
+ }
+ w = b*w+x;
+ if(++j >= cs) {
+ this.dMultiply(d);
+ this.dAddOffset(w,0);
+ j = 0;
+ w = 0;
+ }
+ }
+ if(j > 0) {
+ this.dMultiply(Math.pow(b,j));
+ this.dAddOffset(w,0);
+ }
+ if(mi) BigInteger.ZERO.subTo(this,this);
+}
+
+// (protected) alternate constructor
+function bnpFromNumber(a,b,c) {
+ if("number" == typeof b) {
+ // new BigInteger(int,int,RNG)
+ if(a < 2) this.fromInt(1);
+ else {
+ this.fromNumber(a,c);
+ if(!this.testBit(a-1)) // force MSB set
+ this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this);
+ if(this.isEven()) this.dAddOffset(1,0); // force odd
+ while(!this.isProbablePrime(b)) {
+ this.dAddOffset(2,0);
+ if(this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a-1),this);
+ }
+ }
+ }
+ else {
+ // new BigInteger(int,RNG)
+ var x = new Array(), t = a&7;
+ x.length = (a>>3)+1;
+ b.nextBytes(x);
+ if(t > 0) x[0] &= ((1<<t)-1); else x[0] = 0;
+ this.fromString(x,256);
+ }
+}
+
+// (public) convert to bigendian byte array
+function bnToByteArray() {
+ var i = this.t, r = new Array();
+ r[0] = this.s;
+ var p = this.DB-(i*this.DB)%8, d, k = 0;
+ if(i-- > 0) {
+ if(p < this.DB && (d = this[i]>>p) != (this.s&this.DM)>>p)
+ r[k++] = d|(this.s<<(this.DB-p));
+ while(i >= 0) {
+ if(p < 8) {
+ d = (this[i]&((1<<p)-1))<<(8-p);
+ d |= this[--i]>>(p+=this.DB-8);
+ }
+ else {
+ d = (this[i]>>(p-=8))&0xff;
+ if(p <= 0) { p += this.DB; --i; }
+ }
+ if((d&0x80) != 0) d |= -256;
+ if(k == 0 && (this.s&0x80) != (d&0x80)) ++k;
+ if(k > 0 || d != this.s) r[k++] = d;
+ }
+ }
+ return r;
+}
+
+function bnEquals(a) { return(this.compareTo(a)==0); }
+function bnMin(a) { return(this.compareTo(a)<0)?this:a; }
+function bnMax(a) { return(this.compareTo(a)>0)?this:a; }
+
+// (protected) r = this op a (bitwise)
+function bnpBitwiseTo(a,op,r) {
+ var i, f, m = Math.min(a.t,this.t);
+ for(i = 0; i < m; ++i) r[i] = op(this[i],a[i]);
+ if(a.t < this.t) {
+ f = a.s&this.DM;
+ for(i = m; i < this.t; ++i) r[i] = op(this[i],f);
+ r.t = this.t;
+ }
+ else {
+ f = this.s&this.DM;
+ for(i = m; i < a.t; ++i) r[i] = op(f,a[i]);
+ r.t = a.t;
+ }
+ r.s = op(this.s,a.s);
+ r.clamp();
+}
+
+// (public) this & a
+function op_and(x,y) { return x&y; }
+function bnAnd(a) { var r = nbi(); this.bitwiseTo(a,op_and,r); return r; }
+
+// (public) this | a
+function op_or(x,y) { return x|y; }
+function bnOr(a) { var r = nbi(); this.bitwiseTo(a,op_or,r); return r; }
+
+// (public) this ^ a
+function op_xor(x,y) { return x^y; }
+function bnXor(a) { var r = nbi(); this.bitwiseTo(a,op_xor,r); return r; }
+
+// (public) this & ~a
+function op_andnot(x,y) { return x&~y; }
+function bnAndNot(a) { var r = nbi(); this.bitwiseTo(a,op_andnot,r); return r; }
+
+// (public) ~this
+function bnNot() {
+ var r = nbi();
+ for(var i = 0; i < this.t; ++i) r[i] = this.DM&~this[i];
+ r.t = this.t;
+ r.s = ~this.s;
+ return r;
+}
+
+// (public) this << n
+function bnShiftLeft(n) {
+ var r = nbi();
+ if(n < 0) this.rShiftTo(-n,r); else this.lShiftTo(n,r);
+ return r;
+}
+
+// (public) this >> n
+function bnShiftRight(n) {
+ var r = nbi();
+ if(n < 0) this.lShiftTo(-n,r); else this.rShiftTo(n,r);
+ return r;
+}
+
+// return index of lowest 1-bit in x, x < 2^31
+function lbit(x) {
+ if(x == 0) return -1;
+ var r = 0;
+ if((x&0xffff) == 0) { x >>= 16; r += 16; }
+ if((x&0xff) == 0) { x >>= 8; r += 8; }
+ if((x&0xf) == 0) { x >>= 4; r += 4; }
+ if((x&3) == 0) { x >>= 2; r += 2; }
+ if((x&1) == 0) ++r;
+ return r;
+}
+
+// (public) returns index of lowest 1-bit (or -1 if none)
+function bnGetLowestSetBit() {
+ for(var i = 0; i < this.t; ++i)
+ if(this[i] != 0) return i*this.DB+lbit(this[i]);
+ if(this.s < 0) return this.t*this.DB;
+ return -1;
+}
+
+// return number of 1 bits in x
+function cbit(x) {
+ var r = 0;
+ while(x != 0) { x &= x-1; ++r; }
+ return r;
+}
+
+// (public) return number of set bits
+function bnBitCount() {
+ var r = 0, x = this.s&this.DM;
+ for(var i = 0; i < this.t; ++i) r += cbit(this[i]^x);
+ return r;
+}
+
+// (public) true iff nth bit is set
+function bnTestBit(n) {
+ var j = Math.floor(n/this.DB);
+ if(j >= this.t) return(this.s!=0);
+ return((this[j]&(1<<(n%this.DB)))!=0);
+}
+
+// (protected) this op (1<<n)
+function bnpChangeBit(n,op) {
+ var r = BigInteger.ONE.shiftLeft(n);
+ this.bitwiseTo(r,op,r);
+ return r;
+}
+
+// (public) this | (1<<n)
+function bnSetBit(n) { return this.changeBit(n,op_or); }
+
+// (public) this & ~(1<<n)
+function bnClearBit(n) { return this.changeBit(n,op_andnot); }
+
+// (public) this ^ (1<<n)
+function bnFlipBit(n) { return this.changeBit(n,op_xor); }
+
+// (protected) r = this + a
+function bnpAddTo(a,r) {
+ var i = 0, c = 0, m = Math.min(a.t,this.t);
+ while(i < m) {
+ c += this[i]+a[i];
+ r[i++] = c&this.DM;
+ c >>= this.DB;
+ }
+ if(a.t < this.t) {
+ c += a.s;
+ while(i < this.t) {
+ c += this[i];
+ r[i++] = c&this.DM;
+ c >>= this.DB;
+ }
+ c += this.s;
+ }
+ else {
+ c += this.s;
+ while(i < a.t) {
+ c += a[i];
+ r[i++] = c&this.DM;
+ c >>= this.DB;
+ }
+ c += a.s;
+ }
+ r.s = (c<0)?-1:0;
+ if(c > 0) r[i++] = c;
+ else if(c < -1) r[i++] = this.DV+c;
+ r.t = i;
+ r.clamp();
+}
+
+// (public) this + a
+function bnAdd(a) { var r = nbi(); this.addTo(a,r); return r; }
+
+// (public) this - a
+function bnSubtract(a) { var r = nbi(); this.subTo(a,r); return r; }
+
+// (public) this * a
+function bnMultiply(a) { var r = nbi(); this.multiplyTo(a,r); return r; }
+
+// (public) this / a
+function bnDivide(a) { var r = nbi(); this.divRemTo(a,r,null); return r; }
+
+// (public) this % a
+function bnRemainder(a) { var r = nbi(); this.divRemTo(a,null,r); return r; }
+
+// (public) [this/a,this%a]
+function bnDivideAndRemainder(a) {
+ var q = nbi(), r = nbi();
+ this.divRemTo(a,q,r);
+ return new Array(q,r);
+}
+
+// (protected) this *= n, this >= 0, 1 < n < DV
+function bnpDMultiply(n) {
+ this[this.t] = this.am(0,n-1,this,0,0,this.t);
+ ++this.t;
+ this.clamp();
+}
+
+// (protected) this += n << w words, this >= 0
+function bnpDAddOffset(n,w) {
+ if(n == 0) return;
+ while(this.t <= w) this[this.t++] = 0;
+ this[w] += n;
+ while(this[w] >= this.DV) {
+ this[w] -= this.DV;
+ if(++w >= this.t) this[this.t++] = 0;
+ ++this[w];
+ }
+}
+
+// A "null" reducer
+function NullExp() {}
+function nNop(x) { return x; }
+function nMulTo(x,y,r) { x.multiplyTo(y,r); }
+function nSqrTo(x,r) { x.squareTo(r); }
+
+NullExp.prototype.convert = nNop;
+NullExp.prototype.revert = nNop;
+NullExp.prototype.mulTo = nMulTo;
+NullExp.prototype.sqrTo = nSqrTo;
+
+// (public) this^e
+function bnPow(e) { return this.exp(e,new NullExp()); }
+
+// (protected) r = lower n words of "this * a", a.t <= n
+// "this" should be the larger one if appropriate.
+function bnpMultiplyLowerTo(a,n,r) {
+ var i = Math.min(this.t+a.t,n);
+ r.s = 0; // assumes a,this >= 0
+ r.t = i;
+ while(i > 0) r[--i] = 0;
+ var j;
+ for(j = r.t-this.t; i < j; ++i) r[i+this.t] = this.am(0,a[i],r,i,0,this.t);
+ for(j = Math.min(a.t,n); i < j; ++i) this.am(0,a[i],r,i,0,n-i);
+ r.clamp();
+}
+
+// (protected) r = "this * a" without lower n words, n > 0
+// "this" should be the larger one if appropriate.
+function bnpMultiplyUpperTo(a,n,r) {
+ --n;
+ var i = r.t = this.t+a.t-n;
+ r.s = 0; // assumes a,this >= 0
+ while(--i >= 0) r[i] = 0;
+ for(i = Math.max(n-this.t,0); i < a.t; ++i)
+ r[this.t+i-n] = this.am(n-i,a[i],r,0,0,this.t+i-n);
+ r.clamp();
+ r.drShiftTo(1,r);
+}
+
+// Barrett modular reduction
+function Barrett(m) {
+ // setup Barrett
+ this.r2 = nbi();
+ this.q3 = nbi();
+ BigInteger.ONE.dlShiftTo(2*m.t,this.r2);
+ this.mu = this.r2.divide(m);
+ this.m = m;
+}
+
+function barrettConvert(x) {
+ if(x.s < 0 || x.t > 2*this.m.t) return x.mod(this.m);
+ else if(x.compareTo(this.m) < 0) return x;
+ else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; }
+}
+
+function barrettRevert(x) { return x; }
+
+// x = x mod m (HAC 14.42)
+function barrettReduce(x) {
+ x.drShiftTo(this.m.t-1,this.r2);
+ if(x.t > this.m.t+1) { x.t = this.m.t+1; x.clamp(); }
+ this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3);
+ this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2);
+ while(x.compareTo(this.r2) < 0) x.dAddOffset(1,this.m.t+1);
+ x.subTo(this.r2,x);
+ while(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
+}
+
+// r = x^2 mod m; x != r
+function barrettSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
+
+// r = x*y mod m; x,y != r
+function barrettMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
+
+Barrett.prototype.convert = barrettConvert;
+Barrett.prototype.revert = barrettRevert;
+Barrett.prototype.reduce = barrettReduce;
+Barrett.prototype.mulTo = barrettMulTo;
+Barrett.prototype.sqrTo = barrettSqrTo;
+
+// (public) this^e % m (HAC 14.85)
+function bnModPow(e,m) {
+ var i = e.bitLength(), k, r = nbv(1), z;
+ if(i <= 0) return r;
+ else if(i < 18) k = 1;
+ else if(i < 48) k = 3;
+ else if(i < 144) k = 4;
+ else if(i < 768) k = 5;
+ else k = 6;
+ if(i < 8)
+ z = new Classic(m);
+ else if(m.isEven())
+ z = new Barrett(m);
+ else
+ z = new Montgomery(m);
+
+ // precomputation
+ var g = new Array(), n = 3, k1 = k-1, km = (1<<k)-1;
+ g[1] = z.convert(this);
+ if(k > 1) {
+ var g2 = nbi();
+ z.sqrTo(g[1],g2);
+ while(n <= km) {
+ g[n] = nbi();
+ z.mulTo(g2,g[n-2],g[n]);
+ n += 2;
+ }
+ }
+
+ var j = e.t-1, w, is1 = true, r2 = nbi(), t;
+ i = nbits(e[j])-1;
+ while(j >= 0) {
+ if(i >= k1) w = (e[j]>>(i-k1))&km;
+ else {
+ w = (e[j]&((1<<(i+1))-1))<<(k1-i);
+ if(j > 0) w |= e[j-1]>>(this.DB+i-k1);
+ }
+
+ n = k;
+ while((w&1) == 0) { w >>= 1; --n; }
+ if((i -= n) < 0) { i += this.DB; --j; }
+ if(is1) { // ret == 1, don't bother squaring or multiplying it
+ g[w].copyTo(r);
+ is1 = false;
+ }
+ else {
+ while(n > 1) { z.sqrTo(r,r2); z.sqrTo(r2,r); n -= 2; }
+ if(n > 0) z.sqrTo(r,r2); else { t = r; r = r2; r2 = t; }
+ z.mulTo(r2,g[w],r);
+ }
+
+ while(j >= 0 && (e[j]&(1<<i)) == 0) {
+ z.sqrTo(r,r2); t = r; r = r2; r2 = t;
+ if(--i < 0) { i = this.DB-1; --j; }
+ }
+ }
+ return z.revert(r);
+}
+
+// (public) gcd(this,a) (HAC 14.54)
+function bnGCD(a) {
+ var x = (this.s<0)?this.negate():this.clone();
+ var y = (a.s<0)?a.negate():a.clone();
+ if(x.compareTo(y) < 0) { var t = x; x = y; y = t; }
+ var i = x.getLowestSetBit(), g = y.getLowestSetBit();
+ if(g < 0) return x;
+ if(i < g) g = i;
+ if(g > 0) {
+ x.rShiftTo(g,x);
+ y.rShiftTo(g,y);
+ }
+ while(x.signum() > 0) {
+ if((i = x.getLowestSetBit()) > 0) x.rShiftTo(i,x);
+ if((i = y.getLowestSetBit()) > 0) y.rShiftTo(i,y);
+ if(x.compareTo(y) >= 0) {
+ x.subTo(y,x);
+ x.rShiftTo(1,x);
+ }
+ else {
+ y.subTo(x,y);
+ y.rShiftTo(1,y);
+ }
+ }
+ if(g > 0) y.lShiftTo(g,y);
+ return y;
+}
+
+// (protected) this % n, n < 2^26
+function bnpModInt(n) {
+ if(n <= 0) return 0;
+ var d = this.DV%n, r = (this.s<0)?n-1:0;
+ if(this.t > 0)
+ if(d == 0) r = this[0]%n;
+ else for(var i = this.t-1; i >= 0; --i) r = (d*r+this[i])%n;
+ return r;
+}
+
+// (public) 1/this % m (HAC 14.61)
+function bnModInverse(m) {
+ var ac = m.isEven();
+ if((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO;
+ var u = m.clone(), v = this.clone();
+ var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1);
+ while(u.signum() != 0) {
+ while(u.isEven()) {
+ u.rShiftTo(1,u);
+ if(ac) {
+ if(!a.isEven() || !b.isEven()) { a.addTo(this,a); b.subTo(m,b); }
+ a.rShiftTo(1,a);
+ }
+ else if(!b.isEven()) b.subTo(m,b);
+ b.rShiftTo(1,b);
+ }
+ while(v.isEven()) {
+ v.rShiftTo(1,v);
+ if(ac) {
+ if(!c.isEven() || !d.isEven()) { c.addTo(this,c); d.subTo(m,d); }
+ c.rShiftTo(1,c);
+ }
+ else if(!d.isEven()) d.subTo(m,d);
+ d.rShiftTo(1,d);
+ }
+ if(u.compareTo(v) >= 0) {
+ u.subTo(v,u);
+ if(ac) a.subTo(c,a);
+ b.subTo(d,b);
+ }
+ else {
+ v.subTo(u,v);
+ if(ac) c.subTo(a,c);
+ d.subTo(b,d);
+ }
+ }
+ if(v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO;
+ if(d.compareTo(m) >= 0) return d.subtract(m);
+ if(d.signum() < 0) d.addTo(m,d); else return d;
+ if(d.signum() < 0) return d.add(m); else return d;
+}
+
+var lowprimes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509];
+var lplim = (1<<26)/lowprimes[lowprimes.length-1];
+
+// (public) test primality with certainty >= 1-.5^t
+function bnIsProbablePrime(t) {
+ var i, x = this.abs();
+ if(x.t == 1 && x[0] <= lowprimes[lowprimes.length-1]) {
+ for(i = 0; i < lowprimes.length; ++i)
+ if(x[0] == lowprimes[i]) return true;
+ return false;
+ }
+ if(x.isEven()) return false;
+ i = 1;
+ while(i < lowprimes.length) {
+ var m = lowprimes[i], j = i+1;
+ while(j < lowprimes.length && m < lplim) m *= lowprimes[j++];
+ m = x.modInt(m);
+ while(i < j) if(m%lowprimes[i++] == 0) return false;
+ }
+ return x.millerRabin(t);
+}
+
+// (protected) true if probably prime (HAC 4.24, Miller-Rabin)
+function bnpMillerRabin(t) {
+ var n1 = this.subtract(BigInteger.ONE);
+ var k = n1.getLowestSetBit();
+ if(k <= 0) return false;
+ var r = n1.shiftRight(k);
+ t = (t+1)>>1;
+ if(t > lowprimes.length) t = lowprimes.length;
+ var a = nbi();
+ for(var i = 0; i < t; ++i) {
+ a.fromInt(lowprimes[i]);
+ var y = a.modPow(r,this);
+ if(y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) {
+ var j = 1;
+ while(j++ < k && y.compareTo(n1) != 0) {
+ y = y.modPowInt(2,this);
+ if(y.compareTo(BigInteger.ONE) == 0) return false;
+ }
+ if(y.compareTo(n1) != 0) return false;
+ }
+ }
+ return true;
+}
+
+// protected
+BigInteger.prototype.chunkSize = bnpChunkSize;
+BigInteger.prototype.toRadix = bnpToRadix;
+BigInteger.prototype.fromRadix = bnpFromRadix;
+BigInteger.prototype.fromNumber = bnpFromNumber;
+BigInteger.prototype.bitwiseTo = bnpBitwiseTo;
+BigInteger.prototype.changeBit = bnpChangeBit;
+BigInteger.prototype.addTo = bnpAddTo;
+BigInteger.prototype.dMultiply = bnpDMultiply;
+BigInteger.prototype.dAddOffset = bnpDAddOffset;
+BigInteger.prototype.multiplyLowerTo = bnpMultiplyLowerTo;
+BigInteger.prototype.multiplyUpperTo = bnpMultiplyUpperTo;
+BigInteger.prototype.modInt = bnpModInt;
+BigInteger.prototype.millerRabin = bnpMillerRabin;
+
+// public
+BigInteger.prototype.clone = bnClone;
+BigInteger.prototype.intValue = bnIntValue;
+BigInteger.prototype.byteValue = bnByteValue;
+BigInteger.prototype.shortValue = bnShortValue;
+BigInteger.prototype.signum = bnSigNum;
+BigInteger.prototype.toByteArray = bnToByteArray;
+BigInteger.prototype.equals = bnEquals;
+BigInteger.prototype.min = bnMin;
+BigInteger.prototype.max = bnMax;
+BigInteger.prototype.and = bnAnd;
+BigInteger.prototype.or = bnOr;
+BigInteger.prototype.xor = bnXor;
+BigInteger.prototype.andNot = bnAndNot;
+BigInteger.prototype.not = bnNot;
+BigInteger.prototype.shiftLeft = bnShiftLeft;
+BigInteger.prototype.shiftRight = bnShiftRight;
+BigInteger.prototype.getLowestSetBit = bnGetLowestSetBit;
+BigInteger.prototype.bitCount = bnBitCount;
+BigInteger.prototype.testBit = bnTestBit;
+BigInteger.prototype.setBit = bnSetBit;
+BigInteger.prototype.clearBit = bnClearBit;
+BigInteger.prototype.flipBit = bnFlipBit;
+BigInteger.prototype.add = bnAdd;
+BigInteger.prototype.subtract = bnSubtract;
+BigInteger.prototype.multiply = bnMultiply;
+BigInteger.prototype.divide = bnDivide;
+BigInteger.prototype.remainder = bnRemainder;
+BigInteger.prototype.divideAndRemainder = bnDivideAndRemainder;
+BigInteger.prototype.modPow = bnModPow;
+BigInteger.prototype.modInverse = bnModInverse;
+BigInteger.prototype.pow = bnPow;
+BigInteger.prototype.gcd = bnGCD;
+BigInteger.prototype.isProbablePrime = bnIsProbablePrime;
+
+// BigInteger interfaces not implemented in jsbn:
+
+// BigInteger(int signum, byte[] magnitude)
+// double doubleValue()
+// float floatValue()
+// int hashCode()
+// long longValue()
+// static BigInteger valueOf(long val)
+
diff --git a/js/encoding/BinaryXMLCodec.js b/js/encoding/BinaryXMLCodec.js
deleted file mode 100644
index b1befdd..0000000
--- a/js/encoding/BinaryXMLCodec.js
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * This class is used to encode and decode binary elements ( blog, type/value pairs)
- *
- * @author: ucla-cs
- */
-var XML_EXT = 0x00;
-
-var XML_TAG = 0x01;
-
-var XML_DTAG = 0x02;
-
-var XML_ATTR = 0x03;
-
-var XML_DATTR = 0x04;
-
-var XML_BLOB = 0x05;
-
-var XML_UDATA = 0x06;
-
-var XML_CLOSE = 0x0;
-
-var XML_SUBTYPE_PROCESSING_INSTRUCTIONS = 16;
-
-
-var XML_TT_BITS = 3;
-var XML_TT_MASK = ((1 << XML_TT_BITS) - 1);
-var XML_TT_VAL_BITS = XML_TT_BITS + 1;
-var XML_TT_VAL_MASK = ((1 << (XML_TT_VAL_BITS)) - 1);
-var XML_REG_VAL_BITS = 7;
-var XML_REG_VAL_MASK = ((1 << XML_REG_VAL_BITS) - 1);
-var XML_TT_NO_MORE = (1 << XML_REG_VAL_BITS); // 0x80
-var BYTE_MASK = 0xFF;
-var LONG_BYTES = 8;
-var LONG_BITS = 64;
-
-var bits_11 = 0x0000007FF;
-var bits_18 = 0x00003FFFF;
-var bits_32 = 0x0FFFFFFFF;
-
-
-var TypeAndVal = function TypeAndVal(_type,_val) {
- this.type = _type;
- this.val = _val;
-
-};
-
-var BinaryXMLCodec = function BinaryXMLCodec(){
- this.CODEC_NAME = "Binary";
-};
-
-
-
-BinaryXMLCodec.prototype.encodeTypeAndValOffset = function(
- //int
- type,
- //long
- val,
- //byte []
- buf,
- //int
- offset) {
-
- if ((type > XML_UDATA) || (type < 0) || (val < 0)) {
- throw new Exception("Tag and value must be positive, and tag valid.");
- }
-
- // Encode backwards. Calculate how many bytes we need:
- var/*int*/ numEncodingBytes = numEncodingBytes(val);
-
- if ((offset + numEncodingBytes) > buf.length) {
- throw new Exception("Buffer space of " + (buf.length-offset) +
- " bytes insufficient to hold " +
- numEncodingBytes + " of encoded type and value.");
- }
-
-
- buf[offset + numEncodingBytes - 1] =
- (BYTE_MASK &
- (((XML_TT_MASK & type) |
- ((XML_TT_VAL_MASK & val) << XML_TT_BITS))) |
- XML_TT_NO_MORE);
- val = val >>> XML_TT_VAL_BITS;;
-
- var /*int*/ i = offset + numEncodingBytes - 2;
- while ((0 != val) && (i >= offset)) {
- buf[i] = (BYTE_MASK &
- (val & XML_REG_VAL_MASK));
- val = val >>> XML_REG_VAL_BITS;
- --i;
- }
-
- return numEncodingBytes;
-};
-
-
-BinaryXMLCodec.prototype.encodeTypeAndVal = function(
- //int
- type,
- //long
- val,
- //byte []
- buf,
- //int
- offset) {
-
- if ((type > XML_UDATA) || (type < 0) || (val < 0)) {
- throw new Exception("Tag and value must be positive, and tag valid.");
- }
-
- // Encode backwards. Calculate how many bytes we need:
- //int
- var numEncodingBytes = numEncodingBytes(val);
-
- if ((offset + numEncodingBytes) > buf.length) {
- throw new Exception("Buffer space of " + (buf.length-offset) +
- " bytes insufficient to hold " +
- numEncodingBytes + " of encoded type and value.");
- }
-
- // Bottom 4 bits of val go in last byte with tag.
- buf[offset + numEncodingBytes - 1] =
- //(byte)
- (BYTE_MASK &
- (((XML_TT_MASK & type) |
- ((XML_TT_VAL_MASK & val) << XML_TT_BITS))) |
- XML_TT_NO_MORE); // set top bit for last byte
- val = val >>> XML_TT_VAL_BITS;;
-
- // Rest of val goes into preceding bytes, 7 bits per byte, top bit
- // is "more" flag.
- var i = offset + numEncodingBytes - 2;
- while ((0 != val) && (i >= offset)) {
- buf[i] = //(byte)
- (BYTE_MASK &
- (val & XML_REG_VAL_MASK)); // leave top bit unset
- val = val >>> XML_REG_VAL_BITS;
- --i;
- }
- if (val != 0) {
- throw new Exception( "This should not happen: miscalculated encoding");
- //Log.warning(Log.FAC_ENCODING, "This should not happen: miscalculated encoding length, have " + val + " left.");
- }
-
- return numEncodingBytes;
-}
-
-
-
-BinaryXMLCodec.prototype.decodeTypeAndVal = function(
- /*InputStream*/
- istream) {
-
- /*int*/next;
- /*int*/type = -1;
- /*long*/val = 0;
- /*boolean*/more = true;
-
- do {
- next = istream.read();
-
- if (next < 0) {
- return null;
- }
-
- if ((0 == next) && (0 == val)) {
- return null;
- }
-
- more = (0 == (next & XML_TT_NO_MORE));
-
- if (more) {
- val = val << XML_REG_VAL_BITS;
- val |= (next & XML_REG_VAL_MASK);
- } else {
-
- type = next & XML_TT_MASK;
- val = val << XML_TT_VAL_BITS;
- val |= ((next >>> XML_TT_BITS) & XML_TT_VAL_MASK);
- }
-
- } while (more);
-
- return new TypeAndVal(type, val);
-};
-
-BinaryXMLCodec.prototype.encodeUString = function(
- //OutputStream
- ostream,
- //String
- ustring,
- //byte
- type,
- offset) {
-
- // We elide the encoding of a 0-length UString
- if ((null == ustring) || (ustring.length == 0)) {
- //if (Log.isLoggable(Log.FAC_ENCODING, Level.FINER))
- //Log.finer(Log.FAC_ENCODING, "Eliding 0-length UString.");
- return;
- }
-
- //byte [] data utils
- /*custom*/
- //byte[]
- strBytes = new Array(ustring.Length);
- var i = 0;
- for( ;i<ustring.lengh;i++) //in InStr.ToCharArray())
- {
- strBytes[i] = ustring[i];
- }
- //strBytes = DataUtils.getBytesFromUTF8String(ustring);
-
- this.encodeTypeAndVal(type,
- (((type == XML_TAG) || (type == XML_ATTR)) ?
- (strBytes.length-1) :
- strBytes.length), ostream);
- //
- //console.log(strBytes.toString());
-
- ostream.write(strBytes.toString(),offset);
-
- //
-};
-
-BinaryXMLCodec.prototype.encodeBlob = function(
- //OutputStream
- ostream,
- //byte []
- blob,
- //int
- offset,
- //int
- length) {
- // We elide the encoding of a 0-length blob
- if ((null == blob) || (length == 0)) {
-
- return;
- }
-
- encodeTypeAndVal(XML_BLOB, length, ostream,offset);
- if (null != blob) {
- ostream.write(blob, this.offset, length);
- this.offset += length;
- }
-};
-
-
-var ENCODING_LIMIT_1_BYTE = ((1 << (XML_TT_VAL_BITS)) - 1);
-var ENCODING_LIMIT_2_BYTES = ((1 << (XML_TT_VAL_BITS + XML_REG_VAL_BITS)) - 1);
-var ENCODING_LIMIT_3_BYTES = ((1 << (XML_TT_VAL_BITS + 2 * XML_REG_VAL_BITS)) - 1);
-
-var numEncodingBytes = function(
- //long
- x) {
- if (x <= ENCODING_LIMIT_1_BYTE) return (1);
- if (x <= ENCODING_LIMIT_2_BYTES) return (2);
- if (x <= ENCODING_LIMIT_3_BYTES) return (3);
-
- var numbytes = 1;
-
- // Last byte gives you XML_TT_VAL_BITS
- // Remainder each give you XML_REG_VAL_BITS
- x = x >>> XML_TT_VAL_BITS;
- while (x != 0) {
- numbytes++;
- x = x >>> XML_REG_VAL_BITS;
- }
- return (numbytes);
-}
-
-//TODO
\ No newline at end of file
diff --git a/js/encoding/BinaryXMLDecoder.js b/js/encoding/BinaryXMLDecoder.js
index 1175f28..53343f4 100644
--- a/js/encoding/BinaryXMLDecoder.js
+++ b/js/encoding/BinaryXMLDecoder.js
@@ -1,7 +1,8 @@
/*
- * This class is used to encode and decode binary elements ( blog, type/value pairs)
+ * This class is used to decode ccnb binary elements (blob, type/value pairs).
*
* @author: ucla-cs
+ * See COPYING for copyright and distribution information.
*/
var XML_EXT = 0x00;
@@ -70,49 +71,9 @@
var DEBUG_MAX_LEN = 32768;
this.istream = istream;
- //console.log('istream is '+ this.istream);
this.offset = 0;
};
-
-BinaryXMLDecoder.prototype.readStartElement =function(
- //String
- startTag,
- //TreeMap<String, String>
- attributes) {
-
- try {
- //this.TypeAndVal
- tv = this.decodeTypeAndVal(this.istream);
-
- if (null == tv) {
- throw new Exception("Expected start element: " + startTag + " got something not a tag.");
- }
-
- //String
- decodedTag = null;
-
- if (tv.type() == XML_TAG) {
-
- decodedTag = this.decodeUString(this.Istream, tv.val()+1);
-
- } else if (tv.type() == XML_DTAG) {
- decodedTag = tagToString(tv.val());
- }
-
- if ((null == decodedTag) || decodedTag != startTag) {
- throw new Exception("Expected start element: " + startTag + " got: " + decodedTag + "(" + tv.val() + ")");
- }
-
- if (null != attributes) {
- readAttributes(attributes);
- }
-
- } catch (e) {
- throw new Exception("readStartElement", e);
- }
-};
-
BinaryXMLDecoder.prototype.readAttributes = function(
//TreeMap<String,String>
attributes){
@@ -124,37 +85,37 @@
try {
//this.TypeAndVal
- nextTV = this.peekTypeAndVal(this.istream);
+ nextTV = this.peekTypeAndVal();
while ((null != nextTV) && ((XML_ATTR == nextTV.type()) ||
(XML_DATTR == nextTV.type()))) {
//this.TypeAndVal
- thisTV = this.decodeTypeAndVal(this.Istream);
+ thisTV = this.decodeTypeAndVal();
var attributeName = null;
if (XML_ATTR == thisTV.type()) {
- attributeName = this.decodeUString(this.istream, thisTV.val()+1);
+ attributeName = this.decodeUString(thisTV.val()+1);
} else if (XML_DATTR == thisTV.type()) {
// DKS TODO are attributes same or different dictionary?
attributeName = tagToString(thisTV.val());
if (null == attributeName) {
- throw new ContentDecodingException("Unknown DATTR value" + thisTV.val());
+ throw new ContentDecodingException(new Error("Unknown DATTR value" + thisTV.val()));
}
}
- var attributeValue = this.decodeUString(this.istream);
+ var attributeValue = this.decodeUString();
attributes.put(attributeName, attributeValue);
- nextTV = this.peekTypeAndVal(this.istream);
+ nextTV = this.peekTypeAndVal();
}
} catch ( e) {
- throw new ContentDecodingException("readStartElement", e);
+ throw new ContentDecodingException(new Error("readStartElement", e));
}
};
@@ -184,12 +145,11 @@
//if(typeof startTag == 'number')
//startTag = tagToString(startTag);
- //try {
//TypeAndVal
- tv = this.decodeTypeAndVal(this.istream);
+ tv = this.decodeTypeAndVal();
if (null == tv) {
- throw new Exception("Expected start element: " + startTag + " got something not a tag.");
+ throw new ContentDecodingException(new Error("Expected start element: " + startTag + " got something not a tag."));
}
//String
@@ -211,7 +171,7 @@
//console.log('valval is ' +valval);
- decodedTag = this.decodeUString(this.istream, valval);
+ decodedTag = this.decodeUString(valval);
} else if (tv.type() == XML_DTAG) {
//console.log('gothere');
@@ -227,7 +187,7 @@
if ((null == decodedTag) || decodedTag != startTag ) {
console.log('expecting '+ startag + ' but got '+ decodedTag);
- throw new Exception("Expected start element: " + startTag + " got: " + decodedTag + "(" + tv.val() + ")");
+ throw new ContentDecodingException(new Error("Expected start element: " + startTag + " got: " + decodedTag + "(" + tv.val() + ")"));
}
// DKS: does not read attributes out of stream if caller doesn't
@@ -236,11 +196,6 @@
if (null != attributes) {
readAttributes(attributes);
}
-
- //} catch ( e) {
- //console.log(e);
- //throw new Exception("readStartElement", e);
- //}
}
@@ -255,14 +210,14 @@
try {
// Now need to get attributes.
//TypeAndVal
- nextTV = this.peekTypeAndVal(this.istream);
+ nextTV = this.peekTypeAndVal();
while ((null != nextTV) && ((XML_ATTR == nextTV.type()) ||
(XML_DATTR == nextTV.type()))) {
// Decode this attribute. First, really read the type and value.
//this.TypeAndVal
- thisTV = this.decodeTypeAndVal(this.istream);
+ thisTV = this.decodeTypeAndVal();
//String
attributeName = null;
@@ -275,28 +230,26 @@
else
valval = (tv.val())+ 1;
- attributeName = this.decodeUString(this.istream,valval);
+ attributeName = this.decodeUString(valval);
} else if (XML_DATTR == thisTV.type()) {
// DKS TODO are attributes same or different dictionary?
attributeName = tagToString(thisTV.val());
if (null == attributeName) {
- throw new Exception("Unknown DATTR value" + thisTV.val());
+ throw new ContentDecodingException(new Error("Unknown DATTR value" + thisTV.val()));
}
}
// Attribute values are always UDATA
//String
- attributeValue = this.decodeUString(this.istream);
+ attributeValue = this.decodeUString();
//
attributes.push([attributeName, attributeValue]);
- nextTV = this.peekTypeAndVal(this.istream);
+ nextTV = this.peekTypeAndVal();
}
-
} catch ( e) {
- Log.logStackTrace(Log.FAC_ENCODING, Level.WARNING, e);
- throw new Exception("readStartElement", e);
+ throw new ContentDecodingException(new Error("readStartElement", e));
}
};
@@ -311,13 +264,13 @@
// Have to distinguish genuine errors from wrong tags. Could either use
// a special exception subtype, or redo the work here.
//this.TypeAndVal
- tv = this.decodeTypeAndVal(this.istream);
+ tv = this.decodeTypeAndVal();
if (null != tv) {
if (tv.type() == XML_TAG) {
/*if (tv.val()+1 > DEBUG_MAX_LEN) {
- throw new ContentDecodingException("Decoding error: length " + tv.val()+1 + " longer than expected maximum length!");
+ throw new ContentDecodingException(new Error("Decoding error: length " + tv.val()+1 + " longer than expected maximum length!")(;
}*/
// Tag value represents length-1 as tags can never be empty.
@@ -328,7 +281,7 @@
else
valval = (tv.val())+ 1;
- decodedTag = this.decodeUString(this.istream, valval);
+ decodedTag = this.decodeUString(valval);
//Log.info(Log.FAC_ENCODING, "Unexpected: got text tag in peekStartElement; length: " + valval + " decoded tag = " + decodedTag);
@@ -345,7 +298,7 @@
this.offset = previousOffset;
} catch ( e) {
Log.logStackTrace(Log.FAC_ENCODING, Level.WARNING, e);
- throw new ContentDecodingException("Cannot reset stream! " + e.getMessage(), e);
+ throw new ContentDecodingException(new Error("Cannot reset stream! " + e.getMessage(), e));
}
}
return decodedTag;
@@ -371,7 +324,7 @@
return false;
}
else{
- throw new Exception("SHOULD BE STRING OR NUMBER");
+ throw new ContentDecodingException(new Error("SHOULD BE STRING OR NUMBER"));
}
}
//returns Long
@@ -387,13 +340,13 @@
// Have to distinguish genuine errors from wrong tags. Could either use
// a special exception subtype, or redo the work here.
//this.TypeAndVal
- tv = this.decodeTypeAndVal(this.istream);
+ tv = this.decodeTypeAndVal();
if (null != tv) {
if (tv.type() == XML_TAG) {
if (tv.val()+1 > DEBUG_MAX_LEN) {
- throw new ContentDecodingException("Decoding error: length " + tv.val()+1 + " longer than expected maximum length!");
+ throw new ContentDecodingException(new Error("Decoding error: length " + tv.val()+1 + " longer than expected maximum length!"));
}
var valval ;
@@ -405,7 +358,7 @@
// Tag value represents length-1 as tags can never be empty.
//String
- strTag = this.decodeUString(this.istream, valval);
+ strTag = this.decodeUString(valval);
decodedTag = stringToTag(strTag);
@@ -425,7 +378,7 @@
this.offset = previousOffset;
} catch ( e) {
Log.logStackTrace(Log.FAC_ENCODING, Level.WARNING, e);
- throw new Exception("Cannot reset stream! " + e.getMessage(), e);
+ throw new Error("Cannot reset stream! " + e.getMessage(), e);
}
}
return decodedTag;
@@ -451,23 +404,27 @@
BinaryXMLDecoder.prototype.readEndElement = function(){
- try {
+ if(LOG>4)console.log('this.offset is '+this.offset);
+
var next = this.istream[this.offset];
+
this.offset++;
//read();
+
+ if(LOG>4)console.log('XML_CLOSE IS '+XML_CLOSE);
+ if(LOG>4)console.log('next is '+next);
+
if (next != XML_CLOSE) {
- throw new ContentDecodingException("Expected end element, got: " + next);
+ console.log("Expected end element, got: " + next);
+ throw new ContentDecodingException(new Error("Expected end element, got: " + next));
}
- } catch ( e) {
- throw new ContentDecodingException(e);
- }
};
//String
BinaryXMLDecoder.prototype.readUString = function(){
//String
- ustring = this.decodeUString(this.istream);
+ ustring = this.decodeUString();
this.readEndElement();
return ustring;
@@ -478,7 +435,7 @@
BinaryXMLDecoder.prototype.readBlob = function() {
//byte []
- blob = this.decodeBlob(this.istream);
+ blob = this.decodeBlob();
this.readEndElement();
return blob;
@@ -491,30 +448,39 @@
startTag) {
//byte []
- byteTimestamp = this.readBinaryElement(startTag);
+ var byteTimestamp = this.readBinaryElement(startTag);
+
+ //var lontimestamp = DataUtils.byteArrayToUnsignedLong(byteTimestamp);
+
+ var byteTimestamp = DataUtils.toHex(byteTimestamp);
+
+
+ var byteTimestamp = parseInt(byteTimestamp, 16);
+
+ lontimestamp = (byteTimestamp/ 4096) * 1000;
+
+ //if(lontimestamp<0) lontimestamp = - lontimestamp;
+
+ if(LOG>3) console.log('DECODED DATE WITH VALUE');
+ if(LOG>3) console.log(lontimestamp);
+
+
//CCNTime
- timestamp = new CCNTime(byteTimestamp);
+ timestamp = new CCNTime(lontimestamp);
//timestamp.setDateBinary(byteTimestamp);
if (null == timestamp) {
- throw new ContentDecodingException("Cannot parse timestamp: " + DataUtils.printHexBytes(byteTimestamp));
+ throw new ContentDecodingException(new Error("Cannot parse timestamp: " + DataUtils.printHexBytes(byteTimestamp)));
}
return timestamp;
};
-BinaryXMLDecoder.prototype.decodeTypeAndVal = function(
- /*InputStream*/
- istream) {
+BinaryXMLDecoder.prototype.decodeTypeAndVal = function() {
- /*int*/next;
- /*int*/type = -1;
- /*long*/val = 0;
- /*boolean*/more = true;
+ /*int*/var type = -1;
+ /*long*/var val = 0;
+ /*boolean*/var more = true;
-
- //var savedOffset = this.offset;
- var count = 0;
-
do {
var next = this.istream[this.offset ];
@@ -544,26 +510,26 @@
} while (more);
+ if(LOG>3)console.log('TYPE is '+ type + ' VAL is '+ val);
+
return new TypeAndVal(type, val);
};
//TypeAndVal
-BinaryXMLDecoder.peekTypeAndVal = function(
- //InputStream
- istream) {
+BinaryXMLDecoder.peekTypeAndVal = function() {
//TypeAndVal
tv = null;
- //istream.mark(LONG_BYTES*2);
+ //this.istream.mark(LONG_BYTES*2);
var previousOffset = this.offset;
try {
- tv = this.decodeTypeAndVal(this.istream);
+ tv = this.decodeTypeAndVal();
} finally {
- //istream.reset();
+ //this.istream.reset();
this.offset = previousOffset;
}
@@ -571,17 +537,14 @@
};
-//byte[]
+//Uint8Array
BinaryXMLDecoder.prototype.decodeBlob = function(
- //InputStream
- istream,
//int
blobLength) {
-
if(null == blobLength){
//TypeAndVal
- tv = this.decodeTypeAndVal(this.istream);
+ tv = this.decodeTypeAndVal();
var valval ;
@@ -592,33 +555,31 @@
valval = (tv.val());
//console.log('valval here is ' + valval);
- return this.decodeBlob(this.istream, valval);
+ return this.decodeBlob(valval);
}
//
- //byte []
-
- bytes = this.istream.slice(this.offset, this.offset+ blobLength);
+ //Uint8Array
+ var bytes = this.istream.subarray(this.offset, this.offset+ blobLength);
this.offset += blobLength;
- //int
return bytes;
-
- count = 0;
-
};
-
+var count =0;
//String
BinaryXMLDecoder.prototype.decodeUString = function(
- //InputStream
- istream,
//int
byteLength) {
- if(null == byteLength){
- tv = this.decodeTypeAndVal(this.istream);
+ /*
+ console.log('COUNT IS '+count);
+ console.log('INPUT BYTELENGTH IS '+byteLength);
+ count++;
+ if(null == byteLength|| undefined == byteLength){
+ console.log("!!!!");
+ tv = this.decodeTypeAndVal();
var valval ;
if(typeof tv.val() == 'string'){
valval = (parseInt(tv.val()));
@@ -626,18 +587,82 @@
else
valval = (tv.val());
- byteLength= this.decodeUString(this.istream, valval);
+ if(LOG>4) console.log('valval is ' + valval);
+ byteLength= this.decodeUString(valval);
+
+ //if(LOG>4) console.log('byte Length found in type val is '+ byteLength.charCodeAt(0));
+ byteLength = parseInt(byteLength);
+
+
+ //byteLength = byteLength.charCodeAt(0);
+ //if(LOG>4) console.log('byte Length found in type val is '+ byteLength);
}
-
- stringBytes = this.decodeBlob(this.istream, byteLength);
+ if(LOG>4)console.log('byteLength is '+byteLength);
+ if(LOG>4)console.log('type of byteLength is '+typeof byteLength);
+ stringBytes = this.decodeBlob(byteLength);
+
+ //console.log('String bytes are '+ stringBytes);
+ //console.log('stringBytes);
+
+ if(LOG>4)console.log('byteLength is '+byteLength);
+ if(LOG>4)console.log('this.offset is '+this.offset);
+
tempBuffer = this.istream.slice(this.offset, this.offset+byteLength);
+ if(LOG>4)console.log('TEMPBUFFER IS' + tempBuffer);
+ if(LOG>4)console.log( tempBuffer);
+
+ if(LOG>4)console.log('ADDING to offset value' + byteLength);
this.offset+= byteLength;
- console.log('read the String' + tempBuffer.toString('ascii'));
- return tempBuffer.toString('ascii');//DataUtils.getUTF8StringFromBytes(stringBytes);
+ //if(LOG>3)console.log('read the String' + tempBuffer.toString('ascii'));
+ //return tempBuffer.toString('ascii');//
+
+
+ //if(LOG>3)console.log( 'STRING READ IS '+ DataUtils.getUTF8StringFromBytes(stringBytes) ) ;
+ //if(LOG>3)console.log( 'STRING READ IS '+ DataUtils.getUTF8StringFromBytes(tempBuffer) ) ;
+ //if(LOG>3)console.log(DataUtils.getUTF8StringFromBytes(tempBuffer) ) ;
+ //return DataUtils.getUTF8StringFromBytes(tempBuffer);
+
+ if(LOG>3)console.log( 'STRING READ IS '+ DataUtils.toString(stringBytes) ) ;
+ if(LOG>3)console.log( 'TYPE OF STRING READ IS '+ typeof DataUtils.toString(stringBytes) ) ;
+
+ return DataUtils.toString(stringBytes);*/
+
+ if(null == byteLength ){
+ var tempStreamPosition = this.offset;
+
+ //TypeAndVal
+ tv = this.decodeTypeAndVal();
+
+ if(LOG>3)console.log('TV is '+tv);
+ if(LOG>3)console.log(tv);
+
+ if(LOG>3)console.log('Type of TV is '+typeof tv);
+
+ if ((null == tv) || (XML_UDATA != tv.type())) { // if we just have closers left, will get back null
+ //if (Log.isLoggable(Log.FAC_ENCODING, Level.FINEST))
+ //Log.finest(Log.FAC_ENCODING, "Expected UDATA, got " + ((null == tv) ? " not a tag " : tv.type()) + ", assuming elided 0-length blob.");
+
+ this.offset = tempStreamPosition;
+
+ return "";
+ }
+
+ return this.decodeUString(tv.val());
+ }
+ else{
+ //byte []
+ stringBytes = this.decodeBlob(byteLength);
+
+ //return DataUtils.getUTF8StringFromBytes(stringBytes);
+ return DataUtils.toString(stringBytes);
+
+ }
};
+
+
//OBject containg a pair of type and value
var TypeAndVal = function TypeAndVal(_type,_val) {
this.t = _type;
@@ -651,4 +676,56 @@
TypeAndVal.prototype.val = function(){
return this.v;
};
-//TODO
\ No newline at end of file
+
+
+
+
+BinaryXMLDecoder.prototype.readIntegerElement =function(
+ //String
+ startTag) {
+
+ //String
+ if(LOG>4) console.log('READING INTEGER '+ startTag);
+ if(LOG>4) console.log('TYPE OF '+ typeof startTag);
+
+ strVal = this.readUTF8Element(startTag);
+
+ return parseInt(strVal);
+};
+
+
+BinaryXMLDecoder.prototype.readUTF8Element =function(
+ //String
+ startTag,
+ //TreeMap<String, String>
+ attributes) {
+ //throws Error where name == "ContentDecodingException"
+
+ this.readStartElement(startTag, attributes); // can't use getElementText, can't get attributes
+ //String
+ strElementText = this.readUString();
+ return strElementText;
+};
+
+
+/*
+ * Set the offset into the input, used for the next read.
+ */
+BinaryXMLDecoder.prototype.seek = function(
+ //int
+ offset) {
+ this.offset = offset;
+}
+
+/*
+ * Call with: throw new ContentDecodingException(new Error("message")).
+ */
+function ContentDecodingException(error) {
+ this.message = error.message;
+ // Copy lineNumber, etc. from where new Error was called.
+ for (var prop in error)
+ this[prop] = error[prop];
+}
+ContentDecodingException.prototype = new Error();
+ContentDecodingException.prototype.name = "ContentDecodingException";
+
diff --git a/js/encoding/BinaryXMLEncoder.js b/js/encoding/BinaryXMLEncoder.js
index a633aa8..2a67e05 100644
--- a/js/encoding/BinaryXMLEncoder.js
+++ b/js/encoding/BinaryXMLEncoder.js
@@ -1,7 +1,8 @@
/*
- * This class is used to encode and decode binary elements ( blog, type/value pairs)
+ * This class is used to encode ccnb binary elements (blob, type/value pairs).
*
* @author: ucla-cs
+ * See COPYING for copyright and distribution information.
*/
var XML_EXT = 0x00;
@@ -40,37 +41,37 @@
var BinaryXMLEncoder = function BinaryXMLEncoder(){
-
- this.ostream = new Array(10000);
-
-
+ this.ostream = new Uint8Array(10000);
this.offset =0;
-
this.CODEC_NAME = "Binary";
-
};
-BinaryXMLEncoder.prototype.writeUString = function(/*String*/ utf8Content){
- this.encodeUString(this.ostream, utf8Content);
+
+BinaryXMLEncoder.prototype.writeUString = function(/*String*/ utf8Content) {
+ this.encodeUString(this.ostream, utf8Content, XML_UDATA);
};
-BinaryXMLEncoder.prototype.writeBlob = function(/*byte []*/ binaryContent
+
+BinaryXMLEncoder.prototype.writeBlob = function(
+ /*Uint8Array*/ binaryContent
//, /*int*/ offset, /*int*/ length
- ) {
+ ) {
if(LOG >3) console.log(binaryContent);
this.encodeBlob(this.ostream, binaryContent, this.offset, binaryContent.length);
};
-BinaryXMLEncoder.prototype.writeStartElement = function(/*String*/ tag, /*TreeMap<String,String>*/ attributes){
- /*Long*/ dictionaryVal = tag;//stringToTag(tag);
+BinaryXMLEncoder.prototype.writeStartElement = function(
+ /*String*/ tag,
+ /*TreeMap<String,String>*/ attributes
+ ) {
+
+ /*Long*/ dictionaryVal = tag; //stringToTag(tag);
if (null == dictionaryVal) {
-
this.encodeUString(this.ostream, tag, XML_TAG);
-
} else {
this.encodeTypeAndVal(XML_DTAG, dictionaryVal, this.ostream);
}
@@ -81,14 +82,13 @@
};
-BinaryXMLEncoder.prototype.writeEndElement = function(){
-
+BinaryXMLEncoder.prototype.writeEndElement = function() {
this.ostream[this.offset] = XML_CLOSE;
- this.offset+= 1;
+ this.offset += 1;
}
+
BinaryXMLEncoder.prototype.writeAttributes = function(/*TreeMap<String,String>*/ attributes) {
-
if (null == attributes) {
return;
}
@@ -113,10 +113,9 @@
this.encodeUString(this.ostream, strValue);
}
-
-
}
+
//returns a string
stringToTag = function(/*long*/ tagVal) {
if ((tagVal >= 0) && (tagVal < CCNProtocolDTagsStrings.length)) {
@@ -148,32 +147,35 @@
//byte[]
Content,
//TreeMap<String, String>
- attributes) {
+ attributes
+ ) {
this.writeStartElement(tag, attributes);
// Will omit if 0-length
if(typeof Content === 'number') {
- if(LOG>4) console.log('GOING TO WRITE THE NUMBER ' +Content );
- this.writeBlob(Content.toString());
- //whatever
+ if(LOG>4) console.log('GOING TO WRITE THE NUMBER .charCodeAt(0) ' + Content.toString().charCodeAt(0) );
+ if(LOG>4) console.log('GOING TO WRITE THE NUMBER ' + Content.toString() );
+ if(LOG>4) console.log('type of number is ' + typeof Content.toString() );
+ this.writeUString(Content.toString());
+ //whatever
}
-
+ else if(typeof Content === 'string'){
+ if(LOG>4) console.log('GOING TO WRITE THE STRING ' + Content );
+ if(LOG>4) console.log('type of STRING is ' + typeof Content );
+
+ this.writeUString(Content);
+ }
else{
- //else if(typeof Content === 'string'){
- //console.log('went here');
- //this.writeBlob(Content);
- //}
-
- //else if(typeof Content === 'object'){
+ if(LOG>4) console.log('GOING TO WRITE A BLOB ' + Content );
+
this.writeBlob(Content);
- //}
}
this.writeEndElement();
}
-//TODO
+
var TypeAndVal = function TypeAndVal(_type,_val) {
this.type = _type;
@@ -181,31 +183,35 @@
};
+
BinaryXMLEncoder.prototype.encodeTypeAndVal = function(
//int
type,
//long
val,
- //byte []
- buf) {
+ //ArrayBufferView
+ ostream
+ ) {
- console.log('Encoding type '+ type+ ' and value '+ val);
+ if(LOG>4) console.log('Encoding type '+ type+ ' and value '+ val);
+
+ if(LOG>4) console.log('OFFSET IS ' + this.offset);
if ((type > XML_UDATA) || (type < 0) || (val < 0)) {
- throw new Exception("Tag and value must be positive, and tag valid.");
+ throw new Error("Tag and value must be positive, and tag valid.");
}
// Encode backwards. Calculate how many bytes we need:
var numEncodingBytes = this.numEncodingBytes(val);
- if ((this.offset + numEncodingBytes) > buf.length) {
- throw new Exception("Buffer space of " + (buf.length-this.offset) +
+ if ((this.offset + numEncodingBytes) > ostream.length) {
+ throw new Error("Buffer space of " + (ostream.length - this.offset) +
" bytes insufficient to hold " +
numEncodingBytes + " of encoded type and value.");
}
// Bottom 4 bits of val go in last byte with tag.
- buf[this.offset + numEncodingBytes - 1] =
+ ostream[this.offset + numEncodingBytes - 1] =
//(byte)
(BYTE_MASK &
(((XML_TT_MASK & type) |
@@ -217,14 +223,13 @@
// is "more" flag.
var i = this.offset + numEncodingBytes - 2;
while ((0 != val) && (i >= this.offset)) {
- buf[i] = //(byte)
- (BYTE_MASK &
- (val & XML_REG_VAL_MASK)); // leave top bit unset
+ ostream[i] = //(byte)
+ (BYTE_MASK & (val & XML_REG_VAL_MASK)); // leave top bit unset
val = val >>> XML_REG_VAL_BITS;
--i;
}
if (val != 0) {
- throw new Exception( "This should not happen: miscalculated encoding");
+ throw new Error( "This should not happen: miscalculated encoding");
//Log.warning(Log.FAC_ENCODING, "This should not happen: miscalculated encoding length, have " + val + " left.");
}
this.offset+= numEncodingBytes;
@@ -232,6 +237,7 @@
return numEncodingBytes;
};
+
BinaryXMLEncoder.prototype.encodeUString = function(
//OutputStream
ostream,
@@ -244,16 +250,18 @@
return;
}
-
- //byte [] data utils
- /*custom*/
- //byte[]
- strBytes = new Array(ustring.Length);
- var i = 0;
- for( ;i<ustring.lengh;i++) //in InStr.ToCharArray())
+ if(LOG>3) console.log("The string to write is ");
+ if(LOG>3) console.log(ustring);
+
+ //COPY THE STRING TO AVOID PROBLEMS
+ strBytes = new Array(ustring.length);
+
+ for (i = 0; i < ustring.length; i++) //in InStr.ToCharArray())
{
- strBytes[i] = ustring[i];
+ if(LOG>3) console.log('ustring[' + i + '] = ' + ustring[i]);
+ strBytes[i] = ustring.charCodeAt(i);
}
+
//strBytes = DataUtils.getBytesFromUTF8String(ustring);
this.encodeTypeAndVal(type,
@@ -261,11 +269,12 @@
(strBytes.length-1) :
strBytes.length), ostream);
-
- this.writeString(strBytes,this.offset);
+ if(LOG>3) console.log("THE string to write is ");
+ if(LOG>3) console.log(strBytes);
+
+ this.writeString(strBytes,this.offset);
this.offset+= strBytes.length;
-
};
@@ -273,7 +282,7 @@
BinaryXMLEncoder.prototype.encodeBlob = function(
//OutputStream
ostream,
- //byte []
+ //Uint8Array
blob,
//int
offset,
@@ -281,19 +290,22 @@
length) {
- if ((null == blob) || (length == 0)) {
-
+ if (null == blob)
return;
- }
+ if(LOG>4) console.log('LENGTH OF XML_BLOB IS '+length);
- this.encodeTypeAndVal(XML_BLOB, length, ostream,offset);
+ /*blobCopy = new Array(blob.Length);
- if (null != blob) {
+ for (i = 0; i < blob.length; i++) //in InStr.ToCharArray())
+ {
+ blobCopy[i] = blob[i];
+ }*/
- this.writeString(blob,this.offset);
- this.offset += length;
- }
+ this.encodeTypeAndVal(XML_BLOB, length, ostream, offset);
+
+ this.writeBlobArray(blob, this.offset);
+ this.offset += length;
};
var ENCODING_LIMIT_1_BYTE = ((1 << (XML_TT_VAL_BITS)) - 1);
@@ -324,7 +336,26 @@
tag,
//CCNTime
dateTime) {
- this.writeElement(tag, dateTime.toBinaryTime());
+
+ if(LOG>4)console.log('ENCODING DATE with LONG VALUE');
+ if(LOG>4)console.log(dateTime.msec);
+
+ //var binarydate = DataUtils.unsignedLongToByteArray( Math.round((dateTime.msec/1000) * 4096) );
+
+
+ //parse to hex
+ var binarydate = Math.round((dateTime.msec/1000) * 4096).toString(16) ;
+
+ //HACK
+ var binarydate = DataUtils.toNumbers( '0'.concat(binarydate,'0')) ;
+
+
+ if(LOG>4)console.log('ENCODING DATE with BINARY VALUE');
+ if(LOG>4)console.log(binarydate);
+ if(LOG>4)console.log('ENCODING DATE with BINARY VALUE(HEX)');
+ if(LOG>4)console.log(DataUtils.toHex(binarydate));
+
+ this.writeElement(tag, binarydate);
};
BinaryXMLEncoder.prototype.writeString = function(
@@ -336,37 +367,43 @@
if(typeof input === 'string'){
//console.log('went here');
if(LOG>4) console.log('GOING TO WRITE A STRING');
-
- for (var i = 0; i < input.length; i++) {
+ if(LOG>4) console.log(input);
+
+ for (i = 0; i < input.length; i++) {
+ if(LOG>4) console.log('input.charCodeAt(i)=' + input.charCodeAt(i));
this.ostream[this.offset+i] = (input.charCodeAt(i));
}
}
-
- else if(typeof input === 'object'){
+ else{
+ if(LOG>4) console.log('GOING TO WRITE A STRING IN BINARY FORM');
+ if(LOG>4) console.log(input);
+
this.writeBlobArray(input);
+ }
+ /*
+ else if(typeof input === 'object'){
+
}
-
+ */
};
+
BinaryXMLEncoder.prototype.writeBlobArray = function(
- //String
- Blob,
- //CCNTime
+ //Uint8Array
+ blob,
+ //int
offset) {
if(LOG>4) console.log('GOING TO WRITE A BLOB');
- for (var i = 0; i < Blob.length; i++) {
+ /*for (var i = 0; i < Blob.length; i++) {
this.ostream[this.offset+i] = Blob[i];
- }
-
+ }*/
+ this.ostream.set(blob, this.offset);
};
-
BinaryXMLEncoder.prototype.getReducedOstream = function() {
-
- return this.ostream.slice(0,this.offset);
-
+ return this.ostream.subarray(0, this.offset);
};
diff --git a/js/encoding/BinaryXMLStructureDecoder.js b/js/encoding/BinaryXMLStructureDecoder.js
new file mode 100644
index 0000000..4ad3de9
--- /dev/null
+++ b/js/encoding/BinaryXMLStructureDecoder.js
@@ -0,0 +1,121 @@
+/*
+ * This class uses BinaryXMLDecoder to follow the structure of a ccnb binary element to
+ * determine its end.
+ *
+ * @author: ucla-cs
+ * See COPYING for copyright and distribution information.
+ */
+
+var BinaryXMLStructureDecoder = function BinaryXMLDecoder() {
+ this.gotElementEnd = false;
+ this.offset = 0;
+ this.level = 0;
+ this.state = BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE;
+ this.headerStartOffset = 0;
+ this.readBytesEndOffset = 0;
+};
+
+BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE = 0;
+BinaryXMLStructureDecoder.READ_BYTES = 1;
+
+/*
+ * Continue scanning input starting from this.offset. If found the end of the element
+ * which started at offset 0 then return true, else false.
+ * If this returns false, you should read more into input and call again.
+ * You have to pass in input each time because the array could be reallocated.
+ * This throws an exception for badly formed ccnb.
+ */
+BinaryXMLStructureDecoder.prototype.findElementEnd = function(
+ // byte array
+ input)
+{
+ if (this.gotElementEnd)
+ // Someone is calling when we already got the end.
+ return true;
+
+ var decoder = new BinaryXMLDecoder(input);
+
+ while (true) {
+ if (this.offset >= input.length)
+ // All the cases assume we have some input.
+ return false;
+
+ switch (this.state) {
+ case BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE:
+ // First check for XML_CLOSE.
+ if (this.offset == this.headerStartOffset && input[this.offset] == XML_CLOSE) {
+ ++this.offset;
+ // Close the level.
+ --this.level;
+ if (this.level == 0)
+ // Finished.
+ return true;
+ if (this.level < 0)
+ throw new Error("BinaryXMLStructureDecoder: Unexepected close tag at offset " +
+ (this.offset - 1));
+
+ // Get ready for the next header.
+ this.headerStartOffset = this.offset;
+ break;
+ }
+
+ while (true) {
+ if (this.offset >= input.length)
+ return false;
+ if (input[this.offset++] & XML_TT_NO_MORE)
+ // Break and read the header.
+ break;
+ }
+
+ decoder.seek(this.headerStartOffset);
+ var typeAndVal = decoder.decodeTypeAndVal();
+ if (typeAndVal == null)
+ throw new Error("BinaryXMLStructureDecoder: Can't read header starting at offset " +
+ this.headerStartOffset);
+
+ // Set the next state based on the type.
+ var type = typeAndVal.t;
+ if (type == XML_DATTR)
+ // We already consumed the item. READ_HEADER_OR_CLOSE again.
+ // ccnb has rules about what must follow an attribute, but we are just scanning.
+ this.headerStartOffset = this.offset;
+ else if (type == XML_DTAG || type == XML_EXT) {
+ // Start a new level and READ_HEADER_OR_CLOSE again.
+ ++this.level;
+ this.headerStartOffset = this.offset;
+ }
+ else if (type == XML_TAG || type == XML_ATTR) {
+ if (type == XML_TAG)
+ // Start a new level and read the tag.
+ ++this.level;
+ // Minimum tag or attribute length is 1.
+ this.readBytesEndOffset = this.offset + typeAndVal.v + 1;
+ this.state = BinaryXMLStructureDecoder.READ_BYTES;
+ // ccnb has rules about what must follow an attribute, but we are just scanning.
+ }
+ else if (type == XML_BLOB || type == XML_UDATA) {
+ this.readBytesEndOffset = this.offset + typeAndVal.v;
+ this.state = BinaryXMLStructureDecoder.READ_BYTES;
+ }
+ else
+ throw new Error("BinaryXMLStructureDecoder: Unrecognized header type " + type);
+ break;
+
+ case BinaryXMLStructureDecoder.READ_BYTES:
+ if (input.length < this.readBytesEndOffset) {
+ // Need more.
+ this.offset = input.length;
+ return false;
+ }
+ // Got the bytes. Read a new header or close.
+ this.offset = this.readBytesEndOffset;
+ this.headerStartOffset = this.offset;
+ this.state = BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE;
+ break;
+
+ default:
+ // We don't expect this to happen.
+ throw new Error("BinaryXMLStructureDecoder: Unrecognized state " + this.state);
+ }
+ }
+};
diff --git a/js/encoding/DataUtils.js b/js/encoding/DataUtils.js
index 5386698..eee178a 100644
--- a/js/encoding/DataUtils.js
+++ b/js/encoding/DataUtils.js
@@ -1,7 +1,7 @@
-
/*
* This class contains utilities to help parse the data
* author: ucla-cs
+ * See COPYING for copyright and distribution information.
*/
var DataUtils = function DataUtils(){
@@ -15,12 +15,16 @@
*
*/
- var keyStr = "ABCDEFGHIJKLMNOP" +
+DataUtils.keyStr = "ABCDEFGHIJKLMNOP" +
"QRSTUVWXYZabcdef" +
"ghijklmnopqrstuv" +
"wxyz0123456789+/" +
"=";
+
+/**
+ * Raw String to Base 64
+ */
DataUtils.stringtoBase64=function stringtoBase64(input) {
input = escape(input);
var output = "";
@@ -45,10 +49,10 @@
}
output = output +
- keyStr.charAt(enc1) +
- keyStr.charAt(enc2) +
- keyStr.charAt(enc3) +
- keyStr.charAt(enc4);
+ DataUtils.keyStr.charAt(enc1) +
+ DataUtils.keyStr.charAt(enc2) +
+ DataUtils.keyStr.charAt(enc3) +
+ DataUtils.keyStr.charAt(enc4);
chr1 = chr2 = chr3 = "";
enc1 = enc2 = enc3 = enc4 = "";
} while (i < input.length);
@@ -56,6 +60,9 @@
return output;
}
+/**
+ * Base 64 to Raw String
+ */
DataUtils.base64toString = function base64toString(input) {
var output = "";
var chr1, chr2, chr3 = "";
@@ -64,18 +71,20 @@
// remove all characters that are not A-Z, a-z, 0-9, +, /, or =
var base64test = /[^A-Za-z0-9\+\/\=]/g;
+ /* Test for invalid characters. */
if (base64test.exec(input)) {
alert("There were invalid base64 characters in the input text.\n" +
"Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\n" +
"Expect errors in decoding.");
}
+
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
do {
- enc1 = keyStr.indexOf(input.charAt(i++));
- enc2 = keyStr.indexOf(input.charAt(i++));
- enc3 = keyStr.indexOf(input.charAt(i++));
- enc4 = keyStr.indexOf(input.charAt(i++));
+ enc1 = DataUtils.keyStr.indexOf(input.charAt(i++));
+ enc2 = DataUtils.keyStr.indexOf(input.charAt(i++));
+ enc3 = DataUtils.keyStr.indexOf(input.charAt(i++));
+ enc4 = DataUtils.keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
@@ -99,39 +108,94 @@
};
//byte []
-DataUtils.prototype.unsignedLongToByteArray= function( value) {
+
+/**
+ * NOT WORKING!!!!!
+ *
+ * Unsiged Long Number to Byte Array
+ */
+
+ /*
+DataUtils.unsignedLongToByteArray= function( value) {
+
+ if(LOG>4)console.log('INPUT IS '+value);
+
if( 0 == value )
return [0];
if( 0 <= value && value <= 0x00FF ) {
//byte []
- bb = new Array[1];
+ var bb = new Array(1);
bb[0] = (value & 0x00FF);
return bb;
}
-
+ if(LOG>4) console.log('type of value is '+typeof value);
+ if(LOG>4) console.log('value is '+value);
//byte []
- out = null;
+ var out = null;
//int
var offset = -1;
for(var i = 7; i >=0; --i) {
//byte
- b = ((value >> (i * 8)) & 0xFF);
+ console.log(i);
+ console.log('value is '+value);
+ console.log('(value >> (i * 8)) '+ (value >> (i * 8)) );
+ console.log(' ((value >> (i * 8)) & 0xFF) '+ ((value >> (i * 8)) & 0xFF) );
+
+ var b = ((value >> (i * 8)) & 0xFF) ;
+
+ if(LOG>4) console.log('b is '+b);
+
if( out == null && b != 0 ) {
- out = new byte[i+1];
+ //out = new byte[i+1];
+ out = new Array(i+1);
offset = i;
}
+
if( out != null )
out[ offset - i ] = b;
}
+ if(LOG>4)console.log('OUTPUT IS ');
+ if(LOG>4)console.log(out);
return out;
}
+*/
+
+/**
+ * NOT WORKING!!!!!
+ *
+ * Unsiged Long Number to Byte Array
+ *//*
+DataUtils.byteArrayToUnsignedLong = function(//final byte []
+ src) {
+ if(LOG>4) console.log('INPUT IS ');
+ if(LOG>4) console.log(src);
+
+ var value = 0;
+ for(var i = 0; i < src.length; i++) {
+ value = value << 8;
+ // Java will assume the byte is signed, so extend it and trim it.
+
+
+ var b = ((src[i]) & 0xFF );
+ value |= b;
+ }
+
+ if(LOG>4) console.log('OUTPUT IS ');
+
+ if(LOG>4) console.log(value);
+
+ return value;
+ }*/
-var utf8 = {}
-
-utf8.toByteArray = function(str) {
+/**
+ * Hex String to Byte Array
+ */
+ //THIS IS NOT WORKING
+/*
+DataUtils.HexStringtoByteArray = function(str) {
var byteArray = [];
for (var i = 0; i < str.length; i++)
if (str.charCodeAt(i) <= 0x7F)
@@ -143,29 +207,38 @@
}
return byteArray;
};
+*/
-utf8.parse = function(byteArray) {
- var str = '';
- for (var i = 0; i < byteArray.length; i++)
- str += byteArray[i] <= 0x7F?
- byteArray[i] === 0x25 ? "%25" : // %
- String.fromCharCode(byteArray[i]) :
- "%" + byteArray[i].toString(16).toUpperCase();
- return decodeURIComponent(str);
-};
-
-
+/**
+ * Uint8Array to Hex String
+ */
//http://ejohn.org/blog/numbers-hex-and-colors/
-function toHex(arguments){
- //console.log(arguments);
- var ret = "";
- for ( var i = 0; i < arguments.length; i++ )
- ret += (arguments[i] < 16 ? "0" : "") + arguments[i].toString(16);
- return ret.toUpperCase();
+DataUtils.toHex = function(arguments){
+ if (LOG>4) console.log('ABOUT TO CONVERT '+ arguments);
+ //console.log(arguments);
+ var ret = "";
+ for ( var i = 0; i < arguments.length; i++ )
+ ret += (arguments[i] < 16 ? "0" : "") + arguments[i].toString(16);
+ if (LOG>4) console.log('Converted to: ' + ret);
+ return ret; //.toUpperCase();
}
-//DOES NOT SEEM TO WORK
-function toString(arguments){
+/**
+ * Raw string to hex string.
+ */
+DataUtils.stringToHex = function(arguments){
+ var ret = "";
+ for (var i = 0; i < arguments.length; ++i) {
+ var value = arguments.charCodeAt(i);
+ ret += (value < 16 ? "0" : "") + value.toString(16);
+ }
+ return ret;
+}
+
+/**
+ * Uint8Array to raw string.
+ */
+DataUtils.toString = function(arguments){
//console.log(arguments);
var ret = "";
for ( var i = 0; i < arguments.length; i++ )
@@ -173,19 +246,196 @@
return ret;
}
-function toNumbers( str ){
- if(typeof str =='string'){
- var ret = [];
- str.replace(/(..)/g, function(str){
- ret.push( parseInt( str, 16 ) );
- });
- return ret;
+/**
+ * Hex String to Uint8Array.
+ */
+DataUtils.toNumbers = function(str) {
+ if (typeof str == 'string') {
+ var ret = new Uint8Array(Math.floor(str.length / 2));
+ var i = 0;
+ str.replace(/(..)/g, function(str) {
+ ret[i++] = parseInt(str, 16);
+ });
+ return ret;
}
}
-function toNumbersFromString( str ){
- var bytes = new Array(str.length);
+/**
+ * Hex String to raw string.
+ */
+DataUtils.hexToRawString = function(str) {
+ if(typeof str =='string') {
+ var ret = "";
+ str.replace(/(..)/g, function(s) {
+ ret += String.fromCharCode(parseInt(s, 16));
+ });
+ return ret;
+ }
+}
+
+/**
+ * Raw String to Uint8Array.
+ */
+DataUtils.toNumbersFromString = function( str ){
+ var bytes = new Uint8Array(str.length);
for(var i=0;i<str.length;i++)
bytes[i] = str.charCodeAt(i);
return bytes;
-}
\ No newline at end of file
+}
+
+/*
+ * Return a new Uint8Array which is the Uint8Array concatenated with raw String str.
+ */
+DataUtils.concatFromString = function(array, str) {
+ var bytes = new Uint8Array(array.length + str.length);
+ bytes.set(array);
+ for (var i = 0; i < str.length; ++i)
+ bytes[array.length + i] = str.charCodeAt(i);
+ return bytes;
+}
+
+// TODO: Use TextEncoder and return Uint8Array.
+DataUtils.encodeUtf8 = function (string) {
+ string = string.replace(/\r\n/g,"\n");
+ var utftext = "";
+
+ for (var n = 0; n < string.length; n++) {
+
+ var c = string.charCodeAt(n);
+
+ if (c < 128) {
+ utftext += String.fromCharCode(c);
+ }
+ else if((c > 127) && (c < 2048)) {
+ utftext += String.fromCharCode((c >> 6) | 192);
+ utftext += String.fromCharCode((c & 63) | 128);
+ }
+ else {
+ utftext += String.fromCharCode((c >> 12) | 224);
+ utftext += String.fromCharCode(((c >> 6) & 63) | 128);
+ utftext += String.fromCharCode((c & 63) | 128);
+ }
+
+ }
+
+ return utftext;
+ };
+
+// TODO: Take Uint8Array and use TextDecoder.
+DataUtils.decodeUtf8 = function (utftext) {
+ var string = "";
+ var i = 0;
+ var c = 0;
+ var c1 = 0;
+ var c2 = 0;
+
+ while ( i < utftext.length ) {
+
+ c = utftext.charCodeAt(i);
+
+ if (c < 128) {
+ string += String.fromCharCode(c);
+ i++;
+ }
+ else if((c > 191) && (c < 224)) {
+ c2 = utftext.charCodeAt(i+1);
+ string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
+ i += 2;
+ }
+ else {
+ c2 = utftext.charCodeAt(i+1);
+ var c3 = utftext.charCodeAt(i+2);
+ string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
+ i += 3;
+ }
+
+ }
+
+ return string;
+ };
+
+//NOT WORKING
+/*
+DataUtils.getUTF8StringFromBytes = function(bytes) {
+
+ bytes = toString(bytes);
+
+ var ix = 0;
+
+ if( bytes.slice(0,3) == "\xEF\xBB\xBF") {
+ ix = 3;
+ }
+
+ var string = "";
+ for( ; ix < bytes.length; ix++ ) {
+ var byte1 = bytes[ix].charCodeAt(0);
+ if( byte1 < 0x80 ) {
+ string += String.fromCharCode(byte1);
+ } else if( byte1 >= 0xC2 && byte1 < 0xE0 ) {
+ var byte2 = bytes[++ix].charCodeAt(0);
+ string += String.fromCharCode(((byte1&0x1F)<<6) + (byte2&0x3F));
+ } else if( byte1 >= 0xE0 && byte1 < 0xF0 ) {
+ var byte2 = bytes[++ix].charCodeAt(0);
+ var byte3 = bytes[++ix].charCodeAt(0);
+ string += String.fromCharCode(((byte1&0xFF)<<12) + ((byte2&0x3F)<<6) + (byte3&0x3F));
+ } else if( byte1 >= 0xF0 && byte1 < 0xF5) {
+ var byte2 = bytes[++ix].charCodeAt(0);
+ var byte3 = bytes[++ix].charCodeAt(0);
+ var byte4 = bytes[++ix].charCodeAt(0);
+ var codepoint = ((byte1&0x07)<<18) + ((byte2&0x3F)<<12)+ ((byte3&0x3F)<<6) + (byte4&0x3F);
+ codepoint -= 0x10000;
+ string += String.fromCharCode(
+ (codepoint>>10) + 0xD800,
+ (codepoint&0x3FF) + 0xDC00
+ );
+ }
+ }
+
+ return string;
+}*/
+
+/**
+ * Return true if a1 and a2 are the same length with equal elements.
+ */
+DataUtils.arraysEqual = function(a1, a2){
+ if (a1.length != a2.length)
+ return false;
+
+ for (var i = 0; i < a1.length; ++i) {
+ if (a1[i] != a2[i])
+ return false;
+ }
+
+ return true;
+};
+
+/*
+ * Convert the big endian Uint8Array to an unsigned int.
+ * Don't check for overflow.
+ */
+DataUtils.bigEndianToUnsignedInt = function(bytes) {
+ var result = 0;
+ for (var i = 0; i < bytes.length; ++i) {
+ result <<= 8;
+ result += bytes[i];
+ }
+ return result;
+};
+
+/*
+ * Convert the int value to a new big endian Uint8Array and return.
+ * If value is 0 or negative, return Uint8Array(0).
+ */
+DataUtils.nonNegativeIntToBigEndian = function(value) {
+ if (value <= 0)
+ return new Uint8Array(0);
+
+ // Assume value is not over 64 bits.
+ var result = new Uint8Array(8);
+ var i = 0;
+ while (value != 0) {
+ result[i++] = value & 0xff;
+ value >>= 8;
+ }
+ return result.subarray(0, i);
+};
diff --git a/js/DateFormat.js b/js/encoding/DateFormat.js
similarity index 100%
rename from js/DateFormat.js
rename to js/encoding/DateFormat.js
diff --git a/js/encoding/EncodingUtils.js b/js/encoding/EncodingUtils.js
new file mode 100644
index 0000000..3a784cd
--- /dev/null
+++ b/js/encoding/EncodingUtils.js
@@ -0,0 +1,369 @@
+/*
+ * This file contains utilities to help encode and decode NDN objects.
+ * author: ucla-cs
+ * See COPYING for copyright and distribution information.
+ */
+
+function encodeToHexInterest(interest){
+ var enc = new BinaryXMLEncoder();
+
+ interest.to_ccnb(enc);
+
+ var hex = DataUtils.toHex(enc.getReducedOstream());
+
+ return hex;
+
+}
+
+
+function encodeToBinaryInterest(interest){
+ var enc = new BinaryXMLEncoder();
+
+ interest.to_ccnb(enc);
+
+ var hex = enc.getReducedOstream();
+
+ return hex;
+}
+
+
+function encodeToHexContentObject(co){
+ var enc = new BinaryXMLEncoder();
+
+ co.to_ccnb(enc);
+
+ var hex = DataUtils.toHex(enc.getReducedOstream());
+
+ return hex;
+
+
+}
+
+function encodeToBinaryContentObject(co){
+ var enc = new BinaryXMLEncoder();
+
+ co.to_ccnb(enc);
+
+ var hex = enc.getReducedOstream();
+
+ return hex;
+}
+
+function encodeForwardingEntry(co){
+ var enc = new BinaryXMLEncoder();
+
+ co.to_ccnb(enc);
+
+ var bytes = enc.getReducedOstream();
+
+ return bytes;
+
+
+}
+
+
+
+function decodeHexFaceInstance(result){
+
+ var numbers = DataUtils.toNumbers(result);
+
+
+ decoder = new BinaryXMLDecoder(numbers);
+
+ if(LOG>3)console.log('DECODING HEX FACE INSTANCE \n'+numbers);
+
+ var faceInstance = new FaceInstance();
+
+ faceInstance.from_ccnb(decoder);
+
+ return faceInstance;
+
+}
+
+
+
+function decodeHexInterest(result){
+ var numbers = DataUtils.toNumbers(result);
+
+ decoder = new BinaryXMLDecoder(numbers);
+
+ if(LOG>3)console.log('DECODING HEX INTERST \n'+numbers);
+
+ var interest = new Interest();
+
+ interest.from_ccnb(decoder);
+
+ return interest;
+
+}
+
+
+
+function decodeHexContentObject(result){
+ var numbers = DataUtils.toNumbers(result);
+
+ decoder = new BinaryXMLDecoder(numbers);
+
+ if(LOG>3)console.log('DECODED HEX CONTENT OBJECT \n'+numbers);
+
+ co = new ContentObject();
+
+ co.from_ccnb(decoder);
+
+ return co;
+
+}
+
+
+
+function decodeHexForwardingEntry(result){
+ var numbers = DataUtils.toNumbers(result);
+
+ decoder = new BinaryXMLDecoder(numbers);
+
+ if(LOG>3)console.log('DECODED HEX FORWARDING ENTRY \n'+numbers);
+
+ forwardingEntry = new ForwardingEntry();
+
+ forwardingEntry.from_ccnb(decoder);
+
+ return forwardingEntry;
+
+}
+
+/* Return a user friendly HTML string with the contents of co.
+ This also outputs to console.log.
+ */
+function contentObjectToHtml(/* ContentObject */ co) {
+ var output ="";
+
+ if(co==-1)
+ output+= "NO CONTENT FOUND"
+ else if (co==-2)
+ output+= "CONTENT NAME IS EMPTY"
+ else{
+ if(co.name!=null && co.name.components!=null){
+ output+= "NAME: ";
+
+ for(var i=0;i<co.name.components.length;i++){
+ output+= "/"+ escape(DataUtils.toString(co.name.components[i]));
+ }
+ output+= "<br />";
+ output+= "<br />";
+ }
+
+ if(co.content !=null){
+ output += "CONTENT(ASCII): "+ DataUtils.toString(co.content);
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+ if(co.content !=null){
+ output += "CONTENT(hex): "+ DataUtils.toHex(co.content);
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+ if(co.signature !=null && co.signature.signature!=null){
+ output += "SIGNATURE(hex): "+ DataUtils.toHex(co.signature.signature);
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+ if(co.signedInfo !=null && co.signedInfo.publisher!=null && co.signedInfo.publisher.publisherPublicKeyDigest!=null){
+ output += "Publisher Public Key Digest(hex): "+ DataUtils.toHex(co.signedInfo.publisher.publisherPublicKeyDigest);
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+ if(co.signedInfo !=null && co.signedInfo.timestamp!=null){
+ var d = new Date();
+ d.setTime( co.signedInfo.timestamp.msec );
+
+ var bytes = [217, 185, 12, 225, 217, 185, 12, 225];
+
+ output += "TimeStamp: "+d;
+ output+= "<br />";
+ output += "TimeStamp(number): "+ co.signedInfo.timestamp.msec;
+
+ output+= "<br />";
+ }
+ if(co.signedInfo !=null && co.signedInfo.finalBlockID!=null){
+ output += "FinalBlockID: "+ DataUtils.toHex(co.signedInfo.finalBlockID);
+ output+= "<br />";
+ }
+ if(co.signedInfo!=null && co.signedInfo.locator!=null && co.signedInfo.locator.certificate!=null){
+ var tmp = DataUtils.toString(co.signedInfo.locator.certificate);
+ var publickey = rstr2b64(tmp);
+ var publickeyHex = DataUtils.toHex(co.signedInfo.locator.certificate).toLowerCase();
+ var publickeyString = DataUtils.toString(co.signedInfo.locator.certificate);
+ var signature = DataUtils.toHex(co.signature.signature).toLowerCase();
+ var input = DataUtils.toString(co.rawSignatureData);
+
+ output += "DER Certificate: "+publickey ;
+
+ output+= "<br />";
+ output+= "<br />";
+
+ if(LOG>2) console.log(" ContentName + SignedInfo + Content = "+input);
+
+ if(LOG>2) console.log("HEX OF ContentName + SignedInfo + Content = ");
+ if(LOG>2) console.log(DataUtils.stringtoBase64(input));
+
+ if(LOG>2) console.log(" PublicKey = "+publickey );
+ if(LOG>2) console.log(" PublicKeyHex = "+publickeyHex );
+ if(LOG>2) console.log(" PublicKeyString = "+publickeyString );
+
+ if(LOG>2) console.log(" Signature is");
+ if(LOG>2) console.log( signature );
+ //if(LOG>2) console.log(" Signature NOW IS" );
+ //if(LOG>2) console.log(co.signature.signature);
+
+ var x509 = new X509();
+ x509.readCertPEM(publickey);
+
+ //x509.readCertPEMWithoutRSAInit(publickey);
+
+ var result = x509.subjectPublicKeyRSA.verifyByteArray(co.rawSignatureData, signature);
+ if(LOG>2) console.log('result is '+result);
+
+ var n = x509.subjectPublicKeyRSA.n;
+ var e = x509.subjectPublicKeyRSA.e;
+
+ if(LOG>2) console.log('PUBLIC KEY n after is ');
+ if(LOG>2) console.log(n);
+
+ if(LOG>2) console.log('EXPONENT e after is ');
+ if(LOG>2) console.log(e);
+
+ /*var rsakey = new RSAKey();
+
+ var kp = publickeyHex.slice(56,314);
+
+ output += "PUBLISHER KEY(hex): "+kp ;
+
+ output+= "<br />";
+ output+= "<br />";
+
+ console.log('kp is '+kp);
+
+ var exp = publickeyHex.slice(318,324);
+
+ console.log('kp size is '+kp.length );
+ output += "exponent: "+exp ;
+
+ output+= "<br />";
+ output+= "<br />";
+
+ console.log('exp is '+exp);
+
+ rsakey.setPublic(kp,exp);
+
+ var result = rsakey.verifyString(input, signature);*/
+
+ if(result)
+ output += 'SIGNATURE VALID';
+ else
+ output += 'SIGNATURE INVALID';
+
+ //output += "VALID: "+ toHex(co.signedInfo.locator.publicKey);
+
+ output+= "<br />";
+ output+= "<br />";
+
+ //if(LOG>4) console.log('str'[1]);
+ }
+ if(co.signedInfo!=null && co.signedInfo.locator!=null && co.signedInfo.locator.publicKey!=null){
+ var publickey = rstr2b64(DataUtils.toString(co.signedInfo.locator.publicKey));
+ var publickeyHex = DataUtils.toHex(co.signedInfo.locator.publicKey).toLowerCase();
+ var publickeyString = DataUtils.toString(co.signedInfo.locator.publicKey);
+ var signature = DataUtils.toHex(co.signature.signature).toLowerCase();
+ var input = DataUtils.toString(co.rawSignatureData);
+
+ output += "DER Certificate: "+publickey ;
+
+ output+= "<br />";
+ output+= "<br />";
+
+ if(LOG>2) console.log(" ContentName + SignedInfo + Content = "+input);
+ if(LOG>2) console.log(" PublicKey = "+publickey );
+ if(LOG>2) console.log(" PublicKeyHex = "+publickeyHex );
+ if(LOG>2) console.log(" PublicKeyString = "+publickeyString );
+
+ if(LOG>2) console.log(" Signature "+signature );
+
+ if(LOG>2) console.log(" Signature NOW IS" );
+
+ if(LOG>2) console.log(co.signature.signature);
+
+ /*var x509 = new X509();
+
+ x509.readCertPEM(publickey);
+
+
+ //x509.readCertPEMWithoutRSAInit(publickey);
+
+ var result = x509.subjectPublicKeyRSA.verifyString(input, signature);*/
+ //console.log('result is '+result);
+
+ var kp = publickeyHex.slice(56,314);
+
+ output += "PUBLISHER KEY(hex): "+kp ;
+
+ output+= "<br />";
+ output+= "<br />";
+
+ console.log('PUBLIC KEY IN HEX is ');
+ console.log(kp);
+
+ var exp = publickeyHex.slice(318,324);
+
+ console.log('kp size is '+kp.length );
+ output += "exponent: "+exp ;
+
+ output+= "<br />";
+ output+= "<br />";
+
+ console.log('EXPONENT is ');
+ console.log(exp);
+
+ /*var c1 = hex_sha256(input);
+ var c2 = signature;
+
+ if(LOG>4)console.log('input is ');
+ if(LOG>4)console.log(input);
+ if(LOG>4)console.log('C1 is ');
+ if(LOG>4)console.log(c1);
+ if(LOG>4)console.log('C2 is ');
+ if(LOG>4)console.log(c2);
+ var result = c1 == c2;*/
+
+ var rsakey = new RSAKey();
+
+ rsakey.setPublic(kp,exp);
+
+ var result = rsakey.verifyByteArray(co.rawSignatureData,signature);
+ // var result = rsakey.verifyString(input, signature);
+
+ console.log('PUBLIC KEY n after is ');
+ console.log(rsakey.n);
+
+ console.log('EXPONENT e after is ');
+ console.log(rsakey.e);
+
+ if(result)
+ output += 'SIGNATURE VALID';
+ else
+ output += 'SIGNATURE INVALID';
+
+ //output += "VALID: "+ toHex(co.signedInfo.locator.publicKey);
+
+ output+= "<br />";
+ output+= "<br />";
+
+ //if(LOG>4) console.log('str'[1]);
+ }
+ }
+
+ return output;
+}
diff --git a/js/encoding/MimeTypes.js b/js/encoding/MimeTypes.js
new file mode 100644
index 0000000..b5459ed
--- /dev/null
+++ b/js/encoding/MimeTypes.js
@@ -0,0 +1,542 @@
+var MimeTypes = {
+ /*
+ * Based on filename, return an object with properties contentType and charset.
+ */
+ getContentTypeAndCharset: function(filename) {
+ var iDot = filename.lastIndexOf('.');
+ if (iDot >= 0) {
+ var extension = filename.substr(iDot + 1, filename.length - iDot - 1);
+ var contentType = MimeTypes[extension];
+ if (contentType != null) {
+ var charset = "ISO-8859-1";
+ if (contentType.split('/')[0] == "text")
+ charset = "utf-8";
+ return { contentType: contentType, charset: charset };
+ }
+ }
+
+ // Use a default.
+ return { contentType: "text/html", charset: "utf-8" };
+ },
+
+ /* For each file extension, define the MIME type.
+ */
+ "323": "text/h323",
+ "%": "application/x-trash",
+ "~": "application/x-trash",
+ "3gp": "video/3gpp",
+ "7z": "application/x-7z-compressed",
+ "abw": "application/x-abiword",
+ "ai": "application/postscript",
+ "aif": "audio/x-aiff",
+ "aifc": "audio/x-aiff",
+ "aiff": "audio/x-aiff",
+ "alc": "chemical/x-alchemy",
+ "amr": "audio/amr",
+ "anx": "application/annodex",
+ "apk": "application/vnd.android.package-archive",
+ "art": "image/x-jg",
+ "asc": "text/plain",
+ "asf": "video/x-ms-asf",
+ "asx": "video/x-ms-asf",
+ "asn": "chemical/x-ncbi-asn1",
+ "atom": "application/atom+xml",
+ "atomcat": "application/atomcat+xml",
+ "atomsrv": "application/atomserv+xml",
+ "au": "audio/basic",
+ "snd": "audio/basic",
+ "avi": "video/x-msvideo",
+ "awb": "audio/amr-wb",
+ "axa": "audio/annodex",
+ "axv": "video/annodex",
+ "b": "chemical/x-molconn-Z",
+ "bak": "application/x-trash",
+ "bat": "application/x-msdos-program",
+ "bcpio": "application/x-bcpio",
+ "bib": "text/x-bibtex",
+ "bin": "application/octet-stream",
+ "bmp": "image/x-ms-bmp",
+ "boo": "text/x-boo",
+ "book": "application/x-maker",
+ "brf": "text/plain",
+ "bsd": "chemical/x-crossfire",
+ "c": "text/x-csrc",
+ "c++": "text/x-c++src",
+ "c3d": "chemical/x-chem3d",
+ "cab": "application/x-cab",
+ "cac": "chemical/x-cache",
+ "cache": "chemical/x-cache",
+ "cap": "application/cap",
+ "cascii": "chemical/x-cactvs-binary",
+ "cat": "application/vnd.ms-pki.seccat",
+ "cbin": "chemical/x-cactvs-binary",
+ "cbr": "application/x-cbr",
+ "cbz": "application/x-cbz",
+ "cc": "text/x-c++src",
+ "cda": "application/x-cdf",
+ "cdf": "application/x-cdf",
+ "cdr": "image/x-coreldraw",
+ "cdt": "image/x-coreldrawtemplate",
+ "cdx": "chemical/x-cdx",
+ "cdy": "application/vnd.cinderella",
+ "cer": "chemical/x-cerius",
+ "chm": "chemical/x-chemdraw",
+ "chrt": "application/x-kchart",
+ "cif": "chemical/x-cif",
+ "class": "application/java-vm",
+ "cls": "text/x-tex",
+ "cmdf": "chemical/x-cmdf",
+ "cml": "chemical/x-cml",
+ "cod": "application/vnd.rim.cod",
+ "com": "application/x-msdos-program",
+ "cpa": "chemical/x-compass",
+ "cpio": "application/x-cpio",
+ "cpp": "text/x-c++src",
+ "cpt": "image/x-corelphotopaint",
+ "cr2": "image/x-canon-cr2",
+ "crl": "application/x-pkcs7-crl",
+ "crt": "application/x-x509-ca-cert",
+ "crw": "image/x-canon-crw",
+ "csd": "audio/csound",
+ "csf": "chemical/x-cache-csf",
+ "csh": "application/x-csh",
+ "csml": "chemical/x-csml",
+ "csm": "chemical/x-csml",
+ "css": "text/css",
+ "csv": "text/csv",
+ "ctab": "chemical/x-cactvs-binary",
+ "ctx": "chemical/x-ctx",
+ "cu": "application/cu-seeme",
+ "cub": "chemical/x-gaussian-cube",
+ "cxf": "chemical/x-cxf",
+ "cef": "chemical/x-cxf",
+ "cxx": "text/x-c++src",
+ "d": "text/x-dsrc",
+ "dat": "application/x-ns-proxy-autoconfig",
+ "davmount": "application/davmount+xml",
+ "dcr": "application/x-director",
+ "deb": "application/x-debian-package",
+ "dif": "video/dv",
+ "dv": "video/dv",
+ "diff": "text/x-diff",
+ "patch": "text/x-diff",
+ "dir": "application/x-director",
+ "djvu": "image/vnd.djvu",
+ "djv": "image/vnd.djvu",
+ "dl": "video/dl",
+ "dll": "application/x-msdos-program",
+ "dmg": "application/x-apple-diskimage",
+ "dms": "application/x-dms",
+ "doc": "application/msword",
+ "docm": "application/vnd.ms-word.document.macroEnabled.12",
+ "docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
+ "dot": "application/msword",
+ "dotm": "application/vnd.ms-word.template.macroEnabled.12",
+ "dotx": "application/vnd.openxmlformats-officedocument.wordprocessingml.template",
+ "dvi": "application/x-dvi",
+ "dxr": "application/x-director",
+ "emb": "chemical/x-embl-dl-nucleotide",
+ "embl": "chemical/x-embl-dl-nucleotide",
+ "eml": "message/rfc822",
+ "eps": "application/postscript",
+ "eps2": "application/postscript",
+ "eps3": "application/postscript",
+ "epsf": "application/postscript",
+ "epsi": "application/postscript",
+ "erf": "image/x-epson-erf",
+ "es": "application/ecmascript",
+ "etx": "text/x-setext",
+ "exe": "application/x-msdos-program",
+ "ez": "application/andrew-inset",
+ "fb": "application/x-maker",
+ "fbdoc": "application/x-maker",
+ "fch": "chemical/x-gaussian-checkpoint",
+ "fchk": "chemical/x-gaussian-checkpoint",
+ "fig": "application/x-xfig",
+ "flac": "audio/flac",
+ "fli": "video/fli",
+ "flv": "video/x-flv",
+ "fm": "application/x-maker",
+ "frame": "application/x-maker",
+ "frm": "application/x-maker",
+ "gal": "chemical/x-gaussian-log",
+ "gam": "chemical/x-gamess-input",
+ "gamin": "chemical/x-gamess-input",
+ "gan": "application/x-ganttproject",
+ "gau": "chemical/x-gaussian-input",
+ "gcd": "text/x-pcs-gcd",
+ "gcf": "application/x-graphing-calculator",
+ "gcg": "chemical/x-gcg8-sequence",
+ "gen": "chemical/x-genbank",
+ "gf": "application/x-tex-gf",
+ "gif": "image/gif",
+ "gjc": "chemical/x-gaussian-input",
+ "gjf": "chemical/x-gaussian-input",
+ "gl": "video/gl",
+ "gnumeric": "application/x-gnumeric",
+ "gpt": "chemical/x-mopac-graph",
+ "gsf": "application/x-font",
+ "gsm": "audio/x-gsm",
+ "gtar": "application/x-gtar",
+ "h": "text/x-chdr",
+ "h++": "text/x-c++hdr",
+ "hdf": "application/x-hdf",
+ "hh": "text/x-c++hdr",
+ "hin": "chemical/x-hin",
+ "hpp": "text/x-c++hdr",
+ "hqx": "application/mac-binhex40",
+ "hs": "text/x-haskell",
+ "hta": "application/hta",
+ "htc": "text/x-component",
+ "htm": "text/html",
+ "html": "text/html",
+ "hxx": "text/x-c++hdr",
+ "ica": "application/x-ica",
+ "ice": "x-conference/x-cooltalk",
+ "ico": "image/x-icon",
+ "ics": "text/calendar",
+ "icz": "text/calendar",
+ "ief": "image/ief",
+ "igs": "model/iges",
+ "iges": "model/iges",
+ "iii": "application/x-iphone",
+ "info": "application/x-info",
+ "inp": "chemical/x-gamess-input",
+ "ins": "application/x-internet-signup",
+ "iso": "application/x-iso9660-image",
+ "isp": "application/x-internet-signup",
+ "istr": "chemical/x-isostar",
+ "ist": "chemical/x-isostar",
+ "jad": "text/vnd.sun.j2me.app-descriptor",
+ "jam": "application/x-jam",
+ "jar": "application/java-archive",
+ "java": "text/x-java",
+ "jdx": "chemical/x-jcamp-dx",
+ "dx": "chemical/x-jcamp-dx",
+ "jmz": "application/x-jmol",
+ "jng": "image/x-jng",
+ "jnlp": "application/x-java-jnlp-file",
+ "jpe": "image/jpeg",
+ "jpeg": "image/jpeg",
+ "jpg": "image/jpeg",
+ "js": "application/javascript",
+ "json": "application/json",
+ "kar": "audio/midi",
+ "key": "application/pgp-keys",
+ "kil": "application/x-killustrator",
+ "kin": "chemical/x-kinemage",
+ "kml": "application/vnd.google-earth.kml+xml",
+ "kmz": "application/vnd.google-earth.kmz",
+ "kpr": "application/x-kpresenter",
+ "kpt": "application/x-kpresenter",
+ "ksp": "application/x-kspread",
+ "kwd": "application/x-kword",
+ "kwt": "application/x-kword",
+ "latex": "application/x-latex",
+ "lha": "application/x-lha",
+ "lhs": "text/x-literate-haskell",
+ "lin": "application/bbolin",
+ "lsf": "video/x-la-asf",
+ "lsx": "video/x-la-asf",
+ "ltx": "text/x-tex",
+ "lyx": "application/x-lyx",
+ "lzh": "application/x-lzh",
+ "lzx": "application/x-lzx",
+ "m3g": "application/m3g",
+ "m3u": "audio/mpegurl",
+ "m3u8": "application/x-mpegURL",
+ "m4a": "audio/mpeg",
+ "maker": "application/x-maker",
+ "man": "application/x-troff-man",
+ "manifest": "text/cache-manifest",
+ "mcif": "chemical/x-mmcif",
+ "mcm": "chemical/x-macmolecule",
+ "mdb": "application/msaccess",
+ "me": "application/x-troff-me",
+ "mesh": "model/mesh",
+ "mid": "audio/midi",
+ "midi": "audio/midi",
+ "mif": "application/x-mif",
+ "mm": "application/x-freemind",
+ "mmd": "chemical/x-macromodel-input",
+ "mmod": "chemical/x-macromodel-input",
+ "mmf": "application/vnd.smaf",
+ "mml": "text/mathml",
+ "mng": "video/x-mng",
+ "moc": "text/x-moc",
+ "mol": "chemical/x-mdl-molfile",
+ "mol2": "chemical/x-mol2",
+ "moo": "chemical/x-mopac-out",
+ "mop": "chemical/x-mopac-input",
+ "mopcrt": "chemical/x-mopac-input",
+ "movie": "video/x-sgi-movie",
+ "mp2": "audio/mpeg",
+ "mp3": "audio/mpeg",
+ "mp4": "video/mp4",
+ "mpc": "chemical/x-mopac-input",
+ "mpe": "video/mpeg",
+ "mpeg": "video/mpeg",
+ "mpega": "audio/mpeg",
+ "mpg": "video/mpeg",
+ "mpga": "audio/mpeg",
+ "mph": "application/x-comsol",
+ "mpv": "video/x-matroska",
+ "mkv": "video/x-matroska",
+ "ms": "application/x-troff-ms",
+ "msh": "model/mesh",
+ "msi": "application/x-msi",
+ "mvb": "chemical/x-mopac-vib",
+ "mxf": "application/mxf",
+ "mxu": "video/vnd.mpegurl",
+ "nb": "application/mathematica",
+ "nbp": "application/mathematica",
+ "nc": "application/x-netcdf",
+ "nef": "image/x-nikon-nef",
+ "nwc": "application/x-nwc",
+ "o": "application/x-object",
+ "oda": "application/oda",
+ "odb": "application/vnd.oasis.opendocument.database",
+ "odc": "application/vnd.oasis.opendocument.chart",
+ "odf": "application/vnd.oasis.opendocument.formula",
+ "odg": "application/vnd.oasis.opendocument.graphics",
+ "odi": "application/vnd.oasis.opendocument.image",
+ "odm": "application/vnd.oasis.opendocument.text-master",
+ "odp": "application/vnd.oasis.opendocument.presentation",
+ "ods": "application/vnd.oasis.opendocument.spreadsheet",
+ "odt": "application/vnd.oasis.opendocument.text",
+ "oga": "audio/ogg",
+ "ogg": "audio/ogg",
+ "ogv": "video/ogg",
+ "ogx": "application/ogg",
+ "old": "application/x-trash",
+ "one": "application/onenote",
+ "onepkg": "application/onenote",
+ "onetmp": "application/onenote",
+ "onetoc2": "application/onenote",
+ "orc": "audio/csound",
+ "orf": "image/x-olympus-orf",
+ "otg": "application/vnd.oasis.opendocument.graphics-template",
+ "oth": "application/vnd.oasis.opendocument.text-web",
+ "otp": "application/vnd.oasis.opendocument.presentation-template",
+ "ots": "application/vnd.oasis.opendocument.spreadsheet-template",
+ "ott": "application/vnd.oasis.opendocument.text-template",
+ "oza": "application/x-oz-application",
+ "p": "text/x-pascal",
+ "pas": "text/x-pascal",
+ "p7r": "application/x-pkcs7-certreqresp",
+ "pac": "application/x-ns-proxy-autoconfig",
+ "pat": "image/x-coreldrawpattern",
+ "pbm": "image/x-portable-bitmap",
+ "pcap": "application/cap",
+ "pcf": "application/x-font",
+ "pcx": "image/pcx",
+ "pdb": "chemical/x-pdb",
+ "ent": "chemical/x-pdb",
+ "pdf": "application/pdf",
+ "pfa": "application/x-font",
+ "pfb": "application/x-font",
+ "pgm": "image/x-portable-graymap",
+ "pgn": "application/x-chess-pgn",
+ "pgp": "application/pgp-signature",
+ "php": "application/x-httpd-php",
+ "php3": "application/x-httpd-php3",
+ "php3p": "application/x-httpd-php3-preprocessed",
+ "php4": "application/x-httpd-php4",
+ "php5": "application/x-httpd-php5",
+ "phps": "application/x-httpd-php-source",
+ "pht": "application/x-httpd-php",
+ "phtml": "application/x-httpd-php",
+ "pk": "application/x-tex-pk",
+ "pl": "text/x-perl",
+ "pm": "text/x-perl",
+ "pls": "audio/x-scpls",
+ "png": "image/png",
+ "pnm": "image/x-portable-anymap",
+ "pot": "text/plain",
+ "potm": "application/vnd.ms-powerpoint.template.macroEnabled.12",
+ "potx": "application/vnd.openxmlformats-officedocument.presentationml.template",
+ "ppam": "application/vnd.ms-powerpoint.addin.macroEnabled.12",
+ "ppm": "image/x-portable-pixmap",
+ "pps": "application/vnd.ms-powerpoint",
+ "ppsm": "application/vnd.ms-powerpoint.slideshow.macroEnabled.12",
+ "ppsx": "application/vnd.openxmlformats-officedocument.presentationml.slideshow",
+ "ppt": "application/vnd.ms-powerpoint",
+ "pptm": "application/vnd.ms-powerpoint.presentation.macroEnabled.12",
+ "pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
+ "prf": "application/pics-rules",
+ "prt": "chemical/x-ncbi-asn1-ascii",
+ "ps": "application/postscript",
+ "psd": "image/x-photoshop",
+ "py": "text/x-python",
+ "pyc": "application/x-python-code",
+ "pyo": "application/x-python-code",
+ "qgs": "application/x-qgis",
+ "qt": "video/quicktime",
+ "mov": "video/quicktime",
+ "qtl": "application/x-quicktimeplayer",
+ "ra": "audio/x-realaudio",
+ "ram": "audio/x-pn-realaudio",
+ "rar": "application/rar",
+ "ras": "image/x-cmu-raster",
+ "rb": "application/x-ruby",
+ "rd": "chemical/x-mdl-rdfile",
+ "rdf": "application/rdf+xml",
+ "rdp": "application/x-rdp",
+ "rgb": "image/x-rgb",
+ "rhtml": "application/x-httpd-eruby",
+ "rm": "audio/x-pn-realaudio",
+ "roff": "application/x-troff",
+ "ros": "chemical/x-rosdal",
+ "rpm": "application/x-redhat-package-manager",
+ "rss": "application/rss+xml",
+ "rtf": "application/rtf",
+ "rtx": "text/richtext",
+ "rxn": "chemical/x-mdl-rxnfile",
+ "scala": "text/x-scala",
+ "sci": "application/x-scilab",
+ "sce": "application/x-scilab",
+ "sco": "audio/csound",
+ "scr": "application/x-silverlight",
+ "sct": "text/scriptlet",
+ "wsc": "text/scriptlet",
+ "sd": "chemical/x-mdl-sdfile",
+ "sdf": "chemical/x-mdl-sdfile",
+ "sd2": "audio/x-sd2",
+ "sda": "application/vnd.stardivision.draw",
+ "sdc": "application/vnd.stardivision.calc",
+ "sdd": "application/vnd.stardivision.impress",
+ "sds": "application/vnd.stardivision.chart",
+ "sdw": "application/vnd.stardivision.writer",
+ "ser": "application/java-serialized-object",
+ "sfv": "text/x-sfv",
+ "sgf": "application/x-go-sgf",
+ "sgl": "application/vnd.stardivision.writer-global",
+ "sh": "application/x-sh",
+ "shar": "application/x-shar",
+ "shp": "application/x-qgis",
+ "shtml": "text/html",
+ "shx": "application/x-qgis",
+ "sid": "audio/prs.sid",
+ "sik": "application/x-trash",
+ "silo": "model/mesh",
+ "sis": "application/vnd.symbian.install",
+ "sisx": "x-epoc/x-sisx-app",
+ "sit": "application/x-stuffit",
+ "sitx": "application/x-stuffit",
+ "skd": "application/x-koan",
+ "skm": "application/x-koan",
+ "skp": "application/x-koan",
+ "skt": "application/x-koan",
+ "sldm": "application/vnd.ms-powerpoint.slide.macroEnabled.12",
+ "sldx": "application/vnd.openxmlformats-officedocument.presentationml.slide",
+ "smi": "application/smil",
+ "smil": "application/smil",
+ "spc": "chemical/x-galactic-spc",
+ "spl": "application/futuresplash",
+ "spx": "audio/ogg",
+ "sql": "application/x-sql",
+ "src": "application/x-wais-source",
+ "stc": "application/vnd.sun.xml.calc.template",
+ "std": "application/vnd.sun.xml.draw.template",
+ "sti": "application/vnd.sun.xml.impress.template",
+ "stl": "application/sla",
+ "stw": "application/vnd.sun.xml.writer.template",
+ "sty": "text/x-tex",
+ "sv4cpio": "application/x-sv4cpio",
+ "sv4crc": "application/x-sv4crc",
+ "svg": "image/svg+xml",
+ "svgz": "image/svg+xml",
+ "sw": "chemical/x-swissprot",
+ "swf": "application/x-shockwave-flash",
+ "swfl": "application/x-shockwave-flash",
+ "sxc": "application/vnd.sun.xml.calc",
+ "sxd": "application/vnd.sun.xml.draw",
+ "sxg": "application/vnd.sun.xml.writer.global",
+ "sxi": "application/vnd.sun.xml.impress",
+ "sxm": "application/vnd.sun.xml.math",
+ "sxw": "application/vnd.sun.xml.writer",
+ "t": "application/x-troff",
+ "tar": "application/x-tar",
+ "taz": "application/x-gtar-compressed",
+ "tcl": "application/x-tcl",
+ "tk": "text/x-tcl",
+ "tex": "text/x-tex",
+ "texinfo": "application/x-texinfo",
+ "texi": "application/x-texinfo",
+ "text": "text/plain",
+ "tgf": "chemical/x-mdl-tgf",
+ "tgz": "application/x-gtar-compressed",
+ "thmx": "application/vnd.ms-officetheme",
+ "tiff": "image/tiff",
+ "tif": "image/tiff",
+ "tm": "text/texmacs",
+ "torrent": "application/x-bittorrent",
+ "tr": "application/x-troff",
+ "ts": "video/MP2T",
+ "tsp": "application/dsptype",
+ "tsv": "text/tab-separated-values",
+ "txt": "text/plain",
+ "udeb": "application/x-debian-package",
+ "uls": "text/iuls",
+ "ustar": "application/x-ustar",
+ "val": "chemical/x-ncbi-asn1-binary",
+ "aso": "chemical/x-ncbi-asn1-binary",
+ "vcd": "application/x-cdlink",
+ "vcf": "text/x-vcard",
+ "vcs": "text/x-vcalendar",
+ "vmd": "chemical/x-vmd",
+ "vms": "chemical/x-vamas-iso14976",
+ "vrm": "x-world/x-vrml",
+ "vsd": "application/vnd.visio",
+ "wad": "application/x-doom",
+ "wav": "audio/x-wav",
+ "wax": "audio/x-ms-wax",
+ "wbmp": "image/vnd.wap.wbmp",
+ "wbxml": "application/vnd.wap.wbxml",
+ "webm": "video/webm",
+ "wk": "application/x-123",
+ "wm": "video/x-ms-wm",
+ "wma": "audio/x-ms-wma",
+ "wmd": "application/x-ms-wmd",
+ "wml": "text/vnd.wap.wml",
+ "wmlc": "application/vnd.wap.wmlc",
+ "wmls": "text/vnd.wap.wmlscript",
+ "wmlsc": "application/vnd.wap.wmlscriptc",
+ "wmv": "video/x-ms-wmv",
+ "wmx": "video/x-ms-wmx",
+ "wmz": "application/x-ms-wmz",
+ "wp5": "application/vnd.wordperfect5.1",
+ "wpd": "application/vnd.wordperfect",
+ "wrl": "model/vrml",
+ "vrml": "model/vrml",
+ "wvx": "video/x-ms-wvx",
+ "wz": "application/x-wingz",
+ "x3d": "model/x3d+xml",
+ "x3db": "model/x3d+binary",
+ "x3dv": "model/x3d+vrml",
+ "xbm": "image/x-xbitmap",
+ "xcf": "application/x-xcf",
+ "xht": "application/xhtml+xml",
+ "xhtml": "application/xhtml+xml",
+ "xlam": "application/vnd.ms-excel.addin.macroEnabled.12",
+ "xlb": "application/vnd.ms-excel",
+ "xls": "application/vnd.ms-excel",
+ "xlsb": "application/vnd.ms-excel.sheet.binary.macroEnabled.12",
+ "xlsm": "application/vnd.ms-excel.sheet.macroEnabled.12",
+ "xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+ "xlt": "application/vnd.ms-excel",
+ "xltm": "application/vnd.ms-excel.template.macroEnabled.12",
+ "xltx": "application/vnd.openxmlformats-officedocument.spreadsheetml.template",
+ "xml": "application/xml",
+ "xpi": "application/x-xpinstall",
+ "xpm": "image/x-xpixmap",
+ "xsd": "application/xml",
+ "xsl": "application/xml",
+ "xspf": "application/xspf+xml",
+ "xtel": "chemical/x-xtel",
+ "xul": "application/vnd.mozilla.xul+xml",
+ "xwd": "image/x-xwindowdump",
+ "xyz": "chemical/x-xyz",
+ "zip": "application/zip",
+ "zmt": "chemical/x-mopac-input"
+};
diff --git a/js/encoding/TextXMLCodec.js b/js/encoding/TextXMLCodec.js
index 716aa6d..b8d5662 100644
--- a/js/encoding/TextXMLCodec.js
+++ b/js/encoding/TextXMLCodec.js
@@ -1,6 +1,7 @@
//TODO INCOMPLETE
/*
* @author: ucla-cs
+ * See COPYING for copyright and distribution information.
*
* Encodes CCN object into xml tags
*/
@@ -22,38 +23,3 @@
};
-//returns a string
-
-TextXMLCodec.protpotype.codecName = function() { return this.CODEC_NAME; } ;
-
-//returns a string
-TextXMLCodec.protottype.encodeBinaryElement = function(/*byte []*/ element) {
- if ((null == element) || (0 == element.length))
- return new String("");
- return new String(DataUtils.base64Encode(element));
- };
-
-/* returns a string */
-TextXMLCodec.prototype.encodeBinaryElement = function(/*byte []*/ element, /*int*/ offset, /*int*/ length) {
- if ((null == element) || (0 == element.length))
- return new String("");
- ByteBuffer bbuf = ByteBuffer.wrap(element, offset, length);
- return new String(DataUtils.base64Encode(bbuf.array()));
- };
-
-/*returns a byte array*/
-TextXMLCodec.prototype.decodeBinaryElement = function(/*String*/ element) {
- if ((null == element) || (0 == element.length()))
- return new byte[0];
- return DataUtils.base64Decode(element.getBytes());
- };
-
-
-/*
- Decode Data
-*/
-
-
-/*
- Encode Date
-*/
\ No newline at end of file
diff --git a/js/encoding/TextXMLDecoder.js b/js/encoding/TextXMLDecoder.js
index 6af8be3..54bf2d7 100644
--- a/js/encoding/TextXMLDecoder.js
+++ b/js/encoding/TextXMLDecoder.js
@@ -2,6 +2,7 @@
/*
* @author: ucla-cs
+ * See COPYING for copyright and distribution information.
*
* Decodes CCN object into xml
*/
@@ -12,221 +13,3 @@
};
-
-exports.TextXMLDecoder = TextXMLDecoder;
-
-
-exports.prototype.initializeDecoding = function(){
- try {
- XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
- factory.setNamespaceAware(true);
- _reader = factory.newPullParser();
- _reader.setInput(_istream, null);
- } catch (XmlPullParserException e) {
- throw new ContentDecodingException(e.getMessage(), e);
- }
-};
-
-exports.prototype.readStartDocument = function(){
- try {
- int event = _reader.getEventType();
- _reader.next();
- if (event != XmlPullParser.START_DOCUMENT) {
- throw new ContentDecodingException("Expected start document, got: " + XmlPullParser.TYPES[event]);
- }
- } catch (XmlPullParserException e) {
- throw new ContentDecodingException(e.getMessage(), e);
- } catch (IOException e) {
- throw new ContentDecodingException(e.getMessage(), e);
- }
-};
-
-public void readEndDocument() throws ContentDecodingException {
- int event;
- try {
- event = _reader.getEventType();
- } catch (XmlPullParserException e) {
- throw new ContentDecodingException(e.getMessage(), e);
- }
- if (event != XmlPullParser.END_DOCUMENT) {
- throw new ContentDecodingException("Expected end document, got: " + XmlPullParser.TYPES[event]);
- }
-};
-
-exports.prototype.readStartElement = function(/*String*/ startTag,
- TreeMap<String, String> attributes) throws ContentDecodingException {
-
- int event = readToNextTag(XmlPullParser.START_TAG);
- if (event != XmlPullParser.START_TAG) {
- throw new ContentDecodingException("Expected start element, got: " + XmlPullParser.TYPES[event]);
- }
- // Use getLocalPart to strip namespaces.
- // Assumes we are working with a global default namespace of CCN.
- if (!startTag.equals(_reader.getName())) {
- // Coming back with namespace decoration doesn't match
- throw new ContentDecodingException("Expected start element: " + startTag + " got: " + _reader.getName());
- }
- if (null != attributes) {
- // we might be expecting attributes
- for (int i=0; i < _reader.getAttributeCount(); ++i) {
- // may need fancier namespace handling.
- attributes.put(_reader.getAttributeName(i), _reader.getAttributeValue(i));
- }
- }
- try {
- _reader.next();
- } catch (XmlPullParserException e) {
- throw new ContentDecodingException(e.getMessage());
- } catch (IOException e) {
- throw new ContentDecodingException(e.getMessage());
- }
-}
-
- public void readStartElement(long startTagLong,
- TreeMap<String, String> attributes) throws ContentDecodingException {
-
- String startTag = tagToString(startTagLong);
-
- int event = readToNextTag(XmlPullParser.START_TAG);
- if (event != XmlPullParser.START_TAG) {
- throw new ContentDecodingException("Expected start element, got: " + XmlPullParser.TYPES[event]);
- }
- // Use getLocalPart to strip namespaces.
- // Assumes we are working with a global default namespace of CCN.
- if (!startTag.equals(_reader.getName())) {
- // Coming back with namespace decoration doesn't match
- throw new ContentDecodingException("Expected start element: " + startTag + " got: " + _reader.getName());
- }
- if (null != attributes) {
- // we might be expecting attributes
- for (int i=0; i < _reader.getAttributeCount(); ++i) {
- // may need fancier namespace handling.
- attributes.put(_reader.getAttributeName(i), _reader.getAttributeValue(i));
- }
- }
- try {
- _reader.next();
- } catch (XmlPullParserException e) {
- throw new ContentDecodingException(e.getMessage());
- } catch (IOException e) {
- throw new ContentDecodingException(e.getMessage());
- }
- }
- public String peekStartElementAsString() throws ContentDecodingException {
- int event = readToNextTag(XmlPullParser.START_TAG);
- if (event != XmlPullParser.START_TAG) {
- return null;
- }
- return _reader.getName();
- }
-
- public Long peekStartElementAsLong() throws ContentDecodingException {
- String strTag = peekStartElementAsString();
- if (null == strTag) {
- return null; // e.g. hit an end tag...
- }
- return stringToTag(strTag);
- }
-
- /**
- * Helper method to decode text (UTF-8) and binary elements. Consumes the end element,
- * behavior which other decoders are forced to match.
- * @return the read data, as a String
- * @throws ContentDecodingException if there is a problem decoding the data
- */
- public String readUString() throws ContentDecodingException {
- StringBuffer buf = new StringBuffer();
- try {
- int event = _reader.getEventType();;
- // Handles empty text element.
- while (event == XmlPullParser.TEXT) {
- buf.append(_reader.getText());
- event = _reader.next();
- }
- if (event == XmlPullParser.START_TAG) {
- throw new ContentDecodingException("readElementText expects start element to have been previously consumed, got: " + XmlPullParser.TYPES[event]);
- } else if (event != XmlPullParser.END_TAG) {
- throw new ContentDecodingException("Expected end of text element, got: " + XmlPullParser.TYPES[event]);
- }
- readEndElement();
- return buf.toString();
- } catch (XmlPullParserException e) {
- throw new ContentDecodingException(e.getMessage(), e);
- } catch (IOException e) {
- throw new ContentDecodingException(e.getMessage(), e);
- }
- }
-
- public void readEndElement() throws ContentDecodingException {
- int event = readToNextTag(XmlPullParser.END_TAG);
- if (event != XmlPullParser.END_TAG) {
- throw new ContentDecodingException("Expected end element, got: " + XmlPullParser.TYPES[event]);
- }
- try {
- _reader.next();
- } catch (XmlPullParserException e) {
- throw new ContentDecodingException(e.getMessage());
- } catch (IOException e) {
- throw new ContentDecodingException(e.getMessage());
- }
- }
-
- /**
- * Read a BLOB. Consumes the end element, so force other versions
- * to match.
- */
- public byte [] readBlob() throws ContentDecodingException {
- try {
- String strElementText = readUString();
- // readEndElement(); // readElementText consumes end element
- return TextXMLCodec.decodeBinaryElement(strElementText);
- } catch (IOException e) {
- throw new ContentDecodingException(e.getMessage(),e);
- }
- }
-
- public CCNTime readDateTime(String startTag) throws ContentDecodingException {
- String strTimestamp = readUTF8Element(startTag);
- CCNTime timestamp;
- try {
- timestamp = TextXMLCodec.parseDateTime(strTimestamp);
- } catch (ParseException e) {
- timestamp = null;
- }
- if (null == timestamp) {
- throw new ContentDecodingException("Cannot parse timestamp: " + strTimestamp);
- }
- return timestamp;
- }
-
- public CCNTime readDateTime(long startTag) throws ContentDecodingException {
- String strTimestamp = readUTF8Element(startTag);
- CCNTime timestamp;
- try {
- timestamp = TextXMLCodec.parseDateTime(strTimestamp);
- } catch (ParseException e) {
- timestamp = null;
- }
- if (null == timestamp) {
- throw new ContentDecodingException("Cannot parse timestamp: " + strTimestamp);
- }
- return timestamp;
- }
-
- private int readToNextTag(int type) throws ContentDecodingException {
- int event;
- try {
- event = _reader.getEventType();
- if (event == type)
- return event;
- if (event == XmlPullParser.TEXT || event == XmlPullParser.COMMENT)
- event = _reader.next();
- } catch (IOException e) {
- throw new ContentDecodingException(e.getMessage(), e);
- } catch (XmlPullParserException e) {
- throw new ContentDecodingException(e.getMessage(), e);
- }
- return event;
- }
-
-};
diff --git a/js/encoding/TextXMLEncoder.js b/js/encoding/TextXMLEncoder.js
index 495984b..b22aa0c 100644
--- a/js/encoding/TextXMLEncoder.js
+++ b/js/encoding/TextXMLEncoder.js
@@ -1,6 +1,7 @@
//TODO INCOMPLETE
/*
* @author: ucla-cs
+ * See COPYING for copyright and distribution information.
*
* Encodes CCN object into xml
*/
@@ -17,93 +18,4 @@
this.ostream = new String();
};
-exports.TextXMLEncoder = TextXMLEncoder;
-TextXMLEncoder.prototype.beginEncoding = function(/*OutputStream*/ ostream){
- if (null == ostream)
- throw new IllegalArgumentException("TextXMLEncoder: output stream cannot be null!");
-
-
- /*Start by encoing the begining*/
- //this.IStream = ostream;
- this.ostream.write('<?xml version="1.0" encoding="UTF-8"?>');
-};
-
-TextXMLEncoder.prototype.endEncoding =function() {
- this.IStream.end();
-}
-
-
-TextXMLEncoder.prorotype.writeStartElement(/*String*/ tag, /*TreeMap<String, String>*/ attributes) {
-
-
- this.ostream.write('<'+tab);
-
- if (null != attributes) {
-
- for(var i=0; i<attributes.length;i++){
- this.ostream.write(' '+attributes[i].key +'='+attributes[i].value);
- }
-
- // keySet of a TreeMap is ordered
- }
- this.ostream.write('>');
-};
-
-TextXMLEncoder.prototype.writeUString = function(/*String*/ utf8Content) {
-
- this.ostream.write(utf8Content);
-
-};
-
-
-TextXMLEncoder.prototype.writeBlob = function(/*byte []*/ binaryContent, /*int*/ offset, /*int*/ length) {
-
- this.ostream.write(TextXMLCodec.encodeBinaryElement(binaryContent, offset, length));
-
-};
-
-TextXMLEncoder.prototype.writeElement = function(/*String*/ tag, /*byte[]*/ binaryContent,
- /*TreeMap<String, String>*/ attributes) {
-
- /*if (null == attributes) {
-
- attributes = new TreeMap<String,String>();
- }*/
- if (!attributes.containsKey(TextXMLCodec.BINARY_ATTRIBUTE)) {
- attributes.put(TextXMLCodec.BINARY_ATTRIBUTE, TextXMLCodec.BINARY_ATTRIBUTE_VALUE);
- }
- super.writeElement(tag, binaryContent, attributes);
-}
-
-
-TextXMLEncoder.prototype.writeEndElement(tag) {
-
- this.ostream.write('<'+tab+'>');
-
- };
-
-
-//returns number long
-stringToTag = function(/*String*/ tagName) {
-
- if (null == tagName) {
- return null;
- }
- Long tagVal = null;
- if (null != _dictionaryStack) {
- for (/*XMLDictionary*/ dictionary in _dictionaryStack) {
- tagVal = dictionary.stringToTag(tagName);
- if (null != tagVal) {
- return tagVal;
- }
- }
- }
-
-
- if (XMLDictionaryStack.isUnknownTag(tagName)) {
- return XMLDictionaryStack.decodeUnknownTag(tagName);
- }
- return null;
-};
-
diff --git a/js/java_socket_bridge.js b/js/java_socket_bridge.js
index 8e0e7c7..62f43b5 100644
--- a/js/java_socket_bridge.js
+++ b/js/java_socket_bridge.js
@@ -1,15 +1,16 @@
/*
* @author: ucla-cs
- * This class represents Interest Objects
+ * See COPYING for copyright and distribution information.
+ * This file provides access to the JavaSocketBridge applet.
*/
-//var ccndAddr = unescape(%E0%A0%1E%099h%F9t%0C%E7%F46%1B%AB%F5%BB%05%A4%E5Z%AC%A5%E5%8Fs%ED%DE%B8%E0%13%AA%8F);
-var ccndAddrHex = '%E0%A0%1E%099h%F9t%0C%E7%F46%1B%AB%F5%BB%05%A4%E5Z%AC%A5%E5%8Fs%ED%DE%B8%E0%13%AA%8F';
-//var LOG = 5;
-var LOG = 5;
+//var ccnxnodename = unescape('%E0%A0%1E%099h%F9t%0C%E7%F46%1B%AB%F5%BB%05%A4%E5Z%AC%A5%E5%8Fs%ED%DE%B8%E0%13%AA%8F');
-// Global variables
+
+var LOG = 0;
+
+
var java_socket_bridge_ready_flag = false;
var ndnport =null;
@@ -17,434 +18,72 @@
var registeredPrefixes ={};
+/**
+ * Add a trim funnction for Strings
+ */
String.prototype.trim = function() {
return this.replace(/^\s+|\s+$/g, "");
};
+
// Applet reports it is ready to use
function java_socket_bridge_ready(){
+ console.log('APPLET LOADED');
java_socket_bridge_ready_flag = true;
-}
-
-
-
-
-//Sets the route to ccnx router
-/**
- * Setup the router to use
- * @url the url of the remote NDN router
- * @port the port of the remote NDN router
- */
-function createRoute(url, port){
- ndnport = port;
- ndnurl=url;
-
- console.log(new BinaryXMLDecoder());
-
- //SEND INTERST TO CCNX NODE
-
-
- //Now Start the receiving thread
}
-// Connect to a given url and port
-//Error -1 No countent found
-//Error -2 Empty query
-/**
- * Sends an interest for the given prefix and returns the response (java_socket_bridge.js)
- * @message the prefix to query for
- * @return -1 if no content is found,-2 is the array is empty, the content otherwise
- */
-function queryPrefix(message){
- if(ndnport!=null && ndnurl!=null){
- var newMessage ='';
-
-
- message = message.trim();
-
-
-
- if(message==null || message =="" || message=="/"){
- return -2;
- }
-
- //message = decodeURIComponent(message);
-
- var array = createNameArray(message);
-
- //console.log('ARRAY IS '+ array);
-
- enc = new BinaryXMLEncoder();
-
- int = new Interest(new ContentName(array));
-
- int.encode(enc);
-
- var hex = toHex(enc.getReducedOstream());
-
-
-
- //console.log('Connecting and start '+ ndnurl +':'+ndnport+'-'+message);
-
-
- var result = get_java_socket_bridge().connectAndStart(ndnurl,ndnport,hex);
-
- console.log('BINARY RESPONSE IS ' +result);
-
-
- //result[0] and result[1] should be 0 and 4 if there is a content object found
- if(result==null || result==undefined || result =="" || result[0] != '0'||result[1]!='4'){
- return -1;
- }
-
- else{
-
- var numbers = toNumbers(result);
-
- console.log('HEX RESPONSE IS \n'+numbers);
- decoder = new BinaryXMLDecoder(numbers);
-
-
- co = new ContentObject();
-
- co.decode(decoder);
-
- if(LOG>2) console.log(co);
-
- return co;
-
-
- }
-
-
- }
-
-
- else{
-
- alert('ERROR URL OR PORT NOT SET');
-
- return -3;
-
- }
-
-}
-
-var registerStarted = false;
-function registerPrefix(name, content){
-
- registeredPrefixes[name] = content ;
-
- if(registerStarted == false){
- var result = get_java_socket_bridge().connectAndStartAndPublish();
-
- startRegisterPrefix();
-
- registerStarted = true;
- }
- sendForwardingEntry(10);
-}
-
-
-function unRegisterPrefix(name){
-
- delete registeredPrefixes[name];
-
-}
-
-
-
-
-function on_socket_received_interest(IP, port, interestBinary){
- console.log('WOOOO RECEIVED STUFF' );
- var interest = decodeHexInterest(interestBinary);
-
- console.log('WOOO received interest' + interest.Name.Components);
-
- var stringName = "";
-
- for(var i=0;i<interest.Name.Components.length;i++){
- stringName += "/"+ interest.Name.Components[i];
- }
-
- if(registeredPrefix[stringName]!=null){
- if(LOG>1)console.log("CANNOT FIND THE OBJECT OF NAME " + stringName );
+// Send Test Interest
+function get(host,port,data){
+ if(java_socket_bridge_ready_flag){
+ return get_java_socket_bridge().get(host,port,data,1000);
}
else{
- var co = new ContentObject(interest.Name, null,registeredPrefix[stringName],null );
-
- var hex = encodeToHexContentObject(co);
-
- get_java_socket_bridge().sendContentObject(IP,port,hex);
-
-
+ on_socket_error("Java Socket Bridge send Interest until the applet has loaded");
}
}
-
-
-// Connect to a given url and port
-//Error -1 No countent found
-//Error -2 Empty query
-function startRegisterPrefix(){
- if(LOG>2) console.log('START REGISTER PREFIX');
+// Send Test Interest
+function put(host,port,data,name,toReturn){
- if(ndnport!=null && ndnurl!=null){
- var newMessage ='';
-
-
-
- name = name.trim();
-
-
-
- ///////////////////////
- var face = new FaceInstance('newface',null,null, 17, '127.0.0.1',9876,null,null,null);
-
- var encoder1 = new BinaryXMLEncoder();
-
- face.encode(encoder1);
-
- var faceInstanceBinary = encoder1.getReducedOstream();
-
-
- var si = new SignedInfo();
- si.setFields();
-
- var co = new ContentObject(new ContentName(),si,faceInstanceBinary,new Signature());
- co.sign();
-
- var encoder2 = new BinaryXMLEncoder();
-
- co.encode(encoder2);
-
- var coBinary = encoder2.getReducedOstream();
-
- //if(LOG>3)console.log('ADDESS OF CCND IS'+unescape('%E0%A0%1E%099h%F9t%0C%E7%F46%1B%AB%F5%BB%05%A4%E5Z%AC%A5%E5%8Fs%ED%DE%B8%E0%13%AA%8F'));
-
- //var interestName = new ContentName(['ccnx',co.SignedInfo.Publisher.PublisherPublicKeyDigest,'newface',coBinary]);
- var interestName = new ContentName(['ccnx',unescape('%E0%A0%1E%099h%F9t%0C%E7%F46%1B%AB%F5%BB%05%A4%E5Z%AC%A5%E5%8Fs%ED%DE%B8%E0%13%AA%8F'),'newface',coBinary]);
- //var interestName = new ContentName(['ccnx','%E0%A0%1E%099h%F9t%0C%E7%F46%1B%AB%F5%BB%05%A4%E5Z%AC%A5%E5%8Fs%ED%DE%B8%E0%13%AA%8F','newface',coBinary]);
-
- //var interestName = new ContentName(['ccnx','1234','newface',coBinary]);
- //var interestName = new ContentName(['ccnx',co.SignedInfo.Publisher.PublisherPublicKeyDigest,'newface',coBinary]);
- int = new Interest(interestName,face);
-
- var hex = encodeToHexInterest(int);
- /////////////////
-
-
-
- if(LOG>4)console.log('Interst name of Conntection Message is '+ interestName);
-
-
- if(LOG>4) console.log('Connecting and start '+ ndnurl +':'+ndnport+'-'+hex);
- //console.log('Connecting and start '+ ndnurl +':'+ndnport+'-'+message);
-
- var result = get_java_socket_bridge().connectAndStart(ndnurl,ndnport,hex);
-
-
- //TODO MOVE THIS
-
- //result[0] and result[1] should be 0 and 4 if there is a content object found
- if(result==null || result==undefined || result =="" || result[0] != '0'||result[1]!='4'){
- return -1;
- }
-
- if(LOG>4) console.log('RECEIVED THE FOLLOWING DATA: ' +co.Content);
-
- else{
-
- co = decodeHexContentObject(result);
-
- if(LOG>4) console.log('RECEIVED THE FOLLOWING DATA: ' +co.Content);
-
- return co;
- }
+ if(java_socket_bridge_ready_flag){
+ return get_java_socket_bridge().put(host,port,data,name,toReturn);
}
else{
-
- alert('ERROR URL OR PORT NOT SET');
-
- return -3;
-
- }
-
-}
-
-
-// Connect to a given url and port
-//Error -1 No countent found
-//Error -2 Empty query
-function sendForwardingEntry(faceID){
- if(LOG>2) console.log('START REGISTER PREFIX');
-
- if(ndnport!=null && ndnurl!=null){
- var newMessage ='';
-
-
-
- name = name.trim();
-
-
-
- ///////////////////////
- var face = new ForwardingEntry('prefixreg',new ContentName(['helloworld']),null, faceID, 1,null);
-
- var encoder1 = new BinaryXMLEncoder();
-
- face.encode(encoder1);
-
- var faceInstanceBinary = encoder1.getReducedOstream();
-
-
-
- var si = new SignedInfo();
- si.setFields();
-
- var co = new ContentObject(new ContentName(),si,faceInstanceBinary,new Signature());
- co.sign();
-
- var encoder2 = new BinaryXMLEncoder();
-
- co.encode(encoder2);
-
- var coBinary = encoder2.getReducedOstream();
-
-
-
- var interestName = new ContentName(['ccnx',unescape('%E0%A0%1E%099h%F9t%0C%E7%F46%1B%AB%F5%BB%05%A4%E5Z%AC%A5%E5%8Fs%ED%DE%B8%E0%13%AA%8F'),'prefixreg',coBinary]);
- //var interestName = new ContentName(['ccnx',co.SignedInfo.Publisher.PublisherPublicKeyDigest,'newface',coBinary]);
- //var interestName = new ContentName(['ccnx','%E0%A0%1E%099h%F9t%0C%E7%F46%1B%AB%F5%BB%05%A4%E5Z%AC%A5%E5%8Fs%ED%DE%B8%E0%13%AA%8F','newface',coBinary]);
-
- //var interestName = new ContentName(['ccnx','1234','newface',coBinary]);
- //var interestName = new ContentName(['ccnx',co.SignedInfo.Publisher.PublisherPublicKeyDigest,'prefixreg',coBinary]);
-
- int = new Interest(interestName,face);
-
- var hex = encodeToHexInterest(int);
- /////////////////
-
-
-
- if(LOG>4)console.log('Interst name of Conntection Message is '+ interestName);
-
-
- if(LOG>4) console.log('Connecting and start '+ ndnurl +':'+ndnport+'-'+hex);
- //console.log('Connecting and start '+ ndnurl +':'+ndnport+'-'+message);
-
- var result = get_java_socket_bridge().connectAndStart(ndnurl,ndnport,hex);
-
- if(LOG>3)console.log('BINARY RESPONSE IS ' +result);
-
-
- //result[0] and result[1] should be 0 and 4 if there is a content object found
- if(result==null || result==undefined || result =="" || result[0] != '0'||result[1]!='4'){
- return -1;
- }
-
- if(LOG>4) console.log('RECEIVED THE FOLLOWING DATA: ' +co.Content);
-
- else{
-
- co = decodeHexContentObject(result);
-
- if(LOG>4) console.log('RECEIVED THE FOLLOWING DATA: ' +co.Content);
-
- return co;
- }
+ on_socket_error("Java Socket Bridge send Interest until the applet has loaded");
}
- else{
-
- alert('ERROR URL OR PORT NOT SET');
-
- return -3;
-
- }
-
}
+function on_socket_received_interest(hex,name){
+
+ if(LOG>3)console.log('received interest from host'+ host +':'+port+' with name '+name);
+
+ if(LOG>3)console.log('DATA ');
+
+ if(LOG>3)console.log(hex);
+
+ interest = decodeHexInterest(hex);
+
+ console.log('SUCCESSFULLY PARSED INTEREST');
+
+ console.log('CREATING ANSWER');
+ var si = new SignedInfo();
+ si.setFields();
+
+ var answer = toNumbersFromString('WORLD');
-/**
- * Computes the size in bytes of the ContentObject once encoded
- * @param co the content object to encode
- * @returns the size in bytes of the encoded ContentObject
- */
-function getContentObjectSize(co){
- var enc = new BinaryXMLEncoder();
+ var co = new ContentObject(new Name(name),si,answer,new Signature());
+ co.sign();
- co.encode(enc);
- return enc.getReducedOstream().length;
+ var outputHex = encodeToHexContentObject(co);
+
+ console.log('SENDING ANSWER');
+
+ return get_java_socket_bridge().putAnswer(outputHex,name);
}
-
-
-
-function encodeToHexInterest(int){
-
- var enc = new BinaryXMLEncoder();
-
- int.encode(enc);
-
- var hex = toHex(enc.getReducedOstream());
-
- return hex;
-
-
-}
-
-
-function encodeToHexContentObject(co){
- var enc = new BinaryXMLEncoder();
-
- co.encode(enc);
-
- var reducedOstream = enc.getReducedOstream();
-
- if(LOG>3) console.log("In encodeToHexContentObject, reducedOstream: ", reducedOstream);
-
- var hex = toHex(reducedOstream);
-
- return hex;
-
-
-}
-
-function decodeHexInterest(result){
- var numbers = toNumbers(result);
-
-
- decoder = new BinaryXMLDecoder(numbers);
- if(LOG>3)console.log('DECODED HEX INTERST \n'+numbers);
-
- i = new Interest();
-
- i.decode(decoder);
-
- return i;
-
-}
-
-function decodeHexContentObject(result){
- var numbers = toNumbers(result);
-
- decoder = new BinaryXMLDecoder(numbers);
- if(LOG>3)console.log('DECODED HEX CONTENT OBJECT \n'+numbers);
-
- co = new ContentObject();
-
- co.decode(decoder);
-
- return co;
-
-}
-
-
-
-
// Get something from the socket
function on_socket_get(message){}
diff --git a/js/security/KeyManager.js b/js/security/KeyManager.js
index dcf036d..cb051eb 100644
--- a/js/security/KeyManager.js
+++ b/js/security/KeyManager.js
@@ -1,9 +1,41 @@
-
+/*
+ * @author: ucla-cs
+ * See COPYING for copyright and distribution information.
+ */
var KeyManager = function KeyManager(){
+
+//Certificate from CCNx
+
+this.certificate = 'MIIBmzCCAQQCCQC32FyQa61S7jANBgkqhkiG9w0BAQUFADASMRAwDgYDVQQDEwd'+
+
+'heGVsY2R2MB4XDTEyMDQyODIzNDQzN1oXDTEyMDUyODIzNDQzN1owEjEQMA4GA1'+
+
+'UEAxMHYXhlbGNkdjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4X0wp9goq'+
+
+'xuECxdULcr2IHr9Ih4Iaypg0Wy39URIup8/CLzQmdsh3RYqd55hqonu5VTTpH3i'+
+
+'MLx6xZDVJAZ8OJi7pvXcQ2C4Re2kjL2c8SanI0RfDhlS1zJadfr1VhRPmpivcYa'+
+
+'wJ4aFuOLAi+qHFxtN7lhcGCgpW1OV60oXd58CAwEAATANBgkqhkiG9w0BAQUFAA'+
+
+'OBgQDLOrA1fXzSrpftUB5Ro6DigX1Bjkf7F5Bkd69hSVp+jYeJFBBlsILQAfSxU'+
+
+'ZPQtD+2Yc3iCmSYNyxqu9PcufDRJlnvB7PG29+L3y9lR37tetzUV9eTscJ7rdp8'+
+
+'Wt6AzpW32IJ/54yKNfP7S6ZIoIG+LP6EIxq6s8K1MXRt8uBJKw==';
+
+
+//this.publicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDhfTCn2CirG4QLF1QtyvYgev0iHghrKmDRbLf1REi6nz8IvNCZ2yHdFip3nmGqie7lVNOkfeIwvHrFkNUkBnw4mLum9dxDYLhF7aSMvZzxJqcjRF8OGVLXMlp1+vVWFE+amK9xhrAnhoW44sCL6ocXG03uWFwYKClbU5XrShd3nwIDAQAB';
+this.publicKey ='30819F300D06092A864886F70D010101050003818D0030818902818100E17D30A7D828AB1B840B17542DCAF6207AFD221E086B2A60D16CB7F54448BA9F3F08BCD099DB21DD162A779E61AA89EEE554D3A47DE230BC7AC590D524067C3898BBA6F5DC4360B845EDA48CBD9CF126A723445F0E1952D7325A75FAF556144F9A98AF7186B0278685B8E2C08BEA87171B4DEE585C1828295B5395EB4A17779F0203010001';
+//Private Key from CCNx
+
+this.privateKey ='MIICXQIBAAKBgQDhfTCn2CirG4QLF1QtyvYgev0iHghrKmDRbLf1REi6nz8IvNCZ2yHdFip3nmGqie7lVNOkfeIwvHrFkNUkBnw4mLum9dxDYLhF7aSMvZzxJqcjRF8OGVLXMlp1+vVWFE+amK9xhrAnhoW44sCL6ocXG03uWFwYKClbU5XrShd3nwIDAQABAoGAGkv6T6jC3WmhFZYL6CdCWvlc6gysmKrhjarrLTxgavtFY6R5g2ft5BXAsCCVbUkWxkIFSKqxpVNl0gKZCNGEzPDN6mHJOQI/h0rlxNIHAuGfoAbCzALnqmyZivhJAPGijAyKuU9tczsst5+Kpn+bn7ehzHQuj7iwJonS5WbojqECQQD851K8TpW2GrRizNgG4dx6orZxAaon/Jnl8lS7soXhllQty7qG+oDfzznmdMsiznCqEABzHUUKOVGE9RWPN3aRAkEA5D/w9N55d0ibnChFJlc8cUAoaqH+w+U3oQP2Lb6AZHJpLptN4y4b/uf5d4wYU5/i/gC7SSBH3wFhh9bjRLUDLwJAVOx8vN0Kqt7myfKNbCo19jxjVSlA8TKCn1Oznl/BU1I+rC4oUaEW25DjmX6IpAR8kq7S59ThVSCQPjxqY/A08QJBAIRaF2zGPITQk3r/VumemCvLWiRK/yG0noc9dtibqHOWbCtcXtOm/xDWjq+lis2i3ssOvYrvrv0/HcDY+Dv1An0CQQCLJtMsfSg4kvG/FRY5UMhtMuwo8ovYcMXt4Xv/LWaMhndD67b2UGawQCRqr5ghRTABWdDD/HuuMBjrkPsX0861';
+
+
+/*
this.certificate =
-// "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDhfTCn2CirG4QLF1QtyvYgev0iHghrKmDRbLf1REi6nz8IvNCZ2yHdFip3nmGqie7lVNOkfeIwvHrFkNUkBnw4mLum9dxDYLhF7aSMvZzxJqcjRF8OGVLXMlp1+vVWFE+amK9xhrAnhoW44sCL6ocXG03uWFwYKClbU5XrShd3nwIDAQAB";
'MIIBvTCCASYCCQD55fNzc0WF7TANBgkqhkiG9w0BAQUFADAjMQswCQYDVQQGEwJK'+
'UDEUMBIGA1UEChMLMDAtVEVTVC1SU0EwHhcNMTAwNTI4MDIwODUxWhcNMjAwNTI1'+
'MDIwODUxWjAjMQswCQYDVQQGEwJKUDEUMBIGA1UEChMLMDAtVEVTVC1SU0EwgZ8w'+
@@ -16,9 +48,6 @@
'3OK+u3ivTSj3zwjtpudY5Xo=';
this.privateKey =
-// '3082025c02010002818100bd9565559c1795c049a5ef4dc9d1bc8b981b66097ea253f5d0f50f1a1df908ac4e69a797dadd2c0590944a6e849e1fbb7371c53dfddbe7802656e1d5f449b8530d9c7da8d6abebd90e06124d927f2f6c5721f1d0e49e7f6a1167caf960d96ff5afaa2d2567337772a944c8e6ceb859b25a231d9eca873574ff98225c853f38ef02030100010281805e8e57d7661e014bc1afe87644d5be1365cf2c8a49c5ced888dae1286690a1f9c6b63da7a8baad4d2d3a39117c459d9011d949c64c8a54a17efdd06fb502dbd27c27d89a6d984eddc7c41a20178ad3cf6998c82d4ca576c6e34b47d1e49d39e7f4ddb31371e2af7bf2f6ef21bf79a82132035e756b6e2ab44d4d8521dd0bb461024100efcd7cdc0f32e32565cd4980cd2f42b122b81f9ae49cce5abb4db30ae6b7c3c18433233eb5b7d870197fb4d84b128086ff6d99e0097212d37e3fa5e6511e9631024100ca638d4921c4b3a9aaa28bf1df74a140f63e16fd5c84b51f34002d4da77e23ad68a470bf7cbffd891c040fb867f181d662a769e0cedaad5e5cd7be1efc94591f02400f08f63421ebd1dc0d66f29dd5bf89d1eb5859faef2c79afaca0b18214771f19e9fcfecfb6bb0121fe2748a26b0a8cee69e3684b68ac334bf9556a44677fa07102401970b61bd140d68ca744536f0df5ad276b4c96bb365c002071faebb6ed2ceff3264a3559fca66d8a449946189a084397dd42ca0e56322ac4c7cadebd2a66c365024100c040c81d88e824684420ab98cbdf6615bb90bcedcb82081ab19375972c706d6596101b0d313017e26ec106ff814371b70db2deb00f8b25897b9b46ce8dd135d1';
-// '30820276020100300d06092a864886f70d0101010500048202603082025c02010002818100bd9565559c1795c049a5ef4dc9d1bc8b981b66097ea253f5d0f50f1a1df908ac4e69a797dadd2c0590944a6e849e1fbb7371c53dfddbe7802656e1d5f449b8530d9c7da8d6abebd90e06124d927f2f6c5721f1d0e49e7f6a1167caf960d96ff5afaa2d2567337772a944c8e6ceb859b25a231d9eca873574ff98225c853f38ef02030100010281805e8e57d7661e014bc1afe87644d5be1365cf2c8a49c5ced888dae1286690a1f9c6b63da7a8baad4d2d3a39117c459d9011d949c64c8a54a17efdd06fb502dbd27c27d89a6d984eddc7c41a20178ad3cf6998c82d4ca576c6e34b47d1e49d39e7f4ddb31371e2af7bf2f6ef21bf79a82132035e756b6e2ab44d4d8521dd0bb461024100efcd7cdc0f32e32565cd4980cd2f42b122b81f9ae49cce5abb4db30ae6b7c3c18433233eb5b7d870197fb4d84b128086ff6d99e0097212d37e3fa5e6511e9631024100ca638d4921c4b3a9aaa28bf1df74a140f63e16fd5c84b51f34002d4da77e23ad68a470bf7cbffd891c040fb867f181d662a769e0cedaad5e5cd7be1efc94591f02400f08f63421ebd1dc0d66f29dd5bf89d1eb5859faef2c79afaca0b18214771f19e9fcfecfb6bb0121fe2748a26b0a8cee69e3684b68ac334bf9556a44677fa07102401970b61bd140d68ca744536f0df5ad276b4c96bb365c002071faebb6ed2ceff3264a3559fca66d8a449946189a084397dd42ca0e56322ac4c7cadebd2a66c365024100c040c81d88e824684420ab98cbdf6615bb90bcedcb82081ab19375972c706d6596101b0d313017e26ec106ff814371b70db2deb00f8b25897b9b46ce8dd135d1';
-// "MIICXAIBAAKBgQC9lWVVnBeVwEml703J0byLmBtmCX6iU/XQ9Q8aHfkIrE5pp5fa3SwFkJRKboSeH7tzccU9/dvngCZW4dX0SbhTDZx9qNar69kOBhJNkn8vbFch8dDknn9qEWfK+WDZb/Wvqi0lZzN3cqlEyObOuFmyWiMdnsqHNXT/mCJchT847wIDAQABAoGAXo5X12YeAUvBr+h2RNW+E2XPLIpJxc7YiNrhKGaQofnGtj2nqLqtTS06ORF8RZ2QEdlJxkyKVKF+/dBvtQLb0nwn2JptmE7dx8QaIBeK089pmMgtTKV2xuNLR9HknTnn9N2zE3Hir3vy9u8hv3moITIDXnVrbiq0TU2FId0LtGECQQDvzXzcDzLjJWXNSYDNL0KxIrgfmuSczlq7TbMK5rfDwYQzIz61t9hwGX+02EsSgIb/bZngCXIS034/peZRHpYxAkEAymONSSHEs6mqoovx33ShQPY+Fv1chLUfNAAtTad+I61opHC/fL/9iRwED7hn8YHWYqdp4M7arV5c174e/JRZHwJADwj2NCHr0dwNZvKd1b+J0etYWfrvLHmvrKCxghR3Hxnp/P7PtrsBIf4nSKJrCozuaeNoS2isM0v5VWpEZ3+gcQJAGXC2G9FA1oynRFNvDfWtJ2tMlrs2XAAgcfrrtu0s7/MmSjVZ/KZtikSZRhiaCEOX3ULKDlYyKsTHyt69KmbDZQJBAMBAyB2I6CRoRCCrmMvfZhW7kLzty4IIGrGTdZcscG1llhAbDTEwF+JuwQb/gUNxtw2y3rAPiyWJe5tGzo3RNdE=";
'MIICWwIBAAKBgQDRhGF7X4A0ZVlEg594WmODVVUIiiPQs04aLmvfg8SborHss5gQ'+
'Xu0aIdUT6nb5rTh5hD2yfpF2WIW6M8z0WxRhwicgXwi80H1aLPf6lEPPLvN29EhQ'+
'NjBpkFkAJUbS8uuhJEeKw0cE49g80eBBF4BCqSL6PFQbP9/rByxdxEoAIQIDAQAB'+
@@ -32,6 +61,8 @@
'aYZ5/5B2lwroqnKdZBJMGKFpUDn7Mb5hiSgocxnvMkv6NjT66Xsi3iYakJII9q8C'+
'Ma1qZvT/cigmdbAh7wJAQNXyoizuGEltiSaBXx4H29EdXNYWDJ9SS5f070BRbAIl'+
'dqRh3rcNvpY6BKJqFapda1DjdcncZECMizT/GMrc1w==';
+
+ */
};
@@ -48,7 +79,6 @@
var result = x509.subjectPublicKeyRSA.verifyString(input, signature);
return result;
-
};
KeyManager.prototype.sign= function sign(message){
@@ -58,6 +88,7 @@
var _PEM_PRIVATE_KEY_STRING_ = this.privateKey;
var rsa = new RSAKey();
+
rsa.readPrivateKeyFromPEMString(_PEM_PRIVATE_KEY_STRING_);
var hSig = rsa.signString(input, "sha256");
diff --git a/js/securityLib/sha256.js b/js/securityLib/sha256.js
index 45f3cb3..00ea8af 100644
--- a/js/securityLib/sha256.js
+++ b/js/securityLib/sha256.js
@@ -250,7 +250,7 @@
*/
function rstr2binb(input)
{
- console.log('Raw string comming is '+input);
+ //console.log('Raw string comming is '+input);
var output = Array(input.length >> 2);
for(var i = 0; i < output.length; i++)
output[i] = 0;
@@ -266,7 +266,7 @@
* @return the array of big-endian words
*/
function byteArray2binb(input){
- console.log("Byte array coming is " + input);
+ //console.log("Byte array coming is " + input);
var output = Array(input.length >> 2);
for(var i = 0; i < output.length; i++)
output[i] = 0;
diff --git a/js/test-encode-decode-ContentObject.html b/js/test-encode-decode-ContentObject.html
deleted file mode 100644
index 482e5c0..0000000
--- a/js/test-encode-decode-ContentObject.html
+++ /dev/null
@@ -1,301 +0,0 @@
-<?xml version = "1.0" encoding="utf-8" ?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
-"DTD/xhtml1-strict.dtd">
-<html xmlns = "http://www.w3.org/1999/xhtml">
-
-<head>
- <title>NDN Request Example</title>
-
- <script type="text/javascript" src="java_socket_bridge.js"></script>
-
- <script type="text/javascript" src="CCNProtocolDTags.js"></script>
-
- <script type="text/javascript" src="CCNTime.js"></script>
-
- <script type="text/javascript" src="ContentName.js"></script>
-
- <script type="text/javascript" src="ContentObject.js"></script>
-
- <script type="text/javascript" src="DateFormat.js"></script>
-
- <script type="text/javascript" src="Exclude.js"></script>
-
- <script type="text/javascript" src="ExcludeAny.js"></script>
-
- <script type="text/javascript" src="ExcludeComponent.js"></script>
-
- <script type="text/javascript" src="Interest.js"></script>
-
- <script type="text/javascript" src="KeyLocator.js"></script>
-
- <script type="text/javascript" src="KeyName.js"></script>
-
- <script type="text/javascript" src="PublisherID.js"></script>
-
- <script type="text/javascript" src="Signature.js"></script>
-
- <script type="text/javascript" src="SignedInfo.js"></script>
-
- <script type="text/javascript" src="PublisherPublicKeyDigest.js"></script>
-
- <script type="text/javascript" src="FaceInstance.js"></script>
-
- <script type="text/javascript" src="ForwardingEntry.js"></script>
-
- <script type="text/javascript" src="encoding/BinaryXMLEncoder.js"></script>
-
- <script type="text/javascript" src="encoding/BinaryXMLCodec.js"></script>
-
- <script type="text/javascript" src="encoding/BinaryXMLDecoder.js"></script>
-
- <script type="text/javascript" src="encoding/DataUtils.js"></script>
-
- <script language="JavaScript" type="text/javascript" src="security/KeyManager.js"></script>
-
- <script language="JavaScript" type="text/javascript" src="securityLib/jsbn.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/jsbn2.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/rsa.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/rsa2.js"></script>
-
- <script language="JavaScript" type="text/javascript" src="securityLib/sha1.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/sha256.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/sha512.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/md5.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/ripemd160.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/base64.js"></script>
-
- <script language="JavaScript" type="text/javascript" src="securityLib/rsapem-1.1.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/rsasign-1.2.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/asn1hex-1.1.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/x509-1.1.js"></script>
-
- <script type="text/javascript">
-
- function encode(){
- var contentname = new ContentName( createNameArray(document.getElementById('contentname').value) );
-
- var content = document.getElementById('content').value;
-
- var signedInfo = new SignedInfo();
- signedInfo.setFields();
- //var signatureBits = generateSignatureBits(contentname,content,signedInfo);
-
- //witness is null
- var signature = new Signature();
-
-
- var co = new ContentObject(contentname,signedInfo,content,signature);
-
- co.sign();
-
- var coSize = getContentObjectSize(co);
-
-
- var output = encodeToHexContentObject(co);
-
- if(LOG>3) console.log("Size: ", coSize);
-
-
- document.getElementById('coSize').innerHTML = coSize;
-
- document.getElementById('result').innerHTML = output;
-
- }
-
- function decode(){
-
-
-
- var input = document.getElementById('result').innerHTML;
-
-
- var co = decodeHexContentObject(input);
-
-var output ="";
-
- if(co==-1)
- output+= "NO CONTENT FOUND"
- else if (co==-2)
- output+= "CONTENT NAME IS EMPTY"
- else{
- if(co.Name!=null && co.Name.Components!=null){
- output+= "NAME: ";
-
- for(var i=0;i<co.Name.Components.length;i++){
- output+= "/"+ toString(co.Name.Components[i]);
- }
- output+= "<br />";
- output+= "<br />";
- }
-
- if(co.Content !=null){
- output += "CONTENT(ASCII): "+ toString(co.Content);
-
- output+= "<br />";
- output+= "<br />";
- }
- if(co.Content !=null){
- output += "CONTENT(hex): "+ toHex(co.Content);
-
- output+= "<br />";
- output+= "<br />";
- }
-
- if(co.Signature !=null && co.Signature.Signature!=null){
-
- output += "SIGNATURE(hex): "+ toHex(co.Signature.Signature);
-
- output+= "<br />";
- output+= "<br />";
- }
- if(co.SignedInfo !=null && co.SignedInfo.Publisher!=null && co.SignedInfo.Publisher.PublisherPublicKeyDigest!=null){
-
- output += "Publisher Public Key Digest: " + co.SignedInfo.Publisher.PublisherPublicKeyDigest + "<br />";
- output += "Publisher Public Key Digest(hex): "+ toHex(co.SignedInfo.Publisher.PublisherPublicKeyDigest);
-
- output+= "<br />";
- output+= "<br />";
- }
- if(co.SignedInfo !=null && co.SignedInfo.Timestamp!=null){
-
- output += "TimeStamp(hex): "+ co.SignedInfo.Timestamp.date;
-
- output+= "<br />";
- output+= "<br />";
- }
- if(co.SignedInfo!=null && co.SignedInfo.Locator!=null && co.SignedInfo.Locator.PublicKey!=null){
-
- var publickey = rstr2b64(toString(co.SignedInfo.Locator.PublicKey));
- var publickeyHex = toHex(co.SignedInfo.Locator.PublicKey).toLowerCase();
- var publickeyString = toString(co.SignedInfo.Locator.PublicKey);
-
- var signature = toHex(co.Signature.Signature).toLowerCase();
-
-
- var input = toString(co.rawSignatureData);
-
- if(LOG>2) console.log("Input: ", input, "; raw signature data: ", co.rawSignatureData);
-
-
- output += "DER Certificate: "+publickey ;
-
- output+= "<br />";
- output+= "<br />";
-
-
-
- if(LOG>2) console.log(" ContentName + SignedInfo + Content = "+input);
- if(LOG>2) console.log(" PublicKey = "+publickey );
- if(LOG>2) console.log(" PublicKeyHex = "+publickeyHex );
- if(LOG>2) console.log(" PublicKeyString = "+publickeyString );
-
- if(LOG>2) console.log(" Signature "+signature );
- if(LOG>2) console.log(" Signature NOW IS" );
- if(LOG>2) console.log(co.Signature.Signature);
-
-
- /*var x509 = new X509();
-
- x509.readCertPEM(publickey);
-
-
- //x509.readCertPEMWithoutRSAInit(publickey);
-
- var result = x509.subjectPublicKeyRSA.verifyString(input, signature);*/
- //console.log('result is '+result);
-
-
- //var kp = publickeyHex.slice(56,314);
- var kp = publickeyHex.slice(336,594)
-// var kp = '00bd9565559c1795c049a5ef4dc9d1bc8b981b66097ea253f5d0f50f1a1df908ac4e69a797dadd2c0590944a6e849e1fbb7371c53dfddbe7802656e1d5f449b8530d9c7da8d6abebd90e06124d927f2f6c5721f1d0e49e7f6a1167caf960d96ff5afaa2d2567337772a944c8e6ceb859b25a231d9eca873574ff98225c853f38ef';
-
- output += "PUBLISHER KEY(hex): "+kp ;
-
- output+= "<br />";
- output+= "<br />";
-
- if(LOG>3) console.log('kp is '+kp);
-
- //var exp = publickeyHex.slice(318,324);
- var exp = publickeyHex.slice(598,604);
-// var exp = '5e8e57d7661e014bc1afe87644d5be1365cf2c8a49c5ced888dae1286690a1f9c6b63da7a8baad4d2d3a39117c459d9011d949c64c8a54a17efdd06fb502dbd27c27d89a6d984eddc7c41a20178ad3cf6998c82d4ca576c6e34b47d1e49d39e7f4ddb31371e2af7bf2f6ef21bf79a82132035e756b6e2ab44d4d8521dd0bb461';
-
- if(LOG>3) console.log('kp size is '+kp.length );
- output += "exponent: "+exp ;
-
- output+= "<br />";
- output+= "<br />";
-
- console.log('exp is '+exp);
-
- var rsakey = new RSAKey();
- rsakey.setPublic(kp,exp);
- var result = rsakey.verifyString(input, signature);
-
- var inputBis = toHex(co.Name).concat(toHex(co.SignedInfo), toHex(co.Content));
-
-// if(LOG>0){
-// console.log("Input: ", input);
-// console.log("Input bis: ", inputBis);
-// console.log("Verify input bis: ", rsakey.verifyString(inputBis, signature));
-// }
-
- //var x509 = new X509();
- //x509.readCertPEM(publickey);
- //if(LOG>0) console.log("x509 verif: ", x509.subjectPublicKeyRSA.verifyString(input, signature));
-
- if(result)
- output += 'SIGNATURE VALID';
- else
- output += 'SIGNATURE INVALID';
-
-
-
-
- //output += "VALID: "+ toHex(co.SignedInfo.Locator.PublicKey);
-
- output+= "<br />";
- output+= "<br />";
-
-
- if(LOG>4) console.log('str'[1]);
- }
- }
-
- document.getElementById('result').innerHTML = output;
-
- return input;
-
- }
-
- </script>
-
-</head>
-<body >
- <form>
-
- Please Enter a Content Name:<br />
-
- <input id="contentname" type="text" name="CONTENTNAME" value="/PARC/abc" />
-
- Please Enter the Content:<br />
-
- <textarea id="content" cols="40" rows="5" name="CONTENT" value="SUCCESS" >SUCCESS!</textarea>
-
-
-
- </form>
- <div>
- <button onclick="encode()">Encode</button>
- <button onclick="decode()">Decode</button>
- </div>
- <div>
- <p>Size: <span id="coSize"></span></p>
-
- <p id="result"></p>
-
- </div>
-
-
-</body>
-</html>
\ No newline at end of file
diff --git a/js/test-encode-decode-Interest.html b/js/test-encode-decode-Interest.html
deleted file mode 100644
index 37b9f23..0000000
--- a/js/test-encode-decode-Interest.html
+++ /dev/null
@@ -1,132 +0,0 @@
-<?xml version = "1.0" encoding="utf-8" ?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
-"DTD/xhtml1-strict.dtd">
-<html xmlns = "http://www.w3.org/1999/xhtml">
-
-<head>
- <title>NDN Request Example</title>
-
- <script type="text/javascript" src="java_socket_bridge.js"></script>
-
- <script type="text/javascript" src="CCNProtocolDTags.js"></script>
-
- <script type="text/javascript" src="CCNTime.js"></script>
-
- <script type="text/javascript" src="ContentName.js"></script>
-
- <script type="text/javascript" src="ContentObject.js"></script>
-
- <script type="text/javascript" src="DateFormat.js"></script>
-
- <script type="text/javascript" src="Exclude.js"></script>
-
- <script type="text/javascript" src="ExcludeAny.js"></script>
-
- <script type="text/javascript" src="ExcludeComponent.js"></script>
-
- <script type="text/javascript" src="Interest.js"></script>
-
- <script type="text/javascript" src="KeyLocator.js"></script>
-
- <script type="text/javascript" src="KeyName.js"></script>
-
- <script type="text/javascript" src="PublisherID.js"></script>
-
- <script type="text/javascript" src="Signature.js"></script>
-
- <script type="text/javascript" src="SignedInfo.js"></script>
-
- <script type="text/javascript" src="PublisherPublicKeyDigest.js"></script>
-
- <script type="text/javascript" src="FaceInstance.js"></script>
-
- <script type="text/javascript" src="ForwardingEntry.js"></script>
-
- <script type="text/javascript" src="encoding/BinaryXMLEncoder.js"></script>
-
- <script type="text/javascript" src="encoding/BinaryXMLCodec.js"></script>
-
- <script type="text/javascript" src="encoding/BinaryXMLDecoder.js"></script>
-
- <script type="text/javascript" src="encoding/DataUtils.js"></script>
-
- <script language="JavaScript" type="text/javascript" src="security/KeyManager.js"></script>
-
- <script language="JavaScript" type="text/javascript" src="securityLib/jsbn.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/jsbn2.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/rsa.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/rsa2.js"></script>
-
- <script language="JavaScript" type="text/javascript" src="securityLib/sha1.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/sha256.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/sha512.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/md5.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/ripemd160.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/base64.js"></script>
-
- <script language="JavaScript" type="text/javascript" src="securityLib/rsapem-1.1.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/rsasign-1.2.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/asn1hex-1.1.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/x509-1.1.js"></script>
-
- <script type="text/javascript">
-
- function encode(){
- var interest = new Interest( new ContentName(document.getElementById('interest').value ) );
-
- var output = encodeToHexInterest(interest);
-
- document.getElementById('result').innerHTML = output;
-
- }
-
- function decode(){
-
-
-
- var input = document.getElementById('result').innerHTML;
-
-
- var interest = decodeHexInterest(input);
-
- if(LOG>3)console.log('INTEREST DECODED');
- if(LOG>3)console.log(interest);
-
- ///////////////////////////////////////
-
- var output ="";
-
- if(interest.Name!=null && interest.Name.Components!=null){
- output+= "NAME: ";
-
- for(var i=0;i<interest.Name.Components.length;i++){
- output+= "/"+ toString(interest.Name.Components[i]);
- }
- output+= "<br />";
- output+= "<br />";
- }
-
- document.getElementById('result').innerHTML = output;
-
- }
-
- </script>
-
-</head>
-<body >
- <form>
-
- Please Enter a Interest:<br />
-
- <input id="interest" type="text" name="INTERSET" value="/PARC/abc" />
-
- </form>
- <button onclick="encode()">Encode</button>
- <button onclick="decode()">Decode</button>
-
-
-
- <p id="result"></p>
-
-</body>
-</html>
\ No newline at end of file
diff --git a/js/test-publish-data.html b/js/test-publish-data.html
deleted file mode 100644
index a67e844..0000000
--- a/js/test-publish-data.html
+++ /dev/null
@@ -1,176 +0,0 @@
-<?xml version = "1.0" encoding="utf-8" ?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
-"DTD/xhtml1-strict.dtd">
-<html xmlns = "http://www.w3.org/1999/xhtml">
-
-<head>
- <title>NDN Request Example</title>
- <script type="text/javascript" src="java_socket_bridge.js"></script>
-
- <script type="text/javascript" src="CCNProtocolDTags.js"></script>
-
- <script type="text/javascript" src="CCNTime.js"></script>
-
- <script type="text/javascript" src="ContentName.js"></script>
-
- <script type="text/javascript" src="ContentObject.js"></script>
-
- <script type="text/javascript" src="DateFormat.js"></script>
-
- <script type="text/javascript" src="Exclude.js"></script>
-
- <script type="text/javascript" src="ExcludeAny.js"></script>
-
- <script type="text/javascript" src="ExcludeComponent.js"></script>
-
- <script type="text/javascript" src="Interest.js"></script>
-
- <script type="text/javascript" src="KeyLocator.js"></script>
-
- <script type="text/javascript" src="KeyName.js"></script>
-
- <script type="text/javascript" src="PublisherID.js"></script>
-
- <script type="text/javascript" src="Signature.js"></script>
-
- <script type="text/javascript" src="SignedInfo.js"></script>
-
- <script type="text/javascript" src="PublisherPublicKeyDigest.js"></script>
-
- <script type="text/javascript" src="FaceInstance.js"></script>
-
- <script type="text/javascript" src="ForwardingEntry.js"></script>
-
- <script type="text/javascript" src="encoding/BinaryXMLEncoder.js"></script>
-
- <script type="text/javascript" src="encoding/BinaryXMLCodec.js"></script>
-
- <script type="text/javascript" src="encoding/BinaryXMLDecoder.js"></script>
-
- <script type="text/javascript" src="encoding/DataUtils.js"></script>
-
- <script language="JavaScript" type="text/javascript" src="security/KeyManager.js"></script>
-
- <script language="JavaScript" type="text/javascript" src="securityLib/jsbn.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/jsbn2.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/rsa.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/rsa2.js"></script>
-
- <script language="JavaScript" type="text/javascript" src="securityLib/sha1.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/sha256.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/sha512.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/md5.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/ripemd160.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/base64.js"></script>
-
- <script language="JavaScript" type="text/javascript" src="securityLib/rsapem-1.1.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/rsasign-1.2.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/asn1hex-1.1.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/x509-1.1.js"></script>
-
-
- <script type="text/javascript">
- function run(){
-
- var ContentName = document.getElementById('contentname').value;
-
- var Content = document.getElementById('content').value;
-
- //createRoute('borges.metwi.ucla.edu', 9695);
-
- createRoute('localhost', 9695);
-
- registerPrefix(ContentName, Content);
-
-
-
- ///////////////////////////////////////
- //createRoute('localhost', 9695);
-
- //createRoute('131.179.141.15', 9695);
- //createRoute('borges.metwi.ucla.edu', 9695);
-
- //content object
- //var co = queryPrefix( ContentName );
-
-
-
- ///////////////////////////////////////
-
- /*var output ="";
-
- if(co==-1)
- output+= "NO CONTENT FOUND"
- else if (co==-2)
- output+= "CONTENT NAME IS EMPTY"
- else{
- if(co.Name!=null && co.Name.Components!=null){
- output+= "NAME: ";
-
- for(var i=0;i<co.Name.Components.length;i++){
- output+= "/"+ toString(co.Name.Components[i]);
- }
- output+= "<br />";
- output+= "<br />";
- }
-
- if(co.Content !=null){
- output += "CONTENT(ASCII): "+ toString(co.Content);
-
- output+= "<br />";
- output+= "<br />";
- }
- if(co.Content !=null){
- output += "CONTENT(hex): "+ toHex(co.Content);
-
- output+= "<br />";
- output+= "<br />";
- }
- if(co.Signature !=null && co.Signature.Signature!=null){
-
- output += "SIGNATURE(hex): "+ toHex(co.Signature.Signature);
-
- output+= "<br />";
- output+= "<br />";
- }
- if(co.SignedInfo!=null && co.SignedInfo.Locator!=null && co.SignedInfo.Locator.Key!=null){
-
- output += "PUBLISHER KEY: "+ toHex(co.SignedInfo.Locator.Key);
-
- output+= "<br />";
- output+= "<br />";
-
- }
- }*/
-
- //document.getElementById('result').innerHTML = output;
- document.getElementById('result').innerHTML = 'Content \'' + Content + '\' was published with content name \'' + ContentName +'\'';
-
- }
-
- </script>
-
-</head>
-<body >
- <form>
-
- Please Enter a Content Name:<br />
-
- <input id="contentname" type="text" name="CONTENTNAME" value="/PARC/abc" />
-
- Please Enter the Content:<br />
-
- <textarea id="content" cols="40" rows="5" name="CONTENT" value="SUCCESS" >SUCCESS!</textarea>
-
- <br />
- </form>
- <button onclick="run()">Publish</button>
- <div >
- <applet id="JavaSocketBridge" archive="JavaSocketBridge.jar" code="JavaSocketBridge.class" width="0" height="0">
- </applet>
- </div>
-
- <p id="result"></p>
-
-</body>
-</html>
\ No newline at end of file
diff --git a/js/test-request-data.html b/js/test-request-data.html
deleted file mode 100644
index 582e7ea..0000000
--- a/js/test-request-data.html
+++ /dev/null
@@ -1,285 +0,0 @@
-<?xml version = "1.0" encoding="utf-8" ?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
-"DTD/xhtml1-strict.dtd">
-<html xmlns = "http://www.w3.org/1999/xhtml">
-
-<head>
- <title>NDN Request Example</title>
- <script type="text/javascript" src="java_socket_bridge.js"></script>
-
- <script type="text/javascript" src="CCNProtocolDTags.js"></script>
-
- <script type="text/javascript" src="CCNTime.js"></script>
-
- <script type="text/javascript" src="ContentName.js"></script>
-
- <script type="text/javascript" src="ContentObject.js"></script>
-
- <script type="text/javascript" src="DateFormat.js"></script>
-
- <script type="text/javascript" src="Exclude.js"></script>
-
- <script type="text/javascript" src="ExcludeAny.js"></script>
-
- <script type="text/javascript" src="ExcludeComponent.js"></script>
-
- <script type="text/javascript" src="Interest.js"></script>
-
- <script type="text/javascript" src="KeyLocator.js"></script>
-
- <script type="text/javascript" src="KeyName.js"></script>
-
- <script type="text/javascript" src="PublisherID.js"></script>
-
- <script type="text/javascript" src="Signature.js"></script>
-
- <script type="text/javascript" src="SignedInfo.js"></script>
-
- <script type="text/javascript" src="PublisherPublicKeyDigest.js"></script>
-
- <script type="text/javascript" src="FaceInstance.js"></script>
-
- <script type="text/javascript" src="ForwardingEntry.js"></script>
-
-
- <script type="text/javascript" src="encoding/BinaryXMLEncoder.js"></script>
-
- <script type="text/javascript" src="encoding/BinaryXMLCodec.js"></script>
-
- <script type="text/javascript" src="encoding/BinaryXMLDecoder.js"></script>
-
- <script type="text/javascript" src="encoding/DataUtils.js"></script>
-
- <script language="JavaScript" type="text/javascript" src="security/KeyManager.js"></script>
-
- <script language="JavaScript" type="text/javascript" src="securityLib/jsbn.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/jsbn2.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/rsa.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/rsa2.js"></script>
-
- <script language="JavaScript" type="text/javascript" src="securityLib/sha1.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/sha256.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/sha512.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/md5.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/ripemd160.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/base64.js"></script>
-
- <script language="JavaScript" type="text/javascript" src="securityLib/rsapem-1.1.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/rsasign-1.2.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/asn1hex-1.1.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/x509-1.1.js"></script>
-
- <script type="text/javascript">
- function run(){
- //console.log(unescape('%04%82%02%AA%03%B2%08%85H%8EY%0C%94p%F1-%C5%E2%23lW%19%8B%0D%25%81%8D%DEBeNX%BA%0D%D0%10W%7D%BA%9F%C6%8C%2AU%BC%B8%BA%5E%F3%D1l%CDmJ%EE%C4%9D%21%0F%0Djhm%1Ah%86P%D91x%26%AC%B8%8Co%C1%CF%29.l6Mc%B4%DC%C8%D4%86%97%8F%D2%1A%7C%A2%ED%93%89%F3%E9%9D%3C%E0%D4%90%28%D4%11%A2%5D%08%EB%A4%AF%96j%15%A5s%C8%D2Jr%96q%0F%87%7F%D5%D7%B3%D3T%96%F3%16L%00%00%F2%00%01%A2%03%E2%02%85%20Ht%04Z%9F%AC%98%EB%B7%DF%AD%C4%BB%D1%AB%15%A6%E4%06SI%C6%C8%3A%84%60%84N%AB1%85%00%02%BA%B5%04%FA%C3%F9%D7%97%00%01%E2%01%DA%0A%950%81%9F0%0D%06%09%2A%86H%86%F7%0D%01%01%01%05%00%03%81%8D%000%81%89%02%81%81%00%BD%95eU%9C%17%95%C0I%A5%EFM%C9%D1%BC%8B%98%1Bf%09~%A2S%F5%D0%F5%0F%1A%1D%F9%08%ACNi%A7%97%DA%DD%2C%05%90%94Jn%84%9E%1F%BBsq%C5%3D%FD%DB%E7%80%26V%E1%D5%F4I%B8S%0D%9C%7D%A8%D6%AB%EB%D9%0E%06%12M%92%7F%2FlW%21%F1%D0%E4%9E%7Fj%11g%CA%F9%60%D9o%F5%AF%AA-%25g3wr%A9D%C8%E6%CE%B8Y%B2Z%23%1D%9E%CA%875t%FF%98%22%5C%85%3F8%EF%02%03%01%00%01%00%00%00%01%9A%06%8D%05%82%04%CA%BEnewface%00%03%E2%02%85%E0%A0%1E%099h%F9t%0C%E7%F46%1B%AB%F5%BB%05%A4%E5Z%AC%A5%E5%8Fs%ED%DE%B8%E0%13%AA%8F%00%04%D2%8E0%00%04%DA%9617%00%04%E2%CE127.0.0.1%00%04%EA%A69695%00%03%D2%D62147483647%00%00%00%00'));
-
- //var a = escape('%04%82%02%AA%03%B2%08%85L%90%D5X%2C%B06wHi%C5%E2%1C%03%D2M%5DB%BF%A5%8C%C8%E8g%99%EB%A7%84%25l%8EB%92%3E%AA%D8%F6%85t%FF%BB%CE%3D%B1%F4%F8%27%A7%1D.%B0%EEU%A6%06%AB%CD%1F3%C6W%93%A9%10X%28-7%7CW%D4%E4%8A3%CF%2B%E4%95%D6%B2%1D%3B%7C%E8%7C%88%7D%7B%F5%80%BC%F7%28%3A%FC%F5w%5B%8C%24%0E%0A%24%DBk%9B%8D%B5%28d%D0A%1E%BEq%0F%0Cc%DB%15%B6%26%1B%E7%E3%E3XL%00%00%F2%00%01%A2%03%E2%02%85%20Ht%04Z%9F%AC%98%EB%B7%DF%AD%C4%BB%D1%AB%15%A6%E4%06SI%C6%C8%3A%84%60%84N%AB1%85%00%02%BA%B5%04%FA%C4%C7%D3I%00%01%E2%01%DA%0A%950%81%9F0%0D%06%09%2A%86H%86%F7%0D%01%01%01%05%00%03%81%8D%000%81%89%02%81%81%00%BD%95eU%9C%17%95%C0I%A5%EFM%C9%D1%BC%8B%98%1Bf%09~%A2S%F5%D0%F5%0F%1A%1D%F9%08%ACNi%A7%97%DA%DD%2C%05%90%94Jn%84%9E%1F%BBsq%C5%3D%FD%DB%E7%80%26V%E1%D5%F4I%B8S%0D%9C%7D%A8%D6%AB%EB%D9%0E%06%12M%92%7F%2FlW%21%F1%D0%E4%9E%7Fj%11g%CA%F9%60%D9o%F5%AF%AA-%25g3wr%A9D%C8%E6%CE%B8Y%B2Z%23%1D%9E%CA%875t%FF%98%22%5C%85%3F8%EF%02%03%01%00%01%00%00%00%01%9A%06%8D%05%82%04%CA%BEnewface%00%03%E2%02%85%E0%A0%1E%099h%F9t%0C%E7%F46%1B%AB%F5%BB%05%A4%E5Z%AC%A5%E5%8Fs%ED%DE%B8%E0%13%AA%8F%00%04%D2%8E0%00%04%DA%9617%00%04%E2%CE127.0.0.1%00%04%EA%A69695%00%03%D2%D62147483647%00%00%00%00');
-
- //var n = a.replace("%","");
-
- //console.log(n);
-
- var ContentName = document.getElementById('contentname').value;
-
- ///////////////////////////////////////
- createRoute('localhost', 9695);
-
-
- /// /ndn/ucla.edu/apps/hydra/mainvideo
- //createRoute('131.179.141.15', 9695);
- //createRoute('borges.metwi.ucla.edu', 9695);
-
- //content object
- var co = queryPrefix( ContentName );
-
- var coSize = getContentObjectSize(co);
-
- document.getElementById('coSize').innerHTML = coSize;
-
- ///////////////////////////////////////
-
- var output ="";
-
- if(co==-1)
- output+= "NO CONTENT FOUND"
- else if (co==-2)
- output+= "CONTENT NAME IS EMPTY"
- else{
- output += "Content: " + toString(toHex(co));
- output+="<br />";
- output+= "<br />";
-
- if(co.Name!=null && co.Name.Components!=null){
- output+= "NAME: ";
-
- for(var i=0;i<co.Name.Components.length;i++){
- output+= "/"+ toString(co.Name.Components[i]);
- }
- output+= "<br />";
- output+= "<br />";
- }
-
- if(co.Content !=null){
- output += "CONTENT(ASCII): "+ toString(co.Content);
-
- output+= "<br />";
- output+= "<br />";
- }
- if(co.Content !=null){
- output += "CONTENT(hex): "+ toHex(co.Content);
-
- output+= "<br />";
- output+= "<br />";
- }
-
- if(co.Signature !=null && co.Signature.Signature!=null){
-
- output += "SIGNATURE(hex): "+ toHex(co.Signature.Signature);
-
- output+= "<br />";
- output+= "<br />";
- }
- if(co.SignedInfo !=null && co.SignedInfo.Publisher!=null && co.SignedInfo.Publisher.PublisherPublicKeyDigest!=null){
-
- output += "Publisher Public Key Digest: " + co.SignedInfo.Publisher.PublisherPublicKeyDigest + "<br />";
- output += "Publisher Public Key Digest(hex): "+ toHex(co.SignedInfo.Publisher.PublisherPublicKeyDigest);
-
- output+= "<br />";
- output+= "<br />";
- }
- if(co.SignedInfo !=null && co.SignedInfo.Timestamp!=null){
-
- output += "TimeStamp(hex): "+ co.SignedInfo.Timestamp.date;
-
- output+= "<br />";
- output+= "<br />";
- }
- if(co.SignedInfo!=null && co.SignedInfo.Locator!=null && co.SignedInfo.Locator.PublicKey!=null){
-
- var publickey = rstr2b64(toString(co.SignedInfo.Locator.PublicKey));
- var publickeyHex = toHex(co.SignedInfo.Locator.PublicKey).toLowerCase();
- var publickeyString = toString(co.SignedInfo.Locator.PublicKey);
-
- var signature = toHex(co.Signature.Signature).toLowerCase();
-
-
- var input = toString(co.rawSignatureData);
-
- var inputBis = toString(co.rawSignatureData.slice(0,co.rawSignatureData.length-2).concat([0]));
-
- console.log("Input bis: ", toHex(co.rawSignatureData.slice(0,co.rawSignatureData.length-2).concat([0])));
-
- if(LOG>2) console.log("Input: ", toHex(co.rawSignatureData), "; raw signature data: ", co.rawSignatureData, "; to hex: ", toHex(co.rawSignatureData));
-
-
- output += "DER Certificate: "+publickey ;
-
- output+= "<br />";
- output+= "<br />";
-
-
-
- if(LOG>2) console.log(" ContentName + SignedInfo + Content = "+input);
- if(LOG>2) console.log(" PublicKey = "+publickey );
- if(LOG>2) console.log(" PublicKeyHex = "+publickeyHex );
- if(LOG>2) console.log(" PublicKeyString = "+publickeyString );
-
- if(LOG>2) console.log(" Signature "+signature );
- if(LOG>2) console.log(" Signature NOW IS" );
- if(LOG>2) console.log(co.Signature.Signature);
-
-
- /*var x509 = new X509();
-
- x509.readCertPEM(publickey);
-
-
- //x509.readCertPEMWithoutRSAInit(publickey);
-
- var result = x509.subjectPublicKeyRSA.verifyString(input, signature);*/
- //console.log('result is '+result);
-
-
- var kp = publickeyHex.slice(56,314);
-
- output += "PUBLISHER KEY(hex): "+kp ;
-
- output+= "<br />";
- output+= "<br />";
-
- console.log('kp is '+kp);
-
- var exp = publickeyHex.slice(318,324);
-
- console.log('kp size is '+kp.length );
- output += "exponent: "+exp ;
-
- output+= "<br />";
- output+= "<br />";
-
- console.log('exp is '+exp);
-
- var rsakey = new RSAKey();
- rsakey.setPublic(kp,exp);
- var result = rsakey.verifyString(input, signature);
-
- var resultBis = rsakey.verify(inputBis, signature);
-
- console.log("result bis: ", resultBis);
-
- //var inputBis = toHex(co.Name).concat(toHex(co.SignedInfo), toHex(co.Content));
-
-// if(LOG>0){
-// console.log("Input: ", input);
-// console.log("Input bis: ", inputBis);
-// console.log("Verify input bis: ", rsakey.verifyString(inputBis, signature));
-// }
-
- //var x509 = new X509();
- //x509.readCertPEM(publickey);
- //if(LOG>0) console.log("x509 verif: ", x509.subjectPublicKeyRSA.verifyString(input, signature));
-
- if(result)
- output += 'SIGNATURE VALID';
- else
- output += 'SIGNATURE INVALID';
-
-
-
-
- //output += "VALID: "+ toHex(co.SignedInfo.Locator.PublicKey);
-
- output+= "<br />";
- output+= "<br />";
-
-
- if(LOG>4) console.log('str'[1]);
- }
- }
-
- document.getElementById('result').innerHTML = output;
- }
-
- </script>
-
-</head>
-<body >
- <form>
- Please Enter a Content Name:<br /><input id="contentname" type="text" name="CONTENTNAME" value="/PARC/abc" /> <br />
- </form>
- <div>
- <button onclick="run()">Request Data!</button>
- </div>
- <div >
- <applet id="JavaSocketBridge" archive="JavaSocketBridge.jar" code="JavaSocketBridge.class" width="0" height="0">
- </applet>
- </div>
-
- <div>
- <p>Size: <span id="coSize"></span></p>
-
- <p id="result"></p>
-
- </div>
-</body>
-</html>
\ No newline at end of file
diff --git a/js/test-sha256.html b/js/test-sha256.html
deleted file mode 100644
index 3d9055c..0000000
--- a/js/test-sha256.html
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version = "1.0" encoding="utf-8" ?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
-"DTD/xhtml1-strict.dtd">
-<html xmlns = "http://www.w3.org/1999/xhtml">
-
-<head>
- <title>NDN Request Example</title>
- <script language="JavaScript" type="text/javascript" src="securityLib/jsbn.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/jsbn2.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/rsa.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/rsa2.js"></script>
-
- <script language="JavaScript" type="text/javascript" src="securityLib/sha1.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/sha256.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/sha512.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/md5.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/ripemd160.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/base64.js"></script>
-
- <script language="JavaScript" type="text/javascript" src="securityLib/rsapem-1.1.min.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/rsasign-1.2.min.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/asn1hex-1.1.min.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/x509-1.1.min.js"></script>
-
-
- <script type="text/javascript">
- function hash(){
-
- var input = document.getElementById('contentname').value;
-
- var output = hex_sha256(input);
-
- document.getElementById('result').innerHTML = output;
-
- }
-
- </script>
-
-
-</head>
-<body >
- <form>
-
-
-
- Please Enter a Text to sign:<br /><input id="contentname" type="text" name="CONTENTNAME" value="/PARC/abc" /> <br />
-
- </form>
- <button onclick="hash()">Hash</button>
-
- <p id="result"></p>
-
-</body>
-</html>
\ No newline at end of file
diff --git a/js/testing/image-loader.html b/js/testing/image-loader.html
new file mode 100644
index 0000000..29f908c
--- /dev/null
+++ b/js/testing/image-loader.html
@@ -0,0 +1,110 @@
+<?xml version = "1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"DTD/xhtml1-strict.dtd">
+<html xmlns = "http://www.w3.org/1999/xhtml">
+
+<head>
+ <title>NDN Image Loader</title>
+ <script type="text/javascript" src="../java_socket_bridge.js"></script>
+
+ <script type="text/javascript" src="../util/CCNProtocolDTags.js"></script>
+
+ <script type="text/javascript" src="../util/CCNTime.js"></script>
+
+ <script type="text/javascript" src="../Name.js"></script>
+
+ <script type="text/javascript" src="../ContentObject.js"></script>
+
+ <script type="text/javascript" src="../encoding/DateFormat.js"></script>
+
+ <script type="text/javascript" src="../Interest.js"></script>
+
+ <script type="text/javascript" src="../Key.js"></script>
+
+ <script type="text/javascript" src="../PublisherID.js"></script>
+
+ <script type="text/javascript" src="../PublisherPublicKeyDigest.js"></script>
+
+ <script type="text/javascript" src="../FaceInstance.js"></script>
+
+ <script type="text/javascript" src="../ForwardingEntry.js"></script>
+
+
+ <script type="text/javascript" src="../encoding/BinaryXMLEncoder.js"></script>
+
+ <script type="text/javascript" src="../encoding/BinaryXMLDecoder.js"></script>
+
+ <script type="text/javascript" src="../encoding/DataUtils.js"></script>
+
+ <script type="text/javascript" src="../encoding/EncodingUtils.js"></script>
+
+ <script type="text/javascript" src="../NDN.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../security/KeyManager.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/jsbn.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/jsbn2.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsa.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsa2.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha256.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha512.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/md5.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/ripemd160.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/base64.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsapem-1.1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsasign-1.2.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/asn1hex-1.1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/x509-1.1.js"></script>
+
+ <script type="text/javascript">
+ var loadedImageString = "";
+ var connector = new NDN();
+ var pieceNumber = 0;
+ var count = 0;
+ var end = false;
+ var LOG = 0;
+ var pieceSize = 1000;
+
+
+ function getPiece(){
+ if(!pieceNumber) pieceNumber = 0;
+ var contentName = "/image/piece" + pieceNumber;
+ var co = connector.get( contentName );
+
+ if(co){
+ loadedImageString += DataUtils.toString(co.content);
+ console.log("Received length: " + co.content.length);
+ if(co.content.length == pieceSize){
+ pieceNumber += co.content.length;
+ getPiece();
+ }
+ else document.getElementById('image').src += loadedImageString;
+ }
+ }
+
+
+
+
+
+ </script>
+
+</head>
+<body >
+ <div>
+ <button onclick="getPiece()">Get image</button>
+ </div>
+ <div >
+ <applet id="JavaSocketBridge" archive="../JavaSocketBridge.jar" code="JavaSocketBridge.class" width="0" height="0">
+ </applet>
+ </div>
+
+ <p id="result"></p>
+ <div>
+ <img id="image" src="data:image/png;base64," alt="Image placeholder" />
+ </div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/js/testing/image-sender.html b/js/testing/image-sender.html
new file mode 100644
index 0000000..fea94c7
--- /dev/null
+++ b/js/testing/image-sender.html
@@ -0,0 +1,155 @@
+<?xml version = "1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"DTD/xhtml1-strict.dtd">
+<html xmlns = "http://www.w3.org/1999/xhtml">
+
+<head>
+ <title>NDN Image Sender</title>
+ <script type="text/javascript" src="../java_socket_bridge.js"></script>
+
+ <script type="text/javascript" src="../util/CCNProtocolDTags.js"></script>
+
+ <script type="text/javascript" src="../util/CCNTime.js"></script>
+
+ <script type="text/javascript" src="../Name.js"></script>
+
+ <script type="text/javascript" src="../ContentObject.js"></script>
+
+ <script type="text/javascript" src="../encoding/DateFormat.js"></script>
+
+ <script type="text/javascript" src="../Interest.js"></script>
+
+ <script type="text/javascript" src="../Key.js"></script>
+
+ <script type="text/javascript" src="../PublisherID.js"></script>
+
+ <script type="text/javascript" src="../PublisherPublicKeyDigest.js"></script>
+
+ <script type="text/javascript" src="../FaceInstance.js"></script>
+
+ <script type="text/javascript" src="../ForwardingEntry.js"></script>
+
+ <script type="text/javascript" src="../encoding/BinaryXMLEncoder.js"></script>
+
+ <script type="text/javascript" src="../encoding/BinaryXMLDecoder.js"></script>
+
+ <script type="text/javascript" src="../encoding/DataUtils.js"></script>
+
+ <script type="text/javascript" src="../encoding/EncodingUtils.js"></script>
+
+ <script type="text/javascript" src="../NDN.js"></script>
+
+
+ <script language="JavaScript" type="text/javascript" src="../security/KeyManager.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/jsbn.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/jsbn2.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsa.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsa2.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha256.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha512.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/md5.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/ripemd160.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/base64.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsapem-1.1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsasign-1.2.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/asn1hex-1.1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/x509-1.1.js"></script>
+
+
+ <script type="text/javascript">
+ //var imageString = "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";
+ //var imageString = "iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9YGARc5KB0XV+IAAAAddEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIFRoZSBHSU1Q72QlbgAAAF1JREFUGNO9zL0NglAAxPEfdLTs4BZM4DIO4C7OwQg2JoQ9LE1exdlYvBBeZ7jqch9//q1uH4TLzw4d6+ErXMMcXuHWxId3KOETnnXXV6MJpcq2MLaI97CER3N0vr4MkhoXe0rZigAAAABJRU5ErkJggg==";
+ var imageString = "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"
+ //var imageString = "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";
+ var connector = null;
+ var loadedImageString = "";
+ var LOG = 0;
+
+ function init(){
+ connector = new NDN();
+ }
+
+ function run(){
+
+ var ContentName = document.getElementById('contentname').value;
+
+ var Content = document.getElementById('content').value;
+
+ //createRoute('borges.metwi.ucla.edu', 9695);
+
+
+
+
+ ///////////////////////////////////////
+ //createRoute('localhost', 9695);
+
+ //createRoute('131.179.141.15', 9695);
+ //createRoute('borges.metwi.ucla.edu', 9695);
+
+ //content object
+ //var co = queryPrefix( Name );
+
+ var connector = new NDN();
+
+ var co = connector.put( ContentName, Content );
+
+ ///////////////////////////////////////
+
+
+
+ document.getElementById('result').innerHTML = 'Content \'' + Content + '\' was published with content name \'' + ContentName +'\'';
+
+ }
+
+ function publishImage(){
+ init();
+ var count = 1000;
+ for(var i=0; i < imageString.length; i+=count){
+ console.log("Publish substring: " + i + "; " + Math.min(count, imageString.length - i));
+ const k = i + 0;
+
+ var pubSub = function(y){
+ return function(){ publishSubstring(y, Math.min(count, imageString.length - y));}
+ }(i);
+
+ setTimeout(pubSub, 500);
+
+ loadedImageString += imageString.substr(i, Math.min(count, imageString.length - i));
+ }
+ document.getElementById("image").src += loadedImageString;
+
+ }
+
+ function publishSubstring(beginning, length){
+ var ContentName = "/image/piece" + beginning;
+ var Content = imageString.substr(beginning, length);
+ console.log(beginning + "; " + length);
+ var co = connector.put(ContentName, Content);
+ //document.getElementById('result').innerHTML += 'Content \'' + Content + '\' was published with content name \'' + Name +'\'';
+
+ }
+
+ </script>
+
+</head>
+<body >
+ <div>
+ <button onclick="publishImage()">Publish image</button>
+ </div>
+ <div >
+ <applet id="JavaSocketBridge" archive="../JavaSocketBridge.jar" code="JavaSocketBridge.class" width="0" height="0">
+ </applet>
+ </div>
+
+ <div>
+ <img id="image" src="data:image/png;base64," alt="Image placeholder" />
+ </div>
+
+ <p id="result"></p>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/js/testing/test-connection.html b/js/testing/test-connection.html
new file mode 100644
index 0000000..5829b45
--- /dev/null
+++ b/js/testing/test-connection.html
@@ -0,0 +1,113 @@
+<?xml version = "1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"DTD/xhtml1-strict.dtd">
+<html xmlns = "http://www.w3.org/1999/xhtml">
+
+<head>
+ <title>Test Connection</title>
+ <script type="text/javascript" src="../java_socket_bridge.js"></script>
+
+ <script type="text/javascript" src="../util/CCNProtocolDTags.js"></script>
+
+ <script type="text/javascript" src="../util/CCNTime.js"></script>
+
+ <script type="text/javascript" src="../Name.js"></script>
+
+ <script type="text/javascript" src="../ContentObject.js"></script>
+
+ <script type="text/javascript" src="../encoding/DateFormat.js"></script>
+
+ <script type="text/javascript" src="../Interest.js"></script>
+
+ <script type="text/javascript" src="../Key.js"></script>
+
+ <script type="text/javascript" src="../PublisherID.js"></script>
+
+ <script type="text/javascript" src="../PublisherPublicKeyDigest.js"></script>
+
+ <script type="text/javascript" src="../FaceInstance.js"></script>
+
+ <script type="text/javascript" src="../ForwardingEntry.js"></script>
+
+
+ <script type="text/javascript" src="../encoding/BinaryXMLEncoder.js"></script>
+
+ <script type="text/javascript" src="../encoding/BinaryXMLDecoder.js"></script>
+
+ <script type="text/javascript" src="../encoding/DataUtils.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../security/KeyManager.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/jsbn.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/jsbn2.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsa.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsa2.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha256.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha512.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/md5.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/ripemd160.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/base64.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsapem-1.1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsasign-1.2.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/asn1hex-1.1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/x509-1.1.js"></script>
+
+ <script type="text/javascript">
+
+ function getAction(){
+ console.log('ABOUT TO GET');
+
+ // Interest for "/"
+ var hex = '01d2f20000';
+ var received = get('127.0.0.1', 9695, hex);
+
+ var output= '<br /> received Content: <br/>' + received;
+
+ console.log('INTEREST RECEIVED '+ received);
+
+ document.getElementById('result').innerHTML = output;
+
+ }
+
+
+ function putAction(){
+ console.log('ABOUT TO PUT');
+
+ var hex = '01d2f2faa563636e7800fa0285e0290233a1f9da00a6b0db63b910379f6d98edd2b5ea7b0044109923286e6aaa00fabd73656c6672656700fa1a95048202aa03b20885a4024a492e588eade1bb1f94c151a617a41dde3d571d94ea1ac9d3c77f4c9f0ed5700c9722b3497124f3003320e346a2dead367b92a53bb087298023b0ac15584d3dcfb51482b6f458f24d37d46095c97b708aacaabd3fdfa981a86bd4831b2596b1ac23faa3ac6dcf3cb324dea96bc3d75aee7f1d6178ed82a09d5f31c6fa800000f20001a203e20285b5506b1aba3da7761b0f8d61a4aa7e3b6d15b426feb5bda82389aca765a3b81c0002bab505068dba9ba20001e201da0a9530819f300d06092a864886f70d010101050003818d0030818902818100e17d30a7d828ab1b840b17542dcaf6207afd221e086b2a60d16cb7f54448ba9f3f08bcd099db21dd162a779e61aa89eee554d3a47de230bc7ac590d524067c3898bba6f5dc4360b845eda48cbd9cf126a723445f0e1952d7325a75faf556144f9a98af7186b0278685b8e2c08bea87171b4dee585c1828295b5395eb4a17779f0203010001000000019a03a5058a04cabe73656c6672656700f2faa564656d6f00fabd6d657373616765000004fa8e330003d2d63231343734383336343700000000000002d28e310000';
+ var name = '/demo/message';
+ // Signed content of "It works!".
+ outputHex = '048202aa03b20885c8762b14c1df125229ecc88ff5080d042a2de01cd0b8e4357af88cff993c0c78c9774ebaf00bebfa2699ae81412fe03a155291981f3c914f2bc075446bb3dafce0314a40bc4c93890c6663da80b7798b66d97be6ddbee58ca30761d28b46ce3ac058b1fbbab7fad981626de954c54c09d68ebb8a18d31a4e1fb970677fb43f180000f2faa564656d6f00fabd6d657373616765000001a203e20285b5506b1aba3da7761b0f8d61a4aa7e3b6d15b426feb5bda82389aca765a3b81c0002bab505068dbab1f00001e201da0a9530819f300d06092a864886f70d010101050003818d0030818902818100e17d30a7d828ab1b840b17542dcaf6207afd221e086b2a60d16cb7f54448ba9f3f08bcd099db21dd162a779e61aa89eee554d3a47de230bc7ac590d524067c3898bba6f5dc4360b845eda48cbd9cf126a723445f0e1952d7325a75faf556144f9a98af7186b0278685b8e2c08bea87171b4dee585c1828295b5395eb4a17779f0203010001000000019add5468697320776f726b73210000';
+
+ var received = put('127.0.0.1', 9695, hex, name, outputHex);
+
+ var output= '<br /> received Content: <br/>' + received;
+
+ document.getElementById('result').innerHTML = output;
+
+ }
+
+
+ </script>
+
+</head>
+<body >
+
+ <form>
+ Press Buttons:<br /><!-- input id="contentname" type="text" name="CONTENTNAME" value="/PARC/abc" /--> <br />
+ </form>
+
+ <button onclick="putAction()">PUT!</button>
+ <button onclick="getAction()">GET!</button>
+
+ <div >
+ <applet id="JavaSocketBridge" archive="../JavaSocketBridge.jar" code="JavaSocketBridge.class" width="0" height="0">
+ </applet>
+ </div>
+
+ <p id="result"></p>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/js/testing/test-decode-FaceInstance.html b/js/testing/test-decode-FaceInstance.html
new file mode 100644
index 0000000..e82003a
--- /dev/null
+++ b/js/testing/test-decode-FaceInstance.html
@@ -0,0 +1,155 @@
+<?xml version = "1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"DTD/xhtml1-strict.dtd">
+<html xmlns = "http://www.w3.org/1999/xhtml">
+
+<head>
+ <title>NDN Decode Face Instance</title>
+
+ <script type="text/javascript" src="../java_socket_bridge.js"></script>
+
+ <script type="text/javascript" src="../util/CCNProtocolDTags.js"></script>
+
+ <script type="text/javascript" src="../util/CCNTime.js"></script>
+
+ <script type="text/javascript" src="../Name.js"></script>
+
+ <script type="text/javascript" src="../ContentObject.js"></script>
+
+ <script type="text/javascript" src="../encoding/DateFormat.js"></script>
+
+ <script type="text/javascript" src="../Interest.js"></script>
+
+ <script type="text/javascript" src="../Key.js"></script>
+
+ <script type="text/javascript" src="../PublisherID.js"></script>
+
+ <script type="text/javascript" src="../PublisherPublicKeyDigest.js"></script>
+
+ <script type="text/javascript" src="../FaceInstance.js"></script>
+
+ <script type="text/javascript" src="../ForwardingEntry.js"></script>
+
+ <script type="text/javascript" src="../encoding/BinaryXMLEncoder.js"></script>
+
+ <script type="text/javascript" src="../encoding/BinaryXMLDecoder.js"></script>
+
+ <script type="text/javascript" src="../encoding/DataUtils.js"></script>
+
+ <script type="text/javascript" src="../encoding/EncodingUtils.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../security/KeyManager.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/jsbn.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/jsbn2.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsa.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsa2.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha256.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha512.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/md5.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/ripemd160.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/base64.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsapem-1.1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsasign-1.2.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/asn1hex-1.1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/x509-1.1.js"></script>
+
+ <script type="text/javascript">
+
+ function decode(){
+
+ var input = document.getElementById('result').innerHTML;
+
+
+ var faceInstance = decodeHexFaceInstance(input);
+
+ if(LOG>3)console.log('FACE INSTANCE DECODED');
+ if(LOG>3)console.log(faceInstance);
+
+ ///////////////////////////////////////
+
+ var output ="";
+
+ if(faceInstance.publisherPublicKeyDigest!=null ){
+ output+= "PublisherPublicKeyDigest: ";
+
+ output+= DataUtils.toHex(faceInstance.publisherPublicKeyDigest.publisherPublicKeyDigest);
+
+ //output+= "PUBLISHER ID TYPE: ";
+ //output+= faceInstance.publisherPublicKeyDigest.PublisherPublicKeyDigest;
+
+ output+= "<br />";
+ output+= "<br />";
+
+ }
+
+ if(faceInstance.faceID!=null){
+ output+= "FaceID: ";
+
+ output+= faceInstance.faceID;
+ output+= "<br />";
+ }
+
+ if(faceInstance.ipProto!=null){
+ output+= "IPProto: ";
+
+ output+= faceInstance.ipProto;
+ output+= "<br />";
+ }
+
+ if(faceInstance.host!=null){
+ output+= "Host: ";
+
+ output+= faceInstance.host;
+ output+= "<br />";
+ }
+
+ if(faceInstance.Port!=null){
+ output+= "Port: ";
+
+ output+= faceInstance.Port;
+ output+= "<br />";
+ }
+ if(faceInstance.freshnessSeconds!=null){
+ output+= "FreshnessSeconds: ";
+
+ output+= faceInstance.freshnessSeconds;
+ output+= "<br />";
+ }
+
+ /*if(interest.name!=null && interest.name.components!=null){
+ output+= "NAME: ";
+
+ for(var i=0;i<interest.Name.Components.length;i++){
+ output+= "/"+ DataUtils.toString(interest.Name.Components[i]);
+ }
+ output+= "<br />";
+ output+= "<br />";
+ }*/
+
+ document.getElementById('result').innerHTML = output;
+
+ }
+
+ </script>
+
+</head>
+<body >
+ <form>
+
+ Please Press Decode:<br />
+
+ <!-- input id="faceInstance" type="text" name="FACEINSTANCE" value="/PARC/abc" /-->
+
+ </form>
+ <button onclick="decode()">Decode</button>
+
+
+
+ <p id="result">058203e20285e0a01e093968f9740ce7f4361babf5bb05a4e55aaca5e58f73eddeb8e013aa8f0004d29632310004da9631370004e2c631302e312e312e310004eaa6393639350003d2d6323134373438333634370000</p>
+
+</body>
+</html>
diff --git a/js/testing/test-decode-Interest+Forwarding+Entry.html b/js/testing/test-decode-Interest+Forwarding+Entry.html
new file mode 100644
index 0000000..d9b5e03
--- /dev/null
+++ b/js/testing/test-decode-Interest+Forwarding+Entry.html
@@ -0,0 +1,460 @@
+<?xml version = "1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"DTD/xhtml1-strict.dtd">
+<html xmlns = "http://www.w3.org/1999/xhtml">
+
+<head>
+ <title>NDN Decode Interest + Face Instance</title>
+
+ <script type="text/javascript" src="../java_socket_bridge.js"></script>
+
+ <script type="text/javascript" src="../util/CCNProtocolDTags.js"></script>
+
+ <script type="text/javascript" src="../util/CCNTime.js"></script>
+
+ <script type="text/javascript" src="../Name.js"></script>
+
+ <script type="text/javascript" src="../ContentObject.js"></script>
+
+ <script type="text/javascript" src="../encoding/DateFormat.js"></script>
+
+ <script type="text/javascript" src="../Interest.js"></script>
+
+ <script type="text/javascript" src="../Key.js"></script>
+
+ <script type="text/javascript" src="../PublisherID.js"></script>
+
+ <script type="text/javascript" src="../PublisherPublicKeyDigest.js"></script>
+
+ <script type="text/javascript" src="../FaceInstance.js"></script>
+
+ <script type="text/javascript" src="../ForwardingEntry.js"></script>
+
+ <script type="text/javascript" src="../encoding/BinaryXMLEncoder.js"></script>
+
+ <script type="text/javascript" src="../encoding/BinaryXMLDecoder.js"></script>
+
+ <script type="text/javascript" src="../encoding/DataUtils.js"></script>
+
+ <script type="text/javascript" src="../encoding/EncodingUtils.js"></script>
+
+
+ <script language="JavaScript" type="text/javascript" src="../security/KeyManager.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/jsbn.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/jsbn2.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsa.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsa2.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha256.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha512.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/md5.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/ripemd160.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/base64.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsapem-1.1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsasign-1.2.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/asn1hex-1.1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/x509-1.1.js"></script>
+
+ <script type="text/javascript">
+
+
+
+ function decode(){
+
+ var input = document.getElementById('result').innerHTML;
+
+
+ var interest = decodeHexInterest(input);
+
+ if(LOG>3)console.log('INTEREST DECODED');
+ if(LOG>3)console.log(interest);
+
+ ///////////////////////////////////////
+
+ var output ="";
+
+
+ if(interest.name!=null && interest.name.components!=null){
+ output+= "NAME: ";
+
+ for(var i=0;i<interest.name.components.length;i++){
+ output+= "/"+ DataUtils.toString(interest.name.components[i]);
+ }
+ output+= "<br />";
+ output+= "<br />";
+ }
+
+ if(interest.faceInstance!=null ){
+ output+= "FaceInstance: ";
+
+ output+= interest.faceInstance;
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+
+ if(interest.exclude!=null ){
+ output+= "Exclude: ";
+
+ output+= interest.exclude;
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+
+ if(interest.childSelector!=null ){
+ output+= "ChildSelector: ";
+
+ output+= interest.childSelector;
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+
+ if(interest.answerOriginKind!=null ){
+ output+= "AnswerOriginKind: ";
+
+ output+= interest.answerOriginKind;
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+
+ if(interest.interestLifetime!=null ){
+ output+= "InterestLifetime: ";
+
+ output+= interest.interestLifetime;
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+
+ if(interest.nonce!=null ){
+ output+= "Nonce: ";
+
+ output+= interest.nonce;
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+
+
+ if(interest.scope!=null ){
+ output+= "SCOPE: ";
+
+ output+= interest.scope;
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+
+ if(interest.publisherPublicKeyDigest!=null ){
+ output+= "PUBLISHER PUBLIC KEY DIGEST: ";
+
+ output+= interest.publisherPublicKeyDigest.publisherPublicKeyDigest;
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+
+ if(interest.maxSuffixComponents!=null ){
+ output+= "MaxSuffixComponents : ";
+
+ output+= interest.maxSuffixComponents;
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+
+ if(interest.minSuffixComponents!=null ){
+ output+= "MinSuffixComponents : ";
+
+ output+= interest.minSuffixComponents;
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+
+ if(interest.name.components[3] !=null){
+
+
+ var input = DataUtils.toHex(interest.name.components[3]) ;
+
+ var contentObject = decodeHexContentObject(input);
+
+ if(contentObject.content!=null ){
+ output+= "Content of content Object: ";
+
+ output+= DataUtils.toHex(contentObject.content);
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+
+
+ var content = DataUtils.toHex(contentObject.content);
+
+ var co = contentObject;
+
+
+ ////////////////////////////////////////
+
+
+ if(co.name!=null && co.name.components!=null){
+ output+= "NAME: ";
+
+ for(var i=0;i<co.name.components.length;i++){
+ output+= "/"+ DataUtils.toString(co.name.components[i]);
+ }
+ output+= "<br />";
+ output+= "<br />";
+ }
+
+ if(co.content !=null){
+ output += "CONTENT(ASCII): "+ DataUtils.toString(co.content);
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+ if(co.content !=null){
+ output += "CONTENT(hex): "+ DataUtils.toHex(co.content);
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+ if(co.signature !=null && co.signature.signature!=null){
+
+ output += "SIGNATURE(hex): "+ DataUtils.toHex(co.signature.signature);
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+ if(co.signedInfo !=null && co.signedInfo.publisher!=null && co.signedInfo.publisher.publisherPublicKeyDigest!=null){
+
+ output += "Publisher Public Key Digest(hex): "+ DataUtils.toHex(co.signedInfo.publisher.publisherPublicKeyDigest);
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+ if(co.signedInfo !=null && co.signedInfo.timestamp!=null){
+ var d = new Date();
+ d.setTime( co.signedInfo.timestamp.msec );
+
+ var bytes = [217, 185, 12, 225, 217, 185, 12, 225];
+
+ output += "TimeStamp: "+d;
+ output+= "<br />";
+ output += "TimeStamp(number): "+ co.signedInfo.timestamp.msec;
+
+
+ output+= "<br />";
+ }
+ if(co.signedInfo !=null && co.signedInfo.type!=null){
+
+ output += "Type: "+co.signedInfo.type;
+ output+= "<br />";
+ output+= "<br />";
+ }
+ if(co.signedInfo !=null && co.signedInfo.locator!=null){
+
+ output += "Locator: "+co.signedInfo.locator.type;
+ output+= "<br />";
+ output+= "<br />";
+ }
+ if(co.signedInfo !=null && co.signedInfo.freshnessSeconds!=null){
+
+ output += "FreshnessSeconds: "+co.signedInfo.freshnessSeconds;
+ output+= "<br />";
+ output+= "<br />";
+ }
+ if(co.signedInfo !=null && co.signedInfo.finalBlockID!=null){
+
+ output += "FinalBlockID: "+co.signedInfo.finalBlockID;
+ output+= "<br />";
+ output+= "<br />";
+ }
+
+ if(co.signedInfo!=null && co.signedInfo.locator!=null && co.signedInfo.locator.publicKey!=null){
+
+ var publickey = rstr2b64(DataUtils.toString(co.signedInfo.locator.publicKey));
+ var publickeyHex = DataUtils.toHex(co.signedInfo.locator.publicKey).toLowerCase();
+ var publickeyString = DataUtils.toString(co.signedInfo.locator.publicKey);
+
+ var signature = DataUtils.toHex(co.signature.signature).toLowerCase();
+
+
+ var input = DataUtils.toString(co.rawSignatureData);
+
+
+ output += "DER Certificate: "+publickey ;
+
+ output+= "<br />";
+ output+= "<br />";
+
+
+
+ if(LOG>2) console.log(" ContentName + SignedInfo + Content = "+input);
+ if(LOG>2) console.log(" PublicKey = "+publickey );
+ if(LOG>2) console.log(" PublicKeyHex = "+publickeyHex );
+ if(LOG>2) console.log(" PublicKeyString = "+publickeyString );
+
+ if(LOG>2) console.log(" Signature "+signature );
+
+ if(LOG>2) console.log(" Signature NOW IS" );
+
+ if(LOG>2) console.log(co.signature.signature);
+
+
+ /*var x509 = new X509();
+
+ x509.readCertPEM(publickey);
+
+
+ //x509.readCertPEMWithoutRSAInit(publickey);
+
+ var result = x509.subjectPublicKeyRSA.verifyString(input, signature);*/
+ //console.log('result is '+result);
+
+
+ var kp = publickeyHex.slice(56,314);
+
+ output += "PUBLISHER KEY(hex): "+kp ;
+
+ output+= "<br />";
+ output+= "<br />";
+
+ console.log('PUBLIC KEY IN HEX is ');
+ console.log(kp);
+
+ var exp = publickeyHex.slice(318,324);
+
+ console.log('kp size is '+kp.length );
+ output += "exponent: "+exp ;
+
+ output+= "<br />";
+ output+= "<br />";
+
+ console.log('EXPONENT is ');
+ console.log(exp);
+
+
+
+ /*var c1 = hex_sha256(input);
+ var c2 = signature;
+
+ if(LOG>4)console.log('input is ');
+ if(LOG>4)console.log(input);
+ if(LOG>4)console.log('C1 is ');
+ if(LOG>4)console.log(c1);
+ if(LOG>4)console.log('C2 is ');
+ if(LOG>4)console.log(c2);
+ var result = c1 == c2;*/
+
+ var rsakey = new RSAKey();
+
+ rsakey.setPublic(kp,exp);
+
+ var result = rsakey.verifyString(input, signature);
+
+
+
+ console.log('PUBLIC KEY n after is ');
+ console.log(rsakey.n);
+
+ console.log('EXPONENT e after is ');
+ console.log(rsakey.e);
+
+
+ if(result)
+ output += 'SIGNATURE VALID';
+ else
+ output += 'SIGNATURE INVALID';
+
+ //output += "VALID: "+ toHex(co.signedInfo.locator.publicKey);
+
+ output+= "<br />";
+ output+= "<br />";
+
+
+ //if(LOG>4) console.log('str'[1]);
+ }
+
+ ////////////////////////////////////////
+
+
+ var forwardingEntry = decodeHexForwardingEntry(content);
+
+ if(LOG>3)console.log('FORWARDING ENTRY IS PRESENT');
+ if(LOG>3)console.log(forwardingEntry);
+
+ ///////////////////////////////////////
+
+ //var output ="";
+
+ if(forwardingEntry.action!=null ){
+ output+= "Action: ";
+
+ output+= DataUtils.toHex(forwardingEntry.action);
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+
+ if(forwardingEntry.prefixName!=null){
+ output+= "PrefixName: ";
+
+ output+= forwardingEntry.prefixName.getName();
+ output+= "<br />";
+ }
+
+ if(forwardingEntry.ccndID!=null){
+ output+= "ccndID: ";
+
+ output+= forwardingEntry.ccndID;
+ output+= "<br />";
+ }
+
+ if(forwardingEntry.flags!=null){
+ output+= "Flags: ";
+
+ output+= forwardingEntry.flags;
+ output+= "<br />";
+ }
+
+ if(forwardingEntry.lifetime!=null){
+ output+= "Lifetime: ";
+
+ output+= forwardingEntry.lifetime;
+ output+= "<br />";
+ }
+
+
+ }
+
+
+
+ document.getElementById('result').innerHTML = output;
+
+ }
+
+ </script>
+
+</head>
+<body >
+ <form>
+
+ Please Press Decode:<br />
+
+
+ </form>
+ <button onclick="decode()">Decode</button>
+
+ <!-- p id="result-old-from-ccnx">01d2f2faa563636e7800fa0285e0a01e093968f9740ce7f4361babf5bb05a4e55aaca5e58f73eddeb8e013aa8f00fabd73656c6672656700fa1bf5048202aa03b208854a18988c72aee624da28e2e1acbccb209b8e89429041985521ed68f95a1c546872fba3d854b1377dc249b6d8ec5935e5069256c97a7f6d8a62e86222ccd2cfe5097aed3fe5ede6732ce191a8680d78e39d0c5058a2b7bb0f0687994e9f045de346b66c46498547a08da1f2f0cdfafba3afdfe7107931935ede79040137ba94a90000f20001a203e202851a4860caa4991e829bcdc9429fb711d52440968d23560726606050bf147acffc0002bab504fcb3f03aa40001e201da0a9530819f300d06092a864886f70d010101050003818d00308189028181008ed27580e3d1c4c67672208665133a1ba12d8ebf5cad8e054571926b3ff0782a04c71703384021a6cefb6616b66cbd8a679b761d69d6373a851546e26f7105510b4c23be9a3c7f2e652e100ecc1471855730659f1477ce4e8504ad1fd8f44116baaeae2ff67eec33abba790157a79bf5039e5a528a471d9d67c94e70117ed7490203010001000000019a0585058a04cabe73656c6672656700f2faad726f63636f000003e20285e0a01e093968f9740ce7f4361babf5bb05a4e55aaca5e58f73eddeb8e013aa8f0004fa8e330003d2d63231343734383336343700000000000002d28e310000</p-->
+
+ <p id="result">01d2f2faa563636e7800fa0285e0a01e093968f9740ce7f4361babf5bb05a4e55aaca5e58f73eddeb8e013aa8f00facd70726566697872656700fa29ad048202aa03b208854ddbf69779cdf4ef74be99474478c8bc3ca0873e0ffa1fa60120aa276db122b83404e595a8a3caeaf09630276658ba4e7beaadb4b91a8cc58e19ac4a42289507ed8d609aa9bef61a5a507f349c83d2944b8c16fecfd90d4a40ddb8687592c0a57517564235b2e359db54f51a37e1ac39e518a2196e3ffda7eb2fb301f3c404dd0000f20001a203e20285ef7c4f5d4743a8b8586ea2e741b7fc39d1dc0dbe1b1930e787cfd1d833ea7a610002bab504fce9e253d70001e2018219fd3082019b30820104020900b7d85c906bad52ee300d06092a864886f70d010105050030123110300e060355040313076178656c636476301e170d3132303432383233343433375a170d3132303532383233343433375a30123110300e060355040313076178656c63647630819f300d06092a864886f70d010101050003818d0030818902818100e17d30a7d828ab1b840b17542dcaf6207afd221e086b2a60d16cb7f54448ba9f3f08bcd099db21dd162a779e61aa89eee554d3a47de230bc7ac590d524067c3898bba6f5dc4360b845eda48cbd9cf126a723445f0e1952d7325a75faf556144f9a98af7186b0278685b8e2c08bea87171b4dee585c1828295b5395eb4a17779f0203010001300d06092a864886f70d010105050003818100cb3ab0357d7cd2ae97ed501e51a3a0e2817d418e47fb17906477af61495a7e8d8789141065b082d001f4b15193d0b43fb661cde20a6498372c6abbd3dcb9f0d12659ef07b3c6dbdf8bdf2f65477eed7adcd457d793b1c27badda7c5ade80ce95b7d8827fe78c8a35f3fb4ba648a081be2cfe84231abab3c2b531746df2e0492b000000019a02d5058a04cabe73656c6672656700f2faa56d656b69000004fa8e330003d2d63231343734383336343700000000000002d28e310000</p>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/js/testing/test-encode-decode-ContentObject-bis.html b/js/testing/test-encode-decode-ContentObject-bis.html
new file mode 100644
index 0000000..4bbebe4
--- /dev/null
+++ b/js/testing/test-encode-decode-ContentObject-bis.html
@@ -0,0 +1,260 @@
+<?xml version = "1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"DTD/xhtml1-strict.dtd">
+<html xmlns = "http://www.w3.org/1999/xhtml">
+
+<head>
+ <title>NDN Request Example</title>
+
+ <script type="text/javascript" src="../java_socket_bridge.js"></script>
+
+ <script type="text/javascript" src="../util/CCNProtocolDTags.js"></script>
+
+ <script type="text/javascript" src="../util/CCNTime.js"></script>
+
+ <script type="text/javascript" src="../Name.js"></script>
+
+ <script type="text/javascript" src="../ContentObject.js"></script>
+
+ <script type="text/javascript" src="../encoding/DateFormat.js"></script>
+
+ <script type="text/javascript" src="../Interest.js"></script>
+
+ <script type="text/javascript" src="../Key.js"></script>
+
+ <script type="text/javascript" src="../PublisherID.js"></script>
+
+ <script type="text/javascript" src="../PublisherPublicKeyDigest.js"></script>
+
+ <script type="text/javascript" src="../FaceInstance.js"></script>
+
+ <script type="text/javascript" src="../ForwardingEntry.js"></script>
+
+ <script type="text/javascript" src="../encoding/BinaryXMLEncoder.js"></script>
+
+ <script type="text/javascript" src="../encoding/BinaryXMLDecoder.js"></script>
+
+ <script type="text/javascript" src="../encoding/DataUtils.js"></script>
+
+ <script type="text/javascript" src="../encoding/EncodingUtils.js"></script>
+
+
+ <script language="JavaScript" type="text/javascript" src="../security/KeyManager.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/jsbn.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/jsbn2.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsa.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsa2.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha256.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha512.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/md5.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/ripemd160.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/base64.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsapem-1.1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsasign-1.2.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/asn1hex-1.1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/x509-1.1.js"></script>
+
+ <script type="text/javascript">
+
+ function encode(){
+ var contentname = new Name( Name.createNameArray(document.getElementById('contentname').value) );
+
+ var content = document.getElementById('content').value;
+
+ var signedInfo = new SignedInfo();
+ signedInfo.setFields();
+ //var signatureBits = generateSignatureBits(contentname,content,signedInfo);
+
+ //witness is null
+ var signature = new Signature();
+
+
+ var co = new ContentObject(contentname,signedInfo,content,signature);
+
+ co.sign();
+
+
+ var output = encodeToHexContentObject(co);
+
+ document.getElementById('result').innerHTML = output;
+
+ }
+
+ function decode(){
+
+
+
+ var input = document.getElementById('result').innerHTML;
+
+
+ var co = decodeHexContentObject(input);
+
+ if(LOG>3)console.log('CONTENT OBJECT DECODED');
+ if(LOG>3)console.log(co);
+
+ ///////////////////////////////////////
+
+ var output ="";
+
+ if(co==-1)
+ output+= "NO CONTENT FOUND"
+ else if (co==-2)
+ output+= "CONTENT NAME IS EMPTY"
+ else{
+ if(co.name!=null && co.name.components!=null){
+ output+= "NAME: ";
+
+ for(var i=0;i<co.name.components.length;i++){
+ output+= "/"+ toString(co.name.components[i]);
+ }
+ output+= "<br />";
+ output+= "<br />";
+ }
+
+ if(co.content !=null){
+ output += "CONTENT(ASCII): "+ toString(co.content);
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+ if(co.content !=null){
+ output += "CONTENT(hex): "+ DataUtils.toHex(co.content);
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+ if(co.signature !=null && co.signature.signature!=null){
+
+ output += "SIGNATURE(hex): "+ DataUtils.toHex(co.signature.signature);
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+ if(co.signedInfo !=null && co.signedInfo.publisher!=null && co.signedInfo.publisher.publisherPublicKeyDigest!=null){
+
+ output += "Publisher Public Key Digest(hex): "+ DataUtils.toHex(co.signedInfo.publisher.publisherPublicKeyDigest);
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+ if(co.signedInfo !=null && co.signedInfo.timestamp!=null){
+
+ output += "TimeStamp(hex): "+ co.signedInfo.timestamp.date;
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+ if(co.signedInfo!=null && co.signedInfo.locator!=null && co.signedInfo.locator.publicKey!=null){
+
+ var publickey = rstr2b64(toString(co.signedInfo.locator.publicKey));
+ var publickeyHex = DataUtils.toHex(co.signedInfo.locator.publicKey).toLowerCase();
+ var publickeyString = toString(co.signedInfo.locator.publicKey);
+
+ var signature = DataUtils.toHex(co.signature.signature).toLowerCase();
+
+
+ var input = toString(co.rawSignatureData);
+
+
+ output += "DER Certificate: "+publickey ;
+
+ output+= "<br />";
+ output+= "<br />";
+
+
+
+ if(LOG>2) console.log(" ContentName + SignedInfo + Content = "+input);
+ if(LOG>2) console.log(" PublicKey = "+publickey );
+ if(LOG>2) console.log(" PublicKeyHex = "+publickeyHex );
+ if(LOG>2) console.log(" PublicKeyString = "+publickeyString );
+
+ if(LOG>2) console.log(" Signature "+signature );
+ if(LOG>2) console.log(" Signature NOW IS" );
+ if(LOG>2) console.log(co.signature.signature);
+
+
+ var x509 = new X509();
+
+ x509.readCertPEM(publickey);
+
+
+ //x509.readCertPEMWithoutRSAInit(publickey);
+
+ var result = x509.subjectPublicKeyRSA.verifyString(input, signature);
+ console.log('result is '+result);
+ /*var rsakey = new RSAKey();
+
+ var kp = publickeyHex.slice(56,314);
+
+ output += "PUBLISHER KEY(hex): "+kp ;
+
+ output+= "<br />";
+ output+= "<br />";
+
+ console.log('kp is '+kp);
+
+ var exp = publickeyHex.slice(318,324);
+
+ console.log('kp size is '+kp.length );
+ output += "exponent: "+exp ;
+
+ output+= "<br />";
+ output+= "<br />";
+
+ console.log('exp is '+exp);
+
+
+ rsakey.setPublic(kp,exp);
+
+ var result = rsakey.verifyString(input, signature);*/
+
+ if(result)
+ output += 'SIGNATURE VALID';
+ else
+ output += 'SIGNATURE INVALID';
+
+
+
+
+ //output += "VALID: "+ toHex(co.signedInfo.locator.publicKey);
+
+ output+= "<br />";
+ output+= "<br />";
+
+
+ if(LOG>4) console.log('str'[1]);
+ }
+ }
+
+ document.getElementById('result').innerHTML = output;
+
+ }
+
+ </script>
+
+</head>
+<body >
+ <form>
+
+ Please Enter a Content Name:<br />
+
+ <input id="contentname" type="text" name="CONTENTNAME" value="/PARC/abc" />
+
+ Please Enter the Content:<br />
+
+ <textarea id="content" cols="40" rows="5" name="CONTENT" value="SUCCESS" >SUCCESS!</textarea>
+
+ </form>
+ <button onclick="encode()">Encode</button>
+ <button onclick="decode()">Decode</button>
+
+
+
+ <p id="result"></p>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/js/testing/test-encode-decode-ContentObject.html b/js/testing/test-encode-decode-ContentObject.html
new file mode 100644
index 0000000..092f56f
--- /dev/null
+++ b/js/testing/test-encode-decode-ContentObject.html
@@ -0,0 +1,121 @@
+<?xml version = "1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"DTD/xhtml1-strict.dtd">
+<html xmlns = "http://www.w3.org/1999/xhtml">
+
+<head>
+ <title>NDN Encode/Decode Content Object</title>
+
+ <script type="text/javascript" src="../java_socket_bridge.js"></script>
+
+ <script type="text/javascript" src="../util/CCNProtocolDTags.js"></script>
+
+ <script type="text/javascript" src="../util/CCNTime.js"></script>
+
+ <script type="text/javascript" src="../Name.js"></script>
+
+ <script type="text/javascript" src="../ContentObject.js"></script>
+
+ <script type="text/javascript" src="../Interest.js"></script>
+
+ <script type="text/javascript" src="../Key.js"></script>
+
+ <script type="text/javascript" src="../PublisherID.js"></script>
+
+ <script type="text/javascript" src="../PublisherPublicKeyDigest.js"></script>
+
+ <script type="text/javascript" src="../FaceInstance.js"></script>
+
+ <script type="text/javascript" src="../ForwardingEntry.js"></script>
+
+ <script type="text/javascript" src="../encoding/BinaryXMLEncoder.js"></script>
+
+ <script type="text/javascript" src="../encoding/BinaryXMLDecoder.js"></script>
+
+ <script type="text/javascript" src="../encoding/DataUtils.js"></script>
+
+ <script type="text/javascript" src="../encoding/EncodingUtils.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../security/KeyManager.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/jsbn.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/jsbn2.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsa.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsa2.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha256.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha512.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/md5.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/ripemd160.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/base64.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsapem-1.1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsasign-1.2.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/asn1hex-1.1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/x509-1.1.js"></script>
+
+ <script type="text/javascript">
+
+ function encode(){
+ var contentname = new Name( document.getElementById('contentname').value );
+
+ var content = document.getElementById('content').value;
+
+ var signedInfo = new SignedInfo();
+
+ signedInfo.setFields();
+ //var signatureBits = generateSignatureBits(contentname,content,signedInfo);
+
+ //witness is null
+ var signature = new Signature();
+
+
+ var co = new ContentObject(contentname,signedInfo,content,signature);
+
+ co.sign();
+
+
+ var output = encodeToHexContentObject(co);
+
+ document.getElementById('result').innerHTML = output;
+
+ }
+
+ function decode(){
+ var input = document.getElementById('result').innerHTML;
+
+ input = input.toUpperCase();
+
+ var co = decodeHexContentObject(input);
+
+ if(LOG>3)console.log('CONTENT OBJECT DECODED');
+ if(LOG>3)console.log(co);
+
+ document.getElementById('result').innerHTML = contentObjectToHtml(co);
+ }
+
+ </script>
+
+</head>
+<body >
+ <form>
+
+ Please Enter a Content Name:<br />
+
+ <input id="contentname" type="text" name="CONTENTNAME" value="/PARC/abc" />
+
+ <br />Please Enter the Content:<br />
+
+ <textarea id="content" cols="40" rows="5" name="CONTENT" value="SUCCESS" >SUCCESS!</textarea>
+
+ </form>
+ <button onclick="encode()">Encode</button>
+ <button onclick="decode()">Decode</button>
+
+
+ <p id="result"></p>
+
+
+</body>
+</html>
diff --git a/js/testing/test-encode-decode-Interest.html b/js/testing/test-encode-decode-Interest.html
new file mode 100644
index 0000000..2f59feb
--- /dev/null
+++ b/js/testing/test-encode-decode-Interest.html
@@ -0,0 +1,167 @@
+<?xml version = "1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"DTD/xhtml1-strict.dtd">
+<html xmlns = "http://www.w3.org/1999/xhtml">
+
+<head>
+ <title>NDN Encode/Decode Interest</title>
+
+ <script type="text/javascript" src="../java_socket_bridge.js"></script>
+
+ <script type="text/javascript" src="../util/CCNProtocolDTags.js"></script>
+
+ <script type="text/javascript" src="../util/CCNTime.js"></script>
+
+ <script type="text/javascript" src="../Name.js"></script>
+
+ <script type="text/javascript" src="../ContentObject.js"></script>
+
+ <script type="text/javascript" src="../encoding/DateFormat.js"></script>
+
+ <script type="text/javascript" src="../Interest.js"></script>
+
+ <script type="text/javascript" src="../Key.js"></script>
+
+ <script type="text/javascript" src="../PublisherID.js"></script>
+
+ <script type="text/javascript" src="../PublisherPublicKeyDigest.js"></script>
+
+ <script type="text/javascript" src="../FaceInstance.js"></script>
+
+ <script type="text/javascript" src="../ForwardingEntry.js"></script>
+
+ <script type="text/javascript" src="../encoding/BinaryXMLEncoder.js"></script>
+
+ <script type="text/javascript" src="../encoding/BinaryXMLDecoder.js"></script>
+
+ <script type="text/javascript" src="../encoding/DataUtils.js"></script>
+
+ <script type="text/javascript" src="../encoding/EncodingUtils.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../security/KeyManager.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/jsbn.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/jsbn2.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsa.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsa2.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha256.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha512.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/md5.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/ripemd160.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/base64.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsapem-1.1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsasign-1.2.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/asn1hex-1.1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/x509-1.1.js"></script>
+
+ <script type="text/javascript">
+
+ function encode(){
+ var interest = new Interest( new Name(document.getElementById('interest').value ) );
+
+ interest.scope = 1;
+
+ var output = encodeToHexInterest(interest);
+
+ document.getElementById('result').innerHTML = output;
+
+ }
+
+ function decode(){
+
+
+
+ var input = document.getElementById('result').innerHTML;
+
+
+ var interest = decodeHexInterest(input);
+
+ if(LOG>3)console.log('INTEREST DECODED');
+ if(LOG>3)console.log(interest);
+
+ ///////////////////////////////////////
+
+ var output ="";
+
+ if(interest.name!=null && interest.name.components!=null){
+ output+= "NAME: ";
+
+
+ output+= interest.name.getName();
+
+ /*for(var i=0;i<interest.name.components.length;i++){
+ output+= "/"+ DataUtils.toString(interest.name.Components[i]);
+ }*/
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+
+
+ if(interest.scope!=null ){
+ output+= "SCOPE: ";
+
+ output+= interest.scope;
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+
+ if(interest.publisherID!=null ){
+ output+= "PUBLISHER ID: ";
+
+ output+= interest.publisherID.publisherID;
+
+ output+= "PUBLISHER ID TYPE: ";
+ output+= interest.publisherID.publisherType;
+ output+= "<br />";
+ output+= "<br />";
+ }
+
+ if(interest.maxSuffixComponents!=null ){
+ output+= "MaxSuffixComponents : ";
+
+ output+= interest.maxSuffixComponents;
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+
+ if(interest.minSuffixComponents!=null ){
+ output+= "MinSuffixComponents : ";
+
+ output+= interest.minSuffixComponents;
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+
+ document.getElementById('result').innerHTML = output;
+
+ }
+
+ </script>
+
+</head>
+<body >
+ <form>
+
+ Please Enter an Interest:<br />
+
+ <input id="interest" type="text" name="INTEREST" value="/PARC/abc" />
+
+ </form>
+ <button onclick="encode()">Encode</button>
+ <button onclick="decode()">Decode</button>
+
+ <p id="result"></p>
+
+
+
+ <!-- p id="result">01d2f2fafdc12e4d2e532e6c6f63616c686f737400fabdc12e4d2e53525600faa563636e6400fa9d4b4559000002d28e310000</p-->
+
+</body>
+</html>
diff --git a/js/testing/test-get-async.html b/js/testing/test-get-async.html
new file mode 100644
index 0000000..f93db6c
--- /dev/null
+++ b/js/testing/test-get-async.html
@@ -0,0 +1,56 @@
+<?xml version = "1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"DTD/xhtml1-strict.dtd">
+<html xmlns = "http://www.w3.org/1999/xhtml">
+<meta charset="UTF-8">
+
+<head>
+ <title>NDN Get via WebSocket</title>
+
+ <script type="text/javascript" src="../Helper.js"></script>
+
+ <script type="text/javascript">
+ var ndn = new NDN();
+ ndn.transport.connectWebSocket(ndn);
+
+ var AsyncGetClosure = function AsyncGetClosure() {
+ // Inherit from Closure.
+ Closure.call(this);
+ };
+
+ AsyncGetClosure.prototype.upcall = function(kind, upcallInfo) {
+ if (kind == Closure.UPCALL_FINAL) {
+ // Do nothing.
+ } else if (kind == Closure.UPCALL_CONTENT) {
+ console.log("Closure.upcall() executed.");
+ var content = upcallInfo.contentObject;
+ nameStr = escape(content.name.getName());
+ console.log("In callback, nameStr: " + nameStr);
+ console.log("In callback, content: ");
+ console.log(content);
+ document.getElementById('content').innerHTML = contentObjectToHtml(content);
+ }
+ return Closure.RESULT_OK;
+ };
+
+
+ function run() {
+ ndn.expressInterest(new Name(document.getElementById('interest').value), new AsyncGetClosure());
+ }
+
+ </script>
+
+</head>
+<body >
+
+ <form>
+ Please Enter an Interest:<br />
+ <input id="interest" type="text" name="INTEREST" size="50" value="/%C1.M.S.localhost/%C1.M.SRV/ccnd/KEY" />
+ </form>
+
+ <button onclick="run()">Fetch Content</button>
+
+ <p id="content">Content: <br/></p>
+
+</body>
+</html>
diff --git a/js/testing/test-get.html b/js/testing/test-get.html
new file mode 100644
index 0000000..eb7017d
--- /dev/null
+++ b/js/testing/test-get.html
@@ -0,0 +1,93 @@
+<?xml version = "1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"DTD/xhtml1-strict.dtd">
+<html xmlns = "http://www.w3.org/1999/xhtml">
+
+<head>
+ <title>NDN Get</title>
+ <script type="text/javascript" src="../java_socket_bridge.js"></script>
+
+ <script type="text/javascript" src="../NDN.js"></script>
+
+ <script type="text/javascript" src="../util/CCNProtocolDTags.js"></script>
+
+ <script type="text/javascript" src="../util/CCNTime.js"></script>
+
+ <script type="text/javascript" src="../Name.js"></script>
+
+ <script type="text/javascript" src="../ContentObject.js"></script>
+
+ <script type="text/javascript" src="../encoding/DateFormat.js"></script>
+
+ <script type="text/javascript" src="../Interest.js"></script>
+
+ <script type="text/javascript" src="../Key.js"></script>
+
+ <script type="text/javascript" src="../PublisherID.js"></script>
+
+ <script type="text/javascript" src="../PublisherPublicKeyDigest.js"></script>
+
+ <script type="text/javascript" src="../FaceInstance.js"></script>
+
+ <script type="text/javascript" src="../ForwardingEntry.js"></script>
+
+
+ <script type="text/javascript" src="../encoding/BinaryXMLEncoder.js"></script>
+
+ <script type="text/javascript" src="../encoding/BinaryXMLDecoder.js"></script>
+
+ <script type="text/javascript" src="../encoding/DataUtils.js"></script>
+
+ <script type="text/javascript" src="../encoding/EncodingUtils.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../security/KeyManager.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/jsbn.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/jsbn2.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsa.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsa2.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha256.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha512.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/md5.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/ripemd160.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/base64.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsapem-1.1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsasign-1.2.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/asn1hex-1.1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/x509-1.1.js"></script>
+
+ <script type="text/javascript">
+
+ function getAction(){
+ var connector = new NDN();
+ var co = connector.get(document.getElementById('interest').value);
+
+ var output = '<br/> received Content:<br/>' + contentObjectToHtml(co);
+
+ document.getElementById('result').innerHTML = output;
+ }
+
+ </script>
+
+</head>
+<body >
+
+ <form>
+ Please Enter an Interest:<br />
+ <input id="interest" type="text" name="INTEREST" size="50" value="/" />
+ </form>
+
+ <button onclick="getAction()">GET!</button>
+
+ <div >
+ <applet id="JavaSocketBridge" archive="../JavaSocketBridge.jar" code="JavaSocketBridge.class" width="0" height="0">
+ </applet>
+ </div>
+
+ <p id="result"></p>
+
+</body>
+</html>
diff --git a/js/testing/test-image-parsing.html b/js/testing/test-image-parsing.html
new file mode 100644
index 0000000..5d39f6f
--- /dev/null
+++ b/js/testing/test-image-parsing.html
@@ -0,0 +1,127 @@
+<?xml version = "1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"DTD/xhtml1-strict.dtd">
+<html xmlns = "http://www.w3.org/1999/xhtml">
+
+<head>
+ <title>NDN Image Parsing</title>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/jsbn.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/jsbn2.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsa.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsa2.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha256.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha512.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/md5.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/ripemd160.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/base64.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsapem-1.1.min.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsasign-1.2.min.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/asn1hex-1.1.min.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/x509-1.1.min.js"></script>
+
+
+ <script type="text/javascript">
+ function sign(){
+
+ var input = document.getElementById('contentname').value;
+
+ var _PEM_PRIVATE_KEY_STRING_ = document.getElementById('privateKey').value;
+
+ var rsa = new RSAKey();
+
+ rsa.readPrivateKeyFromPEMString(_PEM_PRIVATE_KEY_STRING_);
+
+ var hSig = rsa.signString(input, "sha256");
+
+ document.getElementById('result').innerHTML = hSig;
+
+ }
+ function verify(){
+ var input = document.getElementById('contentname').value;
+
+ var signature = document.getElementById('result').innerHTML;
+
+ var _PEM_X509CERT_STRING_ = document.getElementById('certificate').value;
+
+ var x509 = new X509();
+
+ x509.readCertPEM(_PEM_X509CERT_STRING_);
+
+ var result = x509.subjectPublicKeyRSA.verifyString(input, signature);
+
+ if(result)
+ document.getElementById('result').innerHTML = 'SIGNATURE VALID';
+ else
+ document.getElementById('result').innerHTML = 'SIGNATURE INVALID';
+
+
+ }
+
+ </script>
+
+
+</head>
+<body >
+ <form>
+
+ <input id="privateKey" type="hidden" value="-----BEGIN RSA PRIVATE KEY-----
+ MIICWwIBAAKBgQDRhGF7X4A0ZVlEg594WmODVVUIiiPQs04aLmvfg8SborHss5gQ
+ Xu0aIdUT6nb5rTh5hD2yfpF2WIW6M8z0WxRhwicgXwi80H1aLPf6lEPPLvN29EhQ
+ NjBpkFkAJUbS8uuhJEeKw0cE49g80eBBF4BCqSL6PFQbP9/rByxdxEoAIQIDAQAB
+ AoGAA9/q3Zk6ib2GFRpKDLO/O2KMnAfR+b4XJ6zMGeoZ7Lbpi3MW0Nawk9ckVaX0
+ ZVGqxbSIX5Cvp/yjHHpww+QbUFrw/gCjLiiYjM9E8C3uAF5AKJ0r4GBPl4u8K4bp
+ bXeSxSB60/wPQFiQAJVcA5xhZVzqNuF3EjuKdHsw+dk+dPECQQDubX/lVGFgD/xY
+ uchz56Yc7VHX+58BUkNSewSzwJRbcueqknXRWwj97SXqpnYfKqZq78dnEF10SWsr
+ /NMKi+7XAkEA4PVqDv/OZAbWr4syXZNv/Mpl4r5suzYMMUD9U8B2JIRnrhmGZPzL
+ x23N9J4hEJ+Xh8tSKVc80jOkrvGlSv+BxwJAaTOtjA3YTV+gU7Hdza53sCnSw/8F
+ YLrgc6NOJtYhX9xqdevbyn1lkU0zPr8mPYg/F84m6MXixm2iuSz8HZoyzwJARi2p
+ aYZ5/5B2lwroqnKdZBJMGKFpUDn7Mb5hiSgocxnvMkv6NjT66Xsi3iYakJII9q8C
+ Ma1qZvT/cigmdbAh7wJAQNXyoizuGEltiSaBXx4H29EdXNYWDJ9SS5f070BRbAIl
+ dqRh3rcNvpY6BKJqFapda1DjdcncZECMizT/GMrc1w==
+ -----END RSA PRIVATE KEY-----"></input>
+
+
+ <input id="certificate" type="hidden" value="-----BEGIN CERTIFICATE-----
+ MIIBvTCCASYCCQD55fNzc0WF7TANBgkqhkiG9w0BAQUFADAjMQswCQYDVQQGEwJK
+ UDEUMBIGA1UEChMLMDAtVEVTVC1SU0EwHhcNMTAwNTI4MDIwODUxWhcNMjAwNTI1
+ MDIwODUxWjAjMQswCQYDVQQGEwJKUDEUMBIGA1UEChMLMDAtVEVTVC1SU0EwgZ8w
+ DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANGEYXtfgDRlWUSDn3haY4NVVQiKI9Cz
+ Thoua9+DxJuiseyzmBBe7Roh1RPqdvmtOHmEPbJ+kXZYhbozzPRbFGHCJyBfCLzQ
+ fVos9/qUQ88u83b0SFA2MGmQWQAlRtLy66EkR4rDRwTj2DzR4EEXgEKpIvo8VBs/
+ 3+sHLF3ESgAhAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAEZ6mXFFq3AzfaqWHmCy1
+ ARjlauYAa8ZmUFnLm0emg9dkVBJ63aEqARhtok6bDQDzSJxiLpCEF6G4b/Nv/M/M
+ LyhP+OoOTmETMegAVQMq71choVJyOFE5BtQa6M/lCHEOya5QUfoRF2HF9EjRF44K
+ 3OK+u3ivTSj3zwjtpudY5Xo=
+ -----END CERTIFICATE-----"></input>
+
+ Please Enter a Text to sign:<br /><input id="contentname" type="text" name="CONTENTNAME" value="/PARC/CCNX" /> <br />
+
+ </form>
+ <button onclick="sign()">Encode</button>
+ <button onclick="verify()">Parse</button>
+
+ <script type="text/javascript">
+
+ var srcString = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9YGARc5KB0XV+IAAAAddEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIFRoZSBHSU1Q72QlbgAAAF1JREFUGNO9zL0NglAAxPEfdLTs4BZM4DIO4C7OwQg2JoQ9LE1exdlYvBBeZ7jqch9//q1uH4TLzw4d6+ErXMMcXuHWxId3KOETnnXXV6MJpcq2MLaI97CER3N0vr4MkhoXe0rZigAAAABJRU5ErkJggg==';
+ var link = document.createElement('img');
+ link.setAttribute('src', srcString);
+
+ document.body.appendChild(link);
+
+</script>
+
+ <img src="data:image/png;base64,
+iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABGdBTUEAALGP
+C/xhBQAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9YGARc5KB0XV+IA
+AAAddEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIFRoZSBHSU1Q72QlbgAAAF1J
+REFUGNO9zL0NglAAxPEfdLTs4BZM4DIO4C7OwQg2JoQ9LE1exdlYvBBeZ7jq
+ch9//q1uH4TLzw4d6+ErXMMcXuHWxId3KOETnnXXV6MJpcq2MLaI97CER3N0
+vr4MkhoXe0rZigAAAABJRU5ErkJggg==" alt="Red dot" />
+
+ <p id="result"></p>
+
+</body>
+</html>
diff --git a/js/testing/test-interest-matches-name.html b/js/testing/test-interest-matches-name.html
new file mode 100644
index 0000000..5bf0e4a
--- /dev/null
+++ b/js/testing/test-interest-matches-name.html
@@ -0,0 +1,90 @@
+<?xml version = "1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"DTD/xhtml1-strict.dtd">
+<html xmlns = "http://www.w3.org/1999/xhtml">
+
+<head>
+ <title>NDN Interest Matches Name</title>
+
+ <script type="text/javascript" src="../java_socket_bridge.js"></script>
+
+ <script type="text/javascript" src="../util/CCNProtocolDTags.js"></script>
+
+ <script type="text/javascript" src="../util/CCNTime.js"></script>
+
+ <script type="text/javascript" src="../Name.js"></script>
+
+ <script type="text/javascript" src="../ContentObject.js"></script>
+
+ <script type="text/javascript" src="../encoding/DateFormat.js"></script>
+
+ <script type="text/javascript" src="../Interest.js"></script>
+
+ <script type="text/javascript" src="../Key.js"></script>
+
+ <script type="text/javascript" src="../PublisherID.js"></script>
+
+ <script type="text/javascript" src="../PublisherPublicKeyDigest.js"></script>
+
+ <script type="text/javascript" src="../FaceInstance.js"></script>
+
+ <script type="text/javascript" src="../ForwardingEntry.js"></script>
+
+ <script type="text/javascript" src="../encoding/BinaryXMLEncoder.js"></script>
+
+ <script type="text/javascript" src="../encoding/BinaryXMLDecoder.js"></script>
+
+ <script type="text/javascript" src="../encoding/DataUtils.js"></script>
+
+ <script type="text/javascript" src="../encoding/EncodingUtils.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../security/KeyManager.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/jsbn.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/jsbn2.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsa.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsa2.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha256.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha512.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/md5.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/ripemd160.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/base64.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsapem-1.1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsasign-1.2.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/asn1hex-1.1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/x509-1.1.js"></script>
+
+ <script type="text/javascript">
+
+ function check(){
+ var interest = new Interest( new Name(document.getElementById('interest').value));
+ interest.scope = 1;
+
+ var nameToCheck = new Name(document.getElementById('nameToCheck').value);
+
+ var output = (interest.matches_name(nameToCheck) ? "matches" : "doesn't match");
+ document.getElementById('result').innerHTML = output;
+ }
+
+ </script>
+
+</head>
+<body >
+ <form>
+
+ Please enter the name of an interest:<br />
+ <input id="interest" type="text" name="INTEREST" value="/ndn/ucla.edu" /> <br/>
+
+ Please enter a name to check if the interest matches the name:<br />
+ <input id="nameToCheck" type="text" name="NAME_TO_CHECK" value="/ndn/ucla.edu" /> <br/>
+
+ </form>
+ <button onclick="check()">Check</button>
+
+ <p id="result"></p>
+
+</body>
+</html>
diff --git a/js/testing/test-put-async.html b/js/testing/test-put-async.html
new file mode 100644
index 0000000..315dec8
--- /dev/null
+++ b/js/testing/test-put-async.html
@@ -0,0 +1,92 @@
+<?xml version = "1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"DTD/xhtml1-strict.dtd">
+<html xmlns = "http://www.w3.org/1999/xhtml">
+<meta charset="UTF-8">
+
+
+<head>
+ <title>NDN Put via WebSocket</title>
+
+ <script type="text/javascript" src="../Helper.js"></script>
+
+ <script type="text/javascript">
+ var ndn = new NDN();
+ ndn.transport.connectWebSocket(ndn);
+
+ var AsyncPutClosure = function AsyncPutClosure() {
+ // Inherit from Closure.
+ Closure.call(this);
+ };
+
+ AsyncPutClosure.prototype.upcall = function(kind, upcallInfo) {
+ if (kind == Closure.UPCALL_FINAL) {
+ // Do nothing.
+ } else if (kind == Closure.UPCALL_INTEREST) {
+ // Extract the Name from the Interest. var name = upcallInfo.Interest.name;;
+ // Check that we want to respond to upcallInfo.interest. If yes, construct a ContentObject
+ // response, put it to the NDN and return Closure.RESULT_INTEREST_CONSUMED. Else fall
+ // through to return Content.RESULT_OK.
+ // See linemaker.py for more details.
+ console.log('AsyncPutClosure.upcall() called.');
+ var content = document.getElementById('content').value;
+ var interest = upcallInfo.interest;
+ var nameStr = escape(interest.name.getName());
+
+ var si = new SignedInfo();
+ si.setFields();
+
+ var answer = DataUtils.toNumbersFromString(content);
+
+ var co = new ContentObject(new Name(nameStr), si, answer, new Signature());
+ co.sign();
+ var hex = encodeToHexContentObject(co);
+
+ var bytearray = new Uint8Array(hex.length / 2);
+ for (var i = 0; i < hex.length; i = i + 2) {
+ bytearray[i / 2] = '0x' + hex.substr(i, 2);
+ }
+
+ upcallInfo.ndn.transport.ws.send(bytearray.buffer);
+ console.log('ws.send() finised.');
+
+ return Closure.RESULT_INTEREST_CONSUMED;
+ }
+ return Closure.RESULT_OK;
+ };
+
+
+ function run() {
+ var contentName = document.getElementById('contentname').value;
+
+ var result = ndn.registerPrefix(new Name(contentName), new AsyncPutClosure());
+
+ document.getElementById('result').innerHTML = 'Content name \'' + contentName
+ +'\' published. Result: ' + result;
+ }
+
+ </script>
+
+</head>
+<body >
+ <form>
+ <div>
+ <p>Please Enter a Content Name:</p>
+
+ <input id="contentname" type="text" name="CONTENTNAME" value="/wentao.shang/regtest001" />
+
+ <p>Please Enter the Content:</p>
+
+ <textarea id="content" cols="40" rows="5" name="CONTENT" >This works!</textarea>
+
+ <br />
+ </div>
+ </form>
+ <div>
+ <button onclick="run()">Publish Content</button>
+ </div>
+
+ <p id="result"></p>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/js/testing/test-put.html b/js/testing/test-put.html
new file mode 100644
index 0000000..89f15a1
--- /dev/null
+++ b/js/testing/test-put.html
@@ -0,0 +1,104 @@
+<?xml version = "1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"DTD/xhtml1-strict.dtd">
+<html xmlns = "http://www.w3.org/1999/xhtml">
+
+<head>
+ <title>NDN Put</title>
+ <script type="text/javascript" src="../java_socket_bridge.js"></script>
+
+ <script type="text/javascript" src="../util/CCNProtocolDTags.js"></script>
+
+ <script type="text/javascript" src="../util/CCNTime.js"></script>
+
+ <script type="text/javascript" src="../Name.js"></script>
+
+ <script type="text/javascript" src="../ContentObject.js"></script>
+
+ <script type="text/javascript" src="../encoding/DateFormat.js"></script>
+
+ <script type="text/javascript" src="../Interest.js"></script>
+
+ <script type="text/javascript" src="../Key.js"></script>
+
+ <script type="text/javascript" src="../PublisherID.js"></script>
+
+ <script type="text/javascript" src="../PublisherPublicKeyDigest.js"></script>
+
+ <script type="text/javascript" src="../FaceInstance.js"></script>
+
+ <script type="text/javascript" src="../ForwardingEntry.js"></script>
+
+ <script type="text/javascript" src="../encoding/BinaryXMLEncoder.js"></script>
+
+ <script type="text/javascript" src="../encoding/BinaryXMLDecoder.js"></script>
+
+ <script type="text/javascript" src="../encoding/DataUtils.js"></script>
+
+ <script type="text/javascript" src="../encoding/EncodingUtils.js"></script>
+
+ <script type="text/javascript" src="../NDN.js"></script>
+
+
+ <script language="JavaScript" type="text/javascript" src="../security/KeyManager.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/jsbn.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/jsbn2.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsa.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsa2.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha256.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha512.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/md5.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/ripemd160.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/base64.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsapem-1.1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsasign-1.2.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/asn1hex-1.1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/x509-1.1.js"></script>
+
+
+ <script type="text/javascript">
+ function run(){
+ var contentName = document.getElementById('contentname').value;
+ var content = document.getElementById('content').value;
+
+ var connector = new NDN();
+ var result = connector.put( contentName, content );
+
+ document.getElementById('result').innerHTML = 'Content \'' + content +
+ '\' was published with content name \'' + contentName +'\'. Result:<br/>' +
+ result;
+ }
+
+ </script>
+
+</head>
+<body >
+ <form>
+ <div>
+ <p>Please Enter a Content Name:</p>
+
+ <input id="contentname" type="text" name="CONTENTNAME" value="/demo/message" />
+
+ <p>Please Enter the Content:</p>
+
+ <textarea id="content" cols="40" rows="5" name="CONTENT" >This works!</textarea>
+
+ <br />
+ </div>
+ </form>
+ <div>
+ <button onclick="run()">PUT!</button>
+ </div>
+ <div >
+ <applet id="JavaSocketBridge" archive="../JavaSocketBridge.jar" code="JavaSocketBridge.class" width="0" height="0">
+ </applet>
+ </div>
+
+ <p id="result"></p>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/js/testing/test-request-send-hex.html b/js/testing/test-request-send-hex.html
new file mode 100644
index 0000000..4b88d34
--- /dev/null
+++ b/js/testing/test-request-send-hex.html
@@ -0,0 +1,144 @@
+<?xml version = "1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"DTD/xhtml1-strict.dtd">
+<html xmlns = "http://www.w3.org/1999/xhtml">
+
+<head>
+ <title>NDN Send Hex</title>
+ <script type="text/javascript" src="../java_socket_bridge.js"></script>
+
+ <script type="text/javascript" src="../util/CCNProtocolDTags.js"></script>
+
+ <script type="text/javascript" src="../util/CCNTime.js"></script>
+
+ <script type="text/javascript" src="../Name.js"></script>
+
+ <script type="text/javascript" src="../ContentObject.js"></script>
+
+ <script type="text/javascript" src="../encoding/DateFormat.js"></script>
+
+ <script type="text/javascript" src="../Interest.js"></script>
+
+ <script type="text/javascript" src="../Key.js"></script>
+
+ <script type="text/javascript" src="../PublisherID.js"></script>
+
+ <script type="text/javascript" src="../PublisherPublicKeyDigest.js"></script>
+
+ <script type="text/javascript" src="../FaceInstance.js"></script>
+
+ <script type="text/javascript" src="../ForwardingEntry.js"></script>
+
+
+ <script type="text/javascript" src="../encoding/BinaryXMLEncoder.js"></script>
+
+ <script type="text/javascript" src="../encoding/BinaryXMLDecoder.js"></script>
+
+ <script type="text/javascript" src="../encoding/DataUtils.js"></script>
+
+ <script type="text/javascript" src="../encoding/EncodingUtils.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../security/KeyManager.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/jsbn.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/jsbn2.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsa.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsa2.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha256.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha512.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/md5.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/ripemd160.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/base64.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsapem-1.1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsasign-1.2.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/asn1hex-1.1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/x509-1.1.js"></script>
+
+ <script type="text/javascript">
+ function run(){
+ //var n = a.replace("%","");
+
+ //console.log(n);
+
+ var hex = document.getElementById('contentname').value;
+
+ ///////////////////////////////////////
+ //createRoute(, 9695);
+
+
+ /// /ndn/ucla.edu/apps/hydra/mainvideo
+ //createRoute('131.179.141.15', 9695);
+ //createRoute('borges.metwi.ucla.edu', 9695);
+
+ //content object
+ //var co = queryPrefix( Name );
+ console.log('HEX IS');
+ console.log(hex);
+
+ var result = get('127.0.0.1', 9695, hex);
+
+ console.log('BINARY RESPONSE IS ' +result);
+
+ var output ="";
+ output += "HEX ANSWER IS: "+ result;
+
+ output+= "<br />";
+ output+= "<br />";
+
+ //result[0] and result[1] should be 0 and 4 if there is a content object found
+ if(result==null || result==undefined || result =="" ){
+
+
+ if(LOG>2)console.log('INVALID ANSWER');
+ output += "NO CONTENT FOUND";
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+
+ else if(result[0] != '0'||result[1]!='4') {
+ if(LOG>2)console.log('INVALID ANSWER');
+ output += "INVALID ANSWER";
+
+ output+= "<br />";
+ output+= "<br />";
+ }
+ else{
+
+ var numbers = DataUtils.toNumbers(result);
+
+ console.log('HEX RESPONSE IS \n'+numbers);
+ decoder = new BinaryXMLDecoder(numbers);
+
+
+ co = new ContentObject();
+
+ co.from_ccnb(decoder);
+
+ if(LOG>2) console.log(co);
+
+ output += contentObjectToHtml(co);
+ }
+ document.getElementById('result').innerHTML = output;
+ }
+
+ </script>
+
+</head>
+<body >
+ <form>
+ Please Enter a Hex Encoded Interest:<br /><input id="contentname" type="text" name="CONTENTNAME" value="01d2f20002d28e310000" /> <br />
+ </form>
+ <button onclick="run()">Request Data!</button>
+ <div >
+ <applet id="JavaSocketBridge" archive="../JavaSocketBridge.jar" code="JavaSocketBridge.class" width="0" height="0">
+ </applet>
+ </div>
+
+ <p id="result"></p>
+
+</body>
+</html>
diff --git a/js/testing/test-sha256.html b/js/testing/test-sha256.html
new file mode 100644
index 0000000..920e9d0
--- /dev/null
+++ b/js/testing/test-sha256.html
@@ -0,0 +1,60 @@
+<?xml version = "1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"DTD/xhtml1-strict.dtd">
+<html xmlns = "http://www.w3.org/1999/xhtml">
+
+<head>
+ <title>Test SHA-256</title>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/jsbn.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/jsbn2.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsa.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsa2.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha256.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha512.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/md5.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/ripemd160.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/base64.js"></script>
+
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsapem-1.1.min.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsasign-1.2.min.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/asn1hex-1.1.min.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/x509-1.1.min.js"></script>
+
+ <script src="http://crypto-js.googlecode.com/svn/tags/3.0.2/build/rollups/sha256.js"></script>
+
+
+ <script type="text/javascript">
+ function hash(){
+
+ var input = document.getElementById('contentname').value;
+
+ var output = "TEST1 "+hex_sha256(input);
+
+ output+= "<br />";
+
+ output += "reference " +CryptoJS.SHA256(input);
+
+ document.getElementById('result').innerHTML = output;
+
+ }
+
+ </script>
+
+
+</head>
+<body >
+ <form>
+
+
+
+ Please Enter Text to Hash:<br /><input id="contentname" type="text" name="CONTENTNAME" value="/PARC/abc" /> <br />
+
+ </form>
+ <button onclick="hash()">Hash</button>
+
+ <p id="result"></p>
+
+</body>
+</html>
diff --git a/js/test-signature-binary.html b/js/testing/test-signature-binary.html
similarity index 70%
rename from js/test-signature-binary.html
rename to js/testing/test-signature-binary.html
index b808b98..dc0abd2 100644
--- a/js/test-signature-binary.html
+++ b/js/testing/test-signature-binary.html
@@ -4,25 +4,25 @@
<html xmlns = "http://www.w3.org/1999/xhtml">
<head>
- <title>NDN Request Example</title>
- <script language="JavaScript" type="text/javascript" src="securityLib/jsbn.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/jsbn2.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/rsa.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/rsa2.js"></script>
+ <title>NDN Signature - Binary</title>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/jsbn.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/jsbn2.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsa.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsa2.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/sha1.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/sha256.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/sha512.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/md5.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/ripemd160.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/base64.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha256.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha512.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/md5.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/ripemd160.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/base64.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/rsapem-1.1.min.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/rsasign-1.2.min.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/asn1hex-1.1.min.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/x509-1.1.min.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsapem-1.1.min.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsasign-1.2.min.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/asn1hex-1.1.min.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/x509-1.1.min.js"></script>
-
+
<script type="text/javascript">
function sign(){
diff --git a/js/test-signature-string.html b/js/testing/test-signature-string.html
similarity index 61%
rename from js/test-signature-string.html
rename to js/testing/test-signature-string.html
index 99a9fbb..fa31102 100644
--- a/js/test-signature-string.html
+++ b/js/testing/test-signature-string.html
@@ -4,32 +4,33 @@
<html xmlns = "http://www.w3.org/1999/xhtml">
<head>
- <title>NDN Request Example</title>
- <script language="JavaScript" type="text/javascript" src="securityLib/jsbn.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/jsbn2.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/rsa.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/rsa2.js"></script>
+ <title>NDN Signature - String</title>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/jsbn.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/jsbn2.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsa.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsa2.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/sha1.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/sha256.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/sha512.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/md5.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/ripemd160.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/base64.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha1.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha256.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/sha512.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/md5.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/ripemd160.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/base64.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/rsapem-1.1.min.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/rsasign-1.2.min.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/asn1hex-1.1.min.js"></script>
- <script language="JavaScript" type="text/javascript" src="securityLib/x509-1.1.min.js"></script>
-
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsapem-1.1.min.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/rsasign-1.2.min.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/asn1hex-1.1.min.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../securityLib/x509-1.1.min.js"></script>
+ <script language="JavaScript" type="text/javascript" src="../security/KeyManager.js"></script>
+
<script type="text/javascript">
function sign(){
-
+ var keyManager = new KeyManager();
var input = document.getElementById('contentname').value;
- var _PEM_PRIVATE_KEY_STRING_ = document.getElementById('privateKey').value;
-
+ var _PEM_PRIVATE_KEY_STRING_ = keyManager.privateKey;
+ //document.getElementById('privateKey').value;
var rsa = new RSAKey();
rsa.readPrivateKeyFromPEMString(_PEM_PRIVATE_KEY_STRING_);
@@ -43,9 +44,9 @@
var input = document.getElementById('contentname').value;
var signature = document.getElementById('result').innerHTML;
-
- var _PEM_X509CERT_STRING_ = document.getElementById('certificate').value;
-
+ var keyManager = new KeyManager();
+ var _PEM_X509CERT_STRING_ = keyManager.certificate;
+ //document.getElementById('certificate').value;
var x509 = new X509();
x509.readCertPEM(_PEM_X509CERT_STRING_);
@@ -107,5 +108,8 @@
<p id="result"></p>
+
+
</body>
-</html>
\ No newline at end of file
+
+</html>
diff --git a/js/testing/test-websocket.html b/js/testing/test-websocket.html
new file mode 100644
index 0000000..d6530cb
--- /dev/null
+++ b/js/testing/test-websocket.html
@@ -0,0 +1,51 @@
+<?xml version = "1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"DTD/xhtml1-strict.dtd">
+<html xmlns = "http://www.w3.org/1999/xhtml">
+
+<head>
+ <title>Test WebSocket Support</title>
+
+ <script type="text/javascript">
+
+ function test(){
+ var output = "";
+
+ if ('WebSocket' in window) {
+ output += "This browser support WebSocket.";
+ } else {
+ output += "No WebSocket support.";
+ }
+
+ document.getElementById('result').innerHTML += output;
+
+ console.log("starting websocket...");
+ if ("WebSocket" in window) {
+ var ws = new WebSocket("ws://localhost:9696");
+
+ ws.onopen = function() {
+ console.log("WebSockets connection opened");
+ ws.send("Hello Server (from client).");
+ }
+ ws.onmessage = function(e) {
+ console.log("Got from server: " + e.data);
+ }
+ ws.onclose = function() {
+ console.log("WebSockets connection closed");
+ }
+ } else {
+ alert("No WebSockets support");
+ }
+
+ }
+
+ </script>
+
+</head>
+<body >
+ <button onclick="test()">Test Now!</button>
+
+ <p id="result">Result here: </p>
+
+</body>
+</html>
diff --git a/js/CCNProtocolDTags.js b/js/util/CCNProtocolDTags.js
similarity index 97%
rename from js/CCNProtocolDTags.js
rename to js/util/CCNProtocolDTags.js
index 36ea03d..6dbae96 100644
--- a/js/CCNProtocolDTags.js
+++ b/js/util/CCNProtocolDTags.js
@@ -1,6 +1,7 @@
/*
* @author: ucla-cs
- * THis class contains all CCNx tags
+ * See COPYING for copyright and distribution information.
+ * This class contains all CCNx tags
*/
diff --git a/js/CCNTime.js b/js/util/CCNTime.js
similarity index 74%
rename from js/CCNTime.js
rename to js/util/CCNTime.js
index 26e98df..91debd4 100644
--- a/js/CCNTime.js
+++ b/js/util/CCNTime.js
@@ -1,27 +1,26 @@
/*
* @author: ucla-cs
+ * See COPYING for copyright and distribution information.
* This class represents CCNTime Objects
*/
var CCNTime = function CCNTime(
- msec) {
+ input) {
this.NANOS_MAX = 999877929;
- if(typeof msec =='object'){
- this.setDateBinary(msec);
- this.msec = msec;
- this.msecHex = toHex(msec);
- }
- else if(typeof msec =='string'){
-
- this.msec = toNumbers(msec);
- this.setDateBinary(this.msec);
- this.msecHex = msec;
+ /*if(typeof input =='object'){
+ this.longDate = DataUtils.byteArrayToUnsignedLong(input);
+ this.binaryDate = input;
+ }*/
+ if(typeof input =='number'){
+ this.msec = input;
+ //this.binaryDate = DataUtils.unsignedLongToByteArray(input);
+
}
else{
if(LOG>1) console.log('UNRECOGNIZED TYPE FOR TIME');
@@ -29,6 +28,12 @@
};
+CCNTime.prototype.getJavascriptDate = function(){
+ var d = new Date();
+ d.setTime( this.msec );
+ return d
+};
+
/**
* Create a CCNTime
* @param timestamp source timestamp to initialize from, some precision will be lost
@@ -39,7 +44,7 @@
* Create a CCNTime from its binary encoding
* @param binaryTime12 the binary representation of a CCNTime
*/
-CCNTime.prototype.setDateBinary = function(
+/*CCNTime.prototype.setDateBinary = function(
//byte []
binaryTime12) {
@@ -55,8 +60,7 @@
b = (binaryTime12[i]) & 0xFF;
value |= b;
}
-
- this.date = value;
+
//this.date = new Date(value);
};
@@ -66,7 +70,7 @@
return this.msec; //unsignedLongToByteArray(this.date.getTime());
-}
+}*/
/*
unsignedLongToByteArray= function( value) {
if( 0 == value )
diff --git a/wsproxy/README.md b/wsproxy/README.md
new file mode 100644
index 0000000..eb0cdc0
--- /dev/null
+++ b/wsproxy/README.md
@@ -0,0 +1,10 @@
+ws-ndn-js
+=========
+
+WebSocket proxy server between NDN javascript stack and ccnd
+
+This proxy runs on top of 'node.js'. 'ws' package is required. It listens for WebSocket connection request on port number 9696. Once it receives a incoming connection, it issues a TCP connection to the specified 'ccnd' router (port number 9695). It then translates packet frames from WebSocket to pure TCP byte streams and vice versa.
+
+To run the proxy, simply use the command 'node ws-ndn.js'.
+
+Acknowledgement: this code is extended from Junxiao's WebSocket proxy implementation (https://gist.github.com/3835425).
\ No newline at end of file
diff --git a/wsproxy/ws-ndn.js b/wsproxy/ws-ndn.js
new file mode 100644
index 0000000..2b67e0d
--- /dev/null
+++ b/wsproxy/ws-ndn.js
@@ -0,0 +1,80 @@
+var WebSocketServer = require('ws').Server;
+var net = require('net');
+
+var wss = new WebSocketServer({port:9696, host:'0.0.0.0'});
+
+var MaxNumOfClients = 2;
+
+wss.on('connection', function(ws) {
+ console.log('WebSocket client connection received.');
+ console.log('Number of clients now is ' + wss.clients.length);
+
+ if (wss.clients.length > MaxNumOfClients) {
+ console.log('Max num of clients exceeded. Close WS connection now.');
+ ws.terminate();
+ return;
+ }
+
+ var sock_ready = false;
+ var send_queue = [];
+ var sock = net.createConnection(9695);
+
+ ws.on('message', function(message) {
+ if (typeof message == 'string')
+ console.log("Message from clinet: " + message);
+ else if (typeof message == 'object') {
+ var bytesView = new Uint8Array(message);
+
+ var logMsg = 'Byte array from client: ';
+ for (var i = 0; i < bytesView.length; i++)
+ logMsg += String.fromCharCode(bytesView[i]);
+ console.log(logMsg);
+
+ if (sock_ready) {
+ sock.write(bytesView.buffer);
+ console.log('sock.write() returned.');
+ } else {
+ send_queue.push(message);
+ }
+ }
+ });
+
+ ws.on('close', function() {
+ console.log('WebSocket connection closed.');
+ sock.end();
+ });
+
+ sock.on('connect', function() {
+ while (send_queue.length > 0) {
+ var message = send_queue.shift();
+ sock.write(message);
+ }
+ sock_ready = true;
+ console.log('ccnd socket connection ready.');
+ });
+
+ sock.on('data', function(data) {
+ if (typeof data == 'object') {
+ var bytesView = new Uint8Array(data);
+
+ console.log('Byte array from server: ');
+ var logMsg = "";
+ for (var i = 0; i < bytesView.length; i++)
+ logMsg += String.fromCharCode(bytesView[i]);
+ console.log(logMsg);
+
+ ws.send(bytesView.buffer, {binary: true, mask: false});
+ console.log('ws.send() returned.');
+ }
+ });
+
+ sock.on('end', function() {
+ console.log('TCP connection terminated by ccnd. Shut down WS connection to client.');
+ ws.terminate();
+ });
+
+ sock.on('error', function() {
+ console.log('Error on TCP connection to ccnd. Shut down WS connection to client.');
+ ws.terminate();
+ });
+});
diff --git a/wsproxy/wsproxy-udp.js b/wsproxy/wsproxy-udp.js
new file mode 100644
index 0000000..bec9421
--- /dev/null
+++ b/wsproxy/wsproxy-udp.js
@@ -0,0 +1,110 @@
+var WebSocketServer = require('ws').Server;
+var dgram = require('dgram');
+
+var ccndhost = 'localhost';
+
+var wss = new WebSocketServer({port:9696, host:ccndhost});
+
+var MaxNumOfClients = 2;
+
+wss.on('connection', function(ws) {
+ console.log('wss.onconnection: WebSocket client connection received.');
+ console.log('wss.onconnection: Number of clients now is ' + wss.clients.length);
+
+ if (wss.clients.length > MaxNumOfClients) {
+ console.log('wss.onconnection: Max num of clients exceeded. Close WS connection now.');
+ ws.terminate();
+ return;
+ }
+
+ var udp = dgram.createSocket("udp4");
+
+ /*
+ * According to the email discussion with Michael, when we use
+ * UDP to connect to ccnd, we MUST first send a 'heartbeat'
+ * UDP packet with 1-byte payload (content of this byte can
+ * be random). The purpose of this packet is to let ccnd
+ * mark the incoming FACE as 'friendly' (with CCN_FACE_GG
+ * flag set). We also need to periodically send this 'heartbeat'
+ * packet every few seconds to keep ccnd from recycling the UDP
+ * face. Michael recomended 8 seconds interval.
+ * --Wentao
+ */
+ // Send 'heartbeat' packet now
+ var heartbeat = new Buffer(1);
+ heartbeat[0] = 0x21;
+ udp.send(heartbeat, 0, 1, 9695, ccndhost, null);
+
+ // Schedule a timer to send 'heartbeat' periodically
+ var timerID = setInterval(function() {
+ if (udp == null || udp == undefined)
+ return;
+
+ var hb = new Buffer(1);
+ hb[0] = 0x21;
+ udp.send(hb, 0, 1, 9695, ccndhost, null);
+ //console.log('UDP heartbeat fired at ccnd.');
+ },
+ 8000 // 8000 ms delay
+ );
+
+ ws.on('message', function(message) {
+ if (typeof message == 'string')
+ console.log("ws.onmessage: Message from clinet: " + message);
+ else if (typeof message == 'object') {
+ // From JS array to Buffer
+ var buffer = new Buffer(message);
+
+ var logMsg = 'ws.onmessage: Byte array from client: ';
+ for (var i = 0; i < buffer.length; i++)
+ logMsg += String.fromCharCode(buffer[i]);
+ console.log(logMsg);
+
+ udp.send(buffer, 0, buffer.length, 9695, ccndhost, null);
+ console.log('ws.onmessage: udp.send() returned.');
+ }
+ });
+
+ ws.on('close', function() {
+ console.log('ws.onclose: WebSocket connection closed. Close UDP connection to ccnd and stop "heartbeat" timer.');
+ clearInterval(timerID);
+ udp.close();
+ udp = null;
+ });
+
+ udp.on('message', function(msg, rinfo) {
+ if (typeof msg == 'object') {
+ // From Buffer to ArrayBuffer
+ var bytesView = new Uint8Array(msg);
+
+ console.log('udp.onmessage: Byte array from server: ');
+ console.log('udp.onmessage: bytesView.length ' + bytesView.length);
+ var logMsg = "";
+ for (var i = 0; i < bytesView.length; i++)
+ logMsg += String.fromCharCode(bytesView[i]);
+ console.log(logMsg);
+
+ ws.send(bytesView.buffer, {binary: true, mask: false});
+ console.log('udp.onmessage: ws.send() returned.');
+ }
+ });
+
+ // Actually the socket close by ccnd will not cause the 'close' event to raise.
+ // So this event handle is only called when the client browser shuts down the WS
+ // connection, causing ws 'close' event to raise. In that event handle, we explicitly
+ // call udp.close(). So in this function we can do nothing. Anyway, here we clear the
+ // timer and terminate ws for a second time since that will not throw exception. 'ws'
+ // will check the 'readyState' before closing, therefore avoids 'close' event loop.
+ // --Wentao
+ udp.on('close', function() {
+ console.log('udp.onclose: UDP connection to ccnd terminated. Shut down WS connection to client and stop "heartbeat" timer.');
+ clearInterval(timerID);
+ ws.terminate();
+ });
+
+ udp.on('error', function() {
+ console.log('udp.onerror: Error on UDP connection to ccnd. Shut down WS connection to client and stop "heartbeat" timer.');
+ clearInterval(timerID);
+ ws.terminate();
+ });
+});