Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   package org.jruby.util.io;
   
   import org.jcodings.Encoding;
  import org.jruby.Ruby;
  import org.jruby.RubyIO;
  
  public class EncodingUtils {    
      public static final int ECONV_ERROR_HANDLER_MASK               = 0x000000ff;
  
      public static final int ECONV_INVALID_MASK                     = 0x0000000f;
      public static final int ECONV_INVALID_REPLACE                  = 0x00000002;
  
      public static final int ECONV_UNDEF_MASK                       = 0x000000f0;
      public static final int ECONV_UNDEF_REPLACE                    = 0x00000020;
      public static final int ECONV_UNDEF_HEX_CHARREF                = 0x00000030;
  
      public static final int ECONV_DECORATOR_MASK                   = 0x0000ff00;
      public static final int ECONV_NEWLINE_DECORATOR_MASK           = 0x00003f00;
      public static final int ECONV_NEWLINE_DECORATOR_READ_MASK      = 0x00000f00;
      public static final int ECONV_NEWLINE_DECORATOR_WRITE_MASK     = 0x00003000;
  
      public static final int ECONV_UNIVERSAL_NEWLINE_DECORATOR      = 0x00000100;
      public static final int ECONV_CRLF_NEWLINE_DECORATOR           = 0x00001000;
      public static final int ECONV_CR_NEWLINE_DECORATOR             = 0x00002000;
      public static final int ECONV_XML_TEXT_DECORATOR               = 0x00004000;
      public static final int ECONV_XML_ATTR_CONTENT_DECORATOR       = 0x00008000;
  
      public static final int ECONV_STATEFUL_DECORATOR_MASK          = 0x00f00000;
      public static final int ECONV_XML_ATTR_QUOTE_DECORATOR         = 0x00100000;
      
      public static final int ECONV_PARTIAL_INPUT                    = 0x00010000;
      public static final int ECONV_AFTER_OUTPUT                     = 0x00020000;
      
      public static final int ECONV_DEFAULT_NEWLINE_DECORATOR = . ?  : 0;
      public static final int DEFAULT_TEXTMODE = . ? . : 0;
      public static final int TEXTMODE_NEWLINE_DECORATOR_ON_WRITE = . ?  : -1;
      
      private static final byte[] NULL_BYTE_ARRAY = new byte[0];
  
      // rb_to_encoding
      public static Encoding rbToEncoding(ThreadContext contextIRubyObject enc) {
          if (enc instanceof RubyEncodingreturn ((RubyEncodingenc).getEncoding();
          
          return toEncoding(contextenc);
      }
      
      // to_encoding
      public static Encoding toEncoding(ThreadContext contextIRubyObject enc) {
          RubyString encStr = enc.convertToString();
          if (!encStr.getEncoding().isAsciiCompatible()) {
              throw context.runtime.newArgumentError("invalid name encoding (non ASCII)");
          }
          Encoding idx = context.runtime.getEncodingService().getEncodingFromObject(enc);
          // check for missing encoding is in getEncodingFromObject
          return idx;
      }
      
      public static IRubyObject[] openArgsToArgs(Ruby runtimeIRubyObject firstElementRubyHash options) {
          IRubyObject value = hashARef(runtimeoptions"open_args");
          
          if (value.isNil()) return new IRubyObject[] { firstElementoptions };
          
          RubyArray array = value.convertToArray();
          
          IRubyObject[] openArgs = new IRubyObject[array.size()];
          value.convertToArray().toArray(openArgs);
          IRubyObject[] args = new IRubyObject[openArgs.length + 1];
          
          args[0] = firstElement;
          
          System.arraycopy(openArgs, 0, args, 1, openArgs.length);
          
         return args;
     }
 
     // FIXME: This could be smarter amount determining whether optionsArg is a RubyHash and !null (invariant)
     // mri: extract_binmode
     public static void extractBinmode(Ruby runtimeIRubyObject optionsArgint[] fmode_p) {
         int fmodeMask = 0;
         
         IRubyObject v = hashARef(runtimeoptionsArg"textmode");
         if (!v.isNil() && v.isTrue()) fmodeMask |= .;
         
         v = hashARef(runtimeoptionsArg"binmode");
         if (!v.isNil() && v.isTrue()) fmodeMask |= .;
 
         if ((fmodeMask & .) != 0 && (fmodeMask & .) != 0) {
             throw runtime.newArgumentError("both textmode and binmode specified");
         }
         
         fmode_p[0] |= fmodeMask;
     }
     
     private static IRubyObject hashARef(Ruby runtimeIRubyObject hashString symbol) {
         if (hash == null || !(hash instanceof RubyHash)) return runtime.getNil();
         
         IRubyObject value = ((RubyHashhash).fastARef(runtime.newSymbol(symbol));
         
         return value == null ? runtime.getNil() : value;
     }
     
     public static Encoding ascii8bitEncoding(Ruby runtime) {
         return runtime.getEncodingService().getAscii8bitEncoding();   
     }
     
     public static final int PERM = 0;
     public static final int VMODE = 1;
     
     public static final int MODE_BTMODE(int fmodeint aint bint c) {
         return (fmode & .) != 0 ? b :
                 (fmode & .) != 0 ? c : a;
     }
     
     public static int SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(Encoding enc2int ecflags) {
         if (enc2 != null && (ecflags & ) != 0) {
             return ecflags | ;
         }
         return ecflags;
     }
     
     /*
      * This is a wacky method which is a very near port from MRI.  pm passes in 
      * a permissions value and a mode value.  As a side-effect mode will get set
      * if this found any 'mode'-like stuff so the caller can know whether mode 
      * has been handled yet.   The same story for permission value.  If it has
      * not been set then we know it needs to default permissions from the caller.
      */
     // mri: rb_io_extract_modeenc
     public static void extractModeEncoding(ThreadContext context
             IOEncodable ioEncodableIRubyObject[] vmodeAndVperm_pIRubyObject optionsint[] oflags_pint[] fmode_p) {
         IRubyObject vmode;
         int ecflags;
         IRubyObject[] ecopts_p = {context.nil};
         boolean hasEnc = falsehasVmode = false;
         IRubyObject intmode;
         
         vmode = vmodeAndVperm_p[];
         
         // Give default encodings
         ioExtIntToEncs(contextioEncodablenullnull, 0);
 
         vmode_handle: do {
             if (vmodeAndVperm_p[] == null || vmodeAndVperm_p[].isNil()) {
                 fmode_p[0] = .;
                 oflags_p[0] = .;
             } else {
                 intmode = TypeConverter.checkIntegerType(context.runtimevmodeAndVperm_p[], "to_int");
 
                 if (!intmode.isNil()) {
                     vmodeAndVperm_p[] = intmode;
                     oflags_p[0] = RubyNumeric.num2int(intmode);
                     fmode_p[0] = ModeFlags.getOpenFileFlagsFor(oflags_p[0]);
                 } else {
                     String p = vmodeAndVperm_p[].convertToString().asJavaString();
                     int colonSplit = p.indexOf(":");
                     String mode = colonSplit == -1 ? p : p.substring(0, colonSplit);
                     try {
                         fmode_p[0] = OpenFile.getFModeFromString(mode);
                         oflags_p[0] = OpenFile.getModeFlagsAsIntFrom(fmode_p[0]);
                     } catch (InvalidValueException e) {
                         throw context.runtime.newArgumentError("illegal access mode " + vmodeAndVperm_p[]);
                     }
 
                     if (colonSplit != -1) {
                         hasEnc = true;
                         parseModeEncoding(contextioEncodablep.substring(colonSplit + 1), fmode_p);
                     } else {
                         Encoding e = (fmode_p[0] & .) != 0 ? ascii8bitEncoding(context.runtime) : null;
                         ioExtIntToEncs(contextioEncodableenullfmode_p[0]);
                     }
                 }
             }
 
             if (options == null || options.isNil()) {
                 ecflags = (fmode_p[0] & .) != 0
                         ? MODE_BTMODE(fmode_p[0], , 0, )
                         : 0;
                 if ( != -1) {
                     ecflags |= (fmode_p[0] & .) != 0
                             ? MODE_BTMODE(fmode_p[0], , 0, )
                             : 0;
                 }
                 ecflags = SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(ioEncodable.getEnc2(), ecflags);
                 ecopts_p[0] = context.nil;
             } else {
                 extractBinmode(context.runtimeoptionsfmode_p);
                 // Differs from MRI but we open with ModeFlags
                 if ((fmode_p[0] & .) != 0) {
                     oflags_p[0] |= .;
                 
                     if (!hasEnc) {
                         ioExtIntToEncs(contextioEncodableascii8bitEncoding(context.runtime), nullfmode_p[0]);
                     }
                 } else if ( != 0 && (vmode == null || vmode.isNil())) {
                     fmode_p[0] |= ;
                 }
 
                 if (!hasVmode) {
                     IRubyObject v = hashARef(context.runtimeoptions"mode");
 
                     if (!v.isNil()) {
                         if (vmodeAndVperm_p[] != null && !vmodeAndVperm_p[].isNil()) {
                             throw context.runtime.newArgumentError("mode specified twice");
                         }
                         hasVmode = true;
                         vmodeAndVperm_p[] = v;
 
                         continue vmode_handle;
                     }
                 }
                 IRubyObject v = hashARef(context.runtimeoptions"perm");
                 if (!v.isNil()) {
                     if (vmodeAndVperm_p[] != null) {
                         if (!vmodeAndVperm_p[].isNil()) throw context.runtime.newArgumentError("perm specified twice");
 
                         vmodeAndVperm_p[] = v;
                     }
                 }
                 
                 ecflags = (fmode_p[0] & .) != 0 ?
                         MODE_BTMODE(fmode_p[0], , 0, ) : 0;
                 if ( != -1) {
                     ecflags |= (fmode_p[0] & .) != 0 ?
                             MODE_BTMODE(fmode_p[0], , 0, ) : 0;
                 }
 
                 if (ioExtractEncodingOption(contextioEncodableoptionsfmode_p)) {
                     if (hasEncthrow context.runtime.newArgumentError("encoding specified twice");
                 }
                 
                 ecflags = SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(ioEncodable.getEnc2(), ecflags);
                 ecflags = econvPrepareOptions(contextoptionsecopts_pecflags);
             }
             
             EncodingUtils.validateEncodingBinmode(contextfmode_pecflagsioEncodable);
             
             ioEncodable.setEcflags(ecflags);
             ioEncodable.setEcopts(ecopts_p[0]);
             return;
         } while (true);
     }
 
     // mri: rb_io_extract_encoding_option
     public static boolean ioExtractEncodingOption(ThreadContext contextIOEncodable ioEncodableIRubyObject optionsint[] fmode_p) {
         Ruby runtime = context.runtime;
         
         IRubyObject encoding = context.nil;
         IRubyObject extenc = null;
         IRubyObject intenc = null;
         IRubyObject tmp;
         boolean extracted = false;
         Encoding extencoding = null;
         Encoding intencoding = null;
         
         if (options != null || !options.isNil()) {
             RubyHash opts = (RubyHashoptions;
 
             IRubyObject encodingOpt = opts.op_aref(contextruntime.newSymbol("encoding"));
             if (!encodingOpt.isNil()) encoding = encodingOpt;
             IRubyObject externalOpt = opts.op_aref(contextruntime.newSymbol("external_encoding"));
             if (!externalOpt.isNil()) extenc = externalOpt;
             IRubyObject internalOpt = opts.op_aref(contextruntime.newSymbol("internal_encoding"));
             if (!internalOpt.isNil()) intenc = internalOpt;
         }
         
         if ((extenc != null || intenc != null) && !encoding.isNil()) {
             if (runtime.isVerbose()) {
                     runtime.getWarnings().warn("Ignoring encoding parameter '" + encoding + "': " + 
                             (extenc == null ? "internal" : "external") + "_encoding is used");
             }
             encoding = context.nil;
         }
         
         if (extenc != null && !extenc.isNil()) {
             extencoding = rbToEncoding(contextextenc);
         }
 
         if (intenc != null) {
             if (intenc.isNil()) {
                 intencoding = null;
             } else if (!(tmp = intenc.checkStringType19()).isNil()) {
                 String p = tmp.toString();
                 if (p.equals("-")) {
                     intencoding = null;
                 } else {
                     intencoding = rbToEncoding(contextintenc);
                 }
             } else {
                 intencoding = rbToEncoding(contextintenc);
             }
             if (extencoding == intencoding) {
                 intencoding = null;
             }
         }
         
         if (!encoding.isNil()) {
             extracted = true;
             
             if (!(tmp = encoding.checkStringType19()).isNil()) {
                 parseModeEncoding(contextioEncodabletmp.asJavaString(), fmode_p);
             } else {
                 ioExtIntToEncs(contextioEncodablerbToEncoding(contextencoding), null, 0);
             }
         } else if (extenc != null || intenc != null) {
             extracted = true;
             ioExtIntToEncs(contextioEncodableextencodingintencoding, 0);
         }
         
         return extracted;
     }
     
     // mri: rb_io_ext_int_to_encs
     public static void ioExtIntToEncs(ThreadContext contextIOEncodable encodableEncoding externalEncoding internalint fmode) {
         boolean defaultExternal = false;
         
         if (external == null) {
             external = context.runtime.getDefaultExternalEncoding();
             defaultExternal = true;
         }
         
         if (external == ascii8bitEncoding(context.runtime)) {
             internal = null;
         } else if (internal == null) {
             internal = context.runtime.getDefaultInternalEncoding();
         }
         
         if (internal == null ||
                 ((fmode & .) == 0) && internal == external) {
             encodable.setEnc((defaultExternal && internal != external) ? null : external);
             encodable.setEnc2(null);
         } else {
             encodable.setEnc(internal);
             encodable.setEnc2(external);
         }
     }    
 
     // mri: parse_mode_enc
     public static void parseModeEncoding(ThreadContext contextIOEncodable ioEncodableString optionint[] fmode_p) {
         Ruby runtime = context.runtime;
         EncodingService service = runtime.getEncodingService();
         Encoding idxidx2 = null;
         Encoding intEncextEnc;
         if (fmode_p == nullfmode_p = new int[]{0};
         String estr;
 
         String[] encs = option.split(":", 2);
 
         if (encs.length == 2) {
             estr = encs[0];
             if (estr.toLowerCase().startsWith("bom|utf-")) {
                 fmode_p[0] |= .;
                 ioEncodable.setBOM(true);
                 estr = estr.substring(4);
             }
             idx = context.runtime.getEncodingService().getEncodingFromString(estr);
         } else {
             estr = option;
             if (estr.toLowerCase().startsWith("bom|utf-")) {
                 fmode_p[0] |= .;
                 ioEncodable.setBOM(true);
                 estr = estr.substring(4);
             }
             idx = context.runtime.getEncodingService().getEncodingFromString(estr);
         }
 
         extEnc = idx;
         
         intEnc = null;
         if (encs.length == 2) {
             if (encs[1].equals("-")) {
                 intEnc = null;
             } else {
                 idx2 = context.runtime.getEncodingService().getEncodingFromString(encs[1]);
                 if (idx2 == idx) {
                     context.runtime.getWarnings().warn("ignoring internal encoding " + idx2 + ": it is identical to external encoding " + idx);
                     intEnc = null;
                 } else {
                     intEnc = idx2;
                 }
             }
         }
 
         ioExtIntToEncs(contextioEncodableextEncintEncfmode_p[0]);
     }
     
     // rb_econv_prepare_opts
     public static int econvPrepareOpts(ThreadContext contextIRubyObject opthashIRubyObject[] opts) {
         return econvPrepareOptions(contextopthashopts, 0);
     }
     
     // rb_econv_prepare_options
     public static int econvPrepareOptions(ThreadContext contextIRubyObject opthashIRubyObject[] optsint ecflags) {
         IRubyObject newhash = context.nil;
         IRubyObject v;
         
         if (opthash.isNil()) {
             opts[0] = context.nil;
             return ecflags;
         }
         ecflags = econvOpts(contextopthashecflags);
         
         v = ((RubyHash)opthash).op_aref(contextcontext.runtime.newSymbol("replace"));
         if (!v.isNil()) {
             RubyString v_str = v.convertToString();
             if (v_str.scanForCodeRange() == .) {
                 throw context.runtime.newArgumentError("replacement string is broken: " + v_str);
             }
             v = v_str.freeze(context);
             newhash = RubyHash.newHash(context.runtime);
             ((RubyHash)newhash).op_aset(contextcontext.runtime.newSymbol("replace"), v);
         }
         
         v = ((RubyHash)opthash).op_aref(contextcontext.runtime.newSymbol("fallback"));
         if (!v.isNil()) {
             IRubyObject h = TypeConverter.checkHashType(context.runtimev);
             boolean condition;
             if (h.isNil()) {
                 condition = (h instanceof RubyProc || h instanceof RubyMethod || h.respondsTo("[]"));
             } else {
                 v = h;
                 condition = true;
             }
             
             if (condition) {
                 if (newhash.isNil()) {
                     newhash = RubyHash.newHash(context.runtime);
                 }
                 ((RubyHash)newhash).op_aset(contextcontext.runtime.newSymbol("fallback"), v);
             }
         }
         
         if (!newhash.isNil()) {
             newhash.setFrozen(true);
         }
         opts[0] = newhash;
         
         return ecflags;
     }
     
     // rb_econv_opts
     public static int econvOpts(ThreadContext contextIRubyObject optint ecflags) {
         Ruby runtime = context.runtime;
         IRubyObject v;
         
         v = ((RubyHash)opt).op_aref(contextruntime.newSymbol("invalid"));
         if (v.isNil()) {
         } else if (v == runtime.newSymbol("replace")) {
             ecflags |= ;
         } else {
             throw runtime.newArgumentError("unknown value for invalid character option");
         }
         
         v = ((RubyHash)opt).op_aref(contextruntime.newSymbol("undef"));
         if (v.isNil()) {
         } else if (v == runtime.newSymbol("replace")) {
             ecflags |= ;
         } else {
             throw runtime.newArgumentError("unknown value for undefined character option");
         }
         
         v = ((RubyHash)opt).op_aref(contextruntime.newSymbol("replace"));
         if (!v.isNil() && (ecflags & ) != 0) {
             ecflags |= ;
         }
         
         v = ((RubyHash)opt).op_aref(contextruntime.newSymbol("xml"));
         if (!v.isNil()) {
             if (v == runtime.newSymbol("text")) {
                 ecflags |= |;
             } else if (v == runtime.newSymbol("attr")) {
             } else {
                 throw runtime.newArgumentError("unexpected value for xml option: " + v);
             }
         }
         
         v = ((RubyHash)opt).op_aref(contextruntime.newSymbol("newline"));
         if (!v.isNil()) {
             ecflags &= ~;
             if (v == runtime.newSymbol("universal")) {
                 ecflags |= ;
             } else if (v == runtime.newSymbol("crlf")) {
                 ecflags |= ;
             } else if (v == runtime.newSymbol("cr")) {
                 ecflags |= ;
             } else if (v == runtime.newSymbol("lf")) {
 //                ecflags |= ECONV_LF_NEWLINE_DECORATOR;
             } else {
                 throw runtime.newArgumentError("unexpected value for newline option");
             }
         }
         
         int setflags = 0;
         boolean newlineflag = false;
         
         v = ((RubyHash)opt).op_aref(contextruntime.newSymbol("universal_newline"));
         if (v.isTrue()) {
             setflags |= ;
         }
         newlineflag |= !v.isNil();
         
         v = ((RubyHash)opt).op_aref(contextruntime.newSymbol("crlf_newline"));
         if (v.isTrue()) {
             setflags |= ;
         }
         newlineflag |= !v.isNil();
         
         v = ((RubyHash)opt).op_aref(contextruntime.newSymbol("cr_newline"));
         if (v.isTrue()) {
             setflags |= ;
         }
         newlineflag |= !v.isNil();
         
         if (newlineflag) {
             ecflags &= ~;
             ecflags |= setflags;
         }
         
         return ecflags;
     }
     
     // rb_econv_open_opts
     public static Transcoder econvOpenOpts(ThreadContext contextbyte[] sourceEncodingbyte[] destinationEncodingint ecflagsIRubyObject opthash) {
         Ruby runtime = context.runtime;
         IRubyObject replacement;
         
         if (opthash == null || opthash.isNil()) {
             replacement = context.nil;
         } else {
             if (!(opthash instanceof RubyHash) || !opthash.isFrozen()) {
                 throw runtime.newRuntimeError("bug: EncodingUtils.econvOpenOpts called with invalid opthash");
             }
             replacement = ((RubyHash)opthash).op_aref(contextruntime.newSymbol("replace"));
         }
         
         return Transcoder.open(contextsourceEncodingdestinationEncodingecflagsreplacement);
         // missing logic for checking replacement encoding, may live in CharsetTranscoder
         // already...
     }
     
     // rb_econv_open_exc
     public static RaiseException econvOpenExc(ThreadContext contextbyte[] sourceEncodingbyte[] destinationEncodingint ecflags) {
         String message = econvDescription(contextsourceEncodingdestinationEncodingecflags"code converter not found (") + ")";
         return context.runtime.newConverterNotFoundError(message);
     }
     
     // rb_econv_description
     public static String econvDescription(ThreadContext contextbyte[] sourceEncodingbyte[] destinationEncodingint ecflagsString message) {
         // limited port for now
         return message + new String(sourceEncoding) + " to " + new String(destinationEncoding);
     }
     
     // rb_econv_asciicompat_encoding
     // Missing proper logic from transcoding subsystem
     public static Encoding econvAsciicompatEncoding(Encoding enc) {
         return ..get(enc);
     }
     
     // rb_enc_asciicompat
     public static boolean encAsciicompat(Encoding enc) {
         return encMbminlen(enc) == 1 && !encDummy(enc);
     }
     
     // rb_enc_ascget
     public static int encAscget(byte[] bytesint offsetint endint[] chlenEncoding enc) {
         int c;
         int l;
         
         if (enc.isAsciiCompatible()) {
             c = bytes[offset];
             if (!Encoding.isAscii((byte)c)) {
                 return -1;
             }
             if (chlen != nullchlen[0] = 1;
             return c;
         }
         l = StringSupport.preciseLength(encbytesoffsetend);
         if (StringSupport.MBCLEN_CHARFOUND_LEN(l) == 0) {
             return -1;
         }
         c = enc.mbcToCode(bytesoffsetend);
         if (!Encoding.isAscii(c)) {
             return -1;
         }
         if (chlen != nullchlen[0] = 1;
         return c;
     }
     
     // rb_enc_mbminlen
     public static int encMbminlen(Encoding encoding) {
         return encoding.minLength();
     }
     
     // rb_enc_dummy_p
     public static boolean encDummy(Encoding enc) {
         return enc.isDummy();
     }
     
     // rb_enc_get
     public static Encoding encGet(ThreadContext contextIRubyObject obj) {
         if (obj instanceof EncodingCapable) {
             return ((EncodingCapable)obj).getEncoding();
         }
         
         return context.runtime.getDefaultInternalEncoding();
     }
     
     // encoding_equal
     public static boolean encodingEqual(byte[] enc1byte[] enc2) {
         return new String(enc1).equalsIgnoreCase(new String(enc2));
     }
     
     // enc_arg
     public static Encoding encArg(ThreadContext contextIRubyObject encvalbyte[][] name_pEncoding[] enc_p) {
         if ((enc_p[0] = toEncodingIndex(contextencval)) == null) {
             name_p[0] = ((RubyString)encval.anyToString()).getBytes();
         } else {
             name_p[0] = enc_p[0].getName();
         }
         
         return enc_p[0];
     }
     
     // rb_to_encoding_index
     public static Encoding toEncodingIndex(ThreadContext contextIRubyObject enc) {
         if (enc instanceof RubyEncoding) {
             return ((RubyEncoding)enc).getEncoding();
         } else if ((enc = enc.checkStringType19()).isNil()) {
             return null;
         }
         if (!((RubyString)enc).getEncoding().isAsciiCompatible()) {
             return null;
         }
         return context.runtime.getEncodingService().getEncodingFromObjectNoError(enc);
     }
     
     // encoded_dup
     public static IRubyObject encodedDup(ThreadContext contextIRubyObject newstrIRubyObject strEncoding encindex) {
         if (encindex == nullreturn str.dup();
         if (newstr == str) {
             newstr = str.dup();
         } else {
             // set to same superclass
             ((RubyBasicObject)newstr).setMetaClass(str.getMetaClass());
         }
         ((RubyString)newstr).modify19();
         return strEncodeAssociate(contextnewstrencindex);
     }
     
     // str_encode_associate
     public static IRubyObject strEncodeAssociate(ThreadContext contextIRubyObject strEncoding encidx) {
         encAssociateIndex(strencidx);
         
         if (encAsciicompat(encidx)) {
             ((RubyString)str).scanForCodeRange();
         } else {
             ((RubyString)str).setCodeRange(.);
         }
         
         return str;
     }
     
     // rb_enc_associate_index
     public static IRubyObject encAssociateIndex(IRubyObject objEncoding encidx) {
         ((RubyBasicObject)obj).checkFrozen();
         if (((EncodingCapable)obj).getEncoding() == encidx) {
             return obj;
         }
         if (!((RubyString)obj).isCodeRangeAsciiOnly() ||
                 encAsciicompat(encidx)) {
             ((RubyString)obj).clearCodeRange();
         }
         ((EncodingCapable)obj).setEncoding(encidx);
         return obj;
     }
     
     // str_encode
     public static IRubyObject strEncode(ThreadContext contextIRubyObject strIRubyObject... args) {
         IRubyObject[] newstr_p = {str};
         
         Encoding dencindex = strTranscode(contextargsnewstr_p);
         
         return encodedDup(contextnewstr_p[0], strdencindex);
     }
     
     // rb_str_encode
     public static IRubyObject rbStrEncode(ThreadContext contextIRubyObject strIRubyObject toint ecflagsIRubyObject ecopt) {
         IRubyObject[] newstr_p = {str};
         
         Encoding dencindex = strTranscode0(context, 1, new IRubyObject[]{to}, newstr_pecflagsecopt);
         
         return encodedDup(contextnewstr_p[0], strdencindex);
         
     }
     
     // str_transcode
     public static Encoding strTranscode(ThreadContext contextIRubyObject[] argsIRubyObject[] self_p) {
         int ecflags = 0;
         int argc = args.length;
         IRubyObject[] ecopts_p = {context.nil};
         
         if (args.length >= 1) {
             IRubyObject tmp = TypeConverter.checkHashType(context.runtimeargs[args.length -1]);
             if (!tmp.isNil()) {
                 argc--;
                 ecflags = econvPrepareOpts(contexttmpecopts_p);
             }
         }
         
         return strTranscode0(contextargcargsself_pecflagsecopts_p[0]);
     }
     
     // str_transcode0
     public static Encoding strTranscode0(ThreadContext contextint argcIRubyObject[] argsIRubyObject[] self_pint ecflagsIRubyObject ecopts) {
         Ruby runtime = context.runtime;
         
         IRubyObject str = self_p[0];
         IRubyObject arg1arg2;
         Encoding[] senc_p = {null}, denc_p = {null};
         byte[][] sname_p = {null}, dname_p = {null};
         Encoding dencindex;
         
         if (argc > 2) {
             throw context.runtime.newArgumentError(args.length, 2);
         }
         
         if (argc == 0) {
             arg1 = runtime.getEncodingService().getDefaultInternal();
             if (arg1 == null || arg1.isNil()) {
                 if (ecflags == 0) return null;
                 arg1 = objEncoding(contextstr);
             }
             ecflags |= . | .;
         } else {
             arg1 = args[0];
         }
         
         arg2 = argc <= 1 ? context.nil : args[1];
         dencindex = strTranscodeEncArgs(contextstrarg1arg2sname_psenc_pdname_pdenc_p);
         
         if ((ecflags & (.
                 | .
                 | .
                 | .)) == 0) {
             if (senc_p[0] != null && senc_p[0] == denc_p[0]) {                
                 // TODO: Ruby 2.0 or 2.1 use String#scrub here
                 if ((ecflags & .) != 0) {
                     // TODO: scrub with replacement
                     str = str.dup();
                 } else {
                     // TODO: scrub without replacement
                     str = str.dup();
                 }
                 self_p[0] = str;
                 return dencindex;
             } else if (senc_p[0] != null && denc_p[0] != null && senc_p[0].isAsciiCompatible() && denc_p[0].isAsciiCompatible()) {
                 if (((RubyString)str).scanForCodeRange() == .) {
                     return dencindex;
                 }
             }
             if (encodingEqual(sname_p[0], dname_p[0])) {
                 return arg2.isNil() ? null : dencindex;
             }
         } else {
             if (encodingEqual(sname_p[0], dname_p[0])) {
                 sname_p[0] = ;
                 dname_p[0] = ;
             }
         }
         
         ByteList fromp = ((RubyString)str).getByteList().shallowDup();
         RubyString dest = runtime.newString();
         ByteList destp = dest.getByteList();
         
         transcodeLoop(contextfrompdestpsname_p[0], dname_p[0], ecflagsecopts);
         
         if (denc_p[0] == null) {
             dencindex = defineDummyEncoding(contextdname_p[0]);
         }
         
         self_p[0] = dest;
         
         return dencindex;
     }
     
     // rb_obj_encoding
     public static IRubyObject objEncoding(ThreadContext contextIRubyObject obj) {
         Encoding enc = encGet(contextobj);
         if (enc == null) {
             throw context.runtime.newTypeError("unknown encoding");
         }
         return context.runtime.getEncodingService().convertEncodingToRubyEncoding(enc);
     }
     
     public static Encoding strTranscodeEncArgs(ThreadContext contextIRubyObject strIRubyObject arg1IRubyObject arg2byte[][] sname_pEncoding[] senc_pbyte[][] dname_pEncoding[] denc_p) {
         Encoding dencindex;
         
         dencindex = encArg(contextarg1dname_pdenc_p);
         
         if (arg2.isNil()) {
             senc_p[0] = encGet(contextstr);
             sname_p[0] = senc_p[0].getName();
         } else {
             encArg(contextarg2sname_psenc_p);
         }
         
         return dencindex;
     }
     
     public static boolean encRegistered(byte[] name) {
         return EncodingDB.getEncodings().get(name) != null;
     }
     
     // enc_check_duplication
     public static void encCheckDuplication(ThreadContext contextbyte[] name) {
         if (encRegistered(name)) {
             throw context.runtime.newArgumentError("encoding " + new String(name) + " is already registered");
         }
     }
     
     // rb_enc_replicate
     public static Encoding encReplicate(ThreadContext contextbyte[] nameEncoding encoding) {
         encCheckDuplication(contextname);
         EncodingDB.replicate(new String(name), new String(encoding.getName()));
         return EncodingDB.getEncodings().get(name).getEncoding();
     }
     
     // rb_define_dummy_encoding
     public static Encoding defineDummyEncoding(ThreadContext contextbyte[] name) {
         Encoding dummy = encReplicate(contextnameascii8bitEncoding(context.runtime));
         // TODO: set dummy on encoding; this probably should live in jcodings
         return dummy;
     }
     
     // transcode_loop
     public static void transcodeLoop(ThreadContext contextByteList frompByteList destbyte[] snamebyte[] dnameint ecflagsIRubyObject ecopts) {
         Transcoder ec;
         
         ec = econvOpenOpts(contextsnamednameecflagsecopts);
         
         if (ec == null) {
             throw econvOpenExc(contextsnamednameecflags);
         }
         
         // TODO: fallback function
         
         RubyCoderResult result = ec.transcode(contextfrompdest);
     }
     
     // io_set_encoding_by_bom
     public static void ioSetEncodingByBOM(ThreadContext contextRubyIO io) {
         Ruby runtime = context.runtime;
         Encoding bomEncoding = ioStripBOM(io);
         
         if (bomEncoding != null) {
             // FIXME: Wonky that we acquire RubyEncoding to pass these encodings through
             IRubyObject theBom = runtime.getEncodingService().getEncoding(bomEncoding);
             IRubyObject theInternal = io.internal_encoding(context);
 
             io.setEncoding(runtime.getCurrentContext(), theBomtheInternalcontext.nil);
         }
     }
     
     // mri: io_strip_bom
     public static Encoding ioStripBOM(RubyIO io) {
         int b1b2b3b4;
 
         switch (b1 = io.getcCommon()) {
             case 0xEF:
                 b2 = io.getcCommon();
                 if (b2 == 0xBB) {
                     b3 = io.getcCommon();
                     if (b3 == 0xBF) {
                         return .;
                     }
                     io.ungetcCommon(b3);
                 }
                 io.ungetcCommon(b2);
                 break;
             case 0xFE:
                 b2 = io.getcCommon();
                 if (b2 == 0xFF) {
                     return .;
                 }
                 io.ungetcCommon(b2);
                 break;
             case 0xFF:
                 b2 = io.getcCommon();
                 if (b2 == 0xFE) {
                     b3 = io.getcCommon();
                     if (b3 == 0) {
                         b4 = io.getcCommon();
                         if (b4 == 0) {
                             return .;
                         }
                         io.ungetcCommon(b4);
                     } else {
                         io.ungetcCommon(b3);
                         return .;
                     }
                     io.ungetcCommon(b3);
                 }
                 io.ungetcCommon(b2);
                 break;
             case 0:
                 b2 = io.getcCommon();
                 if (b2 == 0) {
                     b3 = io.getcCommon();
                     if (b3 == 0xFE) {
                         b4 = io.getcCommon();
                         if (b4 == 0xFF) {
                             return .;
                         }
                         io.ungetcCommon(b4);
                     }
                     io.ungetcCommon(b3);
                 }
                 io.ungetcCommon(b2);
                 break;
         }
         io.ungetcCommon(b1);
         return null;
     }
     
     // validate_enc_binmode
     public static void validateEncodingBinmode(ThreadContext contextint[] fmode_pint ecflagsIOEncodable ioEncodable) {
         Ruby runtime = context.runtime;
         int fmode = fmode_p[0];
         
         if ((fmode & .) != 0 &&
                 ioEncodable.getEnc2() == null && 
                 (fmode & .) == 0 &&
                 !(ioEncodable.getEnc() != null ? ioEncodable.getEnc() : runtime.getDefaultExternalEncoding()).isAsciiCompatible()) {
             throw runtime.newArgumentError("ASCII incompatible encoding needs binmode");
         }
         
         if ((fmode & .) == 0 && (. != 0 || (ecflags & .) != 0)) {
             fmode |= .;
             fmode_p[0] = fmode;
         } else if (. == 0 && (ecflags & ) == 0) {
             fmode &= ~.;