/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
Hierarchical storage layout:
<dict>
<key>/</key>
<dict>
<key>foo</key>
<string>/foo's value</string>
<key>foo/</key>
<dict>
<key>bar</key>
</dict>
</dict>
</dict>
Java pref nodes are stored in several different files. Pref nodes
are stored in a CF prefs file with the first three components as the name.
This way, all preferences for MyApp end up in com.MyCompany.MyApp.plist .
Pref nodes with shorter names are stored in com.apple.java.util.prefs.plist
The filesystem is assumed to be case-insensitive (like HFS+).
Java pref node names are case-sensitive. If two pref node names differ
only in case, they may end up in the same pref file. This is ok
because the CF keys identifying the node span the entire absolute path
to the node and are case-sensitive.
Java node names may contain '.' . When mapping to the CF file name,
these dots are left as-is, even though '/' is mapped to '.' .
This is ok because the CF key contains the correct node name.
*/
#include "jni_util.h"
#include "jlong.h"
#include "jvm.h"
// Throw an OutOfMemoryError with the given message.
{
jclass c;
if (exceptionClass) {
c = exceptionClass;
} else {
}
}
// throwIfNull macro
// If var is NULL, throw an OutOfMemoryError and goto badvar.
// var must be a variable. env must be the current JNIEnv.
// fixme throw BackingStoreExceptions sometimes?
do { \
} \
} while (0)
// Converts CFNumber, CFBoolean, CFString to CFString
// returns NULL if value is of some other type
// throws and returns NULL on memory error
// result must be released (even if value was already a CFStringRef)
// value must not be null
{
if (type == CFStringGetTypeID()) {
}
else if (type == CFBooleanGetTypeID()) {
// Java Preferences API expects "true" and "false" for boolean values.
}
else if (type == CFNumberGetTypeID()) {
if (CFNumberIsFloatType(number)) {
double d;
}
else {
long l;
}
}
else {
// unknown type - return NULL
}
return result;
}
// Create a Java string from the given CF string.
// returns NULL if cfString is NULL
// throws and returns NULL on memory error
{
return NULL;
} else {
if (constchars) {
} else {
}
return javaString;
}
}
// Create a CF string from the given Java string.
// returns NULL if javaString is NULL
// throws and returns NULL on memory error
{
if (javaString == NULL) {
return NULL;
} else {
result =
return result;
}
}
// Create an empty Java string array of the given size.
// Throws and returns NULL on error.
{
jclass c;
if (stringClass) {
c = stringClass;
} else {
}
}
// Java accessors for CF constants.
{
return ptr_to_jlong(kCFPreferencesCurrentUser);
}
{
return ptr_to_jlong(kCFPreferencesAnyUser);
}
{
return ptr_to_jlong(kCFPreferencesCurrentHost);
}
{
return ptr_to_jlong(kCFPreferencesAnyHost);
}
// Create an empty node.
// Does not store the node in any prefs file.
// returns NULL on memory error
static CFMutableDictionaryRef createEmptyNode(void)
{
}
// Create a string that consists of path minus its last component.
// path must end with '/'
// The result will end in '/' (unless path itself is '/')
{
}
// Create a string that consists of path's last component.
// path must end with '/'
// The result will end in '/'.
// The result will not start with '/' (unless path itself is '/')
{
}
// Return the first three components of path, with leading and trailing '/'.
// If path does not have three components, return NULL.
// path must begin and end in '/'
{
&slashRange);
&slashRange);
&slashRange);
return prefix;
}
// Copy the CFPreferences key and value at the base of path's tree.
// path must end in '/'
// topKey or topValue may be NULL
// Returns NULL on error or if there is no tree for path in this file.
{
// Top-level file. Only key "/" is an acceptable root.
} else {
// Second-level file. Key must be the first three components of path.
if (!key) return;
}
if (value) {
// (key, value) is acceptable
}
}
}
// Find the node for path in the given tree.
// Returns NULL on error or if path doesn't have a node in this tree.
// path must end in '/'
{
if (!p) return NULL;
while (CFStringGetLength(p) > 0) {
// guaranteed to succeed because path must end in '/'
CFStringDelete(p, partRange);
// continue search
} else {
// didn't find target node
break;
}
}
CFRelease(p);
else return NULL;
}
// Return a retained copy of the node at path from the given file.
// path must end in '/'
// returns NULL if node doesn't exist.
// returns NULL if the value for key "path" isn't a valid node.
{
return result;
}
// Create a new tree that would store path in the given file.
// Only the root of the tree is created, not all of the links leading to path.
// returns NULL on error
{
*outTopValue = NULL;
// if name is "com.apple.java.util.prefs" then create tree "/"
// "com.apple.java.util.prefs.plist" is also in MacOSXPreferences.java
*outTopValue = createEmptyNode();
} else {
if (prefix) {
*outTopValue = createEmptyNode();
}
}
}
// Return a mutable copy of the tree containing path and the dict for
// path itself. *outTopKey and *outTopValue can be used to write the
// modified tree back to the prefs file.
// *outTopKey and *outTopValue must be released iff the actual return
// value is not NULL.
static CFMutableDictionaryRef
{
if (!topKey) {
} else {
}
if (!topValue) goto badtopValue;
if (!p) goto badp;
while (CFStringGetLength(p) > 0) {
// guaranteed to succeed because path must end in '/'
CFStringDelete(p, partRange);
// continue search
} else {
// didn't find target node - add it and continue
child = createEmptyNode();
}
}
if (result) {
}
CFRelease(p);
badp:
return result;
}
{
jboolean neededNewNode = false;
if (node) {
neededNewNode = false;
} else {
neededNewNode = true;
// copyMutableNode creates the node if necessary
}
return neededNewNode;
}
{
// root node is not allowed to be removed, so parentName is never empty
} else {
// might be trying to remove the root itself in a non-root file
if (topKey) {
}
}
}
}
// child must end with '/'
{
// like addNode, but can put a three-level-deep dict into the root file
node = createEmptyNode();
// copyMutableNode creates the node if necessary
if (!beforeAdd)
else
beforeAdd = false;
return beforeAdd;
}
{
}
}
{
// fixme optimization: check whether old value and new value are identical
}
{
}
}
// path must end in '/'
{
if (node) {
if (!value) {
// key doesn't exist, or other error - no Java errors available
} else {
// memory error in copyToCFString
// bogus value type in prefs file - no Java errors available
} else {
// good cfString
}
}
}
return result;
}
// CFDictionary applier function that builds an array of Java strings
// from a CFDictionary of CFPropertyListRefs.
// If args->allowSlash, only strings that end in '/' are added to the array,
// with the slash removed. Otherwise, only strings that do not end in '/'
// are added.
// args->result must already exist and be large enough to hold all
// strings from the dictionary.
// After complete application, args->result may not be full because
// some of the dictionary values weren't convertible to string. In
// this case, args->used will be the count of used elements.
{
// memory error in copyToCFString
} else if (!cfString) {
// bogus value type in prefs file - no Java errors available
// wrong suffix - ignore
} else {
// good cfString
if (args->allowSlash) {
cfString = s;
}
}
bad:
}
{
if (!node) {
} else {
if (result) {
// array construction succeeded
// finished array is smaller than expected.
// Make a new array of precisely the right size.
if (newresult) {
}
}
}
}
}
return result;
}
{
}
{
}
// Returns false on error instead of throwing.
{
if (name) {
}
return result;
}