Import of lib, io, logging and iterator packages

Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/1320f8db
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/1320f8db
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/1320f8db

Branch: refs/heads/master
Commit: 1320f8dbe2ed08f10fda6e48aac9177557b1ed03
Parents: 692118f
Author: Andy Seaborne <[email protected]>
Authored: Tue Apr 28 22:03:14 2015 +0100
Committer: Andy Seaborne <[email protected]>
Committed: Tue Apr 28 22:03:14 2015 +0100

----------------------------------------------------------------------
 jena-base/pom.xml                               |   2 +-
 .../org/apache/jena/atlas/AtlasException.java   |  27 +
 .../apache/jena/atlas/RuntimeIOException.java   |  34 +
 .../java/org/apache/jena/atlas/io/AWriter.java  |  43 +
 .../org/apache/jena/atlas/io/AWriterBase.java   |  33 +
 .../org/apache/jena/atlas/io/BlockUTF8.java     | 281 ++++++
 .../apache/jena/atlas/io/BufferingWriter.java   | 180 ++++
 .../org/apache/jena/atlas/io/CharStream.java    |  31 +
 .../apache/jena/atlas/io/CharStreamBasic.java   |  58 ++
 .../jena/atlas/io/CharStreamBuffered.java       | 166 ++++
 .../apache/jena/atlas/io/CharStreamReader.java  |  56 ++
 .../jena/atlas/io/CharStreamSequence.java       |  47 +
 .../main/java/org/apache/jena/atlas/io/IO.java  | 325 +++++++
 .../org/apache/jena/atlas/io/InStreamASCII.java |  89 ++
 .../org/apache/jena/atlas/io/InStreamUTF8.java  | 254 +++++
 .../jena/atlas/io/IndentedLineBuffer.java       |  50 +
 .../apache/jena/atlas/io/IndentedWriter.java    | 366 +++++++
 .../jena/atlas/io/InputStreamBuffered.java      | 104 ++
 .../apache/jena/atlas/io/NullOutputStream.java  |  40 +
 .../org/apache/jena/atlas/io/OutStreamUTF8.java | 179 ++++
 .../org/apache/jena/atlas/io/OutputUtils.java   |  77 ++
 .../apache/jena/atlas/io/PeekInputStream.java   | 233 +++++
 .../org/apache/jena/atlas/io/PeekReader.java    | 270 ++++++
 .../org/apache/jena/atlas/io/PrintUtils.java    |  31 +
 .../org/apache/jena/atlas/io/Printable.java     |  24 +
 .../org/apache/jena/atlas/io/PrintableBase.java |  26 +
 .../org/apache/jena/atlas/io/StringWriterI.java |  30 +
 .../java/org/apache/jena/atlas/io/Writer2.java  |  97 ++
 .../apache/jena/atlas/iterator/AccString.java   |  66 ++
 .../apache/jena/atlas/iterator/Accumulate.java  |  27 +
 .../org/apache/jena/atlas/iterator/Action.java  |  24 +
 .../apache/jena/atlas/iterator/ActionCount.java |  31 +
 .../jena/atlas/iterator/ActionNothing.java      |  26 +
 .../org/apache/jena/atlas/iterator/Filter.java  |  22 +
 .../atlas/iterator/FilterDistinctAdjacent.java  |  40 +
 .../jena/atlas/iterator/FilterOutNulls.java     |  32 +
 .../apache/jena/atlas/iterator/FilterStack.java |  67 ++
 .../jena/atlas/iterator/FilterUnique.java       |  39 +
 .../org/apache/jena/atlas/iterator/Iter.java    | 971 +++++++++++++++++++
 .../jena/atlas/iterator/IteratorArray.java      |  92 ++
 .../atlas/iterator/IteratorBlockingQueue.java   |  73 ++
 .../jena/atlas/iterator/IteratorConcat.java     | 104 ++
 .../jena/atlas/iterator/IteratorCons.java       | 122 +++
 .../iterator/IteratorDelayedInitialization.java |  78 ++
 .../jena/atlas/iterator/IteratorInteger.java    |  61 ++
 .../atlas/iterator/IteratorResourceClosing.java | 107 ++
 .../jena/atlas/iterator/IteratorSlotted.java    | 117 +++
 .../jena/atlas/iterator/IteratorTruncate.java   |  79 ++
 .../jena/atlas/iterator/IteratorWithBuffer.java | 132 +++
 .../atlas/iterator/IteratorWithHistory.java     | 109 +++
 .../jena/atlas/iterator/IteratorWrapper.java    |  41 +
 .../apache/jena/atlas/iterator/MapUtils.java    |  36 +
 .../jena/atlas/iterator/NullIterator.java       |  49 +
 .../jena/atlas/iterator/PeekIterator.java       | 100 ++
 .../jena/atlas/iterator/PushbackIterator.java   |  62 ++
 .../atlas/iterator/RepeatApplyIterator.java     |  86 ++
 .../jena/atlas/iterator/SingletonIterator.java  |  51 +
 .../apache/jena/atlas/iterator/Transform.java   |  21 +
 .../jena/atlas/iterator/WrapperIterator.java    |  45 +
 .../apache/jena/atlas/lib/ActionKeyValue.java   |  24 +
 .../org/apache/jena/atlas/lib/AlarmClock.java   |  69 ++
 .../java/org/apache/jena/atlas/lib/Alg.java     | 239 +++++
 .../org/apache/jena/atlas/lib/Allocator.java    |  28 +
 .../org/apache/jena/atlas/lib/ArrayUtils.java   |  64 ++
 .../java/org/apache/jena/atlas/lib/BitsInt.java | 309 ++++++
 .../org/apache/jena/atlas/lib/BitsLong.java     | 311 ++++++
 .../apache/jena/atlas/lib/ByteBufferLib.java    | 211 ++++
 .../java/org/apache/jena/atlas/lib/Bytes.java   | 357 +++++++
 .../java/org/apache/jena/atlas/lib/Cache.java   |  56 ++
 .../org/apache/jena/atlas/lib/CacheFactory.java |  67 ++
 .../org/apache/jena/atlas/lib/CacheSet.java     |  34 +
 .../org/apache/jena/atlas/lib/CacheStats.java   |  28 +
 .../org/apache/jena/atlas/lib/Callback.java     |  24 +
 .../java/org/apache/jena/atlas/lib/Cell.java    |  99 ++
 .../java/org/apache/jena/atlas/lib/Chars.java   | 271 ++++++
 .../org/apache/jena/atlas/lib/Closeable.java    |  27 +
 .../apache/jena/atlas/lib/CollectionUtils.java  |  52 +
 .../org/apache/jena/atlas/lib/ColumnMap.java    | 254 +++++
 .../main/java/org/apache/jena/atlas/lib/DS.java |  45 +
 .../apache/jena/atlas/lib/DateTimeUtils.java    | 127 +++
 .../org/apache/jena/atlas/lib/EscapeStr.java    | 235 +++++
 .../java/org/apache/jena/atlas/lib/FileOps.java | 239 +++++
 .../java/org/apache/jena/atlas/lib/Hex.java     |  97 ++
 .../java/org/apache/jena/atlas/lib/IRILib.java  | 243 +++++
 .../jena/atlas/lib/InternalErrorException.java  |  27 +
 .../java/org/apache/jena/atlas/lib/Lib.java     | 126 +++
 .../org/apache/jena/atlas/lib/ListUtils.java    | 150 +++
 .../java/org/apache/jena/atlas/lib/Map2.java    | 104 ++
 .../org/apache/jena/atlas/lib/MapUtils.java     |  45 +
 .../org/apache/jena/atlas/lib/MultiMap.java     | 146 +++
 .../apache/jena/atlas/lib/MultiMapToList.java   |  43 +
 .../apache/jena/atlas/lib/MultiMapToSet.java    |  47 +
 .../org/apache/jena/atlas/lib/MultiSet.java     | 218 +++++
 .../apache/jena/atlas/lib/NotImplemented.java   |  27 +
 .../org/apache/jena/atlas/lib/NumberUtils.java  | 133 +++
 .../java/org/apache/jena/atlas/lib/Pair.java    |  62 ++
 .../java/org/apache/jena/atlas/lib/Pool.java    |  30 +
 .../org/apache/jena/atlas/lib/PoolBase.java     |  57 ++
 .../org/apache/jena/atlas/lib/PoolSync.java     |  53 +
 .../java/org/apache/jena/atlas/lib/Problem.java |  25 +
 .../apache/jena/atlas/lib/PropertiesSorted.java |  87 ++
 .../apache/jena/atlas/lib/PropertyUtils.java    | 143 +++
 .../org/apache/jena/atlas/lib/RandomLib.java    |  41 +
 .../java/org/apache/jena/atlas/lib/Ref.java     |  54 ++
 .../java/org/apache/jena/atlas/lib/RefLong.java |  38 +
 .../org/apache/jena/atlas/lib/Registry.java     |  39 +
 .../jena/atlas/lib/ReverseComparator.java       |  38 +
 .../org/apache/jena/atlas/lib/SetUtils.java     |  84 ++
 .../java/org/apache/jena/atlas/lib/Sink.java    |  29 +
 .../org/apache/jena/atlas/lib/SinkCounting.java |  41 +
 .../org/apache/jena/atlas/lib/SinkLogging.java  |  41 +
 .../org/apache/jena/atlas/lib/SinkNull.java     |  33 +
 .../org/apache/jena/atlas/lib/SinkPrint.java    |  45 +
 .../org/apache/jena/atlas/lib/SinkSplit.java    |  55 ++
 .../apache/jena/atlas/lib/SinkToCollection.java |  38 +
 .../org/apache/jena/atlas/lib/SinkToQueue.java  |  52 +
 .../org/apache/jena/atlas/lib/SinkWrapper.java  |  44 +
 .../org/apache/jena/atlas/lib/StrUtils.java     | 292 ++++++
 .../java/org/apache/jena/atlas/lib/Sync.java    |  24 +
 .../org/apache/jena/atlas/lib/SystemUtils.java  |  57 ++
 .../java/org/apache/jena/atlas/lib/Timer.java   |  72 ++
 .../java/org/apache/jena/atlas/lib/Trie.java    | 407 ++++++++
 .../java/org/apache/jena/atlas/lib/Tuple.java   | 153 +++
 .../org/apache/jena/atlas/lib/TupleBuilder.java |  50 +
 .../java/org/apache/jena/atlas/lib/XMLLib.java  |  62 ++
 .../org/apache/jena/atlas/lib/cache/Cache0.java |  72 ++
 .../org/apache/jena/atlas/lib/cache/Cache1.java | 127 +++
 .../apache/jena/atlas/lib/cache/CacheGuava.java | 119 +++
 .../apache/jena/atlas/lib/cache/CacheOps.java   |  50 +
 .../jena/atlas/lib/cache/CacheSetImpl.java      |  93 ++
 .../jena/atlas/lib/cache/CacheSetSync.java      |  65 ++
 .../jena/atlas/lib/cache/CacheSetWrapper.java   |  65 ++
 .../jena/atlas/lib/cache/CacheSimple.java       | 161 +++
 .../jena/atlas/lib/cache/CacheWrapper.java      |  65 ++
 .../org/apache/jena/atlas/lib/cache/Getter.java |  25 +
 .../org/apache/jena/atlas/logging/FmtLog.java   | 162 ++++
 .../java/org/apache/jena/atlas/logging/Log.java | 116 +++
 .../org/apache/jena/atlas/logging/LogCtl.java   | 282 ++++++
 .../jena/atlas/logging/ProgressLogger.java      | 133 +++
 .../logging/java/ConsoleHandlerStdout.java      |  75 ++
 .../jena/atlas/logging/java/TextFormatter.java  |  53 +
 .../java/org/apache/jena/base/Closeable.java    |  27 +
 .../src/main/java/org/apache/jena/base/Sys.java |  27 +
 .../java/org/apache/jena/atlas/TC_Atlas.java    |  41 +
 .../atlas/io/AbstractTestPeekInputStream.java   | 243 +++++
 .../jena/atlas/io/AbstractTestPeekReader.java   | 243 +++++
 .../java/org/apache/jena/atlas/io/TS_IO.java    |  45 +
 .../org/apache/jena/atlas/io/TestBlockUTF8.java | 254 +++++
 .../jena/atlas/io/TestBufferingWriter.java      |  97 ++
 .../jena/atlas/io/TestIndentedWriter.java       |  58 ++
 .../jena/atlas/io/TestInputStreamBuffered.java  | 109 +++
 .../atlas/io/TestPeekInputStreamSource.java     |  44 +
 .../atlas/io/TestPeekReaderCharSequence.java    |  32 +
 .../jena/atlas/io/TestPeekReaderSource.java     |  34 +
 .../apache/jena/atlas/io/TestPrintUtils.java    |  59 ++
 .../apache/jena/atlas/io/TestStreamUTF8.java    | 118 +++
 .../apache/jena/atlas/iterator/TS_Iterator.java |  38 +
 .../apache/jena/atlas/iterator/TestIter.java    | 539 ++++++++++
 .../jena/atlas/iterator/TestIteratorArray.java  | 104 ++
 .../jena/atlas/iterator/TestIteratorPeek.java   | 107 ++
 .../atlas/iterator/TestIteratorPushback.java    |  93 ++
 .../atlas/iterator/TestIteratorSlotted.java     | 136 +++
 .../atlas/iterator/TestIteratorWithBuffer.java  |  97 ++
 .../atlas/iterator/TestIteratorWithHistory.java |  87 ++
 .../org/apache/jena/atlas/junit/BaseTest.java   |  45 +
 .../java/org/apache/jena/atlas/lib/TS_Lib.java  |  57 ++
 .../apache/jena/atlas/lib/TestAlarmClock.java   |  92 ++
 .../java/org/apache/jena/atlas/lib/TestAlg.java | 226 +++++
 .../org/apache/jena/atlas/lib/TestBitsInt.java  | 468 +++++++++
 .../org/apache/jena/atlas/lib/TestBitsLong.java | 468 +++++++++
 .../org/apache/jena/atlas/lib/TestBytes.java    | 198 ++++
 .../org/apache/jena/atlas/lib/TestCache.java    | 149 +++
 .../org/apache/jena/atlas/lib/TestCache2.java   |  88 ++
 .../apache/jena/atlas/lib/TestColumnMap.java    | 107 ++
 .../jena/atlas/lib/TestDateTimeUtils.java       |  82 ++
 .../org/apache/jena/atlas/lib/TestFileOps.java  |  78 ++
 .../jena/atlas/lib/TestFilenameProcessing.java  | 136 +++
 .../java/org/apache/jena/atlas/lib/TestHex.java |  81 ++
 .../apache/jena/atlas/lib/TestListUtils.java    |  79 ++
 .../org/apache/jena/atlas/lib/TestMultiSet.java | 143 +++
 .../apache/jena/atlas/lib/TestNumberUtils.java  | 106 ++
 .../org/apache/jena/atlas/lib/TestRefLong.java  |  70 ++
 .../jena/atlas/lib/TestReverseComparator.java   |  91 ++
 .../org/apache/jena/atlas/lib/TestSetUtils.java | 146 +++
 .../org/apache/jena/atlas/lib/TestStrUtils.java |  59 ++
 .../org/apache/jena/atlas/lib/TestTrie.java     | 346 +++++++
 .../org/apache/jena/atlas/lib/TestXMLLib.java   |  47 +
 187 files changed, 20541 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/pom.xml
