0

http://www.fastcgi.com/devkit/doc/fcgi-spec.html In section 3.4:

 typedef struct {
        unsigned char nameLengthB0;  /* nameLengthB0  >> 7 == 0 */
        unsigned char valueLengthB0; /* valueLengthB0 >> 7 == 0 */
        unsigned char nameData[nameLength];
        unsigned char valueData[valueLength];
    } FCGI_NameValuePair11;

    typedef struct {
        unsigned char nameLengthB0;  /* nameLengthB0  >> 7 == 0 */
        unsigned char valueLengthB3; /* valueLengthB3 >> 7 == 1 */
        unsigned char valueLengthB2;
        unsigned char valueLengthB1;
        unsigned char valueLengthB0;
        unsigned char nameData[nameLength];
        unsigned char valueData[valueLength
                ((B3 & 0x7f) << 24) + (B2 << 16) + (B1 << 8) + B0];
    } FCGI_NameValuePair14;

    typedef struct {
        unsigned char nameLengthB3;  /* nameLengthB3  >> 7 == 1 */
        unsigned char nameLengthB2;
        unsigned char nameLengthB1;
        unsigned char nameLengthB0;
        unsigned char valueLengthB0; /* valueLengthB0 >> 7 == 0 */
        unsigned char nameData[nameLength
                ((B3 & 0x7f) << 24) + (B2 << 16) + (B1 << 8) + B0];
        unsigned char valueData[valueLength];
    } FCGI_NameValuePair41;

    typedef struct {
        unsigned char nameLengthB3;  /* nameLengthB3  >> 7 == 1 */
        unsigned char nameLengthB2;
        unsigned char nameLengthB1;
        unsigned char nameLengthB0;
        unsigned char valueLengthB3; /* valueLengthB3 >> 7 == 1 */
        unsigned char valueLengthB2;
        unsigned char valueLengthB1;
        unsigned char valueLengthB0;
        unsigned char nameData[nameLength
                ((B3 & 0x7f) << 24) + (B2 << 16) + (B1 << 8) + B0];
        unsigned char valueData[valueLength
                ((B3 & 0x7f) << 24) + (B2 << 16) + (B1 << 8) + B0];
    } FCGI_NameValuePair44;

I'm implementing this in Java, and in order to do the valueLengthB3 >> 7 == 1, etc, part, I'm just setting it negative. This doesn't work. How do negatives work in Java, and how do you do this operation in Java?

My current code:

public void param(String name, String value) throws IOException {
    if (fp) {
        throw new IOException("Params are already finished!");
    }
    if (name.length() < 128) {
        dpout.write(name.length());
    }else {
        dpout.writeInt(-name.length());
    }
    if (value.length() < 128) {
        dpout.write(value.length());
    }else {
        dpout.writeInt(-value.length());
    }
    dpout.write(name.getBytes());
    dpout.write(value.getBytes());
}
JavaProphet
  • 931
  • 14
  • 29
  • 1
    `struct` isn't meant for specifying representation over the wire. I don't know Java, but it certainly has better serialisation/deserialisation mechanisms than this. "This doesn't work" isn't descriptive, though it doesn't surprise me. Your question is misguided, vague and lacks much research. Want my advice? Tell us which actual problem this is trying to solve, and ask how to do that in Java... Then you'll probably get a good answer. – autistic Mar 30 '15 at 21:47
  • It's not about the structs, it's about the `valueLengthB3 >> 7 == 1`, how do you evaluate this in a 4 byte manner inside of Java? It's basically code conversion. I'm trying to implement variable size lengths inside Java for the FCGI protocol. @undefinedbehaviour @pbacdefp – JavaProphet Mar 30 '15 at 21:51
  • I do not understand what you are asking. – brian beuning Mar 30 '15 at 21:57
  • It would help if you presented the relevant part of the code you're *writing*, and explained what unwanted result you are actually seeing. Inasmuch as the code you posted is neither valid C nor valid C++, it doesn't provide much guidance. – John Bollinger Mar 30 '15 at 21:59
  • Since you are asking about Java, what does your question have to do with C or C++? Maybe you should include other languages that use bit shifting or remove the C and C++ tags. – Thomas Matthews Mar 30 '15 at 22:00
  • I added my own code, which should in theory, perform that needed bitshift, but doesn't? I think my issue is I just am having a hard time visualizing what that shift code does `valueLengthB3 >> 7 == 1`. @JohnBollinger – JavaProphet Mar 30 '15 at 22:22
  • @JohnBollinger The answer you appear to have removed looked like a good start. If I were to extend it, I'd add this detail: if you were to receive `byte`s over the wire, they'd be signed meaning that the most significant bit will be the sign bit. If you want to extract the sign bit from `byte`, there are two sensible ways that come to mind: Test negativity using `< 0` or use the `>>>` operator, rather than the `>>` operator. – autistic Mar 30 '15 at 22:23
  • @undefinedbehaviour FCGI uses signability in this case to determine the length of the length(of the content). 0 = 1 byte, 1 = 4 bytes. I figured just negating the Java value before writing would achieve this affect, but it doesn't work, and I don't know why. I've debugged it enough to determine this is the issue, by removing the >=128 values(skipping them), and then it works flawlessly. – JavaProphet Mar 30 '15 at 22:26
  • No, it doesn't. It uses the most significant bit of an **unsigned** octet. There's no *signability* of unsigned octets. – autistic Mar 30 '15 at 22:46

2 Answers2

1

Java uses pretty routine integer operations. The two main peculiarities relative to C and C++ are

  1. Java has no unsigned integer types other than char (which is 16-bits wide), and
  2. Java has separate arithmetic (>>) and logical (>>>) right-shift operators. The former preserves sign by filling in the needed most-significant bits of the result with copies of the most-significant bit of the left operand, whereas the latter fills in the most-significant bits of the result with zeroes.

Java has the advantage that all primitive types have well-known, consistent sizes and signedness on all platforms, and that its two right-shift operators have well-defined semantics for all valid operands. In contrast, in C, the result of performing a right shift on a negative value is implementation-defined, all of the standard data types have implementation-defined sizes, and some types (char) have implementation-defined signedness.

Now that you have posted some code, however, it appears that none of that is actually your problem. I am at a loss to understand why you think that negating a number would perform any kind of shifting, or indeed, why you think shifting is required at all for what you are trying to do.

Note especially that Java uses two's complement integer representation (as is by far the most common choice of C compilers, too), so negating a number modifies more than just the sign bit. If instead you want to set only the sign bit of an int, then you could spell that

value.length() | 0x80000000
John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • Thanks! I just didn't understand how Java signedness worked. I thought it did what you just showed me. Thanks! – JavaProphet Mar 30 '15 at 22:34
  • Negation and flipping bits aren't quite the same. `~x = -1-x`. – Louis Wasserman Mar 30 '15 at 22:38
  • @user3618509 read this https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html [How are integers internally represented at a bit level in Java?](http://stackoverflow.com/questions/13422259/how-are-integers-internally-represented-at-a-bit-level-in-java) http://en.wikipedia.org/wiki/Two%27s_complement – phuclv Mar 31 '15 at 03:45
  • Thanks, @LouisWasserman, I don't know what I was thinking when I wrote that. Corrected. – John Bollinger Mar 31 '15 at 13:02
0

If you were to receive bytes over the wire, they'd be signed meaning that the most significant bit will be the sign bit. If you want to extract the sign bit from byte, there are two sensible ways that come to mind: Test negativity by comparing against 0 or use the >>> operator, rather than the >> operator.

The following code shows how I'd deserialise such an array of signed chars in C. I can't imagine why this wouldn't work in Java, assuming data is instead an array of bytes... though I'm sure it'd be quite hideous.

long offset = 0;
long nameLength  = data[offset] >= 0 ? data[offset++] : (-(long)data[offset++] << 24)
                                                      + ( (long)data[offset++] << 16)
                                                      + ( (long)data[offset++] <<  8)
                                                      +         data[offset++];
long valueLength = data[offset] >= 0 ? data[offset++] : (-(long)data[offset++] << 24)
                                                      + ( (long)data[offset++] << 16)
                                                      + ( (long)data[offset++] <<  8)
                                                      +         data[offset++];

for (long x = 0; x < nameLength; x++) {
    /* XXX: Copy data[offset++] into name */
}

for (long x = 0; x < valueLength; x++) {
    /* XXX: Copy data[offset++] into value */
}
autistic
  • 1
  • 3
  • 35
  • 80