Need help with streams

php.internals

Stephan Schmidt

22 years ago
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

Sara Golemon

22 years ago
> 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

Stephan Schmidt

22 years ago
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

Sara Golemon

22 years ago
> 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.

Stephan Schmidt

22 years ago
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

Sara Golemon

22 years ago
> 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

Stephan Schmidt

22 years ago
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