1 /*
   2  * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include "JNIUtilities.h"
  27 
  28 NSString* JavaStringToNSString(JNIEnv *env, jstring jstr) {
  29     if (jstr == NULL) {
  30         return NULL;
  31     }
  32     jsize len = (*env)->GetStringLength(env, jstr);
  33     const jchar *chars = (*env)->GetStringChars(env, jstr, NULL);
  34     if (chars == NULL) {
  35         return NULL;
  36     }
  37     NSString *result = [NSString stringWithCharacters:(UniChar *)chars length:len];
  38     (*env)->ReleaseStringChars(env, jstr, chars);
  39     return result;
  40 }
  41 
  42 jstring NSStringToJavaString(JNIEnv* env, NSString *str) {
  43 
  44     if (str == NULL) {
  45        return NULL;
  46     }
  47     jstring jStr = (*env)->NewStringUTF(env, [str UTF8String]);
  48     CHECK_EXCEPTION();
  49     return jStr;
  50 }
  51 
  52 /*
  53  * These next conversion functions are for file system paths.
  54  * The NSString needs to be in de-composed UTF-16 format for the Apple file system
  55  * The Java String needs to be in pre-composed UTF-16 format for display by Java.
  56  * https://developer.apple.com/library/archive/qa/qa1235/_index.html
  57  * has some information on this.
  58  */
  59 
  60 /*
  61  * Returns an NSString in decomposed UTF16 format that is compatible with HFS's
  62  * expectation of the UTF16 format for file system paths.
  63  *
  64  * Example string: "/Users/Amélie/"
  65  *
  66  * Java's UTF16 string is "/ U s e r s / A m \351 l i e /"
  67  * macOS UTF16 string suitable for HFS is "/ U s e r s / A m e \314 \201 l i e /"
  68  *
  69  * There is no direct API that takes in NSString UTF16 encoded by Java
  70  * and produces NSString UTF16 for HFS, so we first need to decompose it
  71  * into chars (suitable for low level C file APIs), and only then
  72  * create NSString representation of this decomposition back into UTF16 string.
  73  *
  74  * https://developer.apple.com/documentation/foundation/nsstring/1414559-filesystemrepresentation?language=objc
  75  * describes how to get a file system representation as a char* from an NSString
  76  * and then using FileManager (!) convert it to an NSString.
  77  * But we want an NSString.
  78  * So the steps are
  79  * 1) Convert to NSString
  80  * 2) call [NSString fileSystemRepresentation] which gives us a char*
  81  * 3) Convert the returned char* to an NSString using FileManager (is there a better way?)
  82  */
  83 NSString* NormalizedPathNSStringFromJavaString(JNIEnv *env, jstring pathStr) {
  84     if (pathStr == NULL) {
  85         return nil;
  86     }
  87     NSString *nsStr = JavaStringToNSString(env, pathStr);
  88     if (nsStr == NULL) {
  89         return nil;
  90     }
  91     const char* chs = [nsStr fileSystemRepresentation];
  92     int len = strlen(chs);
  93     NSString* result = [[NSFileManager defaultManager]
  94                   stringWithFileSystemRepresentation:chs length:len];
  95     return result;
  96 }
  97 
  98 /*
  99  * Given what is (potentially) a de-composed NSString, convert it to pre-composed
 100  * Then convert it into a Java String.
 101  */
 102 jstring NormalizedPathJavaStringFromNSString(JNIEnv* env, NSString *str) {
 103     if (str == nil) {
 104         return NULL;
 105     }
 106     NSString *normStr = [str precomposedStringWithCanonicalMapping];
 107     return NSStringToJavaString(env, normStr);
 108 }