----------------------------------------------------------------------
diff --git a/jena-base/pom.xml b/jena-base/pom.xml
index a8c05e5..0acf545 100644
--- a/jena-base/pom.xml
+++ b/jena-base/pom.xml
@@ -74,7 +74,7 @@
         <artifactId>maven-surefire-plugin</artifactId>
         <configuration>
           <includes>
-            <include>org/apache/jena/iri/test/TestPackage.java</include>
+            <include>**/TS_*.java</include>
           </includes>
         </configuration>
       </plugin>

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/AtlasException.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/AtlasException.java 
b/jena-base/src/main/java/org/apache/jena/atlas/AtlasException.java
new file mode 100644
index 0000000..2754060
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/AtlasException.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas;
+
+public class AtlasException extends RuntimeException
+{
+    public AtlasException()                          { super() ; }
+    public AtlasException(String msg)                { super(msg) ; }
+    public AtlasException(Throwable th)              { super(th) ; }
+    public AtlasException(String msg, Throwable th)  { super(msg, th) ; }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/RuntimeIOException.java
----------------------------------------------------------------------
diff --git 
a/jena-base/src/main/java/org/apache/jena/atlas/RuntimeIOException.java 
b/jena-base/src/main/java/org/apache/jena/atlas/RuntimeIOException.java
new file mode 100644
index 0000000..1d9938b
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/RuntimeIOException.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas;
+
+/** Runtime eception used to wrap IOExceptions */
+public class RuntimeIOException extends AtlasException
+{
+    public RuntimeIOException()                          { super() ; }
+    public RuntimeIOException(String msg)                { super(msg) ; }
+    /**
+     * Wrap a Throwable - this is usually an IOException.
+     */
+    public RuntimeIOException(Throwable th)              { super(th) ; }
+    /**
+     * Wrap a Throwable - this is usually an IOException.
+     */
+    public RuntimeIOException(String msg, Throwable th)  { super(msg, th) ; }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/io/AWriter.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/io/AWriter.java 
b/jena-base/src/main/java/org/apache/jena/atlas/io/AWriter.java
new file mode 100644
index 0000000..c046544
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/io/AWriter.java
@@ -0,0 +1,43 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.io;
+
+import org.apache.jena.atlas.lib.Closeable ;
+
+
+/** Simple abstraction of a string/character output stream */
+
+public interface AWriter extends Closeable, AutoCloseable 
+{
+    public void write(char ch) ;
+    public void write(char[] cbuf) ; 
+    public void write(String string) ;
+
+    public void print(char ch) ;
+    public void print(char[] cbuf) ; 
+    public void print(String string) ;
+    public void printf(String fmt, Object ...arg) ;
+    public void println(String object) ;
+    public void println() ;
+    
+    public void flush() ;
+    @Override
+    public void close() ;
+}
+

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/io/AWriterBase.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/io/AWriterBase.java 
b/jena-base/src/main/java/org/apache/jena/atlas/io/AWriterBase.java
new file mode 100644
index 0000000..bc80fc2
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/io/AWriterBase.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.io;
+
+
+/** Simple abstraction of a string/character output stream */
+
+public abstract class AWriterBase implements AWriter
+{
+    @Override
+    public final void write(char ch)          { print(ch) ; }
+    @Override
+    public final void write(char[] cbuf)      { print(cbuf) ; }
+    @Override
+    public final void write(String string)    { print(string) ; }
+}
+

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/io/BlockUTF8.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/io/BlockUTF8.java 
b/jena-base/src/main/java/org/apache/jena/atlas/io/BlockUTF8.java
new file mode 100644
index 0000000..2d5560b
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/io/BlockUTF8.java
@@ -0,0 +1,281 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.io ;
+
+import java.io.IOException ;
+import java.nio.ByteBuffer ;
+import java.nio.CharBuffer ;
+
+import org.apache.jena.atlas.lib.NotImplemented ;
+
+/**
+ * Convert between bytes and chars, UTF-8 only.
+ * 
+ * This code is just the UTF-8 encoding rules - it does not check for legality
+ * of the Unicode data.  The standard codec do, so do not round-trip with 
binary
+ * compatibility. (Example: a single element of a surrogate pair will
+ * be encoded/decoded without lost.
+ *  
+ * 
+ * The usual Charset encoders/decoders can be expensive to start up - they are 
also
+ * not thread safe. Sometimes we want to convert 10's of chars and UTF-8 can be
+ * done in code with no lookup tables (which, if used, are cache-unfriendly).
+ * 
+ * This code is thread safe.  It uses code in the hope that JITting will
+ * make it fast if used heavily.
+ */
+
+public class BlockUTF8
+{
+    // Looking in java.lang.StringCoding (Sun RT) is illuminating.
+    // The actual encode/decode code is in sun.nio.cs.UTF_8.(Decoder|Encoder)
+    // which has special cases for ByteBuffer, ByteBuffer with array (needs 
offsets)
+    // and byte[] <-> char[]
+
+    // It seems that chars -> bytes (on <100char strings) is faster with 
BlockUTF8
+    // but the conversion from bytes to string is faster with Java decoders 
(not by much though). 
+
+    /*
+     * Bits 
+     * 7    U+007F      1 to 127              0xxxxxxx 
+     * 11   U+07FF      128 to 2,047          110xxxxx 10xxxxxx
+     * 16   U+FFFF      2,048 to 65,535       1110xxxx 10xxxxxx 10xxxxxx
+     * 21   U+1FFFFF    65,536 to 1,114,111   11110xxx 10xxxxxx 10xxxxxx 
10xxxxxx
+     * 26   U+3FFFFFF                         111110xx 10xxxxxx 10xxxxxx 
10xxxxxx 10xxxxxx
+     * 31   U+7FFFFFFF                        1111110x 10xxxxxx 10xxxxxx 
10xxxxxx 10xxxxxx 10xxxxxx
+     */
+    
+    
+    /** Convert the bytes in the ByteBuffer to characters in the CharBuffer.
+     * The CharBuffer must be large enough. 
+     */
+    public static void toChars(ByteBuffer bb, CharBuffer cb)
+    {
+//        if ( bb.hasArray() && cb.hasArray() )
+//        {
+//            toCharsArray(bb.array(), cb.array()) ;
+//            return ;
+//        }
+        toCharsBuffer(bb, cb) ;
+    }
+
+    /** Convert characters to UTF-8 bytes in the ByteBuffer.
+     * The ByteBuffer must be large enough. 
+     */
+    public static void fromChars(CharBuffer cb, ByteBuffer bb)
+    {
+//        if ( bb.hasArray() && cb.hasArray() )
+//        {
+//            fromCharsArray(cb.array(), bb.array()) ;
+//            return ;
+//        }
+        fromCharsBuffer(cb, bb) ;
+    }
+
+    /** Make a string from UTF-8 bytes in a ByteBuffer */ 
+    public static String toString(ByteBuffer bb)
+    {
+        // I think that the copy from some mutable collector to immutable 
string is inevitable in java.  
+        int len = bb.remaining() ;
+        CharBuffer cb = CharBuffer.allocate(len) ;
+        toChars(bb, cb) ;
+        return new String(cb.array(), 0, cb.position()) ;
+    }
+
+    // Using buffer access.
+    private static void toCharsBuffer(ByteBuffer bb, CharBuffer cb)
+    {
+        int idx = bb.position();
+        int limit = bb.limit() ;
+
+        for ( ;  idx < limit ; )
+        {
+            int x = bb.get() ;
+            if ( x > 0 && x <= 127 )
+            {
+                cb.put((char)x) ;
+                idx += 1 ;
+            } else if ( x == 0 )
+            {
+                // Pass through a null byte as the null character (illegal 
Unicode, Java compatible).
+                cb.put((char)x) ;
+                idx += 1 ;
+            }
+            else if ( (x & 0xE0) == 0xC0 )
+            {
+                // 10 => extension byte
+                // 110..... => 2 bytes
+                // Unroll common path
+                //int ch = readMultiBytes(bb, x & 0x1F, 2) ;
+                int x2 = bb.get() ;
+                if ( (x2 & 0xC0) != 0x80 )
+                    exception("Illegal UTF-8 processing character: 0x%04X",x2) 
;
+                // 6 bits of x2
+                int ch = ( (x&0x1F) << 6) | (x2 & 0x3F); 
+                cb.put((char)ch) ;
+                idx += 2  ;
+            } 
+            else if ( (x & 0xF0) == 0xE0 ) 
+            {
+                //  1110.... => 3 bytes : 16 bits : not outside 16bit chars 
+                int ch = readMultiBytes(bb, x & 0x0F, 3) ;
+                cb.put((char)ch) ;
+                idx += 3 ;
+            }
+            else if ( (x & 0xF8) == 0xF0 ) 
+            {
+                // Looking like 4 byte charcater.
+                // 11110zzz => 4 bytes.
+                int ch = readMultiBytes(bb, x & 0x08, 4) ;
+                char chars[] = Character.toChars(ch) ;
+                cb.put(chars) ;
+                idx += 4 ;
+            }
+            else 
+            {
+                exception("Illegal UTF-8: 0x%04X",x) ;
+                return ;
+            }
+        }
+    }
+
+    private static void toCharsArray(byte[] bytes, char[] chars)
+    {
+        throw new NotImplemented() ;
+    }
+    
+    private static void fromCharsBuffer(CharBuffer cb, ByteBuffer bb)
+    {
+        // CharBuffers are CharSequences but charAt(i) adds a layer of work.
+        //int bytesStart = bb.position() ;
+        int idx = cb.position() ;
+        int limit = cb.limit() ;
+        for ( ; idx < limit ; idx ++ )
+        {
+            char ch = cb.get() ;
+            if ( ch != 0 && ch <= 127 )
+            {
+                // 7 bits
+                bb.put((byte)ch) ;
+            } 
+            else if ( ch == 0 )
+            {
+                // Java.
+                bb.put((byte)0x00) ;
+                // Modified UTF-8.
+                //bb.put((byte)0xC0) ;
+                //bb.put((byte)0x80) ;
+            } 
+            else if ( ch <= 0x07FF )
+            {
+                // 11 bits : 110yyyyy 10xxxxxx
+                // int x1 = ( ((ch>>(11-5))&0x7) | 0xC0 ) ; outputBytes(out, 
x1, 2, ch) ; return ;
+                int x1 = ( ((ch>>(11-5))&0x01F ) | 0xC0 ) ; 
+                int x2 = ( (ch&0x3F)  | 0x80 ) ;
+                bb.put((byte)x1) ;
+                bb.put((byte)x2) ;
+            } 
+            else if ( ch <= 0xFFFF )
+            {
+                // 16 bits : 1110aaaa  10bbbbbb  10cccccc
+                // int x1 = ( ((ch>>(16-4))&0x7) | 0xE0 ) ; outputBytes(out, 
x1, 3, ch) ; return ;
+                int x1 = ( ((ch>>(16-4))&0x0F) | 0xE0 ) ;
+                int x2 = ( ((ch>>6)&0x3F) | 0x80 ) ;
+                int x3 = ( (ch&0x3F) | 0x80 ) ;
+                bb.put((byte)x1) ;
+                bb.put((byte)x2) ;
+                bb.put((byte)x3) ;
+            }
+            //            if ( Character.isDefined(ch) )
+            //                throw new AtlasException("not a character") ;
+            //if ( true ) throw new InternalErrorException("Valid code point 
for Java but not encodable") ;
+            // Not java, where chars are 16 bit.
+            else if ( ch <= 0x1FFFFF )
+            {
+                // 21 bits : 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+                int x1 = ( ((ch>>(21-3))&0x7) | 0xF0 ) ;
+                outputBytes(bb, x1, 4, ch) ;
+            } 
+            else if ( ch <= 0x3FFFFFF )
+            {
+                // 26 bits : 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+                int x1 = ( ((ch>>(26-2))&0x3) | 0xF8 ) ;
+                outputBytes(bb, x1, 5, ch) ;
+            }
+            else if ( ch <= 0x7FFFFFFF )
+            {
+                // 32 bits : 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 
10xxxxxx
+                int x1 = ( ((ch>>(32-1))&0x1) | 0xFC ) ;
+                outputBytes(bb, x1, 6, ch) ;
+            }
+        }
+        //int bytesFinish = bb.position() ;
+    }
+
+    private static void fromCharsArray(char[] array, byte[] array2)
+    {
+        throw new NotImplemented() ;
+    }
+    
+    public static void fromChars(CharSequence cs, ByteBuffer bb)
+    {
+        fromChars(CharBuffer.wrap(cs), bb) ;
+    }
+
+    private static int readMultiBytes(ByteBuffer input, int start, int len)
+    {
+        // We have already read one byte.
+        if ( input.remaining() < (len-1) )
+            exception("Premature end to UTF-8 sequence at end of input") ;
+        int x = start ;
+        for ( int i = 0 ; i < len-1 ; i++ )
+        {
+            int x2 = input.get() ;
+            if ( (x2 & 0xC0) != 0x80 )
+                exception("Illegal UTF-8 processing character: 0x%04X",x2) ;
+            // 6 bits of x2
+            x = (x << 6) | (x2 & 0x3F); 
+        }
+        return x ;
+    }
+
+    /** Put bytes to the output ByteBuffer for charcater ch.
+     * The first byte is in x1 and already has the needed bits set. 
+     */
+    private static void outputBytes(ByteBuffer bb, int x1, int byteLength, int 
ch)
+    {
+        bb.put((byte)x1) ;
+        byteLength-- ; // remaining bytes
+        for ( int i = 0 ; i < byteLength ; i++ )
+        {
+            // 6 Bits, loop from high to low  
+            int shift = 6*(byteLength-i-1) ;
+            int x =  (ch>>shift) & 0x3F ;
+            x = x | 0x80 ;  // 10xxxxxx
+            bb.put((byte)x) ;
+        }
+    }
+    
+    // Does not return 
+    private static void exception(String fmt, Object ...args)
+    {
+        String str = String.format(fmt,args) ;
+        IO.exception(new IOException(str)) ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/io/BufferingWriter.java
----------------------------------------------------------------------
diff --git 
a/jena-base/src/main/java/org/apache/jena/atlas/io/BufferingWriter.java 
b/jena-base/src/main/java/org/apache/jena/atlas/io/BufferingWriter.java
new file mode 100644
index 0000000..b17e930
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/io/BufferingWriter.java
@@ -0,0 +1,180 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.io ;
+
+import java.io.IOException ;
+import java.io.Writer ;
+
+import org.apache.jena.atlas.io.IO ;
+
+/**
+ * A buffering writer. Like BufferedWriter but with no synchronization. A
+ * "synchronized" per character can be expensive.
+ * <p>
+ * The standard java.io classes have hidden synchronization so in some very
+ * critical situations, this can be expensive.
+ * </p>
+ * This class is not thread safe.
+ */
+
+public final class BufferingWriter extends Writer {
+    // Default sizes
+    private static final int SIZE      = 8 * 1024 ;      // Unit size in bytes.
+    private static final int BLOB_SIZE = SIZE / 2 ;      // Large object size,
+                                                          // worse case, bytes
+    // Sizes for this instance
+    private final int        blockSize ;
+    private final int        blobSize ;
+
+    private char[]           buffer    = new char[SIZE] ;
+    private int              idx       = 0 ;
+    private Writer           out ;
+
+    /** Create a buffering writer */
+    public BufferingWriter(Writer dest) {
+        this(dest, SIZE, BLOB_SIZE) ;
+    }
+
+    /** Create a buffering writer */
+    public BufferingWriter(Writer dest, int size) {
+        this(dest, size, size/2) ;
+    }
+
+    /** Create a buffering writer */
+    public BufferingWriter(Writer dest, int size, int blobSize) {
+        this.out = dest ;
+        this.blockSize = size ;
+        this.blobSize = blobSize ;
+    }
+
+    /**
+     * Output a string
+     * @param string Characters
+     */
+    public void output(String string) {
+        output(string, 0, string.length()) ;
+    }
+    
+    /**
+     * Output a string
+     * 
+     * @param string Characters
+     * @param off    Starting point in the string
+     * @param length Length
+     */
+    public void output(String string, int off, int length) {
+        boolean largeBlob = (length > blobSize) ;
+
+        // There is no space or too big
+        if ( largeBlob || (blockSize - idx) < length )
+            flushBuffer() ;
+        // If too big, do directly.
+        if ( largeBlob /* too big */) {
+            try { out.write(string, off, length) ; }
+            catch (IOException ex) { IO.exception(ex) ; }
+            return ;
+        }
+        int n = string.length() ;
+        string.getChars(off, (n + off), buffer, idx) ;
+        idx += n ;
+    }
+
+    /** Output an array of characters */
+    public void output(char chars[]) {
+        output(chars, 0, chars.length) ;
+    }
+
+    /**
+     * Output an array of characters
+     * 
+     * @param chars Characters
+     * @param start Start
+     * @param length Length
+     */
+    public void output(char chars[], int start, int length) {
+        boolean largeBlob = (length > blobSize) ;
+
+        // There is no space or too big
+        if ( largeBlob || (blockSize - idx) < length )
+            flushBuffer() ;
+        // If too big, do directly.
+        if ( largeBlob /* too big */) {
+            try { out.write(chars) ; }
+            catch (IOException ex) { IO.exception(ex) ; }
+            return ;
+        }
+        System.arraycopy(chars, start, buffer, idx, length) ;
+        idx += length ;
+    }
+
+    /** Output a single character */
+    public void output(char ch) {
+        if ( blockSize == idx )
+            flushBuffer() ;
+        buffer[idx++] = ch ;
+    }
+
+    private void flushBuffer() {
+        if ( idx > 0 ) {
+            try { out.write(buffer, 0, idx) ; }
+            catch (IOException ex) { IO.exception(ex) ; }
+            idx = 0 ;
+        }
+
+    }
+    
+    // ---- Writer
+
+    @Override
+    public void close() {
+        flushBuffer() ;
+        IO.close(out) ;
+    }
+
+    @Override
+    public void flush() {
+        flushBuffer() ;
+        IO.flush(out) ;
+    }
+
+    @Override
+    public void write(char[] cbuf, int off, int len) throws IOException {
+        output(cbuf, off, len) ;
+    }
+
+    @Override
+    public void write(char[] cbuf) throws IOException {
+        write(cbuf, 0, cbuf.length) ;
+    }
+
+    @Override
+    public void write(String string, int off, int len) throws IOException {
+        output(string, off, len) ;
+    }
+
+    @Override
+    public void write(String string) throws IOException {
+        output(string, 0, string.length()) ;
+    }
+
+    @Override
+    public void write(int ch) throws IOException {
+        output((char)ch) ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/io/CharStream.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/io/CharStream.java 
b/jena-base/src/main/java/org/apache/jena/atlas/io/CharStream.java
new file mode 100644
index 0000000..f066843
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/io/CharStream.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.io;
+
+
+/** A simplifed reader interface without IOExceptions. 
+ * And it's an interface, not an abstract class 
+ */
+public interface CharStream
+{
+    public int advance() ;
+    
+    /** Close the stream - different name from java.io.Reader.close */
+    public void closeStream() ;     
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/io/CharStreamBasic.java
----------------------------------------------------------------------
diff --git 
a/jena-base/src/main/java/org/apache/jena/atlas/io/CharStreamBasic.java 
b/jena-base/src/main/java/org/apache/jena/atlas/io/CharStreamBasic.java
new file mode 100644
index 0000000..27416d9
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/io/CharStreamBasic.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.io;
+
+import java.io.IOException ;
+import java.io.Reader ;
+
+/** A PeekReaderSource that does no buffering - just wraps a reader. */
+public final class CharStreamBasic extends CharStreamReader
+{
+    private Reader reader ;
+
+    CharStreamBasic(Reader reader)
+    {
+        this.reader = reader ;
+    }
+    
+    @Override
+    public int advance()
+    {
+        try
+        {
+            return reader.read() ;
+        } catch (IOException ex)
+        {
+            ex.printStackTrace();
+            return -1 ;
+        }
+    }
+
+    @Override
+    public void closeStream()
+    {
+        try
+        {
+            reader.close() ;
+        } catch (IOException ex)
+        {
+            ex.printStackTrace();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/io/CharStreamBuffered.java
----------------------------------------------------------------------
diff --git 
a/jena-base/src/main/java/org/apache/jena/atlas/io/CharStreamBuffered.java 
b/jena-base/src/main/java/org/apache/jena/atlas/io/CharStreamBuffered.java
new file mode 100644
index 0000000..519dc36
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/io/CharStreamBuffered.java
@@ -0,0 +1,166 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.io;
+
+import static org.apache.jena.atlas.io.IO.EOF ;
+
+import java.io.IOException ;
+import java.io.Reader ;
+
+/** Buffering reader without the (hidden) sync overhead in BufferedReader
+ * 
+ * @see java.io.BufferedReader
+ */ 
+
+
+public final class CharStreamBuffered extends CharStreamReader
+{
+    /*package*/ static final int CB_SIZE       = 128 * 1024 ;
+    
+    private final char[] chars ;            // CharBuffer?
+    private int buffLen = 0 ;
+    private int idx = 0 ;
+
+    private final Source source;
+    
+    public CharStreamBuffered(Reader r)
+    { this(r, CB_SIZE) ; }
+
+    /**
+     * @param r
+     * @param buffSize
+     */
+    public CharStreamBuffered(Reader r, int buffSize)
+    {
+        super() ;
+        source = new SourceReader(r) ;
+        chars = new char[buffSize] ;
+    }
+
+    // Local adapter/encapsulation
+    private interface Source
+    { 
+        int fill(char[] array) ;
+        void close() ; 
+    }
+    
+    static final class SourceReader implements Source
+    {
+        final Reader reader ;
+        SourceReader(Reader r) { reader = r ; }
+        
+        @Override
+        public void close()
+        { 
+            try { reader.close() ; } catch (IOException ex) { IO.exception(ex) 
; } 
+        }
+        
+        @Override
+        public int fill(char[] array)
+        {
+            try { return reader.read(array) ; } catch (IOException ex) { 
IO.exception(ex) ; return -1 ; }
+        }
+    }
+    
+//    /** Faster?? for ASCII */
+//    static final class SourceASCII implements Source
+//    {
+//        final InputStream input ;
+//        SourceASCII(InputStream r) { input = r ; }
+//        public void close()
+//        { try { input.close() ; } catch (IOException ex) { exception(ex) ; } 
} 
+//        
+//        public final int fill(char[] array)
+//        {
+//            try {
+//                // Recycle.
+//                byte[] buff = new byte[array.length] ;
+//                int len = input.read(buff) ;
+//                for ( int i = 0 ; i < len ; i++ )
+//                {
+//                    byte b = buff[i] ;
+//                    if ( b < 0 )
+//                        throw new AtlasException("Illegal ASCII charcater: 
"+b) ;
+//                   array[i] = (char)b ;
+//                }
+//                return len ;
+//            } catch (IOException ex) { exception(ex) ; return -1 ; }
+//        }
+//    }
+//    
+//    static final class SourceChannel implements Source
+//    {
+//        final ReadableByteChannel channel ;
+//        CharsetDecoder decoder = Chars.createDecoder() ;
+//        SourceChannel(ReadableByteChannel r) { channel = r ; }
+//        
+//        @Override
+//        public void close()
+//        { 
+//            try { channel.close() ; } catch (IOException ex) { exception(ex) 
; } 
+//        }
+//        
+//        @Override
+//        public int fill(char[] array)
+//        {
+//            // Encoding foo.
+////             Bytes
+////             
+////            ByteBuffer b = ByteBuffer.wrap(null) ;
+////            
+////            try { return channel.read(null).read(array) ; } catch 
(IOException ex) { exception(ex) ; return -1 ; }
+//            return -1 ;
+//        }
+//    }
+
+    @Override
+    public final int advance()
+    {
+        if ( idx >= buffLen )
+            // Points outside the array.  Refill it 
+            fillArray() ;
+        
+        // Advance one character.
+        if ( buffLen >= 0 )
+        {
+            char ch = chars[idx] ;
+            // Advance the lookahead character
+            idx++ ;
+            return ch ;
+        }  
+        else
+            // Buffer empty, end of stream.
+            return EOF ;
+    }
+
+    private int fillArray()
+    {
+        int x = source.fill(chars) ;
+        idx = 0 ;
+        buffLen = x ;   // Maybe -1
+        return x ;
+    }
+
+    
+    @Override
+    public void closeStream()
+    {
+        source.close() ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/io/CharStreamReader.java
----------------------------------------------------------------------
diff --git 
a/jena-base/src/main/java/org/apache/jena/atlas/io/CharStreamReader.java 
b/jena-base/src/main/java/org/apache/jena/atlas/io/CharStreamReader.java
new file mode 100644
index 0000000..d7dce11
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/io/CharStreamReader.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.io;
+
+import java.io.IOException ;
+import java.io.Reader ;
+
+/** Machinary to add Reader functionality to a CharStream */
+public abstract class CharStreamReader extends Reader implements CharStream
+{
+    @Override
+    public int read(char[] cbuf, int off, int len) throws IOException
+    {
+        for ( int i = 0 ; i < len ; i++ )
+        {
+            int x = advance() ;
+            if ( x == -1 )
+                return (i==0)? -1 : i ;
+            cbuf[i] = (char)x ;
+        }
+        return len ;
+    }
+
+    @Override
+    public int read() throws IOException
+    {
+        return advance() ;
+    }
+
+    
+    @Override
+    public void close() throws IOException
+    { closeStream() ; }
+
+    @Override
+    public abstract int advance() ;
+
+    @Override
+    public abstract void closeStream() ;
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/io/CharStreamSequence.java
----------------------------------------------------------------------
diff --git 
a/jena-base/src/main/java/org/apache/jena/atlas/io/CharStreamSequence.java 
b/jena-base/src/main/java/org/apache/jena/atlas/io/CharStreamSequence.java
new file mode 100644
index 0000000..c0e9f40
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/io/CharStreamSequence.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.io;
+import static org.apache.jena.atlas.io.IO.EOF ;
+
+public final class CharStreamSequence implements CharStream
+{
+    private CharSequence string ;
+    // Next character.
+    private int idx ;
+
+    public CharStreamSequence(CharSequence string)
+    {
+        this.string = string ;
+        this.idx = 0 ;
+    }
+
+    @Override
+    public int advance()
+    {
+        if ( idx >= string.length() )
+            return EOF ;
+        return string.charAt(idx++);
+    }
+
+    @Override
+    public void closeStream()
+    {
+        string = null ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/io/IO.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/io/IO.java 
b/jena-base/src/main/java/org/apache/jena/atlas/io/IO.java
new file mode 100644
index 0000000..ac312e8
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/io/IO.java
@@ -0,0 +1,325 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.io;
+
+import java.io.* ;
+import java.nio.charset.Charset ;
+import java.nio.charset.StandardCharsets ;
+import java.util.zip.GZIPInputStream ;
+import java.util.zip.GZIPOutputStream ;
+
+import org.apache.jena.atlas.RuntimeIOException ;
+import org.apache.jena.atlas.lib.IRILib ;
+
+public class IO
+{
+    public static final int EOF = -1 ;
+    public static final int UNSET = -2 ;
+       
+    private static Charset utf8  = StandardCharsets.UTF_8 ;
+    private static Charset ascii = StandardCharsets.US_ASCII ;
+    
+    /** Open an input stream to a file. 
+     * If the filename is null or "-", return System.in
+     * If the filename ends in .gz, wrap in  GZIPInputStream  
+     */
+    static public InputStream openFile(String filename) {
+        try {
+           return openFileEx(filename) ;
+        }
+        catch (Exception ex) { throw new RuntimeIOException(ex) ; }
+    }
+    
+    /** Open an input stream to a file; do not mask IOExceptions. 
+     * If the filename is null or "-", return System.in
+     * If the filename ends in .gz, wrap in  GZIPInputStream  
+     * @param filename
+     * @throws FileNotFoundException 
+     * @throws IOException
+     */
+    static public InputStream openFileEx(String filename) throws IOException, 
FileNotFoundException {
+        if ( filename == null || filename.equals("-") )
+            return System.in ;
+        if ( filename.startsWith("file:") )
+        {
+            filename = filename.substring("file:".length()) ;
+            filename = IRILib.decode(filename) ;
+        }
+        InputStream in = new FileInputStream(filename) ;
+        if ( filename.endsWith(".gz") )
+            in = new GZIPInputStream(in) ;
+        return in ;
+    }
+    
+    /** Open a UTF8 Reader for a file. 
+     * If the filename is null or "-", use System.in
+     * If the filename ends in .gz, use GZIPInputStream  
+     */
+    static public Reader openFileUTF8(String filename)  { return 
openFileReader(filename, utf8) ; }
+
+    /** Open an ASCII Reader for a file. 
+     * If the filename is null or "-", use System.in
+     * If the filename ends in .gz, use GZIPInputStream  
+     */
+    static public Reader openFileASCII(String filename)  { return 
openFileReader(filename, ascii) ; }
+
+    private static Reader openFileReader(String filename, Charset charset)
+    {
+        InputStream in = openFile(filename) ;
+        return new InputStreamReader(in, charset) ;
+    }
+
+    /** Create an unbuffered reader that uses UTF-8 encoding */ 
+    static public Reader asUTF8(InputStream in)
+    {
+        return new InputStreamReader(in, utf8.newDecoder());
+    }
+    
+    /** Create a unbuffered reader that uses ASCII encoding */ 
+    static public Reader asASCII(InputStream in)
+    {
+        return new InputStreamReader(in, ascii.newDecoder());
+    }
+    
+    /** Create an buffered reader that uses UTF-8 encoding */ 
+    static public BufferedReader asBufferedUTF8(InputStream in) {
+        return new BufferedReader(asUTF8(in)) ;
+    }
+
+    /** Create a writer that uses UTF-8 encoding */ 
+    static public Writer asUTF8(OutputStream out) {
+        return new OutputStreamWriter(out, utf8.newEncoder());
+    }
+
+    /** Create a writer that uses ASCII encoding */ 
+    static public Writer asASCII(OutputStream out) {
+        return new OutputStreamWriter(out, ascii.newEncoder());
+    }
+
+    /** Create a writer that uses UTF-8 encoding and is buffered. */ 
+    static public Writer asBufferedUTF8(OutputStream out) {
+        Writer w =  new OutputStreamWriter(out, utf8.newEncoder());
+        return new BufferingWriter(w) ;
+    }
+
+    /** Open a file for output - may include adding gzip processing. */
+    static public OutputStream openOutputFile(String filename)
+    {
+        try {
+           return openOutputFileEx(filename) ;
+        }
+        catch (IOException ex) { IO.exception(ex) ; return null ; }
+    }
+    
+    /** Open an input stream to a file; do not mask IOExceptions. 
+     * If the filename ends in .gz, wrap in GZIPOutputStream  
+     * @param filename
+     * @throws FileNotFoundException If the output can't be opened.
+     * @throws IOException for bad gzip encoded data
+     */
+    static public OutputStream openOutputFileEx(String filename) throws 
FileNotFoundException,IOException
+    {
+        if ( filename == null || filename.equals("-") )
+            return System.out ;
+        if ( filename.startsWith("file:") )
+        {
+            filename = filename.substring("file:".length()) ;
+            filename = IRILib.decode(filename) ;
+        }
+        OutputStream out = new FileOutputStream(filename) ;
+        if ( filename.endsWith(".gz") )
+            out = new GZIPOutputStream(out) ;
+        return out ;
+    }
+    
+    /** Wrap in a general writer interface */ 
+    static public AWriter wrap(Writer w) { 
+        return Writer2.wrap(w) ;
+    }
+    
+    /** Wrap in a general writer interface */ 
+    static public AWriter wrapUTF8(OutputStream out)        { return 
wrap(asUTF8(out)) ; } 
+    
+    /** Wrap in a general writer interface */ 
+    static public AWriter wrapASCII(OutputStream out)       { return 
wrap(asASCII(out)) ; } 
+
+    /** Create a print writer that uses UTF-8 encoding */ 
+    static public PrintWriter asPrintWriterUTF8(OutputStream out) {
+        return new PrintWriter(asUTF8(out)); 
+    }
+
+    public static void close(org.apache.jena.atlas.lib.Closeable resource) {
+        resource.close() ;
+    }
+
+    public static void closeSilent(org.apache.jena.atlas.lib.Closeable 
resource) {
+        try { resource.close(); } catch (Exception ex) { }
+    }
+    
+    public static void close(java.io.Closeable resource) {
+        if ( resource == null )
+            return ;
+        try { resource.close(); } catch (IOException ex) { exception(ex) ; }
+    }
+    
+    public static void closeSilent(java.io.Closeable resource) {
+        if ( resource == null )
+            return ;
+        try { resource.close(); } catch (IOException ex) { }
+    }
+    
+    public static void close(AWriter resource) {
+        if ( resource == null )
+            return ;
+        resource.close();
+    }
+    
+    public static void closeSilent(AWriter resource) {
+        if ( resource == null )
+            return ;
+        try { resource.close();  } catch (Exception ex) { }
+    }
+
+    public static void close(IndentedWriter resource) {
+        if ( resource == null )
+            return ;
+        resource.close();
+    }
+    
+    public static void closeSilent(IndentedWriter resource) {
+        if ( resource == null )
+            return ;
+        try { resource.close();  } catch (Exception ex) { }
+    }
+
+    public static void exception(IOException ex) {
+        throw new RuntimeIOException(ex) ;
+    }
+
+    public static void exception(String msg, IOException ex) {
+        throw new RuntimeIOException(msg, ex) ;
+    }
+    
+    public static void flush(OutputStream out) { 
+        if ( out == null )
+            return ;
+        try { out.flush(); } catch (IOException ex) { exception(ex) ; }
+    }
+    
+    public static void flush(Writer out) {
+        if ( out == null )
+            return ;
+        try { out.flush(); } catch (IOException ex) { exception(ex) ; } 
+    }
+
+    public static void flush(AWriter out) {
+        if ( out == null )
+            return ;
+        out.flush(); 
+    }
+
+    private static final int BUFFER_SIZE = 32*1024 ; 
+    
+    public static byte[] readWholeFile(InputStream in) {
+        try(ByteArrayOutputStream out = new 
ByteArrayOutputStream(BUFFER_SIZE)) {
+            byte buff[] = new byte[BUFFER_SIZE] ;
+            while (true) {
+                int l = in.read(buff) ;
+                if ( l <= 0 )
+                    break ;
+                out.write(buff, 0, l) ;
+            }
+            return out.toByteArray() ;
+        }
+        catch (IOException ex) {
+            exception(ex) ;
+            return null ;
+        }
+    }
+    
+    /** Read a whole file as UTF-8
+     * @param filename
+     * @return String
+     * @throws IOException
+     */
+    
+    public static String readWholeFileAsUTF8(String filename) throws 
IOException {
+        try ( InputStream in = new FileInputStream(filename) ) {
+            return readWholeFileAsUTF8(in) ;
+        }
+    }
+
+    /** Read a whole stream as UTF-8
+     * 
+     * @param in    InputStream to be read
+     * @return      String
+     * @throws IOException
+     */
+    public static String readWholeFileAsUTF8(InputStream in) throws 
IOException {
+        // Don't buffer - we're going to read in large chunks anyway
+        try ( Reader r = asUTF8(in) ) {
+            return readWholeFileAsUTF8(r) ;
+        }
+    }
+    
+    /** Read a whole file as UTF-8
+     * 
+     * @param r
+     * @return String The whole file
+     * @throws IOException
+     */
+    
+    // Private worker as we are trying to force UTF-8. 
+    private static String readWholeFileAsUTF8(Reader r) throws IOException {
+        try(StringWriter sw = new StringWriter(BUFFER_SIZE)) {
+            char buff[] = new char[BUFFER_SIZE];
+            for (;;)
+            {
+                int l = r.read(buff);
+                if (l < 0)
+                    break;
+                sw.write(buff, 0, l);
+            }
+            return sw.toString();
+        }
+    }
+
+    public static String uniqueFilename(String directory, String base, String 
ext) {
+        File d = new File(directory) ;
+        if ( !d.exists() )
+            throw new IllegalArgumentException("Not found: " + directory) ;
+        try {
+            String fn0 = d.getCanonicalPath() + File.separator + base ;
+            String fn = fn0 ;
+            int x = 1 ;
+            while (true) {
+                if ( ext != null )
+                    fn = fn + "."+ext ;
+                File f = new File(fn) ;
+                if ( ! f.exists() )
+                    return fn ;
+                fn = fn0 + "-" + (x++) ;
+            }
+        } catch (IOException e) {
+            IO.exception(e) ;
+            return null ;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/io/InStreamASCII.java
----------------------------------------------------------------------
diff --git 
a/jena-base/src/main/java/org/apache/jena/atlas/io/InStreamASCII.java 
b/jena-base/src/main/java/org/apache/jena/atlas/io/InStreamASCII.java
new file mode 100644
index 0000000..049449c
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/io/InStreamASCII.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.io;
+
+import java.io.IOException ;
+import java.io.InputStream ;
+import java.io.Reader ;
+
+import org.apache.jena.atlas.AtlasException ;
+
+/** Fast and streaming.
+ */
+public final class InStreamASCII extends Reader implements CharStream
+{
+    private InputStreamBuffered input ;
+    private long count = 0 ;
+
+    public InStreamASCII(InputStream in)
+    {
+        if ( in instanceof InputStreamBuffered )
+        {
+            input = (InputStreamBuffered)in ;
+            return ;
+        }
+        input = new InputStreamBuffered(in) ;
+    }
+    
+    public InStreamASCII(InputStreamBuffered in) { input = in ; }
+
+    @Override
+    public boolean ready() throws IOException
+    {
+        return input.available() > 0 ;
+    }
+    
+    @Override
+    public void close() throws IOException
+    { input.close() ; }
+
+    @Override
+    public void closeStream()
+    { IO.close(input) ; }
+
+    @Override
+    public int read(char[] cbuf, int off, int len) throws IOException
+    {
+        for ( int i = off ; i < off+len ; i++ )
+        {
+            int x = read() ;
+            if ( x == -1 )
+            {
+                if ( i == off )
+                    return -1 ;
+                return (i-off) ;
+            }
+            if ( x > 128 )
+                throw new AtlasException("Illegal ASCII character : "+x) ;
+            cbuf[i] = (char)x ;
+        }
+        return len ; 
+    }
+
+    @Override
+    public int read() throws IOException
+    { return advance() ; }
+    
+    @Override
+    public int advance()
+    {
+        count++ ;
+        return input.advance() ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/io/InStreamUTF8.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/io/InStreamUTF8.java 
b/jena-base/src/main/java/org/apache/jena/atlas/io/InStreamUTF8.java
new file mode 100644
index 0000000..5903882
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/io/InStreamUTF8.java
@@ -0,0 +1,254 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.io;
+
+import java.io.ByteArrayInputStream ;
+import java.io.IOException ;
+import java.io.InputStream ;
+import java.io.Reader ;
+
+import org.apache.jena.atlas.AtlasException ;
+
+/** Fast and streaming UTF-8 */
+public final class InStreamUTF8 extends Reader implements CharStream
+{
+    // TODO Add line and col counts.
+    // See arq.utf8. 
+    // TODO Better ready()/available() in InputStreamBuffered
+    
+    // The standard Java way of doing this is via charset decoders.
+    // One small disadvantage is that bad UTF-8 does not get flagged as to
+    // the byte position of the error.
+    
+    // This class collects knowledge of how UTF-8 encoding works;
+    // the Java classes are usually slightly faster compared to using
+    // this class with an InputStreamBuffered but the difference is small.
+    // This class generated meaningful error messages (when line/col added).
+    
+    // The Java classes copy-convert a byte buffer into a char buffer.
+    // Sometimes, for example in a parser, this isn't a convenient model
+    // because the app is looking one character at a time and accumulating
+    // the chars until it sees the end of a token of arbitrary length
+    // or processes escape sequences.  
+    //
+    // The app might use a StringBuilder so the bytes get copied into
+    // a char buffer and out again.  Instead, this code assumes the
+    // app is in charge of that.
+    
+    // UTF-8 (UTF-16) is different from other character sets because 
+    // the relationship with Java's internal character representation is
+    // arithmetic, not a character mapping. 
+    
+    // Todo: chars > 16 bits -> surrogate pairs. 
+    
+    /*
+     * http://en.wikipedia.org/wiki/UTF-8
+     * http://tools.ietf.org/html/rfc3629
+     * http://www.ietf.org/rfc/rfc3629.txt
+     * 
+     * Unicode                                  Byte1       Byte2       Byte3  
     Byte4
+     * U+0000–U+007F    0 to 127                0xxxxxxx
+     * U+0080–U+07FF    128 to 2,047            110yyyxx    10xxxxxx 
+     * U+0800–U+FFFF    2,048 to 65,535         1110yyyy    10yyyyxx    
10xxxxxx
+     * U+10000–U+10FFFF 65,536 to 1,114,111     11110zzz    10zzyyyy    
10yyyyxx    10xxxxxx
+     * 
+     * Restricted cases (RFC 3629)
+     * 11110101-11110111    F5-F7   245-247     start of 4-byte sequence for 
codepoint above 10FFFF
+     * 11111000-11111011    F8-FB   248-251     start of 5-byte sequence
+     * 11111100-11111101    FC-FD   252-253     start of 6-byte sequence
+     * 
+     * Illegal:
+     * 11000000-11000001    C0-C1   192-193     Overlong encoding: start of a 
2-byte sequence, but code point <= 127
+     * 11111110-11111111    FE-FF   254-255     Invalid: not defined by 
original UTF-8 specification
+     */
+    
+    // There is some sort of stream decoder backing the Sun implementation 
+    // of CharsetDecoder (sun.io.StreamDecoder) but it's not on all platforms
+    // I want a known decoder specifically for UTF8
+    
+    private InputStreamBuffered input ;
+    //private long count = 0 ;
+
+    public InStreamUTF8(InputStream in)
+    {
+        if ( in instanceof InputStreamBuffered )
+        {
+            input = (InputStreamBuffered)in ;
+            return ;
+        }
+        input = new InputStreamBuffered(in) ;
+    }
+    
+    public InStreamUTF8(InputStreamBuffered in) { input = in ; }
+    
+
+    @Override
+    public boolean ready() throws IOException
+    {
+        return input.available() > 0 ;
+    }
+    
+    @Override
+    public void close() throws IOException
+    { input.close() ; }
+    
+    @Override
+    public void closeStream()
+    { IO.close(input) ; }
+
+    @Override
+    public int read(char[] cbuf, int off, int len) throws IOException
+    {
+        // Doing this on a block of bytes may be faster.
+        for ( int i = off ; i < off+len ; i++ )
+        {
+            int x = read() ;
+            if ( x == -1 )
+            {
+                if ( i == off )
+                    return -1 ;
+                return (i-off) ;
+            }
+            cbuf[i] = (char)x ;
+        }
+        return len ; 
+    }
+
+    @Override
+    public final int read() throws IOException
+    { 
+        int ch = advance(input) ;
+        //if ( ! Character.isDefined(ch) ) throw new 
AtlasException(String.format("Undefined codepoint: 0x%04X", ch)) ;
+        return ch ;
+    }
+    
+    
+    /** Next codepoint, given the first byte of any UTF-8 byte sequence is 
already known.
+     *  Not necessarily a valid char (this function can be used a straight 
UTF8 decoder
+     */
+    @Override
+    public final int advance()
+    { return advance(input) ; }
+    
+    /** Next codepoint */
+    public static final int advance(InputStreamBuffered input)
+    {
+        int x = input.advance() ;
+        if ( x == -1 ) return -1 ;
+        return advance(input, x) ;
+    }
+    
+    /** Next codepoint, given the first byte of any UTF-8 byte sequence is 
already known.
+     * Not necessarily a valid char (this function can be used a straight UTF8 
decoder
+     */
+    
+    public static final int advance(InputStreamBuffered input, int x)
+    {
+        //count++ ;
+        // Fastpath
+        if ( x == -1 || x <= 127 ) 
+        {
+            //count++ ;
+            return x ;
+        }
+
+        // 10 => extension byte
+        // 110..... => 2 bytes
+        if ( (x & 0xE0) == 0xC0 )
+        {
+            int ch = readMultiBytes(input, x & 0x1F, 2) ;
+            // count += 2 ;
+            return ch ;
+            
+        }
+        //  1110.... => 3 bytes : 16 bits : not outside 16bit chars 
+        if ( (x & 0xF0) == 0xE0 ) 
+        {
+            int ch = readMultiBytes(input, x & 0x0F, 3) ;
+            // count += 3 ;
+            //if ( ! Character.isDefined(ch) ) throw new 
AtlasException(String.format("Undefined codepoint: 0x%04X", ch)) ;
+            return ch ;
+        }
+
+        // Looking like 4 byte charcater.
+        int ch = -2 ;
+        // 11110zzz => 4 bytes.
+        if ( (x & 0xF8) == 0xF0 )
+        {
+             ch = readMultiBytes(input, x & 0x08, 4) ;
+             // Opsp - need two returns. Character.toChars(ch, chars, 0) ;
+             // count += 4 ;
+        }
+             
+        else 
+            IO.exception(new IOException("Illegal UTF-8: "+x)) ;
+
+        // This test will go off.  We're processing a 4 byte sequence but Java 
only supports 16 bit chars. 
+        if ( ch > Character.MAX_VALUE )
+            throw new AtlasException("Out of range character (must use a 
surrogate pair)") ;
+        if ( ! Character.isDefined(ch) ) throw new 
AtlasException(String.format("Undefined codepoint: 0x%04X", ch)) ;
+        return ch ;
+    }
+    
+    private static int readMultiBytes(InputStreamBuffered input, int start, 
int len) //throws IOException
+    {
+        //System.out.print(" -("+len+")") ; p(start) ;
+        
+        int x = start ;
+        for ( int i = 0 ; i < len-1 ; i++ )
+        {
+            int x2 = input.advance() ;
+            if ( x2 == -1 )
+                throw new AtlasException("Premature end to UTF-8 sequence at 
end of input") ;
+            
+            if ( (x2 & 0xC0) != 0x80 )
+                //throw new AtlasException("Illegal UTF-8 processing character 
"+count+": "+x2) ;
+                throw new AtlasException(String.format("Illegal UTF-8 
processing character: 0x%04X",x2)) ;
+            // 6 bits of x2
+            x = (x << 6) | (x2 & 0x3F); 
+        }
+        return x ;
+    }
+
+    private static void p(int ch)
+    {
+        System.out.printf(" %02X", ch) ;
+        if ( ch == -1 )
+            System.out.println();
+    }
+    
+    public static String decode(byte[] bytes)
+    {
+        try
+        {
+            char[] chars = new char[bytes.length] ;
+            InputStream in = new ByteArrayInputStream(bytes) ;
+            StringBuilder buff = new StringBuilder() ;
+            Reader r = new InStreamUTF8(in) ;
+            int len ;
+            len = r.read(chars) ;
+            IO.close(r) ;
+            return new String(chars, 0, len) ;
+        } catch (IOException ex)
+        {
+            IO.exception(ex) ;
+            return null ;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/io/IndentedLineBuffer.java
----------------------------------------------------------------------
diff --git 
a/jena-base/src/main/java/org/apache/jena/atlas/io/IndentedLineBuffer.java 
b/jena-base/src/main/java/org/apache/jena/atlas/io/IndentedLineBuffer.java
new file mode 100644
index 0000000..7c7b5f5
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/io/IndentedLineBuffer.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.io;
+
+import java.io.StringWriter ;
+
+/** IndentLineBuffer is a buffer that records an indent level 
+ *  and uses that to insert a prefix at each line.
+ *  It can also insert line numbers at the beginning of lines.
+ */
+
+public class IndentedLineBuffer extends IndentedWriter
+{
+    StringWriter sw ;
+    public IndentedLineBuffer() { this(false) ; }
+    
+    public IndentedLineBuffer(boolean withLineNumbers)
+    {
+        super(new StringWriter(), withLineNumbers) ;
+        sw = (StringWriter)super.out ;
+    }
+    
+    public StringBuffer getBuffer() { return sw.getBuffer(); }
+    
+    public String asString() { return sw.toString() ; }
+    @Override
+    public String toString() { return asString() ; }
+
+    // Names more usually used for a buffer.
+    public void append(String fmt, Object... args) { printf(fmt, args) ; }
+    public void append(char ch)  { print(ch) ;}
+    
+    public void clear() { sw.getBuffer().setLength(0) ; }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/io/IndentedWriter.java
----------------------------------------------------------------------
diff --git 
a/jena-base/src/main/java/org/apache/jena/atlas/io/IndentedWriter.java 
b/jena-base/src/main/java/org/apache/jena/atlas/io/IndentedWriter.java
new file mode 100644
index 0000000..51414f9
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/io/IndentedWriter.java
@@ -0,0 +1,366 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.io;
+import static java.lang.String.format ;
+
+import java.io.IOException ;
+import java.io.OutputStream ;
+import java.io.Writer ;
+
+import org.apache.jena.atlas.RuntimeIOException ;
+import org.apache.jena.atlas.lib.Closeable ;
+
+/** A writer that records what the current indentation level is, and
+ *  uses that to insert a prefix at each line. 
+ *  It can also insert line numbers at the beginning of lines. */
+
+public class IndentedWriter extends AWriterBase implements AWriter, Closeable
+{
+    /** Stdout wrapped in an IndentedWriter - no line numbers */
+    public static final IndentedWriter stdout = new IndentedWriter(System.out) 
;
+    /** Stderr wrapped in an IndentedWriter - no line numbers */
+    public static final IndentedWriter stderr = new IndentedWriter(System.err) 
;
+    
+    static {
+        stdout.setFlushOnNewline(true) ;
+        stderr.setFlushOnNewline(true) ;
+    }
+    // Note cases:if (!flatMode) 
+    // 1/ incIndent - decIndent with no output should not cause any padding
+    // 2/ newline() then no text, then finish should not cause a line number.
+    
+    protected Writer out = null ;
+    
+    protected static final int INDENT = 2 ;
+    protected int unitIndent = INDENT ;
+    protected int currentIndent = 0 ;
+    protected int column = 0 ;
+    protected int row = 1 ;
+    protected boolean lineNumbers = false ;
+    protected boolean startingNewLine = true ;
+    private char padChar = ' ' ;
+    private String endOfLineMarker = null ;     // Null mean none.
+    private String padString = null ;
+    
+    protected boolean flatMode = false ;
+    private boolean flushOnNewline = false ;
+    
+    private IndentedWriter() { this(System.out, false) ; }
+    
+    /** Construct a UTF8 IndentedWriter around an OutputStream */
+    public IndentedWriter(OutputStream outStream) { this(outStream, false) ; }
+    
+    /** Construct a UTF8 IndentedWriter around an OutputStream */
+    public IndentedWriter(OutputStream outStream, boolean withLineNumbers)
+    {
+        this(makeWriter(outStream), withLineNumbers) ;
+    }
+    
+    private static Writer makeWriter(OutputStream out)
+    {
+        // return BufferingWriter.create(out) ;
+        return IO.asBufferedUTF8(out) ;
+    }
+    
+    /** Using Writers directly is discouraged */
+    protected IndentedWriter(Writer writer) { this(writer, false) ; }
+    
+    /** Using Writers directly is discouraged */
+    protected IndentedWriter(Writer writer, boolean withLineNumbers)
+    {
+        out = writer ;
+        lineNumbers = withLineNumbers ;
+        startingNewLine = true ;
+    }
+
+    @Override
+    public void print(String str) 
+    {
+        if ( str == null )
+            str = "null" ;
+        if ( false )
+        {
+            // Don't check for embedded newlines.
+            write$(str) ;
+            return ;
+        }
+        for ( int i = 0 ; i < str.length() ; i++ )
+            printOneChar(str.charAt(i)) ;
+    }
+    
+    @Override
+    public void printf(String formatStr, Object... args)
+    {
+        print(format(formatStr, args)) ;
+    }
+    
+    @Override
+    public void print(char ch) { printOneChar(ch) ; }
+    
+    @Override
+    public void println(String str) { print(str) ; newline() ; }
+    public void println(char ch)  { print(ch) ; newline() ; }
+
+    @Override
+    public void println() { newline() ; }
+    
+    @Override
+    public void print(char[] cbuf)
+    {
+        for ( char aCbuf : cbuf )
+        {
+            printOneChar( aCbuf );
+        }
+    }
+
+    /** Print a string N times */
+    public void print(String s, int n)
+    {
+        for ( int i = 0 ; i < n ; i++ ) print(s) ;
+    }
+
+    /** Print a char N times */
+    public void print(char ch, int n)
+    {
+        lineStart() ;
+        for ( int i = 0 ; i < n ; i++ ) printOneChar(ch) ;
+    }
+
+    private char lastChar = '\0' ;
+    // Worker
+    private void printOneChar(char ch) 
+    {
+        // Turn \r\n into a single newline call.
+        // Assumes we don't get \r\r\n etc 
+        if ( ch == '\n' && lastChar == '\r' )
+        {
+            lastChar = ch ;
+            return ;
+        }
+        
+        lineStart() ; 
+        lastChar = ch ;
+        
+        // newline
+        if ( ch == '\n' || ch == '\r' )
+        { 
+            newline() ;
+            return ;
+        }
+        write$(ch) ;
+        column += 1 ;
+    }
+
+    private void write$(char ch) 
+    { try { out.write(ch) ; } catch (IOException ex) { throw new 
RuntimeIOException(ex) ; } }
+    
+    private void write$(String s) 
+    { try { out.write(s) ; } catch (IOException ex) { throw new 
RuntimeIOException(ex) ; } }
+    
+    public void newline()
+    {
+        lineStart() ; 
+
+        if ( endOfLineMarker != null )
+            print(endOfLineMarker) ;
+        if ( ! flatMode )
+            write$('\n') ;
+        startingNewLine = true ;
+        row++ ;
+        column = 0 ;
+        // Note that PrintWriters do not autoflush by default
+        // so if layered over a PrintWirter, need to flush that as well.  
+        if (flushOnNewline) flush() ;
+    }
+    
+    private boolean atStartOfLine() { return column <= currentIndent ; }
+
+    public void ensureStartOfLine()
+    {
+        if ( !atStartOfLine() )
+            newline() ;
+    }
+    
+    @Override
+    public void close() { try { out.close(); } catch (IOException ex) {} }
+    
+    @Override
+    public void flush() { try { out.flush(); } catch (IOException ex) {} }
+    
+    /** Pad to the indent (if we are before it) */
+    public void pad()
+    {
+        if ( startingNewLine && currentIndent > 0 )
+            lineStart() ;
+        padInt() ;
+    }
+    
+    /** Pad to a given number of columns EXCLUDING the indent.
+     * 
+     * @param col Column number (first column is 1).
+     */
+    public void pad(int col) { pad(col, false) ; }
+    
+    /** Pad to a given number of columns maybe including the indent.
+     * 
+     * @param col Column number (first column is 1).
+     * @param absoluteColumn Whether to include the indent
+     */
+    public void pad(int col, boolean absoluteColumn )
+    {
+        // Make absolute
+        if ( !absoluteColumn )
+            col = col+currentIndent ;
+        int spaces = col - column  ;
+        for ( int i = 0 ; i < spaces ; i++ )
+        {
+            write$(' ') ;        // Always a space.
+            column++ ;
+        }
+    }
+    
+    
+    private void padInt() 
+    {
+        if ( padString == null )
+        {
+            for ( int i = column ; i < currentIndent ; i++ )
+            {
+                write$(padChar) ;
+                column++ ;
+            }
+        }
+        else
+        {
+            for ( int i = column ; i < currentIndent ; i += padString.length() 
)
+            {
+                write$(padString) ;
+                column += padString.length() ;
+            }
+        }
+    }
+    
+    /** Get row/line (counts from 1) */
+    public int getRow() { return row ; }
+    /** Get the absolute column.
+     *  This is the location where the next charcter on the line will be 
printed.
+     *  The IndentedWriter may not yet have padded to this place.   
+     */
+    public int getCol() {
+        if ( currentIndent > column )
+            return currentIndent ;
+        return column ;
+    }
+    
+    /** Get indent from the left hand edge */ 
+    public int getAbsoluteIndent()       { return currentIndent ; }
+    /** Set indent from the left hand edge */ 
+    public void setAbsoluteIndent(int x) { currentIndent = x ; }
+
+    /** Position past current indent */ 
+    public int getCurrentOffset()
+    { 
+        int x = getCol() - getAbsoluteIndent() ;
+        if ( x >= 0 )
+            return x ;
+        // At start of line somehow.
+        return 0 ;
+    }
+    
+    public boolean hasLineNumbers()
+    {
+        return lineNumbers ;
+    }
+
+    public void setLineNumbers(boolean lineNumbers)
+    {
+        this.lineNumbers = lineNumbers ;
+    }
+    
+    public String getEndOfLineMarker()              { return endOfLineMarker ; 
}
+    
+    /** Set the marker included at end of line - set to null for "none".  
Usually used for debugging. */ 
+    public void setEndOfLineMarker(String marker)   { endOfLineMarker = marker 
; }
+    
+    /** Flat mode - print without NL, for a more compact representation - 
depends on caller */  
+    public boolean inFlatMode()                 { return flatMode ; }
+    public void setFlatMode(boolean flatMode)   { this.flatMode = flatMode ; }
+    
+    /** Flush on newline **/
+    public boolean getFlushOnNewline()      { return flushOnNewline; }
+    public void setFlushOnNewline(boolean flushOnNewline) { 
this.flushOnNewline = flushOnNewline; } 
+    
+    public char getPadChar()                { return padChar ; }
+    public void setPadChar(char ch)         { this.padChar  = ch ; }
+    public String getPadString()            { return padString ; }
+    public void setPadString(String str)    { this.padString = str ; 
unitIndent = str.length(); }
+
+    public void incIndent()      { incIndent(unitIndent) ; }
+    public void incIndent(int x)
+    {
+        currentIndent += x ;
+    }
+
+    public void decIndent() { decIndent(unitIndent) ; }
+    public void decIndent(int x) 
+    {
+        currentIndent -= x ;
+    }
+    
+    public void setUnitIndent(int x)    { unitIndent = x ; }
+    public int  getUnitIndent()         { return unitIndent ; }
+    public boolean atLineStart()        { return startingNewLine ; }
+    
+    private void lineStart()
+    {
+        if ( flatMode )
+        {
+            if ( startingNewLine && row > 1 )
+                // Space between each line.
+                write$(' ') ;
+            startingNewLine = false ;
+            return ;
+        }
+        
+        // Need to do its just before we append anything, not after a NL,
+        // so that a final blank does not cause a line number  
+        if ( startingNewLine )
+            insertLineNumber() ;
+        padInt() ;
+        startingNewLine = false ;
+    }
+    
+    private static int WidthLineNumber = 3 ;
+    
+    private void insertLineNumber()
+    {
+        if ( ! lineNumbers )
+            return ;
+        String s = Integer.toString(row) ;
+        for ( int i = 0 ; i < WidthLineNumber-s.length() ; i++ )
+            write$(' ') ;
+        write$(s) ;
+        write$(' ') ;
+    }
+    
+    @Override
+    public String toString() {
+        return String.format("Indent = %d : [%d, %d]", currentIndent, row, 
column) ;  
+    }
+}

Reply via email to