/**
* Copyright 2012 Perforce Software Inc., All Rights Reserved.
*/
package com.perforce.p4java.charset;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import com.perforce.p4java.PropertyDefs;
/**
* Charset implementation which performs P4ShiftJIS encoding. P4-ShiftJIS
* encoding uses the MS932 (Microsoft code page 932) encoding, a superset of
* Shift-JIS. Additionally, P4-ShiftJIS applies Perforce specific updates to
* characters
*/
public class PerforceShiftJISCharset extends Charset {
// Environment variable for enabling Perforce specific updates
public static final boolean UNICODE_MAPPING = (System.getProperty(PropertyDefs.UNICODE_MAPPING_SHORT_FORM,
System.getProperty(PropertyDefs.UNICODE_MAPPING, null))) == null ? false : true;
// The name of the real charset encoding delegate.
// Microsoft code page 932 (windows-31j, csWindows31J, windows-932, MS932)
private static final String CHARSET_NAME = "MS932";
// Handle to the real charset for transcoding between characters and bytes.
Charset charset;
/**
* Constructor for the P4ShiftJIS charset. Call the superclass constructor
* to pass along the name and aliases.
*/
protected PerforceShiftJISCharset(String canonical, String[] aliases) {
super(canonical, aliases);
charset = Charset.forName(CHARSET_NAME);
}
// ----------------------------------------------------------
/**
* Called by users of this Charset to obtain an encoder.
*/
public CharsetEncoder newEncoder() {
return new Encoder(this, charset.newEncoder());
}
/**
* Called by users of this Charset to obtain a decoder.
*/
public CharsetDecoder newDecoder() {
return new Decoder(this, charset.newDecoder());
}
/**
* Tells whether or not this charset contains the given charset.
*/
public boolean contains(Charset cs) {
return this.getClass().isInstance(cs);
}
/**
* Apply Perforce specific updates.
*/
private void update(CharBuffer cb) {
if (UNICODE_MAPPING) {
for (int pos = cb.position(); pos < cb.limit(); pos++) {
char c = cb.get(pos);
switch (c) {
case '\\':
cb.put(pos, '\u00A5');
break;
case '\u007E':
cb.put(pos, '\u203E');
break;
default:
}
}
}
}
/**
* The encoder implementation for the P4ShiftJIS Charset.
*/
private class Encoder extends CharsetEncoder {
private CharsetEncoder encoder;
/**
* Call the superclass constructor with the Charset object and the
* encodings sizes from the encoder.
*/
Encoder(Charset cs, CharsetEncoder encoder) {
super(cs, encoder.averageBytesPerChar(), encoder.maxBytesPerChar());
this.encoder = encoder;
}
/**
* Implementation of the encoding loop. Apply Perforce specific updates,
* then reset the encoder and encode the characters to bytes.
*/
protected CoderResult encodeLoop(CharBuffer cb, ByteBuffer bb) {
CharBuffer tmpcb = CharBuffer.allocate(cb.remaining());
while (cb.hasRemaining()) {
tmpcb.put(cb.get());
}
tmpcb.rewind();
update(tmpcb);
encoder.reset();
CoderResult cr = encoder.encode(tmpcb, bb, true);
cb.position(cb.position() - tmpcb.remaining());
return (cr);
}
}
/**
* The decoder implementation for the P4ShiftJIS Charset.
*/
private class Decoder extends CharsetDecoder {
private CharsetDecoder decoder;
/**
* Call the superclass constructor with the Charset object and pass
* along the chars/byte values from the decoder.
*/
Decoder(Charset cs, CharsetDecoder decoder) {
super(cs, decoder.averageCharsPerByte(), decoder.maxCharsPerByte());
this.decoder = decoder;
}
/**
* Implementation of the decoding loop. Reset the decoder and decode the
* bytes into characters, then apply Perforce specific updates.
*/
protected CoderResult decodeLoop(ByteBuffer bb, CharBuffer cb) {
decoder.reset();
CoderResult result = decoder.decode(bb, cb, true);
update(cb);
return (result);
}
}
}