Skip to content

Commit

Permalink
Added com.sun.jna.platform.win32.Kernel32.GetPrivateProfileSection,…
Browse files Browse the repository at this point in the history
… `GetPrivateProfileSectionNames` and `WritePrivateProfileSection` and corresponding `Kernel32Util` helpers.
  • Loading branch information
mkarg authored and dblock committed Oct 7, 2013
1 parent 438d131 commit c7dcf61
Show file tree
Hide file tree
Showing 5 changed files with 259 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Features
* [#101](https://github.com/twall/jna/issues/101): Modify `com.sun.jna.platform.win32.Advapi32Util.registryGet*` API to support `KEY_WOW64` option - [@falldog] (https://github.com/falldog).
* [#271](https://github.com/twall/jna/pull/271): Added `com.sun.jna.platform.win32.Gdi32.ChoosePixelFormat` and `SetPixelFormat` - [@kc7bfi](https://github.com/kc7bfi).
* [#271](https://github.com/twall/jna/pull/271): Added `com.sun.jna.platform.win32.OpenGL32`, `OpenGL32Util` and `WinOpenGL` - [@kc7bfi](https://github.com/kc7bfi).
* [#250](https://github.com/twall/jna/pull/250): Added `com.sun.jna.platform.win32.Kernel32.GetPrivateProfileSection`, `GetPrivateProfileSectionNames` and `WritePrivateProfileSection` and corresponding `Kernel32Util` helpers - [@quipsy-karg](https://github.com/quipsy-karg).

Bug Fixes
---------
Expand Down
61 changes: 61 additions & 0 deletions contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java
Original file line number Diff line number Diff line change
Expand Up @@ -1981,4 +1981,65 @@ DWORD GetPrivateProfileString(String lpAppName, String lpKeyName,
*/
boolean WritePrivateProfileString(String lpAppName, String lpKeyName,
String lpString, String lpFileName);

/**
* Retrieves all the keys and values for the specified section of an initialization file.
*
* <p>
* Each string has the following format: {@code key=string}.
* </p>
* <p>
* This operation is atomic; no updates to the specified initialization file are allowed while the key name and value pairs for the section are being copied
* to the buffer pointed to by the {@code lpReturnedString} parameter.
* </p>
*
* @param lpAppName
* The name of the section in the initialization file.
* @param lpReturnedString
* A buffer that receives the key name and value pairs associated with the named section. The buffer is filled with one or more {@code null}
* -terminated strings; the last string is followed by a second {@code null} character.
* @param nSize
* The size of the buffer pointed to by the {@code lpReturnedString} parameter, in characters. The maximum profile section size is 32,767
* characters.
* @param lpFileName
* The name of the initialization file. If this parameter does not contain a full path to the file, the system searches for the file in the
* Windows directory.
* @return The number of characters copied to the buffer, not including the terminating null character. If the buffer is not large enough to contain all the
* key name and value pairs associated with the named section, the return value is equal to {@code nSize} minus two.
*/
DWORD GetPrivateProfileSection(String lpAppName, char[] lpReturnedString, DWORD nSize, String lpFileName);

/**
* Retrieves the names of all sections in an initialization file.
* <p>
* This operation is atomic; no updates to the initialization file are allowed while the section names are being copied to the buffer.
* </p>
*
* @param lpszReturnBuffer
* A pointer to a buffer that receives the section names associated with the named file. The buffer is filled with one or more {@code null}
* -terminated strings; the last string is followed by a second {@code null} character.
* @param nSize
* size of the buffer pointed to by the {@code lpszReturnBuffer} parameter, in characters.
* @param lpFileName
* The name of the initialization file. If this parameter is {@code NULL}, the function searches the Win.ini file. If this parameter does not
* contain a full path to the file, the system searches for the file in the Windows directory.
* @return The return value specifies the number of characters copied to the specified buffer, not including the terminating {@code null} character. If the
* buffer is not large enough to contain all the section names associated with the specified initialization file, the return value is equal to the
* size specified by {@code nSize} minus two.
*/
DWORD GetPrivateProfileSectionNames(char[] lpszReturnBuffer, DWORD nSize, String lpFileName);

/**
* @param lpAppName
* The name of the section in which data is written. This section name is typically the name of the calling application.
* @param lpString
* The new key names and associated values that are to be written to the named section. This string is limited to 65,535 bytes. Must be filled
* with zero or many {@code null}-terminated strings of the form {@code key=value}, appended by an additional {@code null} byte to terminate the
* list.
* @param lpFileName
* The name of the initialization file. If this parameter does not contain a full path for the file, the function searches the Windows directory
* for the file. If the file does not exist and lpFileName does not contain a full path, the function creates the file in the Windows directory.
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero.
*/
boolean WritePrivateProfileSection(String lpAppName, String lpString, String lpFileName);
}
63 changes: 63 additions & 0 deletions contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -362,4 +362,67 @@ public static final WinNT.SYSTEM_LOGICAL_PROCESSOR_INFORMATION[] getLogicalProce
return (WinNT.SYSTEM_LOGICAL_PROCESSOR_INFORMATION[]) firstInformation
.toArray(new WinNT.SYSTEM_LOGICAL_PROCESSOR_INFORMATION[returnedStructCount]);
}

/**
* Retrieves all the keys and values for the specified section of an initialization file.
*
* <p>
* Each string has the following format: {@code key=string}.
* </p>
* <p>
* This operation is atomic; no updates to the specified initialization file are allowed while this method is executed.
* </p>
*
* @param appName
* The name of the section in the initialization file.
* @param fileName
* The name of the initialization file. If this parameter does not contain a full path to the file, the system searches for the file in the
* Windows directory.
* @return The key name and value pairs associated with the named section.
*/
public static final String[] getPrivateProfileSection(final String appName, final String fileName) {
final char buffer[] = new char[32768]; // Maximum section size according to MSDN (http://msdn.microsoft.com/en-us/library/windows/desktop/ms724348(v=vs.85).aspx)
if (Kernel32.INSTANCE.GetPrivateProfileSection(appName, buffer, new DWORD(buffer.length), fileName).intValue() == 0) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
return new String(buffer).split("\0");
}

/**
* Retrieves the names of all sections in an initialization file.
* <p>
* This operation is atomic; no updates to the initialization file are allowed while this method is executed.
* </p>
*
* @param fileName
* The name of the initialization file. If this parameter is {@code NULL}, the function searches the Win.ini file. If this parameter does not
* contain a full path to the file, the system searches for the file in the Windows directory.
* @return the section names associated with the named file.
*/
public static final String[] getPrivateProfileSectionNames(final String fileName) {
final char buffer[] = new char[65536]; // Maximum INI file size according to MSDN (http://support.microsoft.com/kb/78346)
if (Kernel32.INSTANCE.GetPrivateProfileSectionNames(buffer, new DWORD(buffer.length), fileName).intValue() == 0) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
return new String(buffer).split("\0");
}

/**
* @param appName
* The name of the section in which data is written. This section name is typically the name of the calling application.
* @param strings
* The new key names and associated values that are to be written to the named section. Each entry must be of the form {@code key=value}.
* @param fileName
* The name of the initialization file. If this parameter does not contain a full path for the file, the function searches the Windows directory
* for the file. If the file does not exist and lpFileName does not contain a full path, the function creates the file in the Windows directory.
*/
public static final void writePrivateProfileSection(final String appName, final String[] strings, final String fileName) {
final StringBuilder buffer = new StringBuilder();
for (final String string : strings)
buffer.append(string).append('\0');
buffer.append('\0');
if (! Kernel32.INSTANCE.WritePrivateProfileSection(appName, buffer.toString(), fileName)) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
}
}
62 changes: 62 additions & 0 deletions contrib/platform/test/com/sun/jna/platform/win32/Kernel32Test.java
Original file line number Diff line number Diff line change
Expand Up @@ -531,4 +531,66 @@ public final void testWritePrivateProfileString() throws IOException {
assertEquals(reader.readLine(), null);
reader.close();
}

public final void testGetPrivateProfileSection() throws IOException {
final File tmp = File.createTempFile("testGetPrivateProfileSection", ".ini");
tmp.deleteOnExit();

final PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(tmp)));
try {
writer.println("[X]");
writer.println("A=1");
writer.println("B=X");
} finally {
writer.close();
}

final char[] buffer = new char[9];
final DWORD len = Kernel32.INSTANCE.GetPrivateProfileSection("X", buffer, new DWORD(buffer.length), tmp.getCanonicalPath());

assertEquals(len.intValue(), 7);
assertEquals(new String(buffer), "A=1\0B=X\0\0");
}

