Writing NULL char to file in C - c

I am attempting to write an array of char to a BMP file in C. The problem with this is that whilst 0x00 values are required for the file, it seems C interprets this as the end of string when writing to the file i.e. as a NULL char. Is there any way I can override this and have C rely purely on what I say is the number of char I wish to pass?
Code for writing the header to file (this function is executed in main);
void writeFile(void){
unsigned char bmp1[54] = {
0x42, 0x4D, 0x36, 0x00,
0x0C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x36, 0x00,
0x00, 0x00, 0x28, 0x00,
0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x01, 0x00,
0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x0C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00
};
FILE *picFile = fopen("pic.bmp","w");
fprintf(picFile, bmp1, 54);
fclose(picFile);
}

Don't use fprintf() to write binary data, of course it's going to interpret its formatting string as a string. That's what it does!
Use fwrite(), and open your file in binary mode with "wb".
You can use sizeof to compute the size of the array, no need to hardcode the value:
FILE *picFile = fopen("pic.bmp", "wb");
if(picFile != NULL)
fwrite(bmp1, sizeof bmp1, 1, picFile);
fclose(picFile);
This works because it's in the same scope as the array declaration of bmp1.

The function fprintf() and its relatives are used to format some information and produce a string then write its characters1 into a file or put it on screen or store it into a given array of characters.
Use function fwrite() to write binary data; this function does not interpret the data you give it in any way and just writes the number of bytes you specify into the file.
Try this:
FILE *picFile = fopen("pic.bmp","w");
fwrite(bmp1, sizeof(bmp1), 1, picFile);
fclose(picFile);
(your call to fprintf() was erroneous, anyway)
1
The functions sprintf() and snprintf() (they put the generated string into a provided buffer of characters) copy the entire generated string onto their destination buffer, including the null terminating character.
The functions fprintf() (writes the string into a file) and printf() (puts the string on screen) do not put the null terminating character of the generated string into the output stream.
(Thanks #chux for pointing out that the C strings include the null terminating character.)

Related

How to add a uint8_t array into a char*

I have a char *data that is a Datagram to represent the packet I want to send in but I need to insert on that an uint8_t array.
// Datagram to represent the packet
char datagram[4096], source_ip[32], *data, *pseudogram;
// zero out the packet buffer
memset(datagram, 0, 4096);
// IP header
struct iphdr *iph = (struct iphdr *)datagram;
// UDP header
struct udphdr *udph = (struct udphdr *)(datagram + sizeof(struct ip));
// Data part
data = datagram + sizeof(struct iphdr) + sizeof(struct udphdr);
uint8_t packet_bytes[] = { 0xff, 0xff, 0x81, 0x01, 0x01 };
memcpy(data, packet_bytes, 5);
Doing this allows me to insert what I need and it works but the problem is that I have and uint8_t array with 0x00 in the middle making this harder than I thought because the 0x00 hex also means a termination of an array, how can I make it to work with this array instead ?
char packet_bytes[] = {
0xff, 0xff, 0x81, 0x00, 0x00, 0x00, 0x00, 0x30,
0x13, 0x43, 0x00, 0x01, 0x01, 0x01, 0x02, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
0x06, 0x00, 0x00, 0x10, 0x01, 0x01, 0x00, 0x63,
0x02, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x05,
0x00, 0x00, 0x00, 0x0c, 0x00, 0x09, 0x04, 0x00,
0x0a, 0x00, 0x03, 0x01, 0x00, 0x11, 0x77, 0x25
};
the problem is that I have and uint8_t array with 0x00 in the middle making this harder than I thought because the 0x00 hex also means a termination of an array
There is no such thing as "termination of an array" in C. There is null termination of character arrays used as strings, but that isn't applicable here. So the memcpy part will work just fine.
You have some other problems however:
char datagram[4096], char packet_bytes[] etc
char is unsuitable, dangerous and non-portable for the purpose of holding raw binary data. Use uint8_t instead. See Is char signed or unsigned by default?
struct iphdr *iph = (struct iphdr *)datagram;
This will lead to undefined behavior because of alignment and strict aliasing. What is the strict aliasing rule? You cannot wildly type pun from a character array to another type by pointer casts (though the other way around from "any type" to character type is possible). Furthermore, your struct may contain padding, in which case it is extra non-portable and you don't want to be sending padding bytes around.
(struct udphdr *)(datagram + sizeof(struct ip)); Same problem as above.
The only reliable way to do this is either to disable struct padding and then memcpy in/out of the struct. Or alternatively write serialization/deserialization routines accessing one struct member at a time, moving it to/from the raw data.

How to combine both characters and number in an unsigned array char

I want to see if this is actually possible in C code.
unsigned char message[] = {0x00,0x00,"Hello world"};
There is some firmware that I want to force to take characters other than 0x00 in the same array. It has:
unsigned char message[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
already written in it. I want it to take other characters since both these are possible:
unsigned char message[] = "Hello world";
unsigned char message2[] = {0x00,0x00,0x00};
I have a buffer that stores letters from a UART which I want to combine with
unsigned char message2[] = {0x00,0x00,0x00};
As the compiler told you, you can't do what you attempted in the way you attempted to do it.
Note that you could use:
unsigned char message[] = "\x00\x00Hello world";
but considerable care is required since:
unsigned char message[] = "\x00\x00Byebye world";
has a second byte containing \xB or \013 and the third byte is y. The hex escape stops at the first character that is not a hexadecimal digit (so "\x00Babaganoush" has six digits in the hex escape; and there are lots of ways of spelling 'Babaganoush').

Processing image over tcp socket with c

I have a small c program which connect and authenticate with my security DVR which in turn starts sending me data over the socket. I can connect on port 5000 or port 80 sending different authentification methods to start receiving the video/images. My problem is; I am new to c first of all, and I am very lost on how to process the data received over the socket. This is the data I am sending to authenticate.
char authenticate[] = {
0x31, 0x31, 0x31, 0x31, 0x88, 0x00, 0x00, 0x00,
0x01, 0x01, 0x00, 0x00, 0x88, 0x7d, 0xa6, 0x47,
0x0c, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x61, 0x64, 0x6d, 0x69, 0x6e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x31, 0x32, 0x33, 0x34,
0x35, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x43, 0x6f, 0x6c, 0x74, 0x6f, 0x6e, 0x73, 0x2d,
0x4d, 0x61, 0x63, 0x42, 0x6f, 0x6f, 0x6b, 0x2d,
0x50, 0x72, 0x6f, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
0x6c, 0x00, 0x00, 0x00, 0x35, 0x34, 0x32, 0x36,
0x39, 0x36, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00
};
x = sendto(sockfd, authenticate, sizeof(authenticate), 0,
(struct sockaddr*)&servaddr, sizeof(servaddr));
I am then recieving the data with
while(1)
{
n = recvfrom(sockfd, data, 2048, 0, NULL, NULL);
When I connect via http port 80 This is the image data that I receive:
Content-length: 2153
Content-type: image/jpeg
ˇÿˇ‡JFIFHHˇ€Cˇ€Cˇ¿#ˇƒ
ˇƒ8 2A!$X"#3QRTqëîóò“’÷ˇƒˇƒ#
!1A"2QRqrë#SacÅ°¢≥—“ÒBCstÇí¥”ˇ⁄ ?e›n◊}mÀ⁄ÔÅ≥j¿ò[0ÂáֱNU…9'*‚®#ô &yéïùr‰Ù®{ï“däŒÆl$Kkë R,√fƒSl—EX
z \û£≠âflüÈ‚≠ê*àÉ*—1E;q}Ìp6#>øÆÂòŸR≠^Ì˝çò ı;R∆b¡»ü>aÊ∫a˙5KKüz∑¶Î´D“≤κl∂ÎÓ„∆Àn∫¥•sh8vß4≠äöûñy‰H¢çyºí0TQrÏ#π dÅèåfi*XY*F¨Óƒl™¢‰˝S^sgh]î…flzXNü‡†2∑ñæ5t€Tp`qìåos◊iGùjˆ˙+FÈ™‚‘_§≈[”Jˇ *•<*´∆≥ÁpVGfl
ï¶ñ—€{ñgíJmd*ôï„å[YT-J†∞π∂¯ë…{¶dyÓaÓhå©!øg⁄∆™≤È:
≥Ô`Mú)∞ÚÌǯhˇÿ„Tø∑,9˛õ°˛ıØö~ø«ûÔ˝˙aa{ÜÔû÷Èé‡ÂΩk÷ºµ\sÉÒ¬XÓ∞`¯⁄X“">eäÅœ»G¡ìöÜ"˘mütòÅtuÓbÌh;vB1dflL ∂)
´È
Hm∂Í
Ω¡î*Ä≤e‘nÄï‘HΩ…77ÙIè6%â%ãµ"T¿n¢Í3%‹zj#™:”ÂmR˛=L ZsZ[_ïz±»r…™2®ú.«]∑$q¢1)ùftÙ˘îà[q£°Îü&%Ï÷#á∂¿ôEy!ËÇJ0‚‚j»¥|∆fi–ü5"èRj›D˘„õUäú≥û>•«bdôãq]Ö$2ˆ„Gc#,ó±Ò<√-p}ZÍSÛ £ëóŒsäóNçı≠◊òÊö•mÈÇ_W„Y2∆∫9œxπŸ¸*±’dË⁄1(¸05{üfW∆Éû
‘ÿSÑ‘„û.JTÓ9˙Ìø˝∆º=∆ ¬ï∆h≥!`uˆ’Uçõèd„Ï…ı®*GÕıŸ6iíÆiñ¶’ØmBë‰WáÈö˛â‚ı∞>Ó˛◊_Â’ˇπ?º”˘øh~8TÔÕ/ùˆO¬Ewü^◊]…6
ÕïÊ«p2ˆ◊ä”õU÷ËÖˆ◊䲲ãk–«_2ûk4Éÿ‰aÖƒîP∑ùg⁄†·¢µ’ÂS÷}XNï¯5GWæßGk”óS8fòˇ;˝âp;≈“ƒ5ˇ˜„Éû·&Áa¨ö2tÿ±íÉìcÇeÓ"¬Â„(8¯:øØíM £rmfiá~≠æ(:oT/U≤/täó U√ñT0ëªÕ ê’¢víRT#˙‚ìO7ÖÆÒ‘D<dm#;F®—yÑmPǃ5É+FZÀ"8≥-˙7"ç–ãm{Å∑Öunü»à·®icëcoDìf¬·ñ)!å A¡ñÂNrx√aeP\ZM®£ ‘Y\<kJÿ‚’Ó#„Œª+â3
¨π©%Uü±Àñ¨œò§S2àŸßUJjwûYãZ#Ç∆˚¶&hr⁄xj¬ì È™sàK-… 28Fm‡Ôr√û 8Qè
ª∑ØP ptt£‚N—Œ∆Iπ ıo«Y{Èe.U[´‰•ı∫ÎæöÙU’‘…)¶Gy
†“ä]ãä6U≤Å∞b 7X„ ™˙#ÓMÖ∑>_ó
=fiÔ>·π∂ˇ÷ãÎΩfl«Y!µÎô≥—ß;¨J™èΩ|tLoîRˇM›.#nŸÍ±≈±Ê∏Ï~qkãsv≈Xõ‰í∞Lπ/cR,j*6.Sí„ÿ˘fÑ»7f|_™≥RçÿíE°°bã {{Ïõç#·Ãæ:7çú√´u o
⁄N¨Ω\€ù◊K,Z4àÕ8N\˙πÍë’D∫vbfl∏¢>äz.¸¨⁄Ä‘°dx≈ªàˆÕ45‡ßõub-ü%TVTN8⁄∞¨≤µÁñÜD[;o—˘ƒNˇóóØ[ò;´¡O*∫¿ƒ©∏2ߘG#20˘H∆µªú’2€∂O°Â⁄Ùb®äÌ/hÿQÁXÓŸJzB¬Öw]Ù2ÿ—⁄§∆«gÜö·´˚Ëãt‚+˛Iì¯∂⁄nÎ{ºVʬ)aà∆´°ÀÚËÃkr÷â„ç^1©ôæ
óv'ô8∆ãπkB˙цπ¯zÉsÀpv;Ã]ÓI€[Ìj/˙A≤øÒ}O˚ËS|Dûƒˇ¶3=ÓÍæ6?Ú…å!¥›¨Ûˆ¸f…€·I~à≥ g>∆®‰√Û0≥30®Æ) èMÖçGÃ∑dÑÖ∞¥Œéf≥ÔyµE¢Yå.õ·ç+r˙ú ≤ZÄP ‰y¨Km⁄±~ävfl¡'I+b»Ñî[ö<¬ æñ8raEãk
I am unsure if this data is some weird encoding or if it need to be processed somehow to make it valid. I have searched around with no luck or examples of how to properly do this. If i connect via the data port (port 5000 which sends via instead of an image) the data looks pretty much the same although i know it may be processed or unprocessed H.246 video data.
The raw data is an image. It starts after the blank line which terminate the headers.
Code:
n = recvfrom(sockfd, data, 2048, 0, NULL, NULL); // might as well replace with read().
// use a much larger buffer, ideally large enough to fit largest possible whole image
headers_end_str = "\r\n\r\n";
headers_end_position = strstr(data, headers_end_str);
headers_end_position += strlen(headers_end_str );
if (headers_end_position > n) { ... } // handle errors
FILE* fh = fopen("image.jpg", "wb");
int result = fwrite( &( data[ headers_end_position ), n - headers_end_position, 1, fh);
// check result for errors
// continue reading from socket and writing to file, subsequent reads do not have headers
This should get you started, you need to fine tune reading additional data, and also error handling and end of file.
However, even before you have done all that, you should be able to run "file -s image.jpg" (on linux, or cygwin) and it will tell you it's a JPEG image.
I used WireShark to monitor the communication between the DVR and it's web browser plugin client and the authentication message header is similar to your post (0x31 0x31 0x31 0x31...). How did you construct this array? I searched a lot for this protocol documentation but I didn't find.
In my case I do the requests at port 7171 (it's a DVR settings). I also used a while(true) to keep listening this port and the server sends me a h264 stream.
The problem is that the stream is not like rtps protocol describes, see this great post. In our case we have to parse a kind of proprietary header first (that starts with 0x31 0x31 0x31 0x31) to stract the frame, sps and pps.

Use NSTextfield data to build an array of integers?

Im using the following code to send a hex string to an NSStreamoutput:
uint8_t mirandaroutecommand[] = { 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x30, 0x14 };
NSData *data = [[NSData alloc] initWithBytes:mirandaroutecommand length:sizeof(mirandaroutecommand)];
[hextooloutputStream write:[data bytes] maxLength:[data length]];
This works great but the problem is I need these hex values to come from NSTextfields on the user interface. I've tried to convert the NSTextfield data to an integer but that didn't work. Is there a way to use data from several NSTextfields to build an array of integers using hex values?
I've tried to find an existing topic covering this but I've had no luck.
The NSString methods integerValue and intValue assume a decimal representation and ignore and trailing gumph - so apply them to #"0x01" and they see 0 followed by some gumph (x01) which they ignore.
To read a hex value use NSScanner's scanHexInt: (or scanHexLongLong:):
unsigned scannedHexValue;
if ([[NSScanner scannerWithString:textFieldContents] scanHexInt:&scannedHexValue])
{
// value found
...
}
NSScanner is more powerful than just parsing a single value, so with the appropriate method calls you can scan a comma separated list of hex values if you wish.

How to "replay" wireshark c-array in perl or C

How would one go about taking hex data into a program and sending it back out?
char peer0_0[] = {
0x00, 0x00, 0x10, 0x01, 0xbf, 0x8b, 0xf9, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x07 };
char peer0_1[] = {
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04 };
char peer0_2[] = {
0x02, 0x00, 0x00, 0x00 };
If you already have the code in the format you have posted, then there's not much to do. You haven't actually specified where you want to replay it. Depending on how you want to do this, you simply pass the array to whatever function does the actual sending. For example, if you want to send this data over an existing socket, you can do something like this:
send(my_socket, peer0_0, sizeof(peer0_0), 0);
What you want is bit-twist. It is essentially a replay device for pcap files. You don't have to save the file in any special format, it can be used with the native file format wireshark captures data in.
http://bittwist.sourceforge.net/

Resources