├── README ├── jmusic.tmp ├── Arpeggio1.mid ├── TestMIDI.mid ├── lib ├── core.jar ├── eeml.jar ├── JPachube.jar ├── gson-1.6.jar ├── rwmidi.jar ├── argo-small-2.4.jar └── json-simple-1.1-bundle.jar ├── bin ├── org │ └── json │ │ ├── CDL.class │ │ ├── HTTP.class │ │ ├── Test.class │ │ ├── XML.class │ │ ├── Cookie.class │ │ ├── JSONML.class │ │ ├── JSONArray.class │ │ ├── CookieList.class │ │ ├── HTTPTokener.class │ │ ├── JSONObject.class │ │ ├── JSONString.class │ │ ├── JSONStringer.class │ │ ├── JSONTokener.class │ │ ├── JSONWriter.class │ │ ├── XMLTokener.class │ │ ├── JSONException.class │ │ ├── JSONObject$Null.class │ │ └── README ├── resocontrol │ ├── Tester.class │ ├── Value.class │ ├── FeedsPool.class │ ├── FeedWrapper.class │ ├── IACWrapper.class │ ├── ResoControl.class │ ├── FeedEvaluator.class │ ├── MappingManager.class │ ├── PSensorManager.class │ └── SoundManager.class └── pachube │ └── PachubeRequest.class └── src ├── resocontrol ├── Tester.java ├── ResoControl.java ├── FeedEvaluator.java ├── FeedsPool.java ├── MappingManager.java ├── Value.java ├── IACWrapper.java ├── SoundManager.java ├── FeedWrapper.java └── PSensorManager.java ├── org └── json │ ├── JSONString.java │ ├── JSONException.java │ ├── README │ ├── HTTPTokener.java │ ├── JSONStringer.java │ ├── CookieList.java │ ├── HTTP.java │ ├── Cookie.java │ ├── CDL.java │ ├── JSONWriter.java │ ├── XMLTokener.java │ ├── JSONTokener.java │ ├── JSONML.java │ ├── XML.java │ └── JSONArray.java └── pachube └── PachubeRequest.java /README: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /jmusic.tmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/jmusic.tmp -------------------------------------------------------------------------------- /Arpeggio1.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/Arpeggio1.mid -------------------------------------------------------------------------------- /TestMIDI.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/TestMIDI.mid -------------------------------------------------------------------------------- /lib/core.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/lib/core.jar -------------------------------------------------------------------------------- /lib/eeml.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/lib/eeml.jar -------------------------------------------------------------------------------- /lib/JPachube.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/lib/JPachube.jar -------------------------------------------------------------------------------- /lib/gson-1.6.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/lib/gson-1.6.jar -------------------------------------------------------------------------------- /lib/rwmidi.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/lib/rwmidi.jar -------------------------------------------------------------------------------- /bin/org/json/CDL.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/bin/org/json/CDL.class -------------------------------------------------------------------------------- /bin/org/json/HTTP.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/bin/org/json/HTTP.class -------------------------------------------------------------------------------- /bin/org/json/Test.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/bin/org/json/Test.class -------------------------------------------------------------------------------- /bin/org/json/XML.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/bin/org/json/XML.class -------------------------------------------------------------------------------- /lib/argo-small-2.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/lib/argo-small-2.4.jar -------------------------------------------------------------------------------- /bin/org/json/Cookie.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/bin/org/json/Cookie.class -------------------------------------------------------------------------------- /bin/org/json/JSONML.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/bin/org/json/JSONML.class -------------------------------------------------------------------------------- /bin/org/json/JSONArray.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/bin/org/json/JSONArray.class -------------------------------------------------------------------------------- /bin/resocontrol/Tester.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/bin/resocontrol/Tester.class -------------------------------------------------------------------------------- /bin/resocontrol/Value.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/bin/resocontrol/Value.class -------------------------------------------------------------------------------- /bin/org/json/CookieList.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/bin/org/json/CookieList.class -------------------------------------------------------------------------------- /bin/org/json/HTTPTokener.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/bin/org/json/HTTPTokener.class -------------------------------------------------------------------------------- /bin/org/json/JSONObject.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/bin/org/json/JSONObject.class -------------------------------------------------------------------------------- /bin/org/json/JSONString.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/bin/org/json/JSONString.class -------------------------------------------------------------------------------- /bin/org/json/JSONStringer.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/bin/org/json/JSONStringer.class -------------------------------------------------------------------------------- /bin/org/json/JSONTokener.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/bin/org/json/JSONTokener.class -------------------------------------------------------------------------------- /bin/org/json/JSONWriter.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/bin/org/json/JSONWriter.class -------------------------------------------------------------------------------- /bin/org/json/XMLTokener.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/bin/org/json/XMLTokener.class -------------------------------------------------------------------------------- /bin/resocontrol/FeedsPool.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/bin/resocontrol/FeedsPool.class -------------------------------------------------------------------------------- /lib/json-simple-1.1-bundle.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/lib/json-simple-1.1-bundle.jar -------------------------------------------------------------------------------- /bin/org/json/JSONException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/bin/org/json/JSONException.class -------------------------------------------------------------------------------- /bin/pachube/PachubeRequest.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/bin/pachube/PachubeRequest.class -------------------------------------------------------------------------------- /bin/resocontrol/FeedWrapper.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/bin/resocontrol/FeedWrapper.class -------------------------------------------------------------------------------- /bin/resocontrol/IACWrapper.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/bin/resocontrol/IACWrapper.class -------------------------------------------------------------------------------- /bin/resocontrol/ResoControl.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/bin/resocontrol/ResoControl.class -------------------------------------------------------------------------------- /bin/org/json/JSONObject$Null.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/bin/org/json/JSONObject$Null.class -------------------------------------------------------------------------------- /bin/resocontrol/FeedEvaluator.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/bin/resocontrol/FeedEvaluator.class -------------------------------------------------------------------------------- /bin/resocontrol/MappingManager.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/bin/resocontrol/MappingManager.class -------------------------------------------------------------------------------- /bin/resocontrol/PSensorManager.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/bin/resocontrol/PSensorManager.class -------------------------------------------------------------------------------- /bin/resocontrol/SoundManager.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/policy/resocontrol/master/bin/resocontrol/SoundManager.class -------------------------------------------------------------------------------- /src/resocontrol/Tester.java: -------------------------------------------------------------------------------- 1 | package resocontrol; 2 | import java.util.logging.Logger; 3 | 4 | public class Tester { 5 | static Logger logger = Logger.getLogger("MyLog"); 6 | static final String RESOCONTROLLER_NAME = "Reso-control"; 7 | 8 | public static void main(String[] args){ 9 | IACWrapper iw = new IACWrapper(); 10 | iw.setOutput(); 11 | iw.playTestNote(); 12 | 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/resocontrol/ResoControl.java: -------------------------------------------------------------------------------- 1 | package resocontrol; 2 | 3 | public class ResoControl { 4 | 5 | 6 | public static void main(String args[]){ 7 | //IACWrapper iw = new IACWrapper(); 8 | //iw.setOutput(); 9 | 10 | FeedsPool fp = new FeedsPool(); 11 | PSensorManager psm = new PSensorManager(fp); 12 | new Thread(psm).start(); 13 | 14 | SoundManager sm = new SoundManager(fp); 15 | new Thread(sm).start(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/resocontrol/FeedEvaluator.java: -------------------------------------------------------------------------------- 1 | package resocontrol; 2 | 3 | import java.util.Vector; 4 | 5 | import org.json.JSONObject; 6 | 7 | import Pachube.Feed; 8 | 9 | public class FeedEvaluator { 10 | 11 | Vector feeds = new Vector(); 12 | 13 | public FeedEvaluator(Vector v) { 14 | feeds = v; 15 | } 16 | 17 | public boolean isInteresting(FeedWrapper feed) { 18 | return true; 19 | } 20 | 21 | public boolean needMore() { 22 | if (feeds.size() > 5) 23 | return false; 24 | return true; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/org/json/JSONString.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | /** 3 | * The JSONString interface allows a toJSONString() 4 | * method so that a class can change the behavior of 5 | * JSONObject.toString(), JSONArray.toString(), 6 | * and JSONWriter.value(Object). The 7 | * toJSONString method will be used instead of the default behavior 8 | * of using the Object's toString() method and quoting the result. 9 | */ 10 | public interface JSONString { 11 | /** 12 | * The toJSONString method allows a class to produce its own JSON 13 | * serialization. 14 | * 15 | * @return A strictly syntactically correct JSON text. 16 | */ 17 | public String toJSONString(); 18 | } 19 | -------------------------------------------------------------------------------- /src/org/json/JSONException.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | /** 4 | * The JSONException is thrown by the JSON.org classes when things are amiss. 5 | * @author JSON.org 6 | * @version 2010-12-24 7 | */ 8 | public class JSONException extends Exception { 9 | private static final long serialVersionUID = 0; 10 | private Throwable cause; 11 | 12 | /** 13 | * Constructs a JSONException with an explanatory message. 14 | * @param message Detail about the reason for the exception. 15 | */ 16 | public JSONException(String message) { 17 | super(message); 18 | } 19 | 20 | public JSONException(Throwable cause) { 21 | super(cause.getMessage()); 22 | this.cause = cause; 23 | } 24 | 25 | public Throwable getCause() { 26 | return this.cause; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/resocontrol/FeedsPool.java: -------------------------------------------------------------------------------- 1 | package resocontrol; 2 | 3 | import java.util.Vector; 4 | import java.util.logging.Level; 5 | import java.util.logging.Logger; 6 | 7 | import org.json.JSONException; 8 | 9 | public class FeedsPool { 10 | 11 | Vector feeds = new Vector(); 12 | FeedWrapper currentFeed = null; 13 | static Logger logger = Logger.getLogger("MyLog"); 14 | 15 | public synchronized void update(Vector feeds){ 16 | this.feeds = feeds; 17 | } 18 | 19 | public synchronized Vector get() throws InterruptedException{ 20 | if (this.feeds == null && this.feeds.size() < 1) { 21 | wait(); 22 | } 23 | return this.feeds; 24 | } 25 | 26 | 27 | 28 | public synchronized void needNew(){ 29 | notifyAll(); 30 | } 31 | 32 | public synchronized FeedWrapper getCurrentFeed() throws InterruptedException { 33 | if (this.currentFeed == null) { 34 | wait(); 35 | } 36 | return currentFeed; 37 | } 38 | 39 | public synchronized void setCurrentFeed(FeedWrapper currentFeed) throws JSONException, InterruptedException { 40 | currentFeed.expand(); 41 | logger.log(Level.INFO, "Extracted feed " + currentFeed.getId() + " with name " + currentFeed.getName()); 42 | this.currentFeed = currentFeed; 43 | notify(); 44 | wait(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/resocontrol/MappingManager.java: -------------------------------------------------------------------------------- 1 | package resocontrol; 2 | 3 | import java.util.HashMap; 4 | import java.util.HashSet; 5 | 6 | public class MappingManager { 7 | static final int[] availableCC = {1,2,3,4,5,6,7,8,9,10}; 8 | HashMap midimap = new HashMap(); 9 | 10 | 11 | public void updateInputs(HashMap hm) { 12 | HashSet set= new HashSet(); 13 | set.addAll(hm.keySet()); 14 | HashMap newmidimap = new HashMap(); 15 | for (String s : hm.keySet()){ 16 | if (midimap.containsKey(s)) { 17 | newmidimap.put(s, midimap.get(s)); 18 | set.remove(s); 19 | } 20 | } 21 | for (String s : set){ 22 | int freemidi = -1; 23 | if(availableCC.length > midimap.size()){ 24 | for (int i = 0; i < availableCC.length; i++){ 25 | if (! newmidimap.containsValue(availableCC[i])) { 26 | freemidi = availableCC[i]; 27 | break; 28 | } 29 | } 30 | newmidimap.put(s, freemidi); 31 | } 32 | else break; 33 | } 34 | midimap = newmidimap; 35 | 36 | } 37 | 38 | 39 | public HashMap getMidimap() { 40 | return midimap; 41 | } 42 | 43 | 44 | public void setMidimap(HashMap midimap) { 45 | this.midimap = midimap; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/resocontrol/Value.java: -------------------------------------------------------------------------------- 1 | package resocontrol; 2 | 3 | public class Value { 4 | double min_value; 5 | double max_value; 6 | double current_value; 7 | String id; 8 | 9 | public Value(String id, double current_value, double min_value, double max_value) { 10 | this.current_value = current_value; 11 | this.min_value = min_value; 12 | this.max_value = max_value; 13 | this.id = id; 14 | } 15 | 16 | public double getMin_value() { 17 | return min_value; 18 | } 19 | public void setMin_value(double min_value) { 20 | this.min_value = min_value; 21 | } 22 | public double getMax_value() { 23 | return max_value; 24 | } 25 | public void setMax_value(double max_value) { 26 | this.max_value = max_value; 27 | } 28 | public int getCurrent_value(double i) { 29 | //System.out.println("("+ current_value +" - " + min_value + ")/("+max_value+ " - "+min_value+ " ) * " +i ); 30 | if (max_value == min_value ) return 0; 31 | return safeLongToInt(((current_value*1.0-min_value*1.0)/(max_value*1.0-min_value*1.0)) * i*1.0); 32 | } 33 | public void setCurrent_value(double current_value) { 34 | this.current_value = current_value; 35 | } 36 | 37 | public String getId() { 38 | return id; 39 | } 40 | 41 | public void setId(String id) { 42 | this.id = id; 43 | } 44 | 45 | public int safeLongToInt(double l) { 46 | if (l < Integer.MIN_VALUE || l > Integer.MAX_VALUE) { 47 | return Integer.MAX_VALUE; 48 | } 49 | return (int) l; 50 | } 51 | 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/resocontrol/IACWrapper.java: -------------------------------------------------------------------------------- 1 | package resocontrol; 2 | import rwmidi.*; 3 | 4 | import java.util.logging.Level; 5 | import java.util.logging.Logger; 6 | 7 | import javax.sound.midi.MidiDevice; 8 | import javax.sound.midi.MidiSystem; 9 | import javax.sound.midi.MidiUnavailableException; 10 | import javax.sound.midi.MidiDevice.Info; 11 | 12 | public class IACWrapper { 13 | static Logger logger = Logger.getLogger("MyLog"); 14 | static final String RESOCONTROLLER_NAME = "Reso-control"; 15 | MidiOutput output; 16 | 17 | public IACWrapper(){ 18 | super(); 19 | } 20 | 21 | public void setOutput(){ 22 | 23 | logger.log(Level.INFO, "Output:" ); 24 | String[] outDevices = RWMidi.getOutputDeviceNames() ; 25 | 26 | int l = outDevices.length; 27 | 28 | for (int i = 0; i < l; i++) { 29 | logger.log(Level.INFO, outDevices[i] ); 30 | } 31 | 32 | 33 | try { 34 | output = IACWrapper.getResoMIDIDevice().createOutput(); 35 | } catch (MidiUnavailableException e) { 36 | // TODO Auto-generated catch block 37 | e.printStackTrace(); 38 | } 39 | } 40 | 41 | public void playTestNote(){ 42 | output.sendNoteOn(0, 3, 3); 43 | } 44 | 45 | public static MidiOutputDevice getResoMIDIDevice() throws MidiUnavailableException{ 46 | for (String i : RWMidi.getOutputDeviceNames()){ 47 | logger.log(Level.INFO, i); 48 | if (i.startsWith(RESOCONTROLLER_NAME)){ 49 | MidiOutputDevice d = RWMidi.getOutputDevice(i); 50 | return d; 51 | } 52 | } 53 | throw new MidiUnavailableException(); 54 | 55 | } 56 | 57 | public void sendController(int channel, int cc, int value){ 58 | logger.log(Level.INFO, "Playing value [" + value + "] on " + channel + "#" + cc); 59 | output.sendController(channel, cc, value); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/resocontrol/SoundManager.java: -------------------------------------------------------------------------------- 1 | package resocontrol; 2 | 3 | import java.io.IOException; 4 | import java.util.HashMap; 5 | import java.util.logging.Level; 6 | import java.util.logging.Logger; 7 | 8 | public class SoundManager implements Runnable{ 9 | int MIDICHANNEL = 1; 10 | long SLEEPTIME = 5000; 11 | FeedsPool feedsPool; 12 | IACWrapper iacw = new IACWrapper(); 13 | 14 | static Logger logger = Logger.getLogger("MyLog"); 15 | 16 | public SoundManager(FeedsPool fp) { 17 | this.feedsPool = fp; 18 | iacw.setOutput(); 19 | } 20 | 21 | public void run() { 22 | feedsPool.needNew(); 23 | MappingManager mm = new MappingManager(); 24 | while(true){ 25 | try { 26 | logger.log(Level.INFO, "New Cycle"); 27 | FeedWrapper fw = feedsPool.getCurrentFeed(); 28 | logger.log(Level.INFO, "Sound from: " + fw.getName()); 29 | HashMap hm = fw.readValueMap(); 30 | mm.updateInputs(hm); 31 | HashMap map = mm.getMidimap(); 32 | playSounds(hm, map); 33 | Thread.sleep(SLEEPTIME); 34 | 35 | } catch (InterruptedException e) { 36 | e.printStackTrace(); 37 | } catch (Exception e) { 38 | e.printStackTrace(); 39 | try { 40 | Thread.sleep(SLEEPTIME); 41 | } catch (InterruptedException e1) { 42 | e1.printStackTrace(); 43 | } 44 | feedsPool.needNew(); 45 | continue; 46 | } 47 | } 48 | } 49 | 50 | private void playSounds(HashMap hm, 51 | HashMap map) { 52 | for (String s : map.keySet()){ 53 | int midi = map.get(s); 54 | Value v = hm.get(s); 55 | //logger.log(Level.INFO, "ORIGINAL:"+ v.current_value); 56 | //logger.log(Level.INFO, "ROUNDED:"+ v.getCurrent_value(127)); 57 | iacw.sendController(1, midi, Math.round(v.getCurrent_value(127))); 58 | } 59 | 60 | } 61 | 62 | 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/resocontrol/FeedWrapper.java: -------------------------------------------------------------------------------- 1 | package resocontrol; 2 | 3 | import java.io.IOException; 4 | import java.text.DecimalFormat; 5 | import java.text.ParseException; 6 | import java.util.HashMap; 7 | 8 | import org.json.JSONArray; 9 | import org.json.JSONException; 10 | import org.json.JSONObject; 11 | 12 | import pachube.PachubeRequest; 13 | 14 | public class FeedWrapper { 15 | JSONObject feedInfo; 16 | int id = -1; 17 | String name = null; 18 | 19 | public JSONObject getFeedInfo() { 20 | return feedInfo; 21 | } 22 | 23 | public void setFeedInfo(JSONObject feedInfo) { 24 | this.feedInfo = feedInfo; 25 | } 26 | 27 | public void expand() throws JSONException { 28 | name = feedInfo.get("title").toString(); 29 | id = Integer.parseInt(feedInfo.get("id").toString()); 30 | 31 | } 32 | 33 | public int getId() { 34 | return id; 35 | } 36 | 37 | public void setId(int id) { 38 | this.id = id; 39 | } 40 | 41 | public String getName() { 42 | return name; 43 | } 44 | 45 | public void setName(String name) { 46 | this.name = name; 47 | } 48 | 49 | public HashMap readValueMap() throws IOException { 50 | assert(id != -1); 51 | PachubeRequest pr = new PachubeRequest("http://api.pachube.com/v2/feeds/" + id, "json"); 52 | pr.addParameter("key", PSensorManager.KEY); 53 | try { 54 | return processRequest(pr); 55 | } catch (ParseException e) { 56 | // TODO Auto-generated catch block 57 | e.printStackTrace(); 58 | } 59 | return null; 60 | } 61 | 62 | private HashMap processRequest(PachubeRequest pr) throws IOException, ParseException{ 63 | String js = pr.retrieveJSON(); 64 | JSONObject q; 65 | HashMap hm = new HashMap(); 66 | try { 67 | q = new JSONObject(js); 68 | 69 | JSONArray datastreams = q.getJSONArray("datastreams"); 70 | 71 | for(int i = 0; i < datastreams.length(); i++ ){ 72 | JSONObject finfo = (JSONObject) datastreams.get(i); 73 | DecimalFormat fm = new DecimalFormat("#.#####"); 74 | long max_value = (fm.parse(finfo.getString("max_value")).longValue()); 75 | long min_value = (fm.parse(finfo.getString("min_value")).longValue()); 76 | long value = (fm.parse(finfo.getString("current_value")).longValue()); 77 | 78 | String id = finfo.getString("id"); 79 | 80 | Value v = new Value(id, value, min_value, max_value); 81 | hm.put(v.getId(), v); 82 | 83 | } 84 | } catch (JSONException e1) { 85 | // TODO Auto-generated catch block 86 | e1.printStackTrace(); 87 | } 88 | assert false : "I shouldn't go here"; 89 | return hm; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/pachube/PachubeRequest.java: -------------------------------------------------------------------------------- 1 | package pachube; 2 | import java.net.*; 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.io.InputStreamReader; 7 | 8 | import java.net.MalformedURLException; 9 | import java.net.URL; 10 | import java.util.HashMap; 11 | import java.util.logging.Level; 12 | import java.util.logging.Logger; 13 | 14 | public class PachubeRequest { 15 | static Logger logger = Logger.getLogger("MyLog"); 16 | 17 | private HashMap parameters = new HashMap(); 18 | private String type; 19 | private String address; 20 | 21 | public PachubeRequest(String address, String type, HashMap parameters){ 22 | this(address, type); 23 | this.parameters = parameters; 24 | } 25 | 26 | public PachubeRequest(String address, String type){ 27 | this.type = type; 28 | this.address = address; 29 | } 30 | 31 | public void addParameter(String key, String value){ 32 | parameters.put(key, value); 33 | } 34 | 35 | public String getAddress(){ 36 | String out = address.startsWith("http://") ? address : "http://" + address; 37 | if (type != null && type.length() > 0) out += "." + type + "?"; 38 | for (String o : parameters.keySet()){ 39 | out +=o + "=" + parameters.get(o) + "&"; 40 | } 41 | return (out.indexOf('?') == out.length() - 1) ? out.substring(0, out.length() - 1) : out; 42 | } 43 | 44 | public BufferedReader retrieveJSONReader() throws IOException{ 45 | String address = this.getAddress(); 46 | URL url; 47 | BufferedReader reader = null; 48 | InputStream response; 49 | logger.log(Level.INFO, "Retrieving " + address); 50 | url = new URL(address); 51 | if (((HttpURLConnection) url.openConnection()).getResponseCode() == HttpURLConnection.HTTP_OK){ 52 | response = url.openStream(); 53 | reader = new BufferedReader(new InputStreamReader(response)); 54 | System.out.println(url.toString() + ":" + "Success"); 55 | } 56 | else{ 57 | System.out.println(url.toString() + ":" + ((HttpURLConnection) url.openConnection()).getResponseCode() ); 58 | throw new IOException(); 59 | } 60 | 61 | return reader; 62 | } 63 | 64 | public String retrieveJSON() throws IOException{ 65 | String b = ""; 66 | BufferedReader reader = retrieveJSONReader(); 67 | try { 68 | for (String line; (line = reader.readLine()) != null;) { 69 | b+=line; 70 | } 71 | assert(b.length() > 0); 72 | reader.close(); 73 | } catch (IOException e) { 74 | // TODO Auto-generated catch block 75 | e.printStackTrace(); 76 | } 77 | return b; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /bin/org/json/README: -------------------------------------------------------------------------------- 1 | JSON in Java [package org.json] 2 | 3 | Douglas Crockford 4 | douglas@crockford.com 5 | 6 | 2011-02-02 7 | 8 | 9 | JSON is a light-weight, language independent, data interchange format. 10 | See http://www.JSON.org/ 11 | 12 | The files in this package implement JSON encoders/decoders in Java. 13 | It also includes the capability to convert between JSON and XML, HTTP 14 | headers, Cookies, and CDL. 15 | 16 | This is a reference implementation. There is a large number of JSON packages 17 | in Java. Perhaps someday the Java community will standardize on one. Until 18 | then, choose carefully. 19 | 20 | The license includes this restriction: "The software shall be used for good, 21 | not evil." If your conscience cannot live with that, then choose a different 22 | package. 23 | 24 | The package compiles on Java 1.2 thru Java 1.4. 25 | 26 | 27 | JSONObject.java: The JSONObject can parse text from a String or a JSONTokener 28 | to produce a map-like object. The object provides methods for manipulating its 29 | contents, and for producing a JSON compliant object serialization. 30 | 31 | JSONArray.java: The JSONObject can parse text from a String or a JSONTokener 32 | to produce a vector-like object. The object provides methods for manipulating 33 | its contents, and for producing a JSON compliant array serialization. 34 | 35 | JSONTokener.java: The JSONTokener breaks a text into a sequence of individual 36 | tokens. It can be constructed from a String, Reader, or InputStream. 37 | 38 | JSONException.java: The JSONException is the standard exception type thrown 39 | by this package. 40 | 41 | 42 | JSONString.java: The JSONString interface requires a toJSONString method, 43 | allowing an object to provide its own serialization. 44 | 45 | JSONStringer.java: The JSONStringer provides a convenient facility for 46 | building JSON strings. 47 | 48 | JSONWriter.java: The JSONWriter provides a convenient facility for building 49 | JSON text through a writer. 50 | 51 | 52 | CDL.java: CDL provides support for converting between JSON and comma 53 | delimited lists. 54 | 55 | Cookie.java: Cookie provides support for converting between JSON and cookies. 56 | 57 | CookieList.java: CookieList provides support for converting between JSON and 58 | cookie lists. 59 | 60 | HTTP.java: HTTP provides support for converting between JSON and HTTP headers. 61 | 62 | HTTPTokener.java: HTTPTokener extends JSONTokener for parsing HTTP headers. 63 | 64 | XML.java: XML provides support for converting between JSON and XML. 65 | 66 | JSONML.java: JSONML provides support for converting between JSONML and XML. 67 | 68 | XMLTokener.java: XMLTokener extends JSONTokener for parsing XML text. -------------------------------------------------------------------------------- /src/org/json/README: -------------------------------------------------------------------------------- 1 | JSON in Java [package org.json] 2 | 3 | Douglas Crockford 4 | douglas@crockford.com 5 | 6 | 2011-02-02 7 | 8 | 9 | JSON is a light-weight, language independent, data interchange format. 10 | See http://www.JSON.org/ 11 | 12 | The files in this package implement JSON encoders/decoders in Java. 13 | It also includes the capability to convert between JSON and XML, HTTP 14 | headers, Cookies, and CDL. 15 | 16 | This is a reference implementation. There is a large number of JSON packages 17 | in Java. Perhaps someday the Java community will standardize on one. Until 18 | then, choose carefully. 19 | 20 | The license includes this restriction: "The software shall be used for good, 21 | not evil." If your conscience cannot live with that, then choose a different 22 | package. 23 | 24 | The package compiles on Java 1.2 thru Java 1.4. 25 | 26 | 27 | JSONObject.java: The JSONObject can parse text from a String or a JSONTokener 28 | to produce a map-like object. The object provides methods for manipulating its 29 | contents, and for producing a JSON compliant object serialization. 30 | 31 | JSONArray.java: The JSONObject can parse text from a String or a JSONTokener 32 | to produce a vector-like object. The object provides methods for manipulating 33 | its contents, and for producing a JSON compliant array serialization. 34 | 35 | JSONTokener.java: The JSONTokener breaks a text into a sequence of individual 36 | tokens. It can be constructed from a String, Reader, or InputStream. 37 | 38 | JSONException.java: The JSONException is the standard exception type thrown 39 | by this package. 40 | 41 | 42 | JSONString.java: The JSONString interface requires a toJSONString method, 43 | allowing an object to provide its own serialization. 44 | 45 | JSONStringer.java: The JSONStringer provides a convenient facility for 46 | building JSON strings. 47 | 48 | JSONWriter.java: The JSONWriter provides a convenient facility for building 49 | JSON text through a writer. 50 | 51 | 52 | CDL.java: CDL provides support for converting between JSON and comma 53 | delimited lists. 54 | 55 | Cookie.java: Cookie provides support for converting between JSON and cookies. 56 | 57 | CookieList.java: CookieList provides support for converting between JSON and 58 | cookie lists. 59 | 60 | HTTP.java: HTTP provides support for converting between JSON and HTTP headers. 61 | 62 | HTTPTokener.java: HTTPTokener extends JSONTokener for parsing HTTP headers. 63 | 64 | XML.java: XML provides support for converting between JSON and XML. 65 | 66 | JSONML.java: JSONML provides support for converting between JSONML and XML. 67 | 68 | XMLTokener.java: XMLTokener extends JSONTokener for parsing XML text. -------------------------------------------------------------------------------- /src/org/json/HTTPTokener.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | /* 4 | Copyright (c) 2002 JSON.org 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | The Software shall be used for Good, not Evil. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | */ 26 | 27 | /** 28 | * The HTTPTokener extends the JSONTokener to provide additional methods 29 | * for the parsing of HTTP headers. 30 | * @author JSON.org 31 | * @version 2010-12-24 32 | */ 33 | public class HTTPTokener extends JSONTokener { 34 | 35 | /** 36 | * Construct an HTTPTokener from a string. 37 | * @param string A source string. 38 | */ 39 | public HTTPTokener(String string) { 40 | super(string); 41 | } 42 | 43 | 44 | /** 45 | * Get the next token or string. This is used in parsing HTTP headers. 46 | * @throws JSONException 47 | * @return A String. 48 | */ 49 | public String nextToken() throws JSONException { 50 | char c; 51 | char q; 52 | StringBuffer sb = new StringBuffer(); 53 | do { 54 | c = next(); 55 | } while (Character.isWhitespace(c)); 56 | if (c == '"' || c == '\'') { 57 | q = c; 58 | for (;;) { 59 | c = next(); 60 | if (c < ' ') { 61 | throw syntaxError("Unterminated string."); 62 | } 63 | if (c == q) { 64 | return sb.toString(); 65 | } 66 | sb.append(c); 67 | } 68 | } 69 | for (;;) { 70 | if (c == 0 || Character.isWhitespace(c)) { 71 | return sb.toString(); 72 | } 73 | sb.append(c); 74 | c = next(); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/resocontrol/PSensorManager.java: -------------------------------------------------------------------------------- 1 | package resocontrol; 2 | import java.io.IOException; 3 | import java.io.Reader; 4 | import java.util.HashSet; 5 | import java.util.Map; 6 | import java.util.Set; 7 | import java.util.Vector; 8 | import java.util.logging.Level; 9 | import java.util.logging.Logger; 10 | 11 | import javax.print.attribute.standard.MediaSize.JIS; 12 | 13 | import org.json.JSONArray; 14 | import org.json.JSONException; 15 | import org.json.JSONObject; 16 | import org.json.JSONException; 17 | 18 | import pachube.PachubeRequest; 19 | 20 | 21 | 22 | import Pachube.Data; 23 | import Pachube.Feed; 24 | import Pachube.Pachube; 25 | import Pachube.PachubeException; 26 | 27 | public class PSensorManager implements Runnable { 28 | static Logger logger = Logger.getLogger("MyLog"); 29 | 30 | final public static String KEY = "rlIuOhxTNqW3peQe9bRLAiWBYGlCi3HCsL9iIM32Vb4"; 31 | final long UPDATE_TIME_MS = 5000; 32 | 33 | FeedsPool feedsPool; 34 | 35 | public PSensorManager(FeedsPool fp) { 36 | this.feedsPool = fp; 37 | } 38 | 39 | public JSONArray getFeedArray() throws IOException{ 40 | PachubeRequest pr = new PachubeRequest("http://api.pachube.com/v2/feeds", "json"); 41 | pr.addParameter("key", KEY); 42 | pr.addParameter("content", "summary"); 43 | try { 44 | String JSONAvailableSensors = pr.retrieveJSON(); 45 | JSONObject q = new JSONObject(JSONAvailableSensors); 46 | int o = (Integer) q.get("itemsPerPage"); 47 | System.out.println(""+o); 48 | JSONArray a = q.getJSONArray("results"); 49 | return a; 50 | 51 | } catch (JSONException e) { 52 | // TODO Auto-generated catch block 53 | e.printStackTrace(); 54 | } 55 | return null; 56 | 57 | } 58 | 59 | public void populatePool() throws IOException{ 60 | JSONArray a = getFeedArray(); 61 | Vector v = new Vector(); 62 | FeedEvaluator fe = new FeedEvaluator(v); 63 | try { 64 | for(int i = 0; i < a.length(); i++ ){ 65 | JSONObject finfo = (JSONObject) a.get(i); 66 | FeedWrapper feed = new FeedWrapper(); 67 | feed.setFeedInfo(finfo); 68 | if (fe.isInteresting(feed) && fe.needMore()){ 69 | v.add(feed); 70 | } 71 | } 72 | } catch (JSONException e) { 73 | e.printStackTrace(); 74 | } 75 | 76 | //Synch 77 | feedsPool.update(v); 78 | 79 | 80 | } 81 | 82 | public void run() { 83 | // Every UPDATE_TIME_MS populates a list of interesting feeds 84 | while(true){ 85 | try { 86 | populatePool(); 87 | } catch (IOException e1) { 88 | e1.printStackTrace(); 89 | continue; 90 | } 91 | try { 92 | Vector g = feedsPool.get(); 93 | FeedWrapper currentFeed = g.get((int)(Math.random()*(g.size()-1))); 94 | logger.log(Level.INFO, "Setting the current and waiting"); 95 | feedsPool.setCurrentFeed(currentFeed); 96 | Thread.sleep(UPDATE_TIME_MS); 97 | } 98 | catch (JSONException e) { 99 | e.printStackTrace(); 100 | } 101 | catch (InterruptedException e) { 102 | e.printStackTrace(); 103 | } 104 | } 105 | } 106 | 107 | 108 | } 109 | 110 | -------------------------------------------------------------------------------- /src/org/json/JSONStringer.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | /* 4 | Copyright (c) 2006 JSON.org 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | The Software shall be used for Good, not Evil. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | */ 26 | 27 | import java.io.StringWriter; 28 | 29 | /** 30 | * JSONStringer provides a quick and convenient way of producing JSON text. 31 | * The texts produced strictly conform to JSON syntax rules. No whitespace is 32 | * added, so the results are ready for transmission or storage. Each instance of 33 | * JSONStringer can produce one JSON text. 34 | *

35 | * A JSONStringer instance provides a value method for appending 36 | * values to the 37 | * text, and a key 38 | * method for adding keys before values in objects. There are array 39 | * and endArray methods that make and bound array values, and 40 | * object and endObject methods which make and bound 41 | * object values. All of these methods return the JSONWriter instance, 42 | * permitting cascade style. For example,

43 |  * myString = new JSONStringer()
44 |  *     .object()
45 |  *         .key("JSON")
46 |  *         .value("Hello, World!")
47 |  *     .endObject()
48 |  *     .toString();
which produces the string
49 |  * {"JSON":"Hello, World!"}
50 | *

51 | * The first method called must be array or object. 52 | * There are no methods for adding commas or colons. JSONStringer adds them for 53 | * you. Objects and arrays can be nested up to 20 levels deep. 54 | *

55 | * This can sometimes be easier than using a JSONObject to build a string. 56 | * @author JSON.org 57 | * @version 2008-09-18 58 | */ 59 | public class JSONStringer extends JSONWriter { 60 | /** 61 | * Make a fresh JSONStringer. It can be used to build one JSON text. 62 | */ 63 | public JSONStringer() { 64 | super(new StringWriter()); 65 | } 66 | 67 | /** 68 | * Return the JSON text. This method is used to obtain the product of the 69 | * JSONStringer instance. It will return null if there was a 70 | * problem in the construction of the JSON text (such as the calls to 71 | * array were not properly balanced with calls to 72 | * endArray). 73 | * @return The JSON text. 74 | */ 75 | public String toString() { 76 | return this.mode == 'd' ? this.writer.toString() : null; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/org/json/CookieList.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | /* 4 | Copyright (c) 2002 JSON.org 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | The Software shall be used for Good, not Evil. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | */ 26 | 27 | import java.util.Iterator; 28 | 29 | /** 30 | * Convert a web browser cookie list string to a JSONObject and back. 31 | * @author JSON.org 32 | * @version 2010-12-24 33 | */ 34 | public class CookieList { 35 | 36 | /** 37 | * Convert a cookie list into a JSONObject. A cookie list is a sequence 38 | * of name/value pairs. The names are separated from the values by '='. 39 | * The pairs are separated by ';'. The names and the values 40 | * will be unescaped, possibly converting '+' and '%' sequences. 41 | * 42 | * To add a cookie to a cooklist, 43 | * cookielistJSONObject.put(cookieJSONObject.getString("name"), 44 | * cookieJSONObject.getString("value")); 45 | * @param string A cookie list string 46 | * @return A JSONObject 47 | * @throws JSONException 48 | */ 49 | public static JSONObject toJSONObject(String string) throws JSONException { 50 | JSONObject jo = new JSONObject(); 51 | JSONTokener x = new JSONTokener(string); 52 | while (x.more()) { 53 | String name = Cookie.unescape(x.nextTo('=')); 54 | x.next('='); 55 | jo.put(name, Cookie.unescape(x.nextTo(';'))); 56 | x.next(); 57 | } 58 | return jo; 59 | } 60 | 61 | 62 | /** 63 | * Convert a JSONObject into a cookie list. A cookie list is a sequence 64 | * of name/value pairs. The names are separated from the values by '='. 65 | * The pairs are separated by ';'. The characters '%', '+', '=', and ';' 66 | * in the names and values are replaced by "%hh". 67 | * @param jo A JSONObject 68 | * @return A cookie list string 69 | * @throws JSONException 70 | */ 71 | public static String toString(JSONObject jo) throws JSONException { 72 | boolean b = false; 73 | Iterator keys = jo.keys(); 74 | String string; 75 | StringBuffer sb = new StringBuffer(); 76 | while (keys.hasNext()) { 77 | string = keys.next().toString(); 78 | if (!jo.isNull(string)) { 79 | if (b) { 80 | sb.append(';'); 81 | } 82 | sb.append(Cookie.escape(string)); 83 | sb.append("="); 84 | sb.append(Cookie.escape(jo.getString(string))); 85 | b = true; 86 | } 87 | } 88 | return sb.toString(); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/org/json/HTTP.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | /* 4 | Copyright (c) 2002 JSON.org 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | The Software shall be used for Good, not Evil. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | */ 26 | 27 | import java.util.Iterator; 28 | 29 | /** 30 | * Convert an HTTP header to a JSONObject and back. 31 | * @author JSON.org 32 | * @version 2010-12-24 33 | */ 34 | public class HTTP { 35 | 36 | /** Carriage return/line feed. */ 37 | public static final String CRLF = "\r\n"; 38 | 39 | /** 40 | * Convert an HTTP header string into a JSONObject. It can be a request 41 | * header or a response header. A request header will contain 42 | *

{
 43 |      *    Method: "POST" (for example),
 44 |      *    "Request-URI": "/" (for example),
 45 |      *    "HTTP-Version": "HTTP/1.1" (for example)
 46 |      * }
47 | * A response header will contain 48 | *
{
 49 |      *    "HTTP-Version": "HTTP/1.1" (for example),
 50 |      *    "Status-Code": "200" (for example),
 51 |      *    "Reason-Phrase": "OK" (for example)
 52 |      * }
53 | * In addition, the other parameters in the header will be captured, using 54 | * the HTTP field names as JSON names, so that
 55 |      *    Date: Sun, 26 May 2002 18:06:04 GMT
 56 |      *    Cookie: Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s
 57 |      *    Cache-Control: no-cache
58 | * become 59 | *
{...
 60 |      *    Date: "Sun, 26 May 2002 18:06:04 GMT",
 61 |      *    Cookie: "Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s",
 62 |      *    "Cache-Control": "no-cache",
 63 |      * ...}
64 | * It does no further checking or conversion. It does not parse dates. 65 | * It does not do '%' transforms on URLs. 66 | * @param string An HTTP header string. 67 | * @return A JSONObject containing the elements and attributes 68 | * of the XML string. 69 | * @throws JSONException 70 | */ 71 | public static JSONObject toJSONObject(String string) throws JSONException { 72 | JSONObject jo = new JSONObject(); 73 | HTTPTokener x = new HTTPTokener(string); 74 | String token; 75 | 76 | token = x.nextToken(); 77 | if (token.toUpperCase().startsWith("HTTP")) { 78 | 79 | // Response 80 | 81 | jo.put("HTTP-Version", token); 82 | jo.put("Status-Code", x.nextToken()); 83 | jo.put("Reason-Phrase", x.nextTo('\0')); 84 | x.next(); 85 | 86 | } else { 87 | 88 | // Request 89 | 90 | jo.put("Method", token); 91 | jo.put("Request-URI", x.nextToken()); 92 | jo.put("HTTP-Version", x.nextToken()); 93 | } 94 | 95 | // Fields 96 | 97 | while (x.more()) { 98 | String name = x.nextTo(':'); 99 | x.next(':'); 100 | jo.put(name, x.nextTo('\0')); 101 | x.next(); 102 | } 103 | return jo; 104 | } 105 | 106 | 107 | /** 108 | * Convert a JSONObject into an HTTP header. A request header must contain 109 | *
{
110 |      *    Method: "POST" (for example),
111 |      *    "Request-URI": "/" (for example),
112 |      *    "HTTP-Version": "HTTP/1.1" (for example)
113 |      * }
114 | * A response header must contain 115 | *
{
116 |      *    "HTTP-Version": "HTTP/1.1" (for example),
117 |      *    "Status-Code": "200" (for example),
118 |      *    "Reason-Phrase": "OK" (for example)
119 |      * }
120 | * Any other members of the JSONObject will be output as HTTP fields. 121 | * The result will end with two CRLF pairs. 122 | * @param jo A JSONObject 123 | * @return An HTTP header string. 124 | * @throws JSONException if the object does not contain enough 125 | * information. 126 | */ 127 | public static String toString(JSONObject jo) throws JSONException { 128 | Iterator keys = jo.keys(); 129 | String string; 130 | StringBuffer sb = new StringBuffer(); 131 | if (jo.has("Status-Code") && jo.has("Reason-Phrase")) { 132 | sb.append(jo.getString("HTTP-Version")); 133 | sb.append(' '); 134 | sb.append(jo.getString("Status-Code")); 135 | sb.append(' '); 136 | sb.append(jo.getString("Reason-Phrase")); 137 | } else if (jo.has("Method") && jo.has("Request-URI")) { 138 | sb.append(jo.getString("Method")); 139 | sb.append(' '); 140 | sb.append('"'); 141 | sb.append(jo.getString("Request-URI")); 142 | sb.append('"'); 143 | sb.append(' '); 144 | sb.append(jo.getString("HTTP-Version")); 145 | } else { 146 | throw new JSONException("Not enough material for an HTTP header."); 147 | } 148 | sb.append(CRLF); 149 | while (keys.hasNext()) { 150 | string = keys.next().toString(); 151 | if (!string.equals("HTTP-Version") && !string.equals("Status-Code") && 152 | !string.equals("Reason-Phrase") && !string.equals("Method") && 153 | !string.equals("Request-URI") && !jo.isNull(string)) { 154 | sb.append(string); 155 | sb.append(": "); 156 | sb.append(jo.getString(string)); 157 | sb.append(CRLF); 158 | } 159 | } 160 | sb.append(CRLF); 161 | return sb.toString(); 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /src/org/json/Cookie.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | /* 4 | Copyright (c) 2002 JSON.org 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | The Software shall be used for Good, not Evil. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | */ 26 | 27 | /** 28 | * Convert a web browser cookie specification to a JSONObject and back. 29 | * JSON and Cookies are both notations for name/value pairs. 30 | * @author JSON.org 31 | * @version 2010-12-24 32 | */ 33 | public class Cookie { 34 | 35 | /** 36 | * Produce a copy of a string in which the characters '+', '%', '=', ';' 37 | * and control characters are replaced with "%hh". This is a gentle form 38 | * of URL encoding, attempting to cause as little distortion to the 39 | * string as possible. The characters '=' and ';' are meta characters in 40 | * cookies. By convention, they are escaped using the URL-encoding. This is 41 | * only a convention, not a standard. Often, cookies are expected to have 42 | * encoded values. We encode '=' and ';' because we must. We encode '%' and 43 | * '+' because they are meta characters in URL encoding. 44 | * @param string The source string. 45 | * @return The escaped result. 46 | */ 47 | public static String escape(String string) { 48 | char c; 49 | String s = string.trim(); 50 | StringBuffer sb = new StringBuffer(); 51 | int length = s.length(); 52 | for (int i = 0; i < length; i += 1) { 53 | c = s.charAt(i); 54 | if (c < ' ' || c == '+' || c == '%' || c == '=' || c == ';') { 55 | sb.append('%'); 56 | sb.append(Character.forDigit((char)((c >>> 4) & 0x0f), 16)); 57 | sb.append(Character.forDigit((char)(c & 0x0f), 16)); 58 | } else { 59 | sb.append(c); 60 | } 61 | } 62 | return sb.toString(); 63 | } 64 | 65 | 66 | /** 67 | * Convert a cookie specification string into a JSONObject. The string 68 | * will contain a name value pair separated by '='. The name and the value 69 | * will be unescaped, possibly converting '+' and '%' sequences. The 70 | * cookie properties may follow, separated by ';', also represented as 71 | * name=value (except the secure property, which does not have a value). 72 | * The name will be stored under the key "name", and the value will be 73 | * stored under the key "value". This method does not do checking or 74 | * validation of the parameters. It only converts the cookie string into 75 | * a JSONObject. 76 | * @param string The cookie specification string. 77 | * @return A JSONObject containing "name", "value", and possibly other 78 | * members. 79 | * @throws JSONException 80 | */ 81 | public static JSONObject toJSONObject(String string) throws JSONException { 82 | String name; 83 | JSONObject jo = new JSONObject(); 84 | Object value; 85 | JSONTokener x = new JSONTokener(string); 86 | jo.put("name", x.nextTo('=')); 87 | x.next('='); 88 | jo.put("value", x.nextTo(';')); 89 | x.next(); 90 | while (x.more()) { 91 | name = unescape(x.nextTo("=;")); 92 | if (x.next() != '=') { 93 | if (name.equals("secure")) { 94 | value = Boolean.TRUE; 95 | } else { 96 | throw x.syntaxError("Missing '=' in cookie parameter."); 97 | } 98 | } else { 99 | value = unescape(x.nextTo(';')); 100 | x.next(); 101 | } 102 | jo.put(name, value); 103 | } 104 | return jo; 105 | } 106 | 107 | 108 | /** 109 | * Convert a JSONObject into a cookie specification string. The JSONObject 110 | * must contain "name" and "value" members. 111 | * If the JSONObject contains "expires", "domain", "path", or "secure" 112 | * members, they will be appended to the cookie specification string. 113 | * All other members are ignored. 114 | * @param jo A JSONObject 115 | * @return A cookie specification string 116 | * @throws JSONException 117 | */ 118 | public static String toString(JSONObject jo) throws JSONException { 119 | StringBuffer sb = new StringBuffer(); 120 | 121 | sb.append(escape(jo.getString("name"))); 122 | sb.append("="); 123 | sb.append(escape(jo.getString("value"))); 124 | if (jo.has("expires")) { 125 | sb.append(";expires="); 126 | sb.append(jo.getString("expires")); 127 | } 128 | if (jo.has("domain")) { 129 | sb.append(";domain="); 130 | sb.append(escape(jo.getString("domain"))); 131 | } 132 | if (jo.has("path")) { 133 | sb.append(";path="); 134 | sb.append(escape(jo.getString("path"))); 135 | } 136 | if (jo.optBoolean("secure")) { 137 | sb.append(";secure"); 138 | } 139 | return sb.toString(); 140 | } 141 | 142 | /** 143 | * Convert %hh sequences to single characters, and 144 | * convert plus to space. 145 | * @param string A string that may contain 146 | * + (plus) and 147 | * %hh sequences. 148 | * @return The unescaped string. 149 | */ 150 | public static String unescape(String string) { 151 | int length = string.length(); 152 | StringBuffer sb = new StringBuffer(); 153 | for (int i = 0; i < length; ++i) { 154 | char c = string.charAt(i); 155 | if (c == '+') { 156 | c = ' '; 157 | } else if (c == '%' && i + 2 < length) { 158 | int d = JSONTokener.dehexchar(string.charAt(i + 1)); 159 | int e = JSONTokener.dehexchar(string.charAt(i + 2)); 160 | if (d >= 0 && e >= 0) { 161 | c = (char)(d * 16 + e); 162 | i += 2; 163 | } 164 | } 165 | sb.append(c); 166 | } 167 | return sb.toString(); 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /src/org/json/CDL.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | /* 4 | Copyright (c) 2002 JSON.org 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | The Software shall be used for Good, not Evil. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | */ 26 | 27 | /** 28 | * This provides static methods to convert comma delimited text into a 29 | * JSONArray, and to covert a JSONArray into comma delimited text. Comma 30 | * delimited text is a very popular format for data interchange. It is 31 | * understood by most database, spreadsheet, and organizer programs. 32 | *

33 | * Each row of text represents a row in a table or a data record. Each row 34 | * ends with a NEWLINE character. Each row contains one or more values. 35 | * Values are separated by commas. A value can contain any character except 36 | * for comma, unless is is wrapped in single quotes or double quotes. 37 | *

38 | * The first row usually contains the names of the columns. 39 | *

40 | * A comma delimited list can be converted into a JSONArray of JSONObjects. 41 | * The names for the elements in the JSONObjects can be taken from the names 42 | * in the first row. 43 | * @author JSON.org 44 | * @version 2010-12-24 45 | */ 46 | public class CDL { 47 | 48 | /** 49 | * Get the next value. The value can be wrapped in quotes. The value can 50 | * be empty. 51 | * @param x A JSONTokener of the source text. 52 | * @return The value string, or null if empty. 53 | * @throws JSONException if the quoted string is badly formed. 54 | */ 55 | private static String getValue(JSONTokener x) throws JSONException { 56 | char c; 57 | char q; 58 | StringBuffer sb; 59 | do { 60 | c = x.next(); 61 | } while (c == ' ' || c == '\t'); 62 | switch (c) { 63 | case 0: 64 | return null; 65 | case '"': 66 | case '\'': 67 | q = c; 68 | sb = new StringBuffer(); 69 | for (;;) { 70 | c = x.next(); 71 | if (c == q) { 72 | break; 73 | } 74 | if (c == 0 || c == '\n' || c == '\r') { 75 | throw x.syntaxError("Missing close quote '" + q + "'."); 76 | } 77 | sb.append(c); 78 | } 79 | return sb.toString(); 80 | case ',': 81 | x.back(); 82 | return ""; 83 | default: 84 | x.back(); 85 | return x.nextTo(','); 86 | } 87 | } 88 | 89 | /** 90 | * Produce a JSONArray of strings from a row of comma delimited values. 91 | * @param x A JSONTokener of the source text. 92 | * @return A JSONArray of strings. 93 | * @throws JSONException 94 | */ 95 | public static JSONArray rowToJSONArray(JSONTokener x) throws JSONException { 96 | JSONArray ja = new JSONArray(); 97 | for (;;) { 98 | String value = getValue(x); 99 | char c = x.next(); 100 | if (value == null || 101 | (ja.length() == 0 && value.length() == 0 && c != ',')) { 102 | return null; 103 | } 104 | ja.put(value); 105 | for (;;) { 106 | if (c == ',') { 107 | break; 108 | } 109 | if (c != ' ') { 110 | if (c == '\n' || c == '\r' || c == 0) { 111 | return ja; 112 | } 113 | throw x.syntaxError("Bad character '" + c + "' (" + 114 | (int)c + ")."); 115 | } 116 | c = x.next(); 117 | } 118 | } 119 | } 120 | 121 | /** 122 | * Produce a JSONObject from a row of comma delimited text, using a 123 | * parallel JSONArray of strings to provides the names of the elements. 124 | * @param names A JSONArray of names. This is commonly obtained from the 125 | * first row of a comma delimited text file using the rowToJSONArray 126 | * method. 127 | * @param x A JSONTokener of the source text. 128 | * @return A JSONObject combining the names and values. 129 | * @throws JSONException 130 | */ 131 | public static JSONObject rowToJSONObject(JSONArray names, JSONTokener x) 132 | throws JSONException { 133 | JSONArray ja = rowToJSONArray(x); 134 | return ja != null ? ja.toJSONObject(names) : null; 135 | } 136 | 137 | /** 138 | * Produce a comma delimited text row from a JSONArray. Values containing 139 | * the comma character will be quoted. Troublesome characters may be 140 | * removed. 141 | * @param ja A JSONArray of strings. 142 | * @return A string ending in NEWLINE. 143 | */ 144 | public static String rowToString(JSONArray ja) { 145 | StringBuffer sb = new StringBuffer(); 146 | for (int i = 0; i < ja.length(); i += 1) { 147 | if (i > 0) { 148 | sb.append(','); 149 | } 150 | Object object = ja.opt(i); 151 | if (object != null) { 152 | String string = object.toString(); 153 | if (string.length() > 0 && (string.indexOf(',') >= 0 || 154 | string.indexOf('\n') >= 0 || string.indexOf('\r') >= 0 || 155 | string.indexOf(0) >= 0 || string.charAt(0) == '"')) { 156 | sb.append('"'); 157 | int length = string.length(); 158 | for (int j = 0; j < length; j += 1) { 159 | char c = string.charAt(j); 160 | if (c >= ' ' && c != '"') { 161 | sb.append(c); 162 | } 163 | } 164 | sb.append('"'); 165 | } else { 166 | sb.append(string); 167 | } 168 | } 169 | } 170 | sb.append('\n'); 171 | return sb.toString(); 172 | } 173 | 174 | /** 175 | * Produce a JSONArray of JSONObjects from a comma delimited text string, 176 | * using the first row as a source of names. 177 | * @param string The comma delimited text. 178 | * @return A JSONArray of JSONObjects. 179 | * @throws JSONException 180 | */ 181 | public static JSONArray toJSONArray(String string) throws JSONException { 182 | return toJSONArray(new JSONTokener(string)); 183 | } 184 | 185 | /** 186 | * Produce a JSONArray of JSONObjects from a comma delimited text string, 187 | * using the first row as a source of names. 188 | * @param x The JSONTokener containing the comma delimited text. 189 | * @return A JSONArray of JSONObjects. 190 | * @throws JSONException 191 | */ 192 | public static JSONArray toJSONArray(JSONTokener x) throws JSONException { 193 | return toJSONArray(rowToJSONArray(x), x); 194 | } 195 | 196 | /** 197 | * Produce a JSONArray of JSONObjects from a comma delimited text string 198 | * using a supplied JSONArray as the source of element names. 199 | * @param names A JSONArray of strings. 200 | * @param string The comma delimited text. 201 | * @return A JSONArray of JSONObjects. 202 | * @throws JSONException 203 | */ 204 | public static JSONArray toJSONArray(JSONArray names, String string) 205 | throws JSONException { 206 | return toJSONArray(names, new JSONTokener(string)); 207 | } 208 | 209 | /** 210 | * Produce a JSONArray of JSONObjects from a comma delimited text string 211 | * using a supplied JSONArray as the source of element names. 212 | * @param names A JSONArray of strings. 213 | * @param x A JSONTokener of the source text. 214 | * @return A JSONArray of JSONObjects. 215 | * @throws JSONException 216 | */ 217 | public static JSONArray toJSONArray(JSONArray names, JSONTokener x) 218 | throws JSONException { 219 | if (names == null || names.length() == 0) { 220 | return null; 221 | } 222 | JSONArray ja = new JSONArray(); 223 | for (;;) { 224 | JSONObject jo = rowToJSONObject(names, x); 225 | if (jo == null) { 226 | break; 227 | } 228 | ja.put(jo); 229 | } 230 | if (ja.length() == 0) { 231 | return null; 232 | } 233 | return ja; 234 | } 235 | 236 | 237 | /** 238 | * Produce a comma delimited text from a JSONArray of JSONObjects. The 239 | * first row will be a list of names obtained by inspecting the first 240 | * JSONObject. 241 | * @param ja A JSONArray of JSONObjects. 242 | * @return A comma delimited text. 243 | * @throws JSONException 244 | */ 245 | public static String toString(JSONArray ja) throws JSONException { 246 | JSONObject jo = ja.optJSONObject(0); 247 | if (jo != null) { 248 | JSONArray names = jo.names(); 249 | if (names != null) { 250 | return rowToString(names) + toString(names, ja); 251 | } 252 | } 253 | return null; 254 | } 255 | 256 | /** 257 | * Produce a comma delimited text from a JSONArray of JSONObjects using 258 | * a provided list of names. The list of names is not included in the 259 | * output. 260 | * @param names A JSONArray of strings. 261 | * @param ja A JSONArray of JSONObjects. 262 | * @return A comma delimited text. 263 | * @throws JSONException 264 | */ 265 | public static String toString(JSONArray names, JSONArray ja) 266 | throws JSONException { 267 | if (names == null || names.length() == 0) { 268 | return null; 269 | } 270 | StringBuffer sb = new StringBuffer(); 271 | for (int i = 0; i < ja.length(); i += 1) { 272 | JSONObject jo = ja.optJSONObject(i); 273 | if (jo != null) { 274 | sb.append(rowToString(jo.toJSONArray(names))); 275 | } 276 | } 277 | return sb.toString(); 278 | } 279 | } 280 | -------------------------------------------------------------------------------- /src/org/json/JSONWriter.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | import java.io.IOException; 4 | import java.io.Writer; 5 | 6 | /* 7 | Copyright (c) 2006 JSON.org 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in all 17 | copies or substantial portions of the Software. 18 | 19 | The Software shall be used for Good, not Evil. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | SOFTWARE. 28 | */ 29 | 30 | /** 31 | * JSONWriter provides a quick and convenient way of producing JSON text. 32 | * The texts produced strictly conform to JSON syntax rules. No whitespace is 33 | * added, so the results are ready for transmission or storage. Each instance of 34 | * JSONWriter can produce one JSON text. 35 | *

36 | * A JSONWriter instance provides a value method for appending 37 | * values to the 38 | * text, and a key 39 | * method for adding keys before values in objects. There are array 40 | * and endArray methods that make and bound array values, and 41 | * object and endObject methods which make and bound 42 | * object values. All of these methods return the JSONWriter instance, 43 | * permitting a cascade style. For example,

 44 |  * new JSONWriter(myWriter)
 45 |  *     .object()
 46 |  *         .key("JSON")
 47 |  *         .value("Hello, World!")
 48 |  *     .endObject();
which writes
 49 |  * {"JSON":"Hello, World!"}
50 | *

51 | * The first method called must be array or object. 52 | * There are no methods for adding commas or colons. JSONWriter adds them for 53 | * you. Objects and arrays can be nested up to 20 levels deep. 54 | *

55 | * This can sometimes be easier than using a JSONObject to build a string. 56 | * @author JSON.org 57 | * @version 2010-12-24 58 | */ 59 | public class JSONWriter { 60 | private static final int maxdepth = 20; 61 | 62 | /** 63 | * The comma flag determines if a comma should be output before the next 64 | * value. 65 | */ 66 | private boolean comma; 67 | 68 | /** 69 | * The current mode. Values: 70 | * 'a' (array), 71 | * 'd' (done), 72 | * 'i' (initial), 73 | * 'k' (key), 74 | * 'o' (object). 75 | */ 76 | protected char mode; 77 | 78 | /** 79 | * The object/array stack. 80 | */ 81 | private JSONObject stack[]; 82 | 83 | /** 84 | * The stack top index. A value of 0 indicates that the stack is empty. 85 | */ 86 | private int top; 87 | 88 | /** 89 | * The writer that will receive the output. 90 | */ 91 | protected Writer writer; 92 | 93 | /** 94 | * Make a fresh JSONWriter. It can be used to build one JSON text. 95 | */ 96 | public JSONWriter(Writer w) { 97 | this.comma = false; 98 | this.mode = 'i'; 99 | this.stack = new JSONObject[maxdepth]; 100 | this.top = 0; 101 | this.writer = w; 102 | } 103 | 104 | /** 105 | * Append a value. 106 | * @param string A string value. 107 | * @return this 108 | * @throws JSONException If the value is out of sequence. 109 | */ 110 | private JSONWriter append(String string) throws JSONException { 111 | if (string == null) { 112 | throw new JSONException("Null pointer"); 113 | } 114 | if (this.mode == 'o' || this.mode == 'a') { 115 | try { 116 | if (this.comma && this.mode == 'a') { 117 | this.writer.write(','); 118 | } 119 | this.writer.write(string); 120 | } catch (IOException e) { 121 | throw new JSONException(e); 122 | } 123 | if (this.mode == 'o') { 124 | this.mode = 'k'; 125 | } 126 | this.comma = true; 127 | return this; 128 | } 129 | throw new JSONException("Value out of sequence."); 130 | } 131 | 132 | /** 133 | * Begin appending a new array. All values until the balancing 134 | * endArray will be appended to this array. The 135 | * endArray method must be called to mark the array's end. 136 | * @return this 137 | * @throws JSONException If the nesting is too deep, or if the object is 138 | * started in the wrong place (for example as a key or after the end of the 139 | * outermost array or object). 140 | */ 141 | public JSONWriter array() throws JSONException { 142 | if (this.mode == 'i' || this.mode == 'o' || this.mode == 'a') { 143 | this.push(null); 144 | this.append("["); 145 | this.comma = false; 146 | return this; 147 | } 148 | throw new JSONException("Misplaced array."); 149 | } 150 | 151 | /** 152 | * End something. 153 | * @param mode Mode 154 | * @param c Closing character 155 | * @return this 156 | * @throws JSONException If unbalanced. 157 | */ 158 | private JSONWriter end(char mode, char c) throws JSONException { 159 | if (this.mode != mode) { 160 | throw new JSONException(mode == 'a' ? "Misplaced endArray." : 161 | "Misplaced endObject."); 162 | } 163 | this.pop(mode); 164 | try { 165 | this.writer.write(c); 166 | } catch (IOException e) { 167 | throw new JSONException(e); 168 | } 169 | this.comma = true; 170 | return this; 171 | } 172 | 173 | /** 174 | * End an array. This method most be called to balance calls to 175 | * array. 176 | * @return this 177 | * @throws JSONException If incorrectly nested. 178 | */ 179 | public JSONWriter endArray() throws JSONException { 180 | return this.end('a', ']'); 181 | } 182 | 183 | /** 184 | * End an object. This method most be called to balance calls to 185 | * object. 186 | * @return this 187 | * @throws JSONException If incorrectly nested. 188 | */ 189 | public JSONWriter endObject() throws JSONException { 190 | return this.end('k', '}'); 191 | } 192 | 193 | /** 194 | * Append a key. The key will be associated with the next value. In an 195 | * object, every value must be preceded by a key. 196 | * @param string A key string. 197 | * @return this 198 | * @throws JSONException If the key is out of place. For example, keys 199 | * do not belong in arrays or if the key is null. 200 | */ 201 | public JSONWriter key(String string) throws JSONException { 202 | if (string == null) { 203 | throw new JSONException("Null key."); 204 | } 205 | if (this.mode == 'k') { 206 | try { 207 | stack[top - 1].putOnce(string, Boolean.TRUE); 208 | if (this.comma) { 209 | this.writer.write(','); 210 | } 211 | this.writer.write(JSONObject.quote(string)); 212 | this.writer.write(':'); 213 | this.comma = false; 214 | this.mode = 'o'; 215 | return this; 216 | } catch (IOException e) { 217 | throw new JSONException(e); 218 | } 219 | } 220 | throw new JSONException("Misplaced key."); 221 | } 222 | 223 | 224 | /** 225 | * Begin appending a new object. All keys and values until the balancing 226 | * endObject will be appended to this object. The 227 | * endObject method must be called to mark the object's end. 228 | * @return this 229 | * @throws JSONException If the nesting is too deep, or if the object is 230 | * started in the wrong place (for example as a key or after the end of the 231 | * outermost array or object). 232 | */ 233 | public JSONWriter object() throws JSONException { 234 | if (this.mode == 'i') { 235 | this.mode = 'o'; 236 | } 237 | if (this.mode == 'o' || this.mode == 'a') { 238 | this.append("{"); 239 | this.push(new JSONObject()); 240 | this.comma = false; 241 | return this; 242 | } 243 | throw new JSONException("Misplaced object."); 244 | 245 | } 246 | 247 | 248 | /** 249 | * Pop an array or object scope. 250 | * @param c The scope to close. 251 | * @throws JSONException If nesting is wrong. 252 | */ 253 | private void pop(char c) throws JSONException { 254 | if (this.top <= 0) { 255 | throw new JSONException("Nesting error."); 256 | } 257 | char m = this.stack[this.top - 1] == null ? 'a' : 'k'; 258 | if (m != c) { 259 | throw new JSONException("Nesting error."); 260 | } 261 | this.top -= 1; 262 | this.mode = this.top == 0 ? 263 | 'd' : this.stack[this.top - 1] == null ? 'a' : 'k'; 264 | } 265 | 266 | /** 267 | * Push an array or object scope. 268 | * @param c The scope to open. 269 | * @throws JSONException If nesting is too deep. 270 | */ 271 | private void push(JSONObject jo) throws JSONException { 272 | if (this.top >= maxdepth) { 273 | throw new JSONException("Nesting too deep."); 274 | } 275 | this.stack[this.top] = jo; 276 | this.mode = jo == null ? 'a' : 'k'; 277 | this.top += 1; 278 | } 279 | 280 | 281 | /** 282 | * Append either the value true or the value 283 | * false. 284 | * @param b A boolean. 285 | * @return this 286 | * @throws JSONException 287 | */ 288 | public JSONWriter value(boolean b) throws JSONException { 289 | return this.append(b ? "true" : "false"); 290 | } 291 | 292 | /** 293 | * Append a double value. 294 | * @param d A double. 295 | * @return this 296 | * @throws JSONException If the number is not finite. 297 | */ 298 | public JSONWriter value(double d) throws JSONException { 299 | return this.value(new Double(d)); 300 | } 301 | 302 | /** 303 | * Append a long value. 304 | * @param l A long. 305 | * @return this 306 | * @throws JSONException 307 | */ 308 | public JSONWriter value(long l) throws JSONException { 309 | return this.append(Long.toString(l)); 310 | } 311 | 312 | 313 | /** 314 | * Append an object value. 315 | * @param object The object to append. It can be null, or a Boolean, Number, 316 | * String, JSONObject, or JSONArray, or an object that implements JSONString. 317 | * @return this 318 | * @throws JSONException If the value is out of sequence. 319 | */ 320 | public JSONWriter value(Object object) throws JSONException { 321 | return this.append(JSONObject.valueToString(object)); 322 | } 323 | } 324 | -------------------------------------------------------------------------------- /src/org/json/XMLTokener.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | /* 4 | Copyright (c) 2002 JSON.org 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | The Software shall be used for Good, not Evil. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | */ 26 | 27 | /** 28 | * The XMLTokener extends the JSONTokener to provide additional methods 29 | * for the parsing of XML texts. 30 | * @author JSON.org 31 | * @version 2010-12-24 32 | */ 33 | public class XMLTokener extends JSONTokener { 34 | 35 | 36 | /** The table of entity values. It initially contains Character values for 37 | * amp, apos, gt, lt, quot. 38 | */ 39 | public static final java.util.HashMap entity; 40 | 41 | static { 42 | entity = new java.util.HashMap(8); 43 | entity.put("amp", XML.AMP); 44 | entity.put("apos", XML.APOS); 45 | entity.put("gt", XML.GT); 46 | entity.put("lt", XML.LT); 47 | entity.put("quot", XML.QUOT); 48 | } 49 | 50 | /** 51 | * Construct an XMLTokener from a string. 52 | * @param s A source string. 53 | */ 54 | public XMLTokener(String s) { 55 | super(s); 56 | } 57 | 58 | /** 59 | * Get the text in the CDATA block. 60 | * @return The string up to the ]]>. 61 | * @throws JSONException If the ]]> is not found. 62 | */ 63 | public String nextCDATA() throws JSONException { 64 | char c; 65 | int i; 66 | StringBuffer sb = new StringBuffer(); 67 | for (;;) { 68 | c = next(); 69 | if (end()) { 70 | throw syntaxError("Unclosed CDATA"); 71 | } 72 | sb.append(c); 73 | i = sb.length() - 3; 74 | if (i >= 0 && sb.charAt(i) == ']' && 75 | sb.charAt(i + 1) == ']' && sb.charAt(i + 2) == '>') { 76 | sb.setLength(i); 77 | return sb.toString(); 78 | } 79 | } 80 | } 81 | 82 | 83 | /** 84 | * Get the next XML outer token, trimming whitespace. There are two kinds 85 | * of tokens: the '<' character which begins a markup tag, and the content 86 | * text between markup tags. 87 | * 88 | * @return A string, or a '<' Character, or null if there is no more 89 | * source text. 90 | * @throws JSONException 91 | */ 92 | public Object nextContent() throws JSONException { 93 | char c; 94 | StringBuffer sb; 95 | do { 96 | c = next(); 97 | } while (Character.isWhitespace(c)); 98 | if (c == 0) { 99 | return null; 100 | } 101 | if (c == '<') { 102 | return XML.LT; 103 | } 104 | sb = new StringBuffer(); 105 | for (;;) { 106 | if (c == '<' || c == 0) { 107 | back(); 108 | return sb.toString().trim(); 109 | } 110 | if (c == '&') { 111 | sb.append(nextEntity(c)); 112 | } else { 113 | sb.append(c); 114 | } 115 | c = next(); 116 | } 117 | } 118 | 119 | 120 | /** 121 | * Return the next entity. These entities are translated to Characters: 122 | * & ' > < ". 123 | * @param ampersand An ampersand character. 124 | * @return A Character or an entity String if the entity is not recognized. 125 | * @throws JSONException If missing ';' in XML entity. 126 | */ 127 | public Object nextEntity(char ampersand) throws JSONException { 128 | StringBuffer sb = new StringBuffer(); 129 | for (;;) { 130 | char c = next(); 131 | if (Character.isLetterOrDigit(c) || c == '#') { 132 | sb.append(Character.toLowerCase(c)); 133 | } else if (c == ';') { 134 | break; 135 | } else { 136 | throw syntaxError("Missing ';' in XML entity: &" + sb); 137 | } 138 | } 139 | String string = sb.toString(); 140 | Object object = entity.get(string); 141 | return object != null ? object : ampersand + string + ";"; 142 | } 143 | 144 | 145 | /** 146 | * Returns the next XML meta token. This is used for skipping over 147 | * and structures. 148 | * @return Syntax characters (< > / = ! ?) are returned as 149 | * Character, and strings and names are returned as Boolean. We don't care 150 | * what the values actually are. 151 | * @throws JSONException If a string is not properly closed or if the XML 152 | * is badly structured. 153 | */ 154 | public Object nextMeta() throws JSONException { 155 | char c; 156 | char q; 157 | do { 158 | c = next(); 159 | } while (Character.isWhitespace(c)); 160 | switch (c) { 161 | case 0: 162 | throw syntaxError("Misshaped meta tag"); 163 | case '<': 164 | return XML.LT; 165 | case '>': 166 | return XML.GT; 167 | case '/': 168 | return XML.SLASH; 169 | case '=': 170 | return XML.EQ; 171 | case '!': 172 | return XML.BANG; 173 | case '?': 174 | return XML.QUEST; 175 | case '"': 176 | case '\'': 177 | q = c; 178 | for (;;) { 179 | c = next(); 180 | if (c == 0) { 181 | throw syntaxError("Unterminated string"); 182 | } 183 | if (c == q) { 184 | return Boolean.TRUE; 185 | } 186 | } 187 | default: 188 | for (;;) { 189 | c = next(); 190 | if (Character.isWhitespace(c)) { 191 | return Boolean.TRUE; 192 | } 193 | switch (c) { 194 | case 0: 195 | case '<': 196 | case '>': 197 | case '/': 198 | case '=': 199 | case '!': 200 | case '?': 201 | case '"': 202 | case '\'': 203 | back(); 204 | return Boolean.TRUE; 205 | } 206 | } 207 | } 208 | } 209 | 210 | 211 | /** 212 | * Get the next XML Token. These tokens are found inside of angle 213 | * brackets. It may be one of these characters: / > = ! ? or it 214 | * may be a string wrapped in single quotes or double quotes, or it may be a 215 | * name. 216 | * @return a String or a Character. 217 | * @throws JSONException If the XML is not well formed. 218 | */ 219 | public Object nextToken() throws JSONException { 220 | char c; 221 | char q; 222 | StringBuffer sb; 223 | do { 224 | c = next(); 225 | } while (Character.isWhitespace(c)); 226 | switch (c) { 227 | case 0: 228 | throw syntaxError("Misshaped element"); 229 | case '<': 230 | throw syntaxError("Misplaced '<'"); 231 | case '>': 232 | return XML.GT; 233 | case '/': 234 | return XML.SLASH; 235 | case '=': 236 | return XML.EQ; 237 | case '!': 238 | return XML.BANG; 239 | case '?': 240 | return XML.QUEST; 241 | 242 | // Quoted string 243 | 244 | case '"': 245 | case '\'': 246 | q = c; 247 | sb = new StringBuffer(); 248 | for (;;) { 249 | c = next(); 250 | if (c == 0) { 251 | throw syntaxError("Unterminated string"); 252 | } 253 | if (c == q) { 254 | return sb.toString(); 255 | } 256 | if (c == '&') { 257 | sb.append(nextEntity(c)); 258 | } else { 259 | sb.append(c); 260 | } 261 | } 262 | default: 263 | 264 | // Name 265 | 266 | sb = new StringBuffer(); 267 | for (;;) { 268 | sb.append(c); 269 | c = next(); 270 | if (Character.isWhitespace(c)) { 271 | return sb.toString(); 272 | } 273 | switch (c) { 274 | case 0: 275 | return sb.toString(); 276 | case '>': 277 | case '/': 278 | case '=': 279 | case '!': 280 | case '?': 281 | case '[': 282 | case ']': 283 | back(); 284 | return sb.toString(); 285 | case '<': 286 | case '"': 287 | case '\'': 288 | throw syntaxError("Bad character in a name"); 289 | } 290 | } 291 | } 292 | } 293 | 294 | 295 | /** 296 | * Skip characters until past the requested string. 297 | * If it is not found, we are left at the end of the source with a result of false. 298 | * @param to A string to skip past. 299 | * @throws JSONException 300 | */ 301 | public boolean skipPast(String to) throws JSONException { 302 | boolean b; 303 | char c; 304 | int i; 305 | int j; 306 | int offset = 0; 307 | int length = to.length(); 308 | char[] circle = new char[length]; 309 | 310 | /* 311 | * First fill the circle buffer with as many characters as are in the 312 | * to string. If we reach an early end, bail. 313 | */ 314 | 315 | for (i = 0; i < length; i += 1) { 316 | c = next(); 317 | if (c == 0) { 318 | return false; 319 | } 320 | circle[i] = c; 321 | } 322 | /* 323 | * We will loop, possibly for all of the remaining characters. 324 | */ 325 | for (;;) { 326 | j = offset; 327 | b = true; 328 | /* 329 | * Compare the circle buffer with the to string. 330 | */ 331 | for (i = 0; i < length; i += 1) { 332 | if (circle[j] != to.charAt(i)) { 333 | b = false; 334 | break; 335 | } 336 | j += 1; 337 | if (j >= length) { 338 | j -= length; 339 | } 340 | } 341 | /* 342 | * If we exit the loop with b intact, then victory is ours. 343 | */ 344 | if (b) { 345 | return true; 346 | } 347 | /* 348 | * Get the next character. If there isn't one, then defeat is ours. 349 | */ 350 | c = next(); 351 | if (c == 0) { 352 | return false; 353 | } 354 | /* 355 | * Shove the character in the circle buffer and advance the 356 | * circle offset. The offset is mod n. 357 | */ 358 | circle[offset] = c; 359 | offset += 1; 360 | if (offset >= length) { 361 | offset -= length; 362 | } 363 | } 364 | } 365 | } 366 | -------------------------------------------------------------------------------- /src/org/json/JSONTokener.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.io.InputStreamReader; 7 | import java.io.Reader; 8 | import java.io.StringReader; 9 | 10 | /* 11 | Copyright (c) 2002 JSON.org 12 | 13 | Permission is hereby granted, free of charge, to any person obtaining a copy 14 | of this software and associated documentation files (the "Software"), to deal 15 | in the Software without restriction, including without limitation the rights 16 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | copies of the Software, and to permit persons to whom the Software is 18 | furnished to do so, subject to the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be included in all 21 | copies or substantial portions of the Software. 22 | 23 | The Software shall be used for Good, not Evil. 24 | 25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 | SOFTWARE. 32 | */ 33 | 34 | /** 35 | * A JSONTokener takes a source string and extracts characters and tokens from 36 | * it. It is used by the JSONObject and JSONArray constructors to parse 37 | * JSON source strings. 38 | * @author JSON.org 39 | * @version 2010-12-24 40 | */ 41 | public class JSONTokener { 42 | 43 | private int character; 44 | private boolean eof; 45 | private int index; 46 | private int line; 47 | private char previous; 48 | private Reader reader; 49 | private boolean usePrevious; 50 | 51 | 52 | /** 53 | * Construct a JSONTokener from a Reader. 54 | * 55 | * @param reader A reader. 56 | */ 57 | public JSONTokener(Reader reader) { 58 | this.reader = reader.markSupported() ? 59 | reader : new BufferedReader(reader); 60 | this.eof = false; 61 | this.usePrevious = false; 62 | this.previous = 0; 63 | this.index = 0; 64 | this.character = 1; 65 | this.line = 1; 66 | } 67 | 68 | 69 | /** 70 | * Construct a JSONTokener from an InputStream. 71 | */ 72 | public JSONTokener(InputStream inputStream) throws JSONException { 73 | this(new InputStreamReader(inputStream)); 74 | } 75 | 76 | 77 | /** 78 | * Construct a JSONTokener from a string. 79 | * 80 | * @param s A source string. 81 | */ 82 | public JSONTokener(String s) { 83 | this(new StringReader(s)); 84 | } 85 | 86 | 87 | /** 88 | * Back up one character. This provides a sort of lookahead capability, 89 | * so that you can test for a digit or letter before attempting to parse 90 | * the next number or identifier. 91 | */ 92 | public void back() throws JSONException { 93 | if (usePrevious || index <= 0) { 94 | throw new JSONException("Stepping back two steps is not supported"); 95 | } 96 | this.index -= 1; 97 | this.character -= 1; 98 | this.usePrevious = true; 99 | this.eof = false; 100 | } 101 | 102 | 103 | /** 104 | * Get the hex value of a character (base16). 105 | * @param c A character between '0' and '9' or between 'A' and 'F' or 106 | * between 'a' and 'f'. 107 | * @return An int between 0 and 15, or -1 if c was not a hex digit. 108 | */ 109 | public static int dehexchar(char c) { 110 | if (c >= '0' && c <= '9') { 111 | return c - '0'; 112 | } 113 | if (c >= 'A' && c <= 'F') { 114 | return c - ('A' - 10); 115 | } 116 | if (c >= 'a' && c <= 'f') { 117 | return c - ('a' - 10); 118 | } 119 | return -1; 120 | } 121 | 122 | public boolean end() { 123 | return eof && !usePrevious; 124 | } 125 | 126 | 127 | /** 128 | * Determine if the source string still contains characters that next() 129 | * can consume. 130 | * @return true if not yet at the end of the source. 131 | */ 132 | public boolean more() throws JSONException { 133 | next(); 134 | if (end()) { 135 | return false; 136 | } 137 | back(); 138 | return true; 139 | } 140 | 141 | 142 | /** 143 | * Get the next character in the source string. 144 | * 145 | * @return The next character, or 0 if past the end of the source string. 146 | */ 147 | public char next() throws JSONException { 148 | int c; 149 | if (this.usePrevious) { 150 | this.usePrevious = false; 151 | c = this.previous; 152 | } else { 153 | try { 154 | c = this.reader.read(); 155 | } catch (IOException exception) { 156 | throw new JSONException(exception); 157 | } 158 | 159 | if (c <= 0) { // End of stream 160 | this.eof = true; 161 | c = 0; 162 | } 163 | } 164 | this.index += 1; 165 | if (this.previous == '\r') { 166 | this.line += 1; 167 | this.character = c == '\n' ? 0 : 1; 168 | } else if (c == '\n') { 169 | this.line += 1; 170 | this.character = 0; 171 | } else { 172 | this.character += 1; 173 | } 174 | this.previous = (char) c; 175 | return this.previous; 176 | } 177 | 178 | 179 | /** 180 | * Consume the next character, and check that it matches a specified 181 | * character. 182 | * @param c The character to match. 183 | * @return The character. 184 | * @throws JSONException if the character does not match. 185 | */ 186 | public char next(char c) throws JSONException { 187 | char n = next(); 188 | if (n != c) { 189 | throw syntaxError("Expected '" + c + "' and instead saw '" + 190 | n + "'"); 191 | } 192 | return n; 193 | } 194 | 195 | 196 | /** 197 | * Get the next n characters. 198 | * 199 | * @param n The number of characters to take. 200 | * @return A string of n characters. 201 | * @throws JSONException 202 | * Substring bounds error if there are not 203 | * n characters remaining in the source string. 204 | */ 205 | public String next(int n) throws JSONException { 206 | if (n == 0) { 207 | return ""; 208 | } 209 | 210 | char[] chars = new char[n]; 211 | int pos = 0; 212 | 213 | while (pos < n) { 214 | chars[pos] = next(); 215 | if (end()) { 216 | throw syntaxError("Substring bounds error"); 217 | } 218 | pos += 1; 219 | } 220 | return new String(chars); 221 | } 222 | 223 | 224 | /** 225 | * Get the next char in the string, skipping whitespace. 226 | * @throws JSONException 227 | * @return A character, or 0 if there are no more characters. 228 | */ 229 | public char nextClean() throws JSONException { 230 | for (;;) { 231 | char c = next(); 232 | if (c == 0 || c > ' ') { 233 | return c; 234 | } 235 | } 236 | } 237 | 238 | 239 | /** 240 | * Return the characters up to the next close quote character. 241 | * Backslash processing is done. The formal JSON format does not 242 | * allow strings in single quotes, but an implementation is allowed to 243 | * accept them. 244 | * @param quote The quoting character, either 245 | * " (double quote) or 246 | * ' (single quote). 247 | * @return A String. 248 | * @throws JSONException Unterminated string. 249 | */ 250 | public String nextString(char quote) throws JSONException { 251 | char c; 252 | StringBuffer sb = new StringBuffer(); 253 | for (;;) { 254 | c = next(); 255 | switch (c) { 256 | case 0: 257 | case '\n': 258 | case '\r': 259 | throw syntaxError("Unterminated string"); 260 | case '\\': 261 | c = next(); 262 | switch (c) { 263 | case 'b': 264 | sb.append('\b'); 265 | break; 266 | case 't': 267 | sb.append('\t'); 268 | break; 269 | case 'n': 270 | sb.append('\n'); 271 | break; 272 | case 'f': 273 | sb.append('\f'); 274 | break; 275 | case 'r': 276 | sb.append('\r'); 277 | break; 278 | case 'u': 279 | sb.append((char)Integer.parseInt(next(4), 16)); 280 | break; 281 | case '"': 282 | case '\'': 283 | case '\\': 284 | case '/': 285 | sb.append(c); 286 | break; 287 | default: 288 | throw syntaxError("Illegal escape."); 289 | } 290 | break; 291 | default: 292 | if (c == quote) { 293 | return sb.toString(); 294 | } 295 | sb.append(c); 296 | } 297 | } 298 | } 299 | 300 | 301 | /** 302 | * Get the text up but not including the specified character or the 303 | * end of line, whichever comes first. 304 | * @param delimiter A delimiter character. 305 | * @return A string. 306 | */ 307 | public String nextTo(char delimiter) throws JSONException { 308 | StringBuffer sb = new StringBuffer(); 309 | for (;;) { 310 | char c = next(); 311 | if (c == delimiter || c == 0 || c == '\n' || c == '\r') { 312 | if (c != 0) { 313 | back(); 314 | } 315 | return sb.toString().trim(); 316 | } 317 | sb.append(c); 318 | } 319 | } 320 | 321 | 322 | /** 323 | * Get the text up but not including one of the specified delimiter 324 | * characters or the end of line, whichever comes first. 325 | * @param delimiters A set of delimiter characters. 326 | * @return A string, trimmed. 327 | */ 328 | public String nextTo(String delimiters) throws JSONException { 329 | char c; 330 | StringBuffer sb = new StringBuffer(); 331 | for (;;) { 332 | c = next(); 333 | if (delimiters.indexOf(c) >= 0 || c == 0 || 334 | c == '\n' || c == '\r') { 335 | if (c != 0) { 336 | back(); 337 | } 338 | return sb.toString().trim(); 339 | } 340 | sb.append(c); 341 | } 342 | } 343 | 344 | 345 | /** 346 | * Get the next value. The value can be a Boolean, Double, Integer, 347 | * JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object. 348 | * @throws JSONException If syntax error. 349 | * 350 | * @return An object. 351 | */ 352 | public Object nextValue() throws JSONException { 353 | char c = nextClean(); 354 | String string; 355 | 356 | switch (c) { 357 | case '"': 358 | case '\'': 359 | return nextString(c); 360 | case '{': 361 | back(); 362 | return new JSONObject(this); 363 | case '[': 364 | back(); 365 | return new JSONArray(this); 366 | } 367 | 368 | /* 369 | * Handle unquoted text. This could be the values true, false, or 370 | * null, or it can be a number. An implementation (such as this one) 371 | * is allowed to also accept non-standard forms. 372 | * 373 | * Accumulate characters until we reach the end of the text or a 374 | * formatting character. 375 | */ 376 | 377 | StringBuffer sb = new StringBuffer(); 378 | while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) { 379 | sb.append(c); 380 | c = next(); 381 | } 382 | back(); 383 | 384 | string = sb.toString().trim(); 385 | if (string.equals("")) { 386 | throw syntaxError("Missing value"); 387 | } 388 | return JSONObject.stringToValue(string); 389 | } 390 | 391 | 392 | /** 393 | * Skip characters until the next character is the requested character. 394 | * If the requested character is not found, no characters are skipped. 395 | * @param to A character to skip to. 396 | * @return The requested character, or zero if the requested character 397 | * is not found. 398 | */ 399 | public char skipTo(char to) throws JSONException { 400 | char c; 401 | try { 402 | int startIndex = this.index; 403 | int startCharacter = this.character; 404 | int startLine = this.line; 405 | reader.mark(Integer.MAX_VALUE); 406 | do { 407 | c = next(); 408 | if (c == 0) { 409 | reader.reset(); 410 | this.index = startIndex; 411 | this.character = startCharacter; 412 | this.line = startLine; 413 | return c; 414 | } 415 | } while (c != to); 416 | } catch (IOException exc) { 417 | throw new JSONException(exc); 418 | } 419 | 420 | back(); 421 | return c; 422 | } 423 | 424 | 425 | /** 426 | * Make a JSONException to signal a syntax error. 427 | * 428 | * @param message The error message. 429 | * @return A JSONException object, suitable for throwing 430 | */ 431 | public JSONException syntaxError(String message) { 432 | return new JSONException(message + toString()); 433 | } 434 | 435 | 436 | /** 437 | * Make a printable string of this JSONTokener. 438 | * 439 | * @return " at {index} [character {character} line {line}]" 440 | */ 441 | public String toString() { 442 | return " at " + index + " [character " + this.character + " line " + 443 | this.line + "]"; 444 | } 445 | } -------------------------------------------------------------------------------- /src/org/json/JSONML.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | /* 4 | Copyright (c) 2008 JSON.org 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | The Software shall be used for Good, not Evil. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | */ 26 | 27 | import java.util.Iterator; 28 | 29 | 30 | /** 31 | * This provides static methods to convert an XML text into a JSONArray or 32 | * JSONObject, and to covert a JSONArray or JSONObject into an XML text using 33 | * the JsonML transform. 34 | * @author JSON.org 35 | * @version 2010-12-23 36 | */ 37 | public class JSONML { 38 | 39 | /** 40 | * Parse XML values and store them in a JSONArray. 41 | * @param x The XMLTokener containing the source string. 42 | * @param arrayForm true if array form, false if object form. 43 | * @param ja The JSONArray that is containing the current tag or null 44 | * if we are at the outermost level. 45 | * @return A JSONArray if the value is the outermost tag, otherwise null. 46 | * @throws JSONException 47 | */ 48 | private static Object parse(XMLTokener x, boolean arrayForm, 49 | JSONArray ja) throws JSONException { 50 | String attribute; 51 | char c; 52 | String closeTag = null; 53 | int i; 54 | JSONArray newja = null; 55 | JSONObject newjo = null; 56 | Object token; 57 | String tagName = null; 58 | 59 | // Test for and skip past these forms: 60 | // 61 | // 62 | // 63 | // 64 | 65 | while (true) { 66 | token = x.nextContent(); 67 | if (token == XML.LT) { 68 | token = x.nextToken(); 69 | if (token instanceof Character) { 70 | if (token == XML.SLASH) { 71 | 72 | // Close tag "); 92 | } 93 | x.back(); 94 | } else if (c == '[') { 95 | token = x.nextToken(); 96 | if (token.equals("CDATA") && x.next() == '[') { 97 | if (ja != null) { 98 | ja.put(x.nextCDATA()); 99 | } 100 | } else { 101 | throw x.syntaxError("Expected 'CDATA['"); 102 | } 103 | } else { 104 | i = 1; 105 | do { 106 | token = x.nextMeta(); 107 | if (token == null) { 108 | throw x.syntaxError("Missing '>' after ' 0); 115 | } 116 | } else if (token == XML.QUEST) { 117 | 118 | // "); 121 | } else { 122 | throw x.syntaxError("Misshaped tag"); 123 | } 124 | 125 | // Open tag < 126 | 127 | } else { 128 | if (!(token instanceof String)) { 129 | throw x.syntaxError("Bad tagName '" + token + "'."); 130 | } 131 | tagName = (String)token; 132 | newja = new JSONArray(); 133 | newjo = new JSONObject(); 134 | if (arrayForm) { 135 | newja.put(tagName); 136 | if (ja != null) { 137 | ja.put(newja); 138 | } 139 | } else { 140 | newjo.put("tagName", tagName); 141 | if (ja != null) { 142 | ja.put(newjo); 143 | } 144 | } 145 | token = null; 146 | for (;;) { 147 | if (token == null) { 148 | token = x.nextToken(); 149 | } 150 | if (token == null) { 151 | throw x.syntaxError("Misshaped tag"); 152 | } 153 | if (!(token instanceof String)) { 154 | break; 155 | } 156 | 157 | // attribute = value 158 | 159 | attribute = (String)token; 160 | if (!arrayForm && (attribute == "tagName" || attribute == "childNode")) { 161 | throw x.syntaxError("Reserved attribute."); 162 | } 163 | token = x.nextToken(); 164 | if (token == XML.EQ) { 165 | token = x.nextToken(); 166 | if (!(token instanceof String)) { 167 | throw x.syntaxError("Missing value"); 168 | } 169 | newjo.accumulate(attribute, XML.stringToValue((String)token)); 170 | token = null; 171 | } else { 172 | newjo.accumulate(attribute, ""); 173 | } 174 | } 175 | if (arrayForm && newjo.length() > 0) { 176 | newja.put(newjo); 177 | } 178 | 179 | // Empty tag <.../> 180 | 181 | if (token == XML.SLASH) { 182 | if (x.nextToken() != XML.GT) { 183 | throw x.syntaxError("Misshaped tag"); 184 | } 185 | if (ja == null) { 186 | if (arrayForm) { 187 | return newja; 188 | } else { 189 | return newjo; 190 | } 191 | } 192 | 193 | // Content, between <...> and 194 | 195 | } else { 196 | if (token != XML.GT) { 197 | throw x.syntaxError("Misshaped tag"); 198 | } 199 | closeTag = (String)parse(x, arrayForm, newja); 200 | if (closeTag != null) { 201 | if (!closeTag.equals(tagName)) { 202 | throw x.syntaxError("Mismatched '" + tagName + 203 | "' and '" + closeTag + "'"); 204 | } 205 | tagName = null; 206 | if (!arrayForm && newja.length() > 0) { 207 | newjo.put("childNodes", newja); 208 | } 209 | if (ja == null) { 210 | if (arrayForm) { 211 | return newja; 212 | } else { 213 | return newjo; 214 | } 215 | } 216 | } 217 | } 218 | } 219 | } else { 220 | if (ja != null) { 221 | ja.put(token instanceof String ? 222 | XML.stringToValue((String)token) : token); 223 | } 224 | } 225 | } 226 | } 227 | 228 | 229 | /** 230 | * Convert a well-formed (but not necessarily valid) XML string into a 231 | * JSONArray using the JsonML transform. Each XML tag is represented as 232 | * a JSONArray in which the first element is the tag name. If the tag has 233 | * attributes, then the second element will be JSONObject containing the 234 | * name/value pairs. If the tag contains children, then strings and 235 | * JSONArrays will represent the child tags. 236 | * Comments, prologs, DTDs, and <[ [ ]]> are ignored. 237 | * @param string The source string. 238 | * @return A JSONArray containing the structured data from the XML string. 239 | * @throws JSONException 240 | */ 241 | public static JSONArray toJSONArray(String string) throws JSONException { 242 | return toJSONArray(new XMLTokener(string)); 243 | } 244 | 245 | 246 | /** 247 | * Convert a well-formed (but not necessarily valid) XML string into a 248 | * JSONArray using the JsonML transform. Each XML tag is represented as 249 | * a JSONArray in which the first element is the tag name. If the tag has 250 | * attributes, then the second element will be JSONObject containing the 251 | * name/value pairs. If the tag contains children, then strings and 252 | * JSONArrays will represent the child content and tags. 253 | * Comments, prologs, DTDs, and <[ [ ]]> are ignored. 254 | * @param x An XMLTokener. 255 | * @return A JSONArray containing the structured data from the XML string. 256 | * @throws JSONException 257 | */ 258 | public static JSONArray toJSONArray(XMLTokener x) throws JSONException { 259 | return (JSONArray)parse(x, true, null); 260 | } 261 | 262 | 263 | /** 264 | * Convert a well-formed (but not necessarily valid) XML string into a 265 | * JSONObject using the JsonML transform. Each XML tag is represented as 266 | * a JSONObject with a "tagName" property. If the tag has attributes, then 267 | * the attributes will be in the JSONObject as properties. If the tag 268 | * contains children, the object will have a "childNodes" property which 269 | * will be an array of strings and JsonML JSONObjects. 270 | 271 | * Comments, prologs, DTDs, and <[ [ ]]> are ignored. 272 | * @param x An XMLTokener of the XML source text. 273 | * @return A JSONObject containing the structured data from the XML string. 274 | * @throws JSONException 275 | */ 276 | public static JSONObject toJSONObject(XMLTokener x) throws JSONException { 277 | return (JSONObject)parse(x, false, null); 278 | } 279 | 280 | 281 | /** 282 | * Convert a well-formed (but not necessarily valid) XML string into a 283 | * JSONObject using the JsonML transform. Each XML tag is represented as 284 | * a JSONObject with a "tagName" property. If the tag has attributes, then 285 | * the attributes will be in the JSONObject as properties. If the tag 286 | * contains children, the object will have a "childNodes" property which 287 | * will be an array of strings and JsonML JSONObjects. 288 | 289 | * Comments, prologs, DTDs, and <[ [ ]]> are ignored. 290 | * @param string The XML source text. 291 | * @return A JSONObject containing the structured data from the XML string. 292 | * @throws JSONException 293 | */ 294 | public static JSONObject toJSONObject(String string) throws JSONException { 295 | return toJSONObject(new XMLTokener(string)); 296 | } 297 | 298 | 299 | /** 300 | * Reverse the JSONML transformation, making an XML text from a JSONArray. 301 | * @param ja A JSONArray. 302 | * @return An XML string. 303 | * @throws JSONException 304 | */ 305 | public static String toString(JSONArray ja) throws JSONException { 306 | int i; 307 | JSONObject jo; 308 | String key; 309 | Iterator keys; 310 | int length; 311 | Object object; 312 | StringBuffer sb = new StringBuffer(); 313 | String tagName; 314 | String value; 315 | 316 | // Emit = length) { 353 | sb.append('/'); 354 | sb.append('>'); 355 | } else { 356 | sb.append('>'); 357 | do { 358 | object = ja.get(i); 359 | i += 1; 360 | if (object != null) { 361 | if (object instanceof String) { 362 | sb.append(XML.escape(object.toString())); 363 | } else if (object instanceof JSONObject) { 364 | sb.append(toString((JSONObject)object)); 365 | } else if (object instanceof JSONArray) { 366 | sb.append(toString((JSONArray)object)); 367 | } 368 | } 369 | } while (i < length); 370 | sb.append('<'); 371 | sb.append('/'); 372 | sb.append(tagName); 373 | sb.append('>'); 374 | } 375 | return sb.toString(); 376 | } 377 | 378 | /** 379 | * Reverse the JSONML transformation, making an XML text from a JSONObject. 380 | * The JSONObject must contain a "tagName" property. If it has children, 381 | * then it must have a "childNodes" property containing an array of objects. 382 | * The other properties are attributes with string values. 383 | * @param jo A JSONObject. 384 | * @return An XML string. 385 | * @throws JSONException 386 | */ 387 | public static String toString(JSONObject jo) throws JSONException { 388 | StringBuffer sb = new StringBuffer(); 389 | int i; 390 | JSONArray ja; 391 | String key; 392 | Iterator keys; 393 | int length; 394 | Object object; 395 | String tagName; 396 | String value; 397 | 398 | //Emit '); 434 | } else { 435 | sb.append('>'); 436 | length = ja.length(); 437 | for (i = 0; i < length; i += 1) { 438 | object = ja.get(i); 439 | if (object != null) { 440 | if (object instanceof String) { 441 | sb.append(XML.escape(object.toString())); 442 | } else if (object instanceof JSONObject) { 443 | sb.append(toString((JSONObject)object)); 444 | } else if (object instanceof JSONArray) { 445 | sb.append(toString((JSONArray)object)); 446 | } 447 | } 448 | } 449 | sb.append('<'); 450 | sb.append('/'); 451 | sb.append(tagName); 452 | sb.append('>'); 453 | } 454 | return sb.toString(); 455 | } 456 | } -------------------------------------------------------------------------------- /src/org/json/XML.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | /* 4 | Copyright (c) 2002 JSON.org 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | The Software shall be used for Good, not Evil. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | */ 26 | 27 | import java.util.Iterator; 28 | 29 | 30 | /** 31 | * This provides static methods to convert an XML text into a JSONObject, 32 | * and to covert a JSONObject into an XML text. 33 | * @author JSON.org 34 | * @version 2011-02-11 35 | */ 36 | public class XML { 37 | 38 | /** The Character '&'. */ 39 | public static final Character AMP = new Character('&'); 40 | 41 | /** The Character '''. */ 42 | public static final Character APOS = new Character('\''); 43 | 44 | /** The Character '!'. */ 45 | public static final Character BANG = new Character('!'); 46 | 47 | /** The Character '='. */ 48 | public static final Character EQ = new Character('='); 49 | 50 | /** The Character '>'. */ 51 | public static final Character GT = new Character('>'); 52 | 53 | /** The Character '<'. */ 54 | public static final Character LT = new Character('<'); 55 | 56 | /** The Character '?'. */ 57 | public static final Character QUEST = new Character('?'); 58 | 59 | /** The Character '"'. */ 60 | public static final Character QUOT = new Character('"'); 61 | 62 | /** The Character '/'. */ 63 | public static final Character SLASH = new Character('/'); 64 | 65 | /** 66 | * Replace special characters with XML escapes: 67 | *

 68 |      * & (ampersand) is replaced by &amp;
 69 |      * < (less than) is replaced by &lt;
 70 |      * > (greater than) is replaced by &gt;
 71 |      * " (double quote) is replaced by &quot;
 72 |      * 
73 | * @param string The string to be escaped. 74 | * @return The escaped string. 75 | */ 76 | public static String escape(String string) { 77 | StringBuffer sb = new StringBuffer(); 78 | for (int i = 0, length = string.length(); i < length; i++) { 79 | char c = string.charAt(i); 80 | switch (c) { 81 | case '&': 82 | sb.append("&"); 83 | break; 84 | case '<': 85 | sb.append("<"); 86 | break; 87 | case '>': 88 | sb.append(">"); 89 | break; 90 | case '"': 91 | sb.append("""); 92 | break; 93 | case '\'': 94 | sb.append("'"); 95 | break; 96 | default: 97 | sb.append(c); 98 | } 99 | } 100 | return sb.toString(); 101 | } 102 | 103 | /** 104 | * Throw an exception if the string contains whitespace. 105 | * Whitespace is not allowed in tagNames and attributes. 106 | * @param string 107 | * @throws JSONException 108 | */ 109 | public static void noSpace(String string) throws JSONException { 110 | int i, length = string.length(); 111 | if (length == 0) { 112 | throw new JSONException("Empty string."); 113 | } 114 | for (i = 0; i < length; i += 1) { 115 | if (Character.isWhitespace(string.charAt(i))) { 116 | throw new JSONException("'" + string + 117 | "' contains a space character."); 118 | } 119 | } 120 | } 121 | 122 | /** 123 | * Scan the content following the named tag, attaching it to the context. 124 | * @param x The XMLTokener containing the source string. 125 | * @param context The JSONObject that will include the new material. 126 | * @param name The tag name. 127 | * @return true if the close tag is processed. 128 | * @throws JSONException 129 | */ 130 | private static boolean parse(XMLTokener x, JSONObject context, 131 | String name) throws JSONException { 132 | char c; 133 | int i; 134 | JSONObject jsonobject = null; 135 | String string; 136 | String tagName; 137 | Object token; 138 | 139 | // Test for and skip past these forms: 140 | // 141 | // 142 | // 143 | // 144 | // Report errors for these forms: 145 | // <> 146 | // <= 147 | // << 148 | 149 | token = x.nextToken(); 150 | 151 | // "); 158 | return false; 159 | } 160 | x.back(); 161 | } else if (c == '[') { 162 | token = x.nextToken(); 163 | if (token.equals("CDATA")) { 164 | if (x.next() == '[') { 165 | string = x.nextCDATA(); 166 | if (string.length() > 0) { 167 | context.accumulate("content", string); 168 | } 169 | return false; 170 | } 171 | } 172 | throw x.syntaxError("Expected 'CDATA['"); 173 | } 174 | i = 1; 175 | do { 176 | token = x.nextMeta(); 177 | if (token == null) { 178 | throw x.syntaxError("Missing '>' after ' 0); 185 | return false; 186 | } else if (token == QUEST) { 187 | 188 | // "); 191 | return false; 192 | } else if (token == SLASH) { 193 | 194 | // Close tag 240 | 241 | } else if (token == SLASH) { 242 | if (x.nextToken() != GT) { 243 | throw x.syntaxError("Misshaped tag"); 244 | } 245 | if (jsonobject.length() > 0) { 246 | context.accumulate(tagName, jsonobject); 247 | } else { 248 | context.accumulate(tagName, ""); 249 | } 250 | return false; 251 | 252 | // Content, between <...> and 253 | 254 | } else if (token == GT) { 255 | for (;;) { 256 | token = x.nextContent(); 257 | if (token == null) { 258 | if (tagName != null) { 259 | throw x.syntaxError("Unclosed tag " + tagName); 260 | } 261 | return false; 262 | } else if (token instanceof String) { 263 | string = (String)token; 264 | if (string.length() > 0) { 265 | jsonobject.accumulate("content", 266 | XML.stringToValue(string)); 267 | } 268 | 269 | // Nested element 270 | 271 | } else if (token == LT) { 272 | if (parse(x, jsonobject, tagName)) { 273 | if (jsonobject.length() == 0) { 274 | context.accumulate(tagName, ""); 275 | } else if (jsonobject.length() == 1 && 276 | jsonobject.opt("content") != null) { 277 | context.accumulate(tagName, 278 | jsonobject.opt("content")); 279 | } else { 280 | context.accumulate(tagName, jsonobject); 281 | } 282 | return false; 283 | } 284 | } 285 | } 286 | } else { 287 | throw x.syntaxError("Misshaped tag"); 288 | } 289 | } 290 | } 291 | } 292 | 293 | 294 | /** 295 | * Try to convert a string into a number, boolean, or null. If the string 296 | * can't be converted, return the string. This is much less ambitious than 297 | * JSONObject.stringToValue, especially because it does not attempt to 298 | * convert plus forms, octal forms, hex forms, or E forms lacking decimal 299 | * points. 300 | * @param string A String. 301 | * @return A simple JSON value. 302 | */ 303 | public static Object stringToValue(String string) { 304 | if (string.equals("")) { 305 | return string; 306 | } 307 | if (string.equalsIgnoreCase("true")) { 308 | return Boolean.TRUE; 309 | } 310 | if (string.equalsIgnoreCase("false")) { 311 | return Boolean.FALSE; 312 | } 313 | if (string.equalsIgnoreCase("null")) { 314 | return JSONObject.NULL; 315 | } 316 | if (string.equals("0")) { 317 | return new Integer(0); 318 | } 319 | 320 | // If it might be a number, try converting it. If that doesn't work, 321 | // return the string. 322 | 323 | try { 324 | char initial = string.charAt(0); 325 | boolean negative = false; 326 | if (initial == '-') { 327 | initial = string.charAt(1); 328 | negative = true; 329 | } 330 | if (initial == '0' && string.charAt(negative ? 2 : 1) == '0') { 331 | return string; 332 | } 333 | if ((initial >= '0' && initial <= '9')) { 334 | if (string.indexOf('.') >= 0) { 335 | return Double.valueOf(string); 336 | } else if (string.indexOf('e') < 0 && string.indexOf('E') < 0) { 337 | Long myLong = new Long(string); 338 | if (myLong.longValue() == myLong.intValue()) { 339 | return new Integer(myLong.intValue()); 340 | } else { 341 | return myLong; 342 | } 343 | } 344 | } 345 | } catch (Exception ignore) { 346 | } 347 | return string; 348 | } 349 | 350 | 351 | /** 352 | * Convert a well-formed (but not necessarily valid) XML string into a 353 | * JSONObject. Some information may be lost in this transformation 354 | * because JSON is a data format and XML is a document format. XML uses 355 | * elements, attributes, and content text, while JSON uses unordered 356 | * collections of name/value pairs and arrays of values. JSON does not 357 | * does not like to distinguish between elements and attributes. 358 | * Sequences of similar elements are represented as JSONArrays. Content 359 | * text may be placed in a "content" member. Comments, prologs, DTDs, and 360 | * <[ [ ]]> are ignored. 361 | * @param string The source string. 362 | * @return A JSONObject containing the structured data from the XML string. 363 | * @throws JSONException 364 | */ 365 | public static JSONObject toJSONObject(String string) throws JSONException { 366 | JSONObject jo = new JSONObject(); 367 | XMLTokener x = new XMLTokener(string); 368 | while (x.more() && x.skipPast("<")) { 369 | parse(x, jo, null); 370 | } 371 | return jo; 372 | } 373 | 374 | 375 | /** 376 | * Convert a JSONObject into a well-formed, element-normal XML string. 377 | * @param object A JSONObject. 378 | * @return A string. 379 | * @throws JSONException 380 | */ 381 | public static String toString(Object object) throws JSONException { 382 | return toString(object, null); 383 | } 384 | 385 | 386 | /** 387 | * Convert a JSONObject into a well-formed, element-normal XML string. 388 | * @param object A JSONObject. 389 | * @param tagName The optional name of the enclosing tag. 390 | * @return A string. 391 | * @throws JSONException 392 | */ 393 | public static String toString(Object object, String tagName) 394 | throws JSONException { 395 | StringBuffer sb = new StringBuffer(); 396 | int i; 397 | JSONArray ja; 398 | JSONObject jo; 399 | String key; 400 | Iterator keys; 401 | int length; 402 | String string; 403 | Object value; 404 | if (object instanceof JSONObject) { 405 | 406 | // Emit 407 | 408 | if (tagName != null) { 409 | sb.append('<'); 410 | sb.append(tagName); 411 | sb.append('>'); 412 | } 413 | 414 | // Loop thru the keys. 415 | 416 | jo = (JSONObject)object; 417 | keys = jo.keys(); 418 | while (keys.hasNext()) { 419 | key = keys.next().toString(); 420 | value = jo.opt(key); 421 | if (value == null) { 422 | value = ""; 423 | } 424 | if (value instanceof String) { 425 | string = (String)value; 426 | } else { 427 | string = null; 428 | } 429 | 430 | // Emit content in body 431 | 432 | if (key.equals("content")) { 433 | if (value instanceof JSONArray) { 434 | ja = (JSONArray)value; 435 | length = ja.length(); 436 | for (i = 0; i < length; i += 1) { 437 | if (i > 0) { 438 | sb.append('\n'); 439 | } 440 | sb.append(escape(ja.get(i).toString())); 441 | } 442 | } else { 443 | sb.append(escape(value.toString())); 444 | } 445 | 446 | // Emit an array of similar keys 447 | 448 | } else if (value instanceof JSONArray) { 449 | ja = (JSONArray)value; 450 | length = ja.length(); 451 | for (i = 0; i < length; i += 1) { 452 | value = ja.get(i); 453 | if (value instanceof JSONArray) { 454 | sb.append('<'); 455 | sb.append(key); 456 | sb.append('>'); 457 | sb.append(toString(value)); 458 | sb.append("'); 461 | } else { 462 | sb.append(toString(value, key)); 463 | } 464 | } 465 | } else if (value.equals("")) { 466 | sb.append('<'); 467 | sb.append(key); 468 | sb.append("/>"); 469 | 470 | // Emit a new tag 471 | 472 | } else { 473 | sb.append(toString(value, key)); 474 | } 475 | } 476 | if (tagName != null) { 477 | 478 | // Emit the close tag 479 | 480 | sb.append("'); 483 | } 484 | return sb.toString(); 485 | 486 | // XML does not have good support for arrays. If an array appears in a place 487 | // where XML is lacking, synthesize an element. 488 | 489 | } else { 490 | if (object.getClass().isArray()) { 491 | object = new JSONArray(object); 492 | } 493 | if (object instanceof JSONArray) { 494 | ja = (JSONArray)object; 495 | length = ja.length(); 496 | for (i = 0; i < length; i += 1) { 497 | sb.append(toString(ja.opt(i), tagName == null ? "array" : tagName)); 498 | } 499 | return sb.toString(); 500 | } else { 501 | string = (object == null) ? "null" : escape(object.toString()); 502 | return (tagName == null) ? "\"" + string + "\"" : 503 | (string.length() == 0) ? "<" + tagName + "/>" : 504 | "<" + tagName + ">" + string + ""; 505 | } 506 | } 507 | } 508 | } -------------------------------------------------------------------------------- /src/org/json/JSONArray.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | /* 4 | Copyright (c) 2002 JSON.org 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | The Software shall be used for Good, not Evil. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | */ 26 | 27 | import java.io.IOException; 28 | import java.io.Writer; 29 | import java.lang.reflect.Array; 30 | import java.util.ArrayList; 31 | import java.util.Collection; 32 | import java.util.Iterator; 33 | import java.util.Map; 34 | 35 | /** 36 | * A JSONArray is an ordered sequence of values. Its external text form is a 37 | * string wrapped in square brackets with commas separating the values. The 38 | * internal form is an object having get and opt 39 | * methods for accessing the values by index, and put methods for 40 | * adding or replacing values. The values can be any of these types: 41 | * Boolean, JSONArray, JSONObject, 42 | * Number, String, or the 43 | * JSONObject.NULL object. 44 | *

45 | * The constructor can convert a JSON text into a Java object. The 46 | * toString method converts to JSON text. 47 | *

48 | * A get method returns a value if one can be found, and throws an 49 | * exception if one cannot be found. An opt method returns a 50 | * default value instead of throwing an exception, and so is useful for 51 | * obtaining optional values. 52 | *

53 | * The generic get() and opt() methods return an 54 | * object which you can cast or query for type. There are also typed 55 | * get and opt methods that do type checking and type 56 | * coercion for you. 57 | *

58 | * The texts produced by the toString methods strictly conform to 59 | * JSON syntax rules. The constructors are more forgiving in the texts they will 60 | * accept: 61 | *

    62 | *
  • An extra , (comma) may appear just 63 | * before the closing bracket.
  • 64 | *
  • The null value will be inserted when there 65 | * is , (comma) elision.
  • 66 | *
  • Strings may be quoted with ' (single 67 | * quote).
  • 68 | *
  • Strings do not need to be quoted at all if they do not begin with a quote 69 | * or single quote, and if they do not contain leading or trailing spaces, 70 | * and if they do not contain any of these characters: 71 | * { } [ ] / \ : , = ; # and if they do not look like numbers 72 | * and if they are not the reserved words true, 73 | * false, or null.
  • 74 | *
  • Values can be separated by ; (semicolon) as 75 | * well as by , (comma).
  • 76 | *
  • Numbers may have the 77 | * 0x- (hex) prefix.
  • 78 | *
79 | 80 | * @author JSON.org 81 | * @version 2010-12-28 82 | */ 83 | public class JSONArray { 84 | 85 | 86 | /** 87 | * The arrayList where the JSONArray's properties are kept. 88 | */ 89 | private ArrayList myArrayList; 90 | 91 | 92 | /** 93 | * Construct an empty JSONArray. 94 | */ 95 | public JSONArray() { 96 | this.myArrayList = new ArrayList(); 97 | } 98 | 99 | /** 100 | * Construct a JSONArray from a JSONTokener. 101 | * @param x A JSONTokener 102 | * @throws JSONException If there is a syntax error. 103 | */ 104 | public JSONArray(JSONTokener x) throws JSONException { 105 | this(); 106 | if (x.nextClean() != '[') { 107 | throw x.syntaxError("A JSONArray text must start with '['"); 108 | } 109 | if (x.nextClean() != ']') { 110 | x.back(); 111 | for (;;) { 112 | if (x.nextClean() == ',') { 113 | x.back(); 114 | this.myArrayList.add(JSONObject.NULL); 115 | } else { 116 | x.back(); 117 | this.myArrayList.add(x.nextValue()); 118 | } 119 | switch (x.nextClean()) { 120 | case ';': 121 | case ',': 122 | if (x.nextClean() == ']') { 123 | return; 124 | } 125 | x.back(); 126 | break; 127 | case ']': 128 | return; 129 | default: 130 | throw x.syntaxError("Expected a ',' or ']'"); 131 | } 132 | } 133 | } 134 | } 135 | 136 | 137 | /** 138 | * Construct a JSONArray from a source JSON text. 139 | * @param source A string that begins with 140 | * [ (left bracket) 141 | * and ends with ] (right bracket). 142 | * @throws JSONException If there is a syntax error. 143 | */ 144 | public JSONArray(String source) throws JSONException { 145 | this(new JSONTokener(source)); 146 | } 147 | 148 | 149 | /** 150 | * Construct a JSONArray from a Collection. 151 | * @param collection A Collection. 152 | */ 153 | public JSONArray(Collection collection) { 154 | this.myArrayList = new ArrayList(); 155 | if (collection != null) { 156 | Iterator iter = collection.iterator(); 157 | while (iter.hasNext()) { 158 | this.myArrayList.add(JSONObject.wrap(iter.next())); 159 | } 160 | } 161 | } 162 | 163 | 164 | /** 165 | * Construct a JSONArray from an array 166 | * @throws JSONException If not an array. 167 | */ 168 | public JSONArray(Object array) throws JSONException { 169 | this(); 170 | if (array.getClass().isArray()) { 171 | int length = Array.getLength(array); 172 | for (int i = 0; i < length; i += 1) { 173 | this.put(JSONObject.wrap(Array.get(array, i))); 174 | } 175 | } else { 176 | throw new JSONException( 177 | "JSONArray initial value should be a string or collection or array."); 178 | } 179 | } 180 | 181 | 182 | /** 183 | * Get the object value associated with an index. 184 | * @param index 185 | * The index must be between 0 and length() - 1. 186 | * @return An object value. 187 | * @throws JSONException If there is no value for the index. 188 | */ 189 | public Object get(int index) throws JSONException { 190 | Object object = opt(index); 191 | if (object == null) { 192 | throw new JSONException("JSONArray[" + index + "] not found."); 193 | } 194 | return object; 195 | } 196 | 197 | 198 | /** 199 | * Get the boolean value associated with an index. 200 | * The string values "true" and "false" are converted to boolean. 201 | * 202 | * @param index The index must be between 0 and length() - 1. 203 | * @return The truth. 204 | * @throws JSONException If there is no value for the index or if the 205 | * value is not convertible to boolean. 206 | */ 207 | public boolean getBoolean(int index) throws JSONException { 208 | Object object = get(index); 209 | if (object.equals(Boolean.FALSE) || 210 | (object instanceof String && 211 | ((String)object).equalsIgnoreCase("false"))) { 212 | return false; 213 | } else if (object.equals(Boolean.TRUE) || 214 | (object instanceof String && 215 | ((String)object).equalsIgnoreCase("true"))) { 216 | return true; 217 | } 218 | throw new JSONException("JSONArray[" + index + "] is not a boolean."); 219 | } 220 | 221 | 222 | /** 223 | * Get the double value associated with an index. 224 | * 225 | * @param index The index must be between 0 and length() - 1. 226 | * @return The value. 227 | * @throws JSONException If the key is not found or if the value cannot 228 | * be converted to a number. 229 | */ 230 | public double getDouble(int index) throws JSONException { 231 | Object object = get(index); 232 | try { 233 | return object instanceof Number ? 234 | ((Number)object).doubleValue() : 235 | Double.parseDouble((String)object); 236 | } catch (Exception e) { 237 | throw new JSONException("JSONArray[" + index + 238 | "] is not a number."); 239 | } 240 | } 241 | 242 | 243 | /** 244 | * Get the int value associated with an index. 245 | * 246 | * @param index The index must be between 0 and length() - 1. 247 | * @return The value. 248 | * @throws JSONException If the key is not found or if the value is not a number. 249 | */ 250 | public int getInt(int index) throws JSONException { 251 | Object object = get(index); 252 | try { 253 | return object instanceof Number ? 254 | ((Number)object).intValue() : 255 | Integer.parseInt((String)object); 256 | } catch (Exception e) { 257 | throw new JSONException("JSONArray[" + index + 258 | "] is not a number."); 259 | } 260 | } 261 | 262 | 263 | /** 264 | * Get the JSONArray associated with an index. 265 | * @param index The index must be between 0 and length() - 1. 266 | * @return A JSONArray value. 267 | * @throws JSONException If there is no value for the index. or if the 268 | * value is not a JSONArray 269 | */ 270 | public JSONArray getJSONArray(int index) throws JSONException { 271 | Object object = get(index); 272 | if (object instanceof JSONArray) { 273 | return (JSONArray)object; 274 | } 275 | throw new JSONException("JSONArray[" + index + 276 | "] is not a JSONArray."); 277 | } 278 | 279 | 280 | /** 281 | * Get the JSONObject associated with an index. 282 | * @param index subscript 283 | * @return A JSONObject value. 284 | * @throws JSONException If there is no value for the index or if the 285 | * value is not a JSONObject 286 | */ 287 | public JSONObject getJSONObject(int index) throws JSONException { 288 | Object object = get(index); 289 | if (object instanceof JSONObject) { 290 | return (JSONObject)object; 291 | } 292 | throw new JSONException("JSONArray[" + index + 293 | "] is not a JSONObject."); 294 | } 295 | 296 | 297 | /** 298 | * Get the long value associated with an index. 299 | * 300 | * @param index The index must be between 0 and length() - 1. 301 | * @return The value. 302 | * @throws JSONException If the key is not found or if the value cannot 303 | * be converted to a number. 304 | */ 305 | public long getLong(int index) throws JSONException { 306 | Object object = get(index); 307 | try { 308 | return object instanceof Number ? 309 | ((Number)object).longValue() : 310 | Long.parseLong((String)object); 311 | } catch (Exception e) { 312 | throw new JSONException("JSONArray[" + index + 313 | "] is not a number."); 314 | } 315 | } 316 | 317 | 318 | /** 319 | * Get the string associated with an index. 320 | * @param index The index must be between 0 and length() - 1. 321 | * @return A string value. 322 | * @throws JSONException If there is no value for the index. 323 | */ 324 | public String getString(int index) throws JSONException { 325 | Object object = get(index); 326 | return object == JSONObject.NULL ? null : object.toString(); 327 | } 328 | 329 | 330 | /** 331 | * Determine if the value is null. 332 | * @param index The index must be between 0 and length() - 1. 333 | * @return true if the value at the index is null, or if there is no value. 334 | */ 335 | public boolean isNull(int index) { 336 | return JSONObject.NULL.equals(opt(index)); 337 | } 338 | 339 | 340 | /** 341 | * Make a string from the contents of this JSONArray. The 342 | * separator string is inserted between each element. 343 | * Warning: This method assumes that the data structure is acyclical. 344 | * @param separator A string that will be inserted between the elements. 345 | * @return a string. 346 | * @throws JSONException If the array contains an invalid number. 347 | */ 348 | public String join(String separator) throws JSONException { 349 | int len = length(); 350 | StringBuffer sb = new StringBuffer(); 351 | 352 | for (int i = 0; i < len; i += 1) { 353 | if (i > 0) { 354 | sb.append(separator); 355 | } 356 | sb.append(JSONObject.valueToString(this.myArrayList.get(i))); 357 | } 358 | return sb.toString(); 359 | } 360 | 361 | 362 | /** 363 | * Get the number of elements in the JSONArray, included nulls. 364 | * 365 | * @return The length (or size). 366 | */ 367 | public int length() { 368 | return this.myArrayList.size(); 369 | } 370 | 371 | 372 | /** 373 | * Get the optional object value associated with an index. 374 | * @param index The index must be between 0 and length() - 1. 375 | * @return An object value, or null if there is no 376 | * object at that index. 377 | */ 378 | public Object opt(int index) { 379 | return (index < 0 || index >= length()) ? 380 | null : this.myArrayList.get(index); 381 | } 382 | 383 | 384 | /** 385 | * Get the optional boolean value associated with an index. 386 | * It returns false if there is no value at that index, 387 | * or if the value is not Boolean.TRUE or the String "true". 388 | * 389 | * @param index The index must be between 0 and length() - 1. 390 | * @return The truth. 391 | */ 392 | public boolean optBoolean(int index) { 393 | return optBoolean(index, false); 394 | } 395 | 396 | 397 | /** 398 | * Get the optional boolean value associated with an index. 399 | * It returns the defaultValue if there is no value at that index or if 400 | * it is not a Boolean or the String "true" or "false" (case insensitive). 401 | * 402 | * @param index The index must be between 0 and length() - 1. 403 | * @param defaultValue A boolean default. 404 | * @return The truth. 405 | */ 406 | public boolean optBoolean(int index, boolean defaultValue) { 407 | try { 408 | return getBoolean(index); 409 | } catch (Exception e) { 410 | return defaultValue; 411 | } 412 | } 413 | 414 | 415 | /** 416 | * Get the optional double value associated with an index. 417 | * NaN is returned if there is no value for the index, 418 | * or if the value is not a number and cannot be converted to a number. 419 | * 420 | * @param index The index must be between 0 and length() - 1. 421 | * @return The value. 422 | */ 423 | public double optDouble(int index) { 424 | return optDouble(index, Double.NaN); 425 | } 426 | 427 | 428 | /** 429 | * Get the optional double value associated with an index. 430 | * The defaultValue is returned if there is no value for the index, 431 | * or if the value is not a number and cannot be converted to a number. 432 | * 433 | * @param index subscript 434 | * @param defaultValue The default value. 435 | * @return The value. 436 | */ 437 | public double optDouble(int index, double defaultValue) { 438 | try { 439 | return getDouble(index); 440 | } catch (Exception e) { 441 | return defaultValue; 442 | } 443 | } 444 | 445 | 446 | /** 447 | * Get the optional int value associated with an index. 448 | * Zero is returned if there is no value for the index, 449 | * or if the value is not a number and cannot be converted to a number. 450 | * 451 | * @param index The index must be between 0 and length() - 1. 452 | * @return The value. 453 | */ 454 | public int optInt(int index) { 455 | return optInt(index, 0); 456 | } 457 | 458 | 459 | /** 460 | * Get the optional int value associated with an index. 461 | * The defaultValue is returned if there is no value for the index, 462 | * or if the value is not a number and cannot be converted to a number. 463 | * @param index The index must be between 0 and length() - 1. 464 | * @param defaultValue The default value. 465 | * @return The value. 466 | */ 467 | public int optInt(int index, int defaultValue) { 468 | try { 469 | return getInt(index); 470 | } catch (Exception e) { 471 | return defaultValue; 472 | } 473 | } 474 | 475 | 476 | /** 477 | * Get the optional JSONArray associated with an index. 478 | * @param index subscript 479 | * @return A JSONArray value, or null if the index has no value, 480 | * or if the value is not a JSONArray. 481 | */ 482 | public JSONArray optJSONArray(int index) { 483 | Object o = opt(index); 484 | return o instanceof JSONArray ? (JSONArray)o : null; 485 | } 486 | 487 | 488 | /** 489 | * Get the optional JSONObject associated with an index. 490 | * Null is returned if the key is not found, or null if the index has 491 | * no value, or if the value is not a JSONObject. 492 | * 493 | * @param index The index must be between 0 and length() - 1. 494 | * @return A JSONObject value. 495 | */ 496 | public JSONObject optJSONObject(int index) { 497 | Object o = opt(index); 498 | return o instanceof JSONObject ? (JSONObject)o : null; 499 | } 500 | 501 | 502 | /** 503 | * Get the optional long value associated with an index. 504 | * Zero is returned if there is no value for the index, 505 | * or if the value is not a number and cannot be converted to a number. 506 | * 507 | * @param index The index must be between 0 and length() - 1. 508 | * @return The value. 509 | */ 510 | public long optLong(int index) { 511 | return optLong(index, 0); 512 | } 513 | 514 | 515 | /** 516 | * Get the optional long value associated with an index. 517 | * The defaultValue is returned if there is no value for the index, 518 | * or if the value is not a number and cannot be converted to a number. 519 | * @param index The index must be between 0 and length() - 1. 520 | * @param defaultValue The default value. 521 | * @return The value. 522 | */ 523 | public long optLong(int index, long defaultValue) { 524 | try { 525 | return getLong(index); 526 | } catch (Exception e) { 527 | return defaultValue; 528 | } 529 | } 530 | 531 | 532 | /** 533 | * Get the optional string value associated with an index. It returns an 534 | * empty string if there is no value at that index. If the value 535 | * is not a string and is not null, then it is coverted to a string. 536 | * 537 | * @param index The index must be between 0 and length() - 1. 538 | * @return A String value. 539 | */ 540 | public String optString(int index) { 541 | return optString(index, ""); 542 | } 543 | 544 | 545 | /** 546 | * Get the optional string associated with an index. 547 | * The defaultValue is returned if the key is not found. 548 | * 549 | * @param index The index must be between 0 and length() - 1. 550 | * @param defaultValue The default value. 551 | * @return A String value. 552 | */ 553 | public String optString(int index, String defaultValue) { 554 | Object object = opt(index); 555 | return object != null ? object.toString() : defaultValue; 556 | } 557 | 558 | 559 | /** 560 | * Append a boolean value. This increases the array's length by one. 561 | * 562 | * @param value A boolean value. 563 | * @return this. 564 | */ 565 | public JSONArray put(boolean value) { 566 | put(value ? Boolean.TRUE : Boolean.FALSE); 567 | return this; 568 | } 569 | 570 | 571 | /** 572 | * Put a value in the JSONArray, where the value will be a 573 | * JSONArray which is produced from a Collection. 574 | * @param value A Collection value. 575 | * @return this. 576 | */ 577 | public JSONArray put(Collection value) { 578 | put(new JSONArray(value)); 579 | return this; 580 | } 581 | 582 | 583 | /** 584 | * Append a double value. This increases the array's length by one. 585 | * 586 | * @param value A double value. 587 | * @throws JSONException if the value is not finite. 588 | * @return this. 589 | */ 590 | public JSONArray put(double value) throws JSONException { 591 | Double d = new Double(value); 592 | JSONObject.testValidity(d); 593 | put(d); 594 | return this; 595 | } 596 | 597 | 598 | /** 599 | * Append an int value. This increases the array's length by one. 600 | * 601 | * @param value An int value. 602 | * @return this. 603 | */ 604 | public JSONArray put(int value) { 605 | put(new Integer(value)); 606 | return this; 607 | } 608 | 609 | 610 | /** 611 | * Append an long value. This increases the array's length by one. 612 | * 613 | * @param value A long value. 614 | * @return this. 615 | */ 616 | public JSONArray put(long value) { 617 | put(new Long(value)); 618 | return this; 619 | } 620 | 621 | 622 | /** 623 | * Put a value in the JSONArray, where the value will be a 624 | * JSONObject which is produced from a Map. 625 | * @param value A Map value. 626 | * @return this. 627 | */ 628 | public JSONArray put(Map value) { 629 | put(new JSONObject(value)); 630 | return this; 631 | } 632 | 633 | 634 | /** 635 | * Append an object value. This increases the array's length by one. 636 | * @param value An object value. The value should be a 637 | * Boolean, Double, Integer, JSONArray, JSONObject, Long, or String, or the 638 | * JSONObject.NULL object. 639 | * @return this. 640 | */ 641 | public JSONArray put(Object value) { 642 | this.myArrayList.add(value); 643 | return this; 644 | } 645 | 646 | 647 | /** 648 | * Put or replace a boolean value in the JSONArray. If the index is greater 649 | * than the length of the JSONArray, then null elements will be added as 650 | * necessary to pad it out. 651 | * @param index The subscript. 652 | * @param value A boolean value. 653 | * @return this. 654 | * @throws JSONException If the index is negative. 655 | */ 656 | public JSONArray put(int index, boolean value) throws JSONException { 657 | put(index, value ? Boolean.TRUE : Boolean.FALSE); 658 | return this; 659 | } 660 | 661 | 662 | /** 663 | * Put a value in the JSONArray, where the value will be a 664 | * JSONArray which is produced from a Collection. 665 | * @param index The subscript. 666 | * @param value A Collection value. 667 | * @return this. 668 | * @throws JSONException If the index is negative or if the value is 669 | * not finite. 670 | */ 671 | public JSONArray put(int index, Collection value) throws JSONException { 672 | put(index, new JSONArray(value)); 673 | return this; 674 | } 675 | 676 | 677 | /** 678 | * Put or replace a double value. If the index is greater than the length of 679 | * the JSONArray, then null elements will be added as necessary to pad 680 | * it out. 681 | * @param index The subscript. 682 | * @param value A double value. 683 | * @return this. 684 | * @throws JSONException If the index is negative or if the value is 685 | * not finite. 686 | */ 687 | public JSONArray put(int index, double value) throws JSONException { 688 | put(index, new Double(value)); 689 | return this; 690 | } 691 | 692 | 693 | /** 694 | * Put or replace an int value. If the index is greater than the length of 695 | * the JSONArray, then null elements will be added as necessary to pad 696 | * it out. 697 | * @param index The subscript. 698 | * @param value An int value. 699 | * @return this. 700 | * @throws JSONException If the index is negative. 701 | */ 702 | public JSONArray put(int index, int value) throws JSONException { 703 | put(index, new Integer(value)); 704 | return this; 705 | } 706 | 707 | 708 | /** 709 | * Put or replace a long value. If the index is greater than the length of 710 | * the JSONArray, then null elements will be added as necessary to pad 711 | * it out. 712 | * @param index The subscript. 713 | * @param value A long value. 714 | * @return this. 715 | * @throws JSONException If the index is negative. 716 | */ 717 | public JSONArray put(int index, long value) throws JSONException { 718 | put(index, new Long(value)); 719 | return this; 720 | } 721 | 722 | 723 | /** 724 | * Put a value in the JSONArray, where the value will be a 725 | * JSONObject which is produced from a Map. 726 | * @param index The subscript. 727 | * @param value The Map value. 728 | * @return this. 729 | * @throws JSONException If the index is negative or if the the value is 730 | * an invalid number. 731 | */ 732 | public JSONArray put(int index, Map value) throws JSONException { 733 | put(index, new JSONObject(value)); 734 | return this; 735 | } 736 | 737 | 738 | /** 739 | * Put or replace an object value in the JSONArray. If the index is greater 740 | * than the length of the JSONArray, then null elements will be added as 741 | * necessary to pad it out. 742 | * @param index The subscript. 743 | * @param value The value to put into the array. The value should be a 744 | * Boolean, Double, Integer, JSONArray, JSONObject, Long, or String, or the 745 | * JSONObject.NULL object. 746 | * @return this. 747 | * @throws JSONException If the index is negative or if the the value is 748 | * an invalid number. 749 | */ 750 | public JSONArray put(int index, Object value) throws JSONException { 751 | JSONObject.testValidity(value); 752 | if (index < 0) { 753 | throw new JSONException("JSONArray[" + index + "] not found."); 754 | } 755 | if (index < length()) { 756 | this.myArrayList.set(index, value); 757 | } else { 758 | while (index != length()) { 759 | put(JSONObject.NULL); 760 | } 761 | put(value); 762 | } 763 | return this; 764 | } 765 | 766 | 767 | /** 768 | * Remove an index and close the hole. 769 | * @param index The index of the element to be removed. 770 | * @return The value that was associated with the index, 771 | * or null if there was no value. 772 | */ 773 | public Object remove(int index) { 774 | Object o = opt(index); 775 | this.myArrayList.remove(index); 776 | return o; 777 | } 778 | 779 | 780 | /** 781 | * Produce a JSONObject by combining a JSONArray of names with the values 782 | * of this JSONArray. 783 | * @param names A JSONArray containing a list of key strings. These will be 784 | * paired with the values. 785 | * @return A JSONObject, or null if there are no names or if this JSONArray 786 | * has no values. 787 | * @throws JSONException If any of the names are null. 788 | */ 789 | public JSONObject toJSONObject(JSONArray names) throws JSONException { 790 | if (names == null || names.length() == 0 || length() == 0) { 791 | return null; 792 | } 793 | JSONObject jo = new JSONObject(); 794 | for (int i = 0; i < names.length(); i += 1) { 795 | jo.put(names.getString(i), this.opt(i)); 796 | } 797 | return jo; 798 | } 799 | 800 | 801 | /** 802 | * Make a JSON text of this JSONArray. For compactness, no 803 | * unnecessary whitespace is added. If it is not possible to produce a 804 | * syntactically correct JSON text then null will be returned instead. This 805 | * could occur if the array contains an invalid number. 806 | *

807 | * Warning: This method assumes that the data structure is acyclical. 808 | * 809 | * @return a printable, displayable, transmittable 810 | * representation of the array. 811 | */ 812 | public String toString() { 813 | try { 814 | return '[' + join(",") + ']'; 815 | } catch (Exception e) { 816 | return null; 817 | } 818 | } 819 | 820 | 821 | /** 822 | * Make a prettyprinted JSON text of this JSONArray. 823 | * Warning: This method assumes that the data structure is acyclical. 824 | * @param indentFactor The number of spaces to add to each level of 825 | * indentation. 826 | * @return a printable, displayable, transmittable 827 | * representation of the object, beginning 828 | * with [ (left bracket) and ending 829 | * with ] (right bracket). 830 | * @throws JSONException 831 | */ 832 | public String toString(int indentFactor) throws JSONException { 833 | return toString(indentFactor, 0); 834 | } 835 | 836 | 837 | /** 838 | * Make a prettyprinted JSON text of this JSONArray. 839 | * Warning: This method assumes that the data structure is acyclical. 840 | * @param indentFactor The number of spaces to add to each level of 841 | * indentation. 842 | * @param indent The indention of the top level. 843 | * @return a printable, displayable, transmittable 844 | * representation of the array. 845 | * @throws JSONException 846 | */ 847 | String toString(int indentFactor, int indent) throws JSONException { 848 | int len = length(); 849 | if (len == 0) { 850 | return "[]"; 851 | } 852 | int i; 853 | StringBuffer sb = new StringBuffer("["); 854 | if (len == 1) { 855 | sb.append(JSONObject.valueToString(this.myArrayList.get(0), 856 | indentFactor, indent)); 857 | } else { 858 | int newindent = indent + indentFactor; 859 | sb.append('\n'); 860 | for (i = 0; i < len; i += 1) { 861 | if (i > 0) { 862 | sb.append(",\n"); 863 | } 864 | for (int j = 0; j < newindent; j += 1) { 865 | sb.append(' '); 866 | } 867 | sb.append(JSONObject.valueToString(this.myArrayList.get(i), 868 | indentFactor, newindent)); 869 | } 870 | sb.append('\n'); 871 | for (i = 0; i < indent; i += 1) { 872 | sb.append(' '); 873 | } 874 | } 875 | sb.append(']'); 876 | return sb.toString(); 877 | } 878 | 879 | 880 | /** 881 | * Write the contents of the JSONArray as JSON text to a writer. 882 | * For compactness, no whitespace is added. 883 | *

884 | * Warning: This method assumes that the data structure is acyclical. 885 | * 886 | * @return The writer. 887 | * @throws JSONException 888 | */ 889 | public Writer write(Writer writer) throws JSONException { 890 | try { 891 | boolean b = false; 892 | int len = length(); 893 | 894 | writer.write('['); 895 | 896 | for (int i = 0; i < len; i += 1) { 897 | if (b) { 898 | writer.write(','); 899 | } 900 | Object v = this.myArrayList.get(i); 901 | if (v instanceof JSONObject) { 902 | ((JSONObject)v).write(writer); 903 | } else if (v instanceof JSONArray) { 904 | ((JSONArray)v).write(writer); 905 | } else { 906 | writer.write(JSONObject.valueToString(v)); 907 | } 908 | b = true; 909 | } 910 | writer.write(']'); 911 | return writer; 912 | } catch (IOException e) { 913 | throw new JSONException(e); 914 | } 915 | } 916 | } --------------------------------------------------------------------------------