Hi,
I'm working on ext/id3 (proposed in pecl) and I'm currently experiencing
a problem.
I got a function that is used to update the information in an ID3 tag.
The user passes an array and I update all information that has been
passed. One of the possible tokens is a genre ID which is represented by
an integer:
$new = array(
'title' => 'My Song',
'genre' => 23
);
Now I need to write the character that represents 34 to the stream. Using
zend_hash_get_current_data(array, (void**) &data);
I copy the value 23 into data. Then I convert it to long, if the value
is not a long already:
convert_to_long(*data);
And now I move the pointer to the position where the genre ID is stored:
php_stream_seek(stream, ID3_SEEK_V1_GENRE, SEEK_END);
But I do not know how to write the value to the stream
php_stream_write(stream, (char*)Z_LVAL_P(*data), 1);
This does not produce the result I need, instead the file contains 48 at
this position.
If I return RETURN_LONG(Z_LVAL_P(*data); I get 23 as expected.
Hope anybody is able to help or direct me to the correct mailinglist if
internals is not the appropriate list.
Best regards,
Stephan
But I do not know how to write the value to the stream
php_stream_write(stream, (char*)Z_LVAL_P(*data), 1);
This does not produce the result I need, instead the file contains 48 at
this position.
That's because you're telling it to write one character from the position
POINTED TO by the integer value. (i.e. Treat the integer like a pointer)
You're lucky you're getting data at all and not a segfault.
Try:
php_stream_putc(stream, (char)(Z_LVAL_P(*data) & 0xFF));
-Sara
Hi,
That's because you're telling it to write one character from the position
POINTED TO by the integer value. (i.e. Treat the integer like a pointer)
You're lucky you're getting data at all and not a segfault.Try:
php_stream_putc(stream, (char)(Z_LVAL_P(*data) & 0xFF));
You are a livesaver! Thanks very much. I got one more problem though:
What's the best way to create a string with a fixed length, that's
padded with zero-bytes?
I'm currently using:
php_stream_write(stream, Z_STRVAL_P(*data), 30);
As the string is terminated with a zero-byte, it already works, but it
would be better to fill the unused space with zero-bytes.
Do I have to create a second buffer and copy byte-by-byte and then fill
the remaining bytes with zeros, or is there an easier way? The only
other solution I could think of is to check for the exact length of the
string, write the string and then use php_stream_putc() in a loop to
write the remaining zero bytes...
Stephan
I'm currently using:
php_stream_write(stream, Z_STRVAL_P(*data), 30);
As the string is terminated with a zero-byte, it already works, but it
would be better to fill the unused space with zero-bytes.
Actually, that'll also open the door to a potential segfault since you may
overrun the allocated block of memory.
Try:
/* Not binary safe, but depending on your data that may be okay */
if (Z_STRLEN_PP(data) > 30) {
php_stream_write(stream, Z_STRVAL_PP(data), 30);
} else {
php_stream_printf(stream TSRMLS_CC, "%-30s", Z_STRVAL_PP(data));
}
or:
/* This is binary safe /
if (Z_STRLEN_PP(data) > 30) {
php_stream_write(stream, Z_STRVAL_PP(data), 30);
} else {
php_stream_write(stream, Z_STRVAL_PP(data), Z_STRLEN_PP(data));
/ That's 30 spaces in that string constant */
php_stream_write(stream, " ", 30 -
Z_STRLEN_PP(data));
}
-Sara
P.S. - As you might have noticed in the above code Z_STRVAL_PP(data) is the
same as Z_STRVAL_P(*data). The same is true of the Z_LVAL_P(*data) you used
in your previous question. I don't recall if using the _PP is dictated by
the coding standards, but it's certainly in line with established
convention. You'll probably find your code becomes more readable by others
who are accostomed to the PHP Core if you stick to the secondary indirection
macros.
Hi,
/* Not binary safe, but depending on your data that may be okay */
if (Z_STRLEN_PP(data) > 30) {
php_stream_write(stream, Z_STRVAL_PP(data), 30);
} else {
php_stream_printf(stream TSRMLS_CC, "%-30s", Z_STRVAL_PP(data));
}
Both solutions will pad the string with ' ', but I need to pad it with '\0'.
P.S. - As you might have noticed in the above code Z_STRVAL_PP(data) is the
same as Z_STRVAL_P(*data). The same is true of the Z_LVAL_P(*data) you used
in your previous question. I don't recall if using the _PP is dictated by
the coding standards, but it's certainly in line with established
convention. You'll probably find your code becomes more readable by others
who are accostomed to the PHP Core if you stick to the secondary indirection
macros.
OK, I'll adjust this in the extension.
Thanks,
Stephan
Both solutions will pad the string with ' ', but I need to pad it with
'\0'.
Ah, misunderstood you, try this one:
if (Z_STRLEN_PP(data) > 30) {
php_stream_write(stream, Z_STRVAL_PP(data), 30);
} else {
char blanks[30];
memset(blanks, 0, 30);
php_stream_write(stream, Z_STRVAL_PP(data), Z_STRLEN_PP(data));
php_stream_write(stream, blanks, 30 - Z_STRLEN_PP(data));
}
iirc there may be a printf means to specify NULL
as the padding character,
or to repeat an aribtrary character for a certain number of characters, but
it's escaping me at the moment. For the size of your padding this method
should introduce to horrible of a penalty.
-Sara
Hi,
iirc there may be a printf means to specify
NULL
as the padding character,
or to repeat an aribtrary character for a certain number of characters, but
it's escaping me at the moment. For the size of your padding this method
should introduce to horrible of a penalty.
Works like a charm, thanks.
Stephan