SMACK-361 Changed default for filename encoding to Base 32 (which should work on all file systems) and added a Base 64 filename and url safe implementation of the StringEncoder.

git-svn-id: http://svn.igniterealtime.org/svn/repos/smack/branches/smack_3_3_0@13619 b35dd754-fafc-0310-a699-88a17e54d16e
This commit is contained in:
rcollier 2013-04-20 21:55:27 +00:00
parent a3faa41696
commit 13d87e3d40
5 changed files with 67 additions and 100 deletions

View File

@ -7,66 +7,9 @@
package org.jivesoftware.smack.util;
/**
* <p>Encodes and decodes to and from Base64 notation.</p>
* <p>Homepage: <a href="http://iharder.net/base64">http://iharder.net/base64</a>.</p>
* <p>Encodes and decodes to and from Base64 notation.</p>
* This code was obtained from <a href="http://iharder.net/base64">http://iharder.net/base64</a></p>
*
* <p>
* Change Log:
* </p>
* <ul>
* <li>v2.2.1 - Fixed bug using URL_SAFE and ORDERED encodings. Fixed bug
* when using very small files (~< 40 bytes).</li>
* <li>v2.2 - Added some helper methods for encoding/decoding directly from
* one file to the next. Also added a main() method to support command line
* encoding/decoding from one file to the next. Also added these Base64 dialects:
* <ol>
* <li>The default is RFC3548 format.</li>
* <li>Calling Base64.setFormat(Base64.BASE64_FORMAT.URLSAFE_FORMAT) generates
* URL and file name friendly format as described in Section 4 of RFC3548.
* http://www.faqs.org/rfcs/rfc3548.html</li>
* <li>Calling Base64.setFormat(Base64.BASE64_FORMAT.ORDERED_FORMAT) generates
* URL and file name friendly format that preserves lexical ordering as described
* in http://www.faqs.org/qa/rfcc-1940.html</li>
* </ol>
* Special thanks to Jim Kellerman at <a href="http://www.powerset.com/">http://www.powerset.com/</a>
* for contributing the new Base64 dialects.
* </li>
*
* <li>v2.1 - Cleaned up javadoc comments and unused variables and methods. Added
* some convenience methods for reading and writing to and from files.</li>
* <li>v2.0.2 - Now specifies UTF-8 encoding in places where the code fails on systems
* with other encodings (like EBCDIC).</li>
* <li>v2.0.1 - Fixed an error when decoding a single byte, that is, when the
* encoded data was a single byte.</li>
* <li>v2.0 - I got rid of methods that used booleans to set options.
* Now everything is more consolidated and cleaner. The code now detects
* when data that's being decoded is gzip-compressed and will decompress it
* automatically. Generally things are cleaner. You'll probably have to
* change some method calls that you were making to support the new
* options format (<tt>int</tt>s that you "OR" together).</li>
* <li>v1.5.1 - Fixed bug when decompressing and decoding to a
* byte[] using <tt>decode( String s, boolean gzipCompressed )</tt>.
* Added the ability to "suspend" encoding in the Output Stream so
* you can turn on and off the encoding if you need to embed base64
* data in an otherwise "normal" stream (like an XML file).</li>
* <li>v1.5 - Output stream pases on flush() command but doesn't do anything itself.
* This helps when using GZIP streams.
* Added the ability to GZip-compress objects before encoding them.</li>
* <li>v1.4 - Added helper methods to read/write files.</li>
* <li>v1.3.6 - Fixed OutputStream.flush() so that 'position' is reset.</li>
* <li>v1.3.5 - Added flag to turn on and off line breaks. Fixed bug in input stream
* where last buffer being read, if not completely full, was not returned.</li>
* <li>v1.3.4 - Fixed when "improperly padded stream" error was thrown at the wrong time.</li>
* <li>v1.3.3 - Fixed I/O streams which were totally messed up.</li>
* </ul>
*
* <p>
* I am placing this code in the Public Domain. Do with it as you will.
* This software comes with no guarantees or warranties but with
* plenty of well-wishing instead!
* Please visit <a href="http://iharder.net/base64">http://iharder.net/base64</a>
* periodically to check for updates or to contribute improvements.
* </p>
*
* @author Robert Harder
* @author rob@iharder.net
@ -368,33 +311,6 @@ public class Base64
/** Defeats instantiation. */
private Base64(){}
/**
* Encodes or decodes two files from the command line;
* <strong>feel free to delete this method (in fact you probably should)
* if you're embedding this code into a larger program.</strong>
*/
public final static void main( String[] args )
{
if( args.length < 3 ){
usage("Not enough arguments.");
} // end if: args.length < 3
else {
String flag = args[0];
String infile = args[1];
String outfile = args[2];
if( flag.equals( "-e" ) ){
Base64.encodeFileToFile( infile, outfile );
} // end if: encode
else if( flag.equals( "-d" ) ) {
Base64.decodeFileToFile( infile, outfile );
} // end else if: decode
else {
usage( "Unknown flag: " + flag );
} // end else
} // end else
} // end main
/**
* Prints command line usage.
*

View File

@ -16,6 +16,7 @@ package org.jivesoftware.smack.util;
/**
* A Base 64 encoding implementation.
* @author Florian Schmaus
*/
public class Base64Encoder implements StringEncoder {

View File

@ -0,0 +1,48 @@
/**
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smack.util;
/**
* A Base 64 encoding implementation that generates filename and Url safe encodings.
*
* <p>
* Note: This does NOT produce standard Base 64 encodings, but a variant as defined in
* Section 4 of RFC3548:
* <a href="http://www.faqs.org/rfcs/rfc3548.html">http://www.faqs.org/rfcs/rfc3548.html</a>.
*
* @author Robin Collier
*/
public class Base64FileUrlEncoder implements StringEncoder {
private static Base64FileUrlEncoder instance = new Base64FileUrlEncoder();
private Base64FileUrlEncoder() {
// Use getInstance()
}
public static Base64FileUrlEncoder getInstance() {
return instance;
}
public String encode(String s) {
return Base64.encodeBytes(s.getBytes(), Base64.URL_SAFE);
}
public String decode(String s) {
return new String(Base64.decode(s, Base64.URL_SAFE));
}
}

View File

@ -27,6 +27,7 @@ import java.io.StringReader;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.provider.IQProvider;
import org.jivesoftware.smack.util.Base32Encoder;
import org.jivesoftware.smack.util.Base64Encoder;
import org.jivesoftware.smack.util.StringEncoder;
import org.jivesoftware.smackx.entitycaps.EntityCapsManager;
@ -47,19 +48,20 @@ import org.xmlpull.v1.XmlPullParserException;
public class SimpleDirectoryPersistentCache implements EntityCapsPersistentCache {
private File cacheDir;
private StringEncoder stringEncoder;
private StringEncoder filenameEncoder;
/**
* Creates a new SimpleDirectoryPersistentCache Object. Make sure that the
* cacheDir exists and that it's an directory.
*
* If your cacheDir is case insensitive then make sure to set the
* StringEncoder to Base32.
* <p>
* Default filename encoder {@link Base32Encoder}, as this will work on all
* filesystems, both case sensitive and case insensitive. It does however
* produce longer filenames.
*
* @param cacheDir
*/
public SimpleDirectoryPersistentCache(File cacheDir) {
this(cacheDir, Base64Encoder.getInstance());
this(cacheDir, Base32Encoder.getInstance());
}
/**
@ -67,26 +69,25 @@ public class SimpleDirectoryPersistentCache implements EntityCapsPersistentCache
* cacheDir exists and that it's an directory.
*
* If your cacheDir is case insensitive then make sure to set the
* StringEncoder to Base32.
* StringEncoder to {@link Base32Encoder} (which is the default).
*
* @param cacheDir
* @param stringEncoder
* @param cacheDir The directory where the cache will be stored.
* @param filenameEncoder Encodes the node string into a filename.
*/
public SimpleDirectoryPersistentCache(File cacheDir, StringEncoder stringEncoder) {
public SimpleDirectoryPersistentCache(File cacheDir, StringEncoder filenameEncoder) {
if (!cacheDir.exists())
throw new IllegalStateException("Cache directory \"" + cacheDir + "\" does not exist");
if (!cacheDir.isDirectory())
throw new IllegalStateException("Cache directory \"" + cacheDir + "\" is not a directory");
this.cacheDir = cacheDir;
this.stringEncoder = stringEncoder;
this.filenameEncoder = filenameEncoder;
}
@Override
public void addDiscoverInfoByNodePersistent(String node, DiscoverInfo info) {
String filename = stringEncoder.encode(node);
String filename = filenameEncoder.encode(node);
File nodeFile = new File(cacheDir, filename);
try {
if (nodeFile.createNewFile())
writeInfoToFile(nodeFile, info);
@ -99,7 +100,7 @@ public class SimpleDirectoryPersistentCache implements EntityCapsPersistentCache
public void replay() throws IOException {
File[] files = cacheDir.listFiles();
for (File f : files) {
String node = stringEncoder.decode(f.getName());
String node = filenameEncoder.decode(f.getName());
DiscoverInfo info = restoreInfoFromFile(f);
if (info == null)
continue;

View File

@ -10,6 +10,7 @@ import java.util.LinkedList;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.util.Base32Encoder;
import org.jivesoftware.smack.util.Base64Encoder;
import org.jivesoftware.smack.util.Base64FileUrlEncoder;
import org.jivesoftware.smack.util.StringEncoder;
import org.jivesoftware.smackx.FormField;
import org.jivesoftware.smackx.entitycaps.EntityCapsManager;
@ -37,7 +38,7 @@ public class EntityCapsManagerTest {
@Test
public void testSimpleDirectoryCacheBase64() throws IOException {
EntityCapsManager.persistentCache = null;
testSimpleDirectoryCache(Base64Encoder.getInstance());
testSimpleDirectoryCache(Base64FileUrlEncoder.getInstance());
}
@Test