public final void testGetPrivateProfileSectionNames() throws IOException {
final File tmp = File.createTempFile("testGetPrivateProfileSectionNames", ".ini");
tmp.deleteOnExit();

final PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(tmp)));
try {
writer.println("[S1]");
writer.println("[S2]");
} finally {
writer.close();
}

final char[] buffer = new char[7];
final DWORD len = Kernel32.INSTANCE.GetPrivateProfileSectionNames(buffer, new DWORD(buffer.length), tmp.getCanonicalPath());
assertEquals(len.intValue(), 5);
assertEquals(new String(buffer), "S1\0S2\0\0");
}

public final void testWritePrivateProfileSection() throws IOException {
final File tmp = File.createTempFile("testWritePrivateProfileSection", ".ini");
tmp.deleteOnExit();

final PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(tmp)));
try {
writer.println("[S1]");
writer.println("A=1");
writer.println("B=X");
} finally {
writer.close();
}

final boolean result = Kernel32.INSTANCE.WritePrivateProfileSection("S1", "A=3\0E=Z\0\0", tmp.getCanonicalPath());
assertTrue(result);

final BufferedReader reader = new BufferedReader(new FileReader(tmp));
assertEquals(reader.readLine(), "[S1]");
assertTrue(reader.readLine().matches("A\\s*=\\s*3"));
assertTrue(reader.readLine().matches("E\\s*=\\s*Z"));
reader.close();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -180,4 +180,76 @@ public final void testWritePrivateProfileString() throws IOException {
assertEquals(reader.readLine(), null);
reader.close();
}

public final void testGetPrivateProfileSection() throws IOException {
final File tmp = File.createTempFile("testGetPrivateProfileSection", ".ini");
tmp.deleteOnExit();

final PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(tmp)));
try {
writer.println("[X]");
writer.println("A=1");
writer.println("foo=bar");
} finally {
writer.close();
}

final String[] lines = Kernel32Util.getPrivateProfileSection("X", tmp.getCanonicalPath());
assertEquals(lines.length, 2);
assertEquals(lines[0], "A=1");
assertEquals(lines[1], "foo=bar");
}

public final void testGetPrivateProfileSectionNames() throws IOException {
final File tmp = File.createTempFile("testGetPrivateProfileSectionNames", "ini");
tmp.deleteOnExit();

final PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(tmp)));
try {
writer.println("[S1]");
writer.println("A=1");
writer.println("B=X");
writer.println("[S2]");
writer.println("C=2");
writer.println("D=Y");
} finally {
writer.close();
}

String[] sectionNames = Kernel32Util.getPrivateProfileSectionNames(tmp.getCanonicalPath());
assertEquals(sectionNames.length, 2);
assertEquals(sectionNames[0], "S1");
assertEquals(sectionNames[1], "S2");
}

public final void testWritePrivateProfileSection() throws IOException {
final File tmp = File.createTempFile("testWritePrivateProfileSecion", "ini");
tmp.deleteOnExit();

final PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(tmp)));
try {
writer.println("[S1]");
writer.println("A=1");
writer.println("B=X");
writer.println("[S2]");
writer.println("C=2");
writer.println("foo=bar");
} finally {
writer.close();
}

Kernel32Util.writePrivateProfileSection("S1", new String[] { "A=3", "E=Z" }, tmp.getCanonicalPath());

final BufferedReader reader = new BufferedReader(new FileReader(tmp));
try {
assertEquals(reader.readLine(), "[S1]");
assertEquals(reader.readLine(), "A=3");
assertEquals(reader.readLine(), "E=Z");
assertEquals(reader.readLine(), "[S2]");
assertEquals(reader.readLine(), "C=2");
assertEquals(reader.readLine(), "foo=bar");
} finally {
reader.close();
}
}
}

0 comments on commit c7dcf61

Please sign in to comment.