Conversion from .NET 3.5 to .NET 2.0 - .net-2.0

How I can convert the following methods to C# 2.0?
private static string ToHexString(byte[] bytes)
{
return string.Join(string.Empty, bytes.Select(x => x.ToString("X2")).ToArray());
}
private static byte[] ToByteArray(string hex)
{
return Enumerable.Range(0, hex.Length).
Where(x => 0 == x % 2).
Select(x => Convert.ToByte(hex.Substring(x, 2), 16)).
ToArray();
}
I haven't got experience with .NET 2.0. Thanks!

void Main()
{
string s = ToHexString(new byte[]{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15});
Console.WriteLine(s);
foreach (byte b in ToByteArray(s))
Console.WriteLine(b);
}
private static string ToHexString(byte[] bytes)
{
StringBuilder sb = new StringBuilder();
foreach (byte b in bytes)
sb.Append(b.ToString("X2"));
return sb.ToString();
}
private static byte[] ToByteArray(string hex)
{
byte[] b = new byte[hex.Length/2];
for (int i = 0; i < b.Length; i++)
{
b[i] = Convert.ToByte(hex.Substring(i*2,2), 16);
}
return b;
}

You should be able to do this conversion yourself. Obviously you'll want to convert it into a for loop. Enumerable.Range essentially provides an int[] array upon which to loop. After that, the Where equates to an if check, the Select is a transformation from the int to a substring and finally to a byte, and last, you stuff all that into an array, probably by adding them to a List<byte> declared outside the loop. (and when you're done, you can call ToArray on the list)
I could provide a complete answer, but I think this sort of exercise is best left to you so you can learn from it.

Related

how to transform string in integer in jaspersoft studio with the condition [duplicate]

How can I convert a String to an int?
"1234" → 1234
String myString = "1234";
int foo = Integer.parseInt(myString);
If you look at the Java documentation you'll notice the "catch" is that this function can throw a NumberFormatException, which you can handle:
int foo;
try {
foo = Integer.parseInt(myString);
}
catch (NumberFormatException e) {
foo = 0;
}
(This treatment defaults a malformed number to 0, but you can do something else if you like.)
Alternatively, you can use an Ints method from the Guava library, which in combination with Java 8's Optional, makes for a powerful and concise way to convert a string into an int:
import com.google.common.primitives.Ints;
int foo = Optional.ofNullable(myString)
.map(Ints::tryParse)
.orElse(0)
For example, here are two ways:
Integer x = Integer.valueOf(str);
// or
int y = Integer.parseInt(str);
There is a slight difference between these methods:
valueOf returns a new or cached instance of java.lang.Integer
parseInt returns primitive int.
The same is for all cases: Short.valueOf/parseShort, Long.valueOf/parseLong, etc.
Well, a very important point to consider is that the Integer parser throws NumberFormatException as stated in Javadoc.
int foo;
String StringThatCouldBeANumberOrNot = "26263Hello"; //will throw exception
String StringThatCouldBeANumberOrNot2 = "26263"; //will not throw exception
try {
foo = Integer.parseInt(StringThatCouldBeANumberOrNot);
} catch (NumberFormatException e) {
//Will Throw exception!
//do something! anything to handle the exception.
}
try {
foo = Integer.parseInt(StringThatCouldBeANumberOrNot2);
} catch (NumberFormatException e) {
//No problem this time, but still it is good practice to care about exceptions.
//Never trust user input :)
//Do something! Anything to handle the exception.
}
It is important to handle this exception when trying to get integer values from split arguments or dynamically parsing something.
Do it manually:
public static int strToInt(String str){
int i = 0;
int num = 0;
boolean isNeg = false;
// Check for negative sign; if it's there, set the isNeg flag
if (str.charAt(0) == '-') {
isNeg = true;
i = 1;
}
// Process each character of the string;
while( i < str.length()) {
num *= 10;
num += str.charAt(i++) - '0'; // Minus the ASCII code of '0' to get the value of the charAt(i++).
}
if (isNeg)
num = -num;
return num;
}
An alternate solution is to use Apache Commons' NumberUtils:
int num = NumberUtils.toInt("1234");
The Apache utility is nice because if the string is an invalid number format then 0 is always returned. Hence saving you the try catch block.
Apache NumberUtils API Version 3.4
Integer.decode
You can also use public static Integer decode(String nm) throws NumberFormatException.
It also works for base 8 and 16:
// base 10
Integer.parseInt("12"); // 12 - int
Integer.valueOf("12"); // 12 - Integer
Integer.decode("12"); // 12 - Integer
// base 8
// 10 (0,1,...,7,10,11,12)
Integer.parseInt("12", 8); // 10 - int
Integer.valueOf("12", 8); // 10 - Integer
Integer.decode("012"); // 10 - Integer
// base 16
// 18 (0,1,...,F,10,11,12)
Integer.parseInt("12",16); // 18 - int
Integer.valueOf("12",16); // 18 - Integer
Integer.decode("#12"); // 18 - Integer
Integer.decode("0x12"); // 18 - Integer
Integer.decode("0X12"); // 18 - Integer
// base 2
Integer.parseInt("11",2); // 3 - int
Integer.valueOf("11",2); // 3 - Integer
If you want to get int instead of Integer you can use:
Unboxing:
int val = Integer.decode("12");
intValue():
Integer.decode("12").intValue();
Currently I'm doing an assignment for college, where I can't use certain expressions, such as the ones above, and by looking at the ASCII table, I managed to do it. It's a far more complex code, but it could help others that are restricted like I was.
The first thing to do is to receive the input, in this case, a string of digits; I'll call it String number, and in this case, I'll exemplify it using the number 12, therefore String number = "12";
Another limitation was the fact that I couldn't use repetitive cycles, therefore, a for cycle (which would have been perfect) can't be used either. This limits us a bit, but then again, that's the goal. Since I only needed two digits (taking the last two digits), a simple charAtsolved it:
// Obtaining the integer values of the char 1 and 2 in ASCII
int semilastdigitASCII = number.charAt(number.length() - 2);
int lastdigitASCII = number.charAt(number.length() - 1);
Having the codes, we just need to look up at the table, and make the necessary adjustments:
double semilastdigit = semilastdigitASCII - 48; // A quick look, and -48 is the key
double lastdigit = lastdigitASCII - 48;
Now, why double? Well, because of a really "weird" step. Currently we have two doubles, 1 and 2, but we need to turn it into 12, there isn't any mathematic operation that we can do.
We're dividing the latter (lastdigit) by 10 in the fashion 2/10 = 0.2 (hence why double) like this:
lastdigit = lastdigit / 10;
This is merely playing with numbers. We were turning the last digit into a decimal. But now, look at what happens:
double jointdigits = semilastdigit + lastdigit; // 1.0 + 0.2 = 1.2
Without getting too into the math, we're simply isolating units the digits of a number. You see, since we only consider 0-9, dividing by a multiple of 10 is like creating a "box" where you store it (think back at when your first grade teacher explained you what a unit and a hundred were). So:
int finalnumber = (int) (jointdigits*10); // Be sure to use parentheses "()"
And there you go. You turned a String of digits (in this case, two digits), into an integer composed of those two digits, considering the following limitations:
No repetitive cycles
No "Magic" Expressions such as parseInt
Methods to do that:
Integer.parseInt(s)
Integer.parseInt(s, radix)
Integer.parseInt(s, beginIndex, endIndex, radix)
Integer.parseUnsignedInt(s)
Integer.parseUnsignedInt(s, radix)
Integer.parseUnsignedInt(s, beginIndex, endIndex, radix)
Integer.valueOf(s)
Integer.valueOf(s, radix)
Integer.decode(s)
NumberUtils.toInt(s)
NumberUtils.toInt(s, defaultValue)
Integer.valueOf produces an Integer object and all other methods a primitive int.
The last two methods are from commons-lang3 and a big article about converting here.
Whenever there is the slightest possibility that the given String does not contain an Integer, you have to handle this special case. Sadly, the standard Java methods Integer::parseInt and Integer::valueOf throw a NumberFormatException to signal this special case. Thus, you have to use exceptions for flow control, which is generally considered bad coding style.
In my opinion, this special case should be handled by returning an empty Optional<Integer>. Since Java does not offer such a method, I use the following wrapper:
private Optional<Integer> tryParseInteger(String string) {
try {
return Optional.of(Integer.valueOf(string));
} catch (NumberFormatException e) {
return Optional.empty();
}
}
Example usage:
// prints "12"
System.out.println(tryParseInteger("12").map(i -> i.toString()).orElse("invalid"));
// prints "-1"
System.out.println(tryParseInteger("-1").map(i -> i.toString()).orElse("invalid"));
// prints "invalid"
System.out.println(tryParseInteger("ab").map(i -> i.toString()).orElse("invalid"));
While this is still using exceptions for flow control internally, the usage code becomes very clean. Also, you can clearly distinguish the case where -1 is parsed as a valid value and the case where an invalid String could not be parsed.
Use Integer.parseInt(yourString).
Remember the following things:
Integer.parseInt("1"); // ok
Integer.parseInt("-1"); // ok
Integer.parseInt("+1"); // ok
Integer.parseInt(" 1"); // Exception (blank space)
Integer.parseInt("2147483648"); // Exception (Integer is limited to a maximum value of 2,147,483,647)
Integer.parseInt("1.1"); // Exception (. or , or whatever is not allowed)
Integer.parseInt(""); // Exception (not 0 or something)
There is only one type of exception: NumberFormatException
Converting a string to an int is more complicated than just converting a number. You have think about the following issues:
Does the string only contain numbers 0-9?
What's up with -/+ before or after the string? Is that possible (referring to accounting numbers)?
What's up with MAX_-/MIN_INFINITY? What will happen if the string is 99999999999999999999? Can the machine treat this string as an int?
We can use the parseInt(String str) method of the Integer wrapper class for converting a String value to an integer value.
For example:
String strValue = "12345";
Integer intValue = Integer.parseInt(strVal);
The Integer class also provides the valueOf(String str) method:
String strValue = "12345";
Integer intValue = Integer.valueOf(strValue);
We can also use toInt(String strValue) of NumberUtils Utility Class for the conversion:
String strValue = "12345";
Integer intValue = NumberUtils.toInt(strValue);
I'm have a solution, but I do not know how effective it is. But it works well, and I think you could improve it. On the other hand, I did a couple of tests with JUnit which step correctly. I attached the function and testing:
static public Integer str2Int(String str) {
Integer result = null;
if (null == str || 0 == str.length()) {
return null;
}
try {
result = Integer.parseInt(str);
}
catch (NumberFormatException e) {
String negativeMode = "";
if(str.indexOf('-') != -1)
negativeMode = "-";
str = str.replaceAll("-", "" );
if (str.indexOf('.') != -1) {
str = str.substring(0, str.indexOf('.'));
if (str.length() == 0) {
return (Integer)0;
}
}
String strNum = str.replaceAll("[^\\d]", "" );
if (0 == strNum.length()) {
return null;
}
result = Integer.parseInt(negativeMode + strNum);
}
return result;
}
Testing with JUnit:
#Test
public void testStr2Int() {
assertEquals("is numeric", (Integer)(-5), Helper.str2Int("-5"));
assertEquals("is numeric", (Integer)50, Helper.str2Int("50.00"));
assertEquals("is numeric", (Integer)20, Helper.str2Int("$ 20.90"));
assertEquals("is numeric", (Integer)5, Helper.str2Int(" 5.321"));
assertEquals("is numeric", (Integer)1000, Helper.str2Int("1,000.50"));
assertEquals("is numeric", (Integer)0, Helper.str2Int("0.50"));
assertEquals("is numeric", (Integer)0, Helper.str2Int(".50"));
assertEquals("is numeric", (Integer)0, Helper.str2Int("-.10"));
assertEquals("is numeric", (Integer)Integer.MAX_VALUE, Helper.str2Int(""+Integer.MAX_VALUE));
assertEquals("is numeric", (Integer)Integer.MIN_VALUE, Helper.str2Int(""+Integer.MIN_VALUE));
assertEquals("Not
is numeric", null, Helper.str2Int("czv.,xcvsa"));
/**
* Dynamic test
*/
for(Integer num = 0; num < 1000; num++) {
for(int spaces = 1; spaces < 6; spaces++) {
String numStr = String.format("%0"+spaces+"d", num);
Integer numNeg = num * -1;
assertEquals(numStr + ": is numeric", num, Helper.str2Int(numStr));
assertEquals(numNeg + ": is numeric", numNeg, Helper.str2Int("- " + numStr));
}
}
}
You can also begin by removing all non-numerical characters and then parsing the integer:
String mystr = mystr.replaceAll("[^\\d]", "");
int number = Integer.parseInt(mystr);
But be warned that this only works for non-negative numbers.
Google Guava has tryParse(String), which returns null if the string couldn't be parsed, for example:
Integer fooInt = Ints.tryParse(fooString);
if (fooInt != null) {
...
}
Apart from the previous answers, I would like to add several functions. These are results while you use them:
public static void main(String[] args) {
System.out.println(parseIntOrDefault("123", 0)); // 123
System.out.println(parseIntOrDefault("aaa", 0)); // 0
System.out.println(parseIntOrDefault("aaa456", 3, 0)); // 456
System.out.println(parseIntOrDefault("aaa789bbb", 3, 6, 0)); // 789
}
Implementation:
public static int parseIntOrDefault(String value, int defaultValue) {
int result = defaultValue;
try {
result = Integer.parseInt(value);
}
catch (Exception e) {
}
return result;
}
public static int parseIntOrDefault(String value, int beginIndex, int defaultValue) {
int result = defaultValue;
try {
String stringValue = value.substring(beginIndex);
result = Integer.parseInt(stringValue);
}
catch (Exception e) {
}
return result;
}
public static int parseIntOrDefault(String value, int beginIndex, int endIndex, int defaultValue) {
int result = defaultValue;
try {
String stringValue = value.substring(beginIndex, endIndex);
result = Integer.parseInt(stringValue);
}
catch (Exception e) {
}
return result;
}
As mentioned, Apache Commons' NumberUtils can do it. It returns 0 if it cannot convert a string to an int.
You can also define your own default value:
NumberUtils.toInt(String str, int defaultValue)
Example:
NumberUtils.toInt("3244", 1) = 3244
NumberUtils.toInt("", 1) = 1
NumberUtils.toInt(null, 5) = 5
NumberUtils.toInt("Hi", 6) = 6
NumberUtils.toInt(" 32 ", 1) = 1 // Space in numbers are not allowed
NumberUtils.toInt(StringUtils.trimToEmpty(" 32 ", 1)) = 32;
You can use new Scanner("1244").nextInt(). Or ask if even an int exists: new Scanner("1244").hasNextInt()
You can use this code also, with some precautions.
Option #1: Handle the exception explicitly, for example, showing a message dialog and then stop the execution of the current workflow. For example:
try
{
String stringValue = "1234";
// From String to Integer
int integerValue = Integer.valueOf(stringValue);
// Or
int integerValue = Integer.ParseInt(stringValue);
// Now from integer to back into string
stringValue = String.valueOf(integerValue);
}
catch (NumberFormatException ex) {
//JOptionPane.showMessageDialog(frame, "Invalid input string!");
System.out.println("Invalid input string!");
return;
}
Option #2: Reset the affected variable if the execution flow can continue in case of an exception. For example, with some modifications in the catch block
catch (NumberFormatException ex) {
integerValue = 0;
}
Using a string constant for comparison or any sort of computing is always a good idea, because a constant never returns a null value.
In programming competitions, where you're assured that number will always be a valid integer, then you can write your own method to parse input. This will skip all validation related code (since you don't need any of that) and will be a bit more efficient.
For valid positive integer:
private static int parseInt(String str) {
int i, n = 0;
for (i = 0; i < str.length(); i++) {
n *= 10;
n += str.charAt(i) - 48;
}
return n;
}
For both positive and negative integers:
private static int parseInt(String str) {
int i=0, n=0, sign=1;
if (str.charAt(0) == '-') {
i = 1;
sign = -1;
}
for(; i<str.length(); i++) {
n* = 10;
n += str.charAt(i) - 48;
}
return sign*n;
}
If you are expecting a whitespace before or after these numbers,
then make sure to do a str = str.trim() before processing further.
For a normal string you can use:
int number = Integer.parseInt("1234");
For a String builder and String buffer you can use:
Integer.parseInt(myBuilderOrBuffer.toString());
Simply you can try this:
Use Integer.parseInt(your_string); to convert a String to int
Use Double.parseDouble(your_string); to convert a String to double
Example
String str = "8955";
int q = Integer.parseInt(str);
System.out.println("Output>>> " + q); // Output: 8955
String str = "89.55";
double q = Double.parseDouble(str);
System.out.println("Output>>> " + q); // Output: 89.55
int foo = Integer.parseInt("1234");
Make sure there is no non-numeric data in the string.
Here we go
String str = "1234";
int number = Integer.parseInt(str);
print number; // 1234
I am a little bit surprised that nobody mentioned the Integer constructor that takes String as a parameter.
So, here it is:
String myString = "1234";
int i1 = new Integer(myString);
Java 8 - Integer(String).
Of course, the constructor will return type Integer, and an unboxing operation converts the value to int.
Note 1: It's important to mention: This constructor calls the parseInt method.
public Integer(String var1) throws NumberFormatException {
this.value = parseInt(var1, 10);
}
Note 2: It's deprecated: #Deprecated(since="9") - JavaDoc.
Use Integer.parseInt() and put it inside a try...catch block to handle any errors just in case a non-numeric character is entered, for example,
private void ConvertToInt(){
String string = txtString.getText();
try{
int integerValue=Integer.parseInt(string);
System.out.println(integerValue);
}
catch(Exception e){
JOptionPane.showMessageDialog(
"Error converting string to integer\n" + e.toString,
"Error",
JOptionPane.ERROR_MESSAGE);
}
}
It can be done in seven ways:
import com.google.common.primitives.Ints;
import org.apache.commons.lang.math.NumberUtils;
String number = "999";
Ints.tryParse:
int result = Ints.tryParse(number);
NumberUtils.createInteger:
Integer result = NumberUtils.createInteger(number);
NumberUtils.toInt:
int result = NumberUtils.toInt(number);
Integer.valueOf:
Integer result = Integer.valueOf(number);
Integer.parseInt:
int result = Integer.parseInt(number);
Integer.decode:
int result = Integer.decode(number);
Integer.parseUnsignedInt:
int result = Integer.parseUnsignedInt(number);
This is a complete program with all conditions positive and negative without using a library
import java.util.Scanner;
public class StringToInt {
public static void main(String args[]) {
String inputString;
Scanner s = new Scanner(System.in);
inputString = s.nextLine();
if (!inputString.matches("([+-]?([0-9]*[.])?[0-9]+)")) {
System.out.println("Not a Number");
}
else {
Double result2 = getNumber(inputString);
System.out.println("result = " + result2);
}
}
public static Double getNumber(String number) {
Double result = 0.0;
Double beforeDecimal = 0.0;
Double afterDecimal = 0.0;
Double afterDecimalCount = 0.0;
int signBit = 1;
boolean flag = false;
int count = number.length();
if (number.charAt(0) == '-') {
signBit = -1;
flag = true;
}
else if (number.charAt(0) == '+') {
flag = true;
}
for (int i = 0; i < count; i++) {
if (flag && i == 0) {
continue;
}
if (afterDecimalCount == 0.0) {
if (number.charAt(i) - '.' == 0) {
afterDecimalCount++;
}
else {
beforeDecimal = beforeDecimal * 10 + (number.charAt(i) - '0');
}
}
else {
afterDecimal = afterDecimal * 10 + number.charAt(i) - ('0');
afterDecimalCount = afterDecimalCount * 10;
}
}
if (afterDecimalCount != 0.0) {
afterDecimal = afterDecimal / afterDecimalCount;
result = beforeDecimal + afterDecimal;
}
else {
result = beforeDecimal;
}
return result * signBit;
}
}
One method is parseInt(String). It returns a primitive int:
String number = "10";
int result = Integer.parseInt(number);
System.out.println(result);
The second method is valueOf(String), and it returns a new Integer() object:
String number = "10";
Integer result = Integer.valueOf(number);
System.out.println(result);
public static int parseInt(String s)throws NumberFormatException
You can use Integer.parseInt() to convert a String to an int.
Convert a String, "20", to a primitive int:
String n = "20";
int r = Integer.parseInt(n); // Returns a primitive int
System.out.println(r);
Output-20
If the string does not contain a parsable integer, it will throw NumberFormatException:
String n = "20I"; // Throws NumberFormatException
int r = Integer.parseInt(n);
System.out.println(r);
public static Integer valueOf(String s)throws NumberFormatException
You can use Integer.valueOf(). In this it will return an Integer object.
String n = "20";
Integer r = Integer.valueOf(n); // Returns a new Integer() object.
System.out.println(r);
Output-20
References
https://docs.oracle.com/en/

How to use ByteArrayOutputStream and ByteBuffer

I have this code in Java, how can I write it with dart?
I need to write some String to a Socket, but before it, I need to write the length of this string. So I use the ByteBuffer class to create some byte array with the string length, and after that I concatenate this two byte arrays. Thank you.
public void writeUTF(String s, OutputStream out) throws IOException {
if (s != null) {
ByteArrayOutputStream bytArray = new ByteArrayOutputStream();
int length = s.getBytes("UTF-8").length;
// Create buffer
byte[] bytesMessageLenght = ByteBuffer.allocate(4).putInt(length).array();
byte[] bytes = s.getBytes();
bytArray.write(bytesMessageLenght);
bytArray.write(bytes);
// Write
out.write(bytArray.toByteArray());
out.flush();
}
}
Use a Dart ByteData which allows you to set the length directly, and then use asUint8List to make a byte array to copy in the rest.
Uint8List encode(String s) {
var encodedString = utf8.encode(s);
var encodedLength = encodedString.length;
var data = ByteData(encodedLength + 4);
data.setUint32(0, encodedLength, Endian.big);
var bytes = data.buffer.asUint8List();
bytes.setRange(4, encodedLength + 4, encodedString);
return bytes;
}

Can I drag items from Outlook into my SWT application?

Background
Our Eclipse RCP 3.6-based application lets people drag files in for storage/processing. This works fine when the files are dragged from a filesystem, but not when people drag items (messages or attachments) directly from Outlook.
This appears to be because Outlook wants to feed our application the files via a FileGroupDescriptorW and FileContents, but SWT only includes a FileTransfer type. (In a FileTransfer, only the file paths are passed, with the assumption that the receiver can locate and read them. The FileGroupDescriptorW/FileContents approach can supply files directly application-to-application without writing temporary files out to disk.)
We have tried to produce a ByteArrayTransfer subclass that could accept FileGroupDescriptorW and FileContents. Based on some examples on the Web, we were able to receive and parse the FileGroupDescriptorW, which (as the name implies) describes the files available for transfer. (See code sketch below.) But we have been unable to accept the FileContents.
This seems to be because Outlook offers the FileContents data only as TYMED_ISTREAM or TYMED_ISTORAGE, but SWT only understands how to exchange data as TYMED_HGLOBAL. Of those, it appears that TYMED_ISTORAGE would be preferable, since it's not clear how TYMED_ISTREAM could provide access to multiple files' contents.
(We also have some concerns about SWT's desire to pick and convert only a single TransferData type, given that we need to process two, but we think we could probably hack around that in Java somehow: it seems that all the TransferDatas are available at other points of the process.)
Questions
Are we on the right track here? Has anyone managed to accept FileContents in SWT yet? Is there any chance that we could process the TYMED_ISTORAGE data without leaving Java (even if by creating a fragment-based patch to, or a derived version of, SWT), or would we have to build some new native support code too?
Relevant code snippets
Sketch code that extracts file names:
// THIS IS NOT PRODUCTION-QUALITY CODE - FOR ILLUSTRATION ONLY
final Transfer transfer = new ByteArrayTransfer() {
private final String[] typeNames = new String[] { "FileGroupDescriptorW", "FileContents" };
private final int[] typeIds = new int[] { registerType(typeNames[0]), registerType(typeNames[1]) };
#Override
protected String[] getTypeNames() {
return typeNames;
}
#Override
protected int[] getTypeIds() {
return typeIds;
}
#Override
protected Object nativeToJava(TransferData transferData) {
if (!isSupportedType(transferData))
return null;
final byte[] buffer = (byte[]) super.nativeToJava(transferData);
if (buffer == null)
return null;
try {
final DataInputStream in = new DataInputStream(new ByteArrayInputStream(buffer));
long count = 0;
for (int i = 0; i < 4; i++) {
count += in.readUnsignedByte() << i;
}
for (int i = 0; i < count; i++) {
final byte[] filenameBytes = new byte[260 * 2];
in.skipBytes(72); // probable architecture assumption(s) - may be wrong outside standard 32-bit Win XP
in.read(filenameBytes);
final String fileNameIncludingTrailingNulls = new String(filenameBytes, "UTF-16LE");
int stringLength = fileNameIncludingTrailingNulls.indexOf('\0');
if (stringLength == -1)
stringLength = 260;
final String fileName = fileNameIncludingTrailingNulls.substring(0, stringLength);
System.out.println("File " + i + ": " + fileName);
}
in.close();
return buffer;
}
catch (final Exception e) {
return null;
}
}
};
In the debugger, we see that ByteArrayTransfer's isSupportedType() ultimately returns false for the FileContents because the following test is not passed (since its tymed is TYMED_ISTREAM | TYMED_ISTORAGE):
if (format.cfFormat == types[i] &&
(format.dwAspect & COM.DVASPECT_CONTENT) == COM.DVASPECT_CONTENT &&
(format.tymed & COM.TYMED_HGLOBAL) == COM.TYMED_HGLOBAL )
return true;
This excerpt from org.eclipse.swt.internal.ole.win32.COM leaves us feeling less hope for an easy solution:
public static final int TYMED_HGLOBAL = 1;
//public static final int TYMED_ISTORAGE = 8;
//public static final int TYMED_ISTREAM = 4;
Thanks.
even if
//public static final int TYMED_ISTREAM = 4;
Try below code.. it should work
package com.nagarro.jsag.poc.swtdrag;
imports ...
public class MyTransfer extends ByteArrayTransfer {
private static int BYTES_COUNT = 592;
private static int SKIP_BYTES = 72;
private final String[] typeNames = new String[] { "FileGroupDescriptorW", "FileContents" };
private final int[] typeIds = new int[] { registerType(typeNames[0]), registerType(typeNames[1]) };
#Override
protected String[] getTypeNames() {
return typeNames;
}
#Override
protected int[] getTypeIds() {
return typeIds;
}
#Override
protected Object nativeToJava(TransferData transferData) {
String[] result = null;
if (!isSupportedType(transferData) || transferData.pIDataObject == 0)
return null;
IDataObject data = new IDataObject(transferData.pIDataObject);
data.AddRef();
// Check for descriptor format type
try {
FORMATETC formatetcFD = transferData.formatetc;
STGMEDIUM stgmediumFD = new STGMEDIUM();
stgmediumFD.tymed = COM.TYMED_HGLOBAL;
transferData.result = data.GetData(formatetcFD, stgmediumFD);
if (transferData.result == COM.S_OK) {
// Check for contents format type
long hMem = stgmediumFD.unionField;
long fileDiscriptorPtr = OS.GlobalLock(hMem);
int[] fileCount = new int[1];
try {
OS.MoveMemory(fileCount, fileDiscriptorPtr, 4);
fileDiscriptorPtr += 4;
result = new String[fileCount[0]];
for (int i = 0; i < fileCount[0]; i++) {
String fileName = handleFile(fileDiscriptorPtr, data);
System.out.println("FileName : = " + fileName);
result[i] = fileName;
fileDiscriptorPtr += BYTES_COUNT;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
OS.GlobalFree(hMem);
}
}
} finally {
data.Release();
}
return result;
}
private String handleFile(long fileDiscriptorPtr, IDataObject data) throws Exception {
// GetFileName
char[] fileNameChars = new char[OS.MAX_PATH];
byte[] fileNameBytes = new byte[OS.MAX_PATH];
COM.MoveMemory(fileNameBytes, fileDiscriptorPtr, BYTES_COUNT);
// Skip some bytes.
fileNameBytes = Arrays.copyOfRange(fileNameBytes, SKIP_BYTES, fileNameBytes.length);
String fileNameIncludingTrailingNulls = new String(fileNameBytes, "UTF-16LE");
fileNameChars = fileNameIncludingTrailingNulls.toCharArray();
StringBuilder builder = new StringBuilder(OS.MAX_PATH);
for (int i = 0; fileNameChars[i] != 0 && i < fileNameChars.length; i++) {
builder.append(fileNameChars[i]);
}
String name = builder.toString();
try {
File file = saveFileContent(name, data);
if (file != null) {
System.out.println("File Saved # " + file.getAbsolutePath());
;
}
} catch (IOException e) {
System.out.println("Count not save file content");
;
}
return name;
}
private File saveFileContent(String fileName, IDataObject data) throws IOException {
File file = null;
FORMATETC formatetc = new FORMATETC();
formatetc.cfFormat = typeIds[1];
formatetc.dwAspect = COM.DVASPECT_CONTENT;
formatetc.lindex = 0;
formatetc.tymed = 4; // content.
STGMEDIUM stgmedium = new STGMEDIUM();
stgmedium.tymed = 4;
if (data.GetData(formatetc, stgmedium) == COM.S_OK) {
file = new File(fileName);
IStream iStream = new IStream(stgmedium.unionField);
iStream.AddRef();
try (FileOutputStream outputStream = new FileOutputStream(file)) {
int increment = 1024 * 4;
long pv = COM.CoTaskMemAlloc(increment);
int[] pcbWritten = new int[1];
while (iStream.Read(pv, increment, pcbWritten) == COM.S_OK && pcbWritten[0] > 0) {
byte[] buffer = new byte[pcbWritten[0]];
OS.MoveMemory(buffer, pv, pcbWritten[0]);
outputStream.write(buffer);
}
COM.CoTaskMemFree(pv);
} finally {
iStream.Release();
}
return file;
} else {
return null;
}
}
}
Have you looked at https://bugs.eclipse.org/bugs/show_bug.cgi?id=132514 ?
Attached to this bugzilla entry is an patch (against an rather old version of SWT) that might be of interest.
I had the same problem and created a small library providing a Drag'n Drop Transfer Class for JAVA SWT. It can be found here:
https://github.com/HendrikHoetker/OutlookItemTransfer
Currently it supports dropping Mail Items from Outlook to your Java SWT application and will provide a list of OutlookItems with the Filename and a byte array of the file contents.
All is pure Java and in-memory (no temp files).
Usage in your SWT java application:
if (OutlookItemTransfer.getInstance().isSupportedType(event.currentDataType)) {
Object o = OutlookItemTransfer.getInstance().nativeToJava(event.currentDataType);
if (o != null && o instanceof OutlookMessage[]) {
OutlookMessage[] outlookMessages = (OutlookMessage[])o;
for (OutlookMessage msg: outlookMessages) {
//...
}
}
}
The OutlookItem will then provide two elements: filename as String and file contents as array of byte.
From here on, one could write it to a file or further process the byte array.
To your question above:
- What you find in the file descriptor is the filename of the outlook item and a pointer to an IDataObject
- the IDataObject can be parsed and will provide an IStorage object
- The IStorageObject will be then a root container providing further sub-IStorageObjects or IStreams similar to a filesystem (directory = IStorage, file = IStream
You find those elements in the following lines of code:
Get File Contents, see OutlookItemTransfer.java, method nativeToJava:
FORMATETC format = new FORMATETC();
format.cfFormat = getTypeIds()[1];
format.dwAspect = COM.DVASPECT_CONTENT;
format.lindex = <fileIndex>;
format.ptd = 0;
format.tymed = TYMED_ISTORAGE | TYMED_ISTREAM | COM.TYMED_HGLOBAL;
STGMEDIUM medium = new STGMEDIUM();
if (data.GetData(format, medium) == COM.S_OK) {
// medium.tymed will now contain TYMED_ISTORAGE
// in medium.unionfield you will find the root IStorage
}
Read the root IStorage, see CompoundStorage, method readOutlookStorage:
// open IStorage object
IStorage storage = new IStorage(pIStorage);
storage.AddRef();
// walk through the content of the IStorage object
long[] pEnumStorage = new long[1];
if (storage.EnumElements(0, 0, 0, pEnumStorage) == COM.S_OK) {
// get storage iterator
IEnumSTATSTG enumStorage = new IEnumSTATSTG(pEnumStorage[0]);
enumStorage.AddRef();
enumStorage.Reset();
// prepare statstg structure which tells about the object found by the iterator
long pSTATSTG = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, STATSTG.sizeof);
int[] fetched = new int[1];
while (enumStorage.Next(1, pSTATSTG, fetched) == COM.S_OK && fetched[0] == 1) {
// get the description of the the object found
STATSTG statstg = new STATSTG();
COM.MoveMemory(statstg, pSTATSTG, STATSTG.sizeof);
// get the name of the object found
String name = readPWCSName(statstg);
// depending on type of object
switch (statstg.type) {
case COM.STGTY_STREAM: { // load an IStream (=File)
long[] pIStream = new long[1];
// get the pointer to the IStream
if (storage.OpenStream(name, 0, COM.STGM_DIRECT | COM.STGM_READ | COM.STGM_SHARE_EXCLUSIVE, 0, pIStream) == COM.S_OK) {
// load the IStream
}
}
case COM.STGTY_STORAGE: { // load an IStorage (=SubDirectory) - requires recursion to traverse the sub dies
}
}
}
}
// close the iterator
enumStorage.Release();
}
// close the IStorage object
storage.Release();

How to better rewrite this repeat function

I have the following function that takes a string as parameter and repeats it a number of times (also a parameter). I feel like this is something that's already in the framework or at least could be done better. Any suggestions?
private string chr(string s, int repeat)
{
string result = string.Empty;
for (int i = 0; i < repeat; i++)
{
result += s;
}
return result;
}
The most important improvement you could make to your function is to give it a descriptive name.
Not the most efficient, but concise:
.NET 4:
String.Join(String.Empty, Enumerable.Repeat(s, repeat));
.NET 3.0/3.5:
String.Join(String.Empty, Enumerable.Repeat(s, repeat).ToArray());
If your input is really a single character rather than a string, you could simply do this:
var someChar = 'f';
var repeat = 10;
var repeated = new String(someChar, repeat);
Otherwise, I dont' think there's much else to do aside from using StringBuilder instead of concatenation:
private string chr(string s, int repeat)
{
var result = new StringBuilder(s.Length * repeat);
for (int i = 0; i < repeat; i++)
{
result.Append(s);
}
return result.ToString();
}
private string chr (string s, int repeat) {
string result = new String(' ', repeat).Replace(" ", s);
return result;
}
I'd use a StringBuilder as currently you're potentially allocating and deallocating lots of strings:
private string chr(string s, int repeat)
{
StringBuilder result = new StringBuilder();
for (int i = 0; i < repeat; i++)
{
result.Append(s);
}
return result.ToString();
}
Or even better if the string is only a single character:
private string chr(char s, int repeat)
{
StringBuilder result = new StringBuilder();
result.Append(s, repeat);
return result.ToString();
}
Functional programming-style approach:
(requires at least C# 3.0)
static class StringRepetitionExtension
{
public static string Times(this int count, string what)
{
return count > 0 ? string.Concat(what, (count-1).Times(what))
: string.Empty;
}
}
Usage:
3.Times("Foobar") // returns "FoobarFoobarFoobar"
(Certainly not the most efficient solution, and due to the recursion there's always the danger of stack overflow with unreasonably large values for count; but I nevertheless wanted to share a slightly different, easy-to-understand approach.)
return new System.Text.StringBuilder().Insert(0,"repeatme",count).ToString()
You might want to consider using StringBuilder if your repeat parameter is very large.
http://msdn.microsoft.com/en-us/library/system.text.stringbuilder.aspx
http://channel9.msdn.com/forums/TechOff/14294-C-string-vs-StringBuilder/
private string chr(string s, int repeat)
{
return Enumerable.Range(0, repeat)
.Aggregate(new StringBuilder(), (sb, i) => sb.Append(s)).ToString();
}

XML serialization of hash table(C#3.0)

Hi I am trying to serialize a hash table but not happening
private void Form1_Load(object sender, EventArgs e)
{
Hashtable ht = new Hashtable();
DateTime dt = DateTime.Now;
for (int i = 0; i < 10; i++)
ht.Add(dt.AddDays(i), i);
SerializeToXmlAsFile(typeof(Hashtable), ht);
}
private void SerializeToXmlAsFile(Type targetType, Object targetObject)
{
try
{
string fileName = #"C:\output.xml";
//Serialize to XML
XmlSerializer s = new XmlSerializer(targetType);
TextWriter w = new StreamWriter(fileName);
s.Serialize(w, targetObject);
w.Flush();
w.Close();
}
catch (Exception ex) { throw ex; }
}
After a google search , I found that objects that impelment IDictonary cannot be serialized. However, I got success with binary serialization.
But I want to have xml one. Is there any way of doing so?
I am using C#3.0
Thanks
First of all starting with C# 2.0 you can use type safe version of very old Hashtable which come from .NET 1.0. So you can use Dictionary<DateTime, int>.
Starting with .NET 3.0 you can use DataContractSerializer. So you can rewrite you code like following
private void Form1_Load(object sender, EventArgs e)
{
MyHashtable ht = new MyHashtable();
DateTime dt = DateTime.Now;
for (int i = 0; i < 10; i++)
ht.Add(dt.AddDays(i), i);
SerializeToXmlAsFile(typeof(Hashtable), ht);
}
where SerializeToXmlAsFile and MyHashtable type you define like following:
[CollectionDataContract (Name = "AllMyHashtable", ItemName = "MyEntry",
KeyName = "MyDate", ValueName = "MyValue")]
public class MyHashtable : Dictionary<DateTime, int> { }
private void SerializeToXmlAsFile(Type targetType, Object targetObject)
{
try {
string fileName = #"C:\output.xml";
DataContractSerializer s = new DataContractSerializer (targetType);
XmlWriterSettings settings = new XmlWriterSettings ();
settings.Indent = true;
settings.IndentChars = (" ");
using (XmlWriter w = XmlWriter.Create (fileName, settings)) {
s.WriteObject (w, targetObject);
w.Flush ();
}
}
catch (Exception ex) { throw ex; }
}
This code produce C:\output.xml file with the following contain:
<?xml version="1.0" encoding="utf-8"?>
<AllMyHashtable xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://schemas.datacontract.org/2004/07/DataContractXmlSerializer">
<MyEntry>
<MyDate>2010-06-09T22:30:00.9474539+02:00</MyDate>
<MyValue>0</MyValue>
</MyEntry>
<MyEntry>
<MyDate>2010-06-10T22:30:00.9474539+02:00</MyDate>
<MyValue>1</MyValue>
</MyEntry>
<!-- ... -->
</AllMyHashtable>
So how we can see all names of the elements of the destination XML files we can free define.
You can create your own Hashtable derived from standart Hashtable with implementation of IXmlSerializable. So you will implmenent ReadXml(XmlReader reader) & WriteXml(XmlWriter writer) where you can put your own logic on how to read and write values from your Hashtablw with given XmlReader & XmlWriter.
I suggest you use DataContractSerializer, it's more powerful and easier to use.