Scarica il sorgente database/2001-http_download_v0.01.05.cpp
  1. #include "http_download.h"
  2.  
  3. http_download::http_download(){
  4.  
  5. file_size = 0;
  6. buffer_size = 0;
  7. multidownload = 0;
  8. status = HD_STATUS_UNINITIALIZED;
  9.  
  10. is_range_accepted = 0;
  11. is_size_comunicated = 0;
  12.  
  13. //variabili di comunicazione interna
  14. luncher_ready_to_pause = 0;
  15. luncher_ready_to_stop = 0;
  16. vanilla_ready_to_stop = 0;
  17.  
  18. }
  19.  
  20. http_download::~http_download(){
  21.  
  22. }
  23.  
  24. int http_download::initialize(char *_url, char *_file, int _multidownload){
  25.  
  26. int x;
  27.  
  28. if(status != HD_STATUS_UNINITIALIZED)
  29. return 0;
  30. if(_multidownload<0)
  31. return 0;
  32.  
  33. //url
  34. strncpy(url, _url, strlen(_url)+1);
  35.  
  36. //file
  37. strncpy(file, _file, strlen(_file)+1);
  38.  
  39. //host
  40. for(x=7; x<(int)strlen(_url) ;x++)
  41. if(_url[x] == '/'){
  42. break;
  43. }
  44. strncpy(host, &url[7], x-7);
  45. host[x-7] = '\0';
  46.  
  47. //host_url
  48. strncpy(host_url, &url[x], strlen(_url)-x+1);
  49. host_url[strlen(_url)-x+1] = '\0';
  50.  
  51. //multidownload
  52. multidownload = _multidownload;
  53.  
  54. //porta http
  55. porta = HD_HTTP_DEFAULT_PORT;
  56.  
  57. //download buffer size
  58. buffer_size = HD_DOWNLOAD_BUFFER_DEFAULT_SIZE;
  59.  
  60. //aggiornamento status
  61. status = HD_STATUS_INITIALIZED;
  62.  
  63. return 1;
  64. }
  65.  
  66. int http_download::settings(long _buffer_size, int _porta_http){
  67.  
  68. if(status == HD_STATUS_INITIALIZED){
  69.  
  70. if(_buffer_size != 0)
  71. buffer_size = _buffer_size;
  72.  
  73. if(_porta_http != 0)
  74. porta = _porta_http;
  75.  
  76. return 1;
  77.  
  78. }
  79. else{
  80. #ifdef DEBUG_MODE
  81. printf("WARNING settings(): l'oggetto non è nello status HD_STATUS_INITIALIZED\n");
  82. #endif
  83.  
  84. return 0;
  85. }
  86.  
  87. }
  88.  
  89. int http_download::start(){
  90.  
  91. long x;
  92. DWORD thread_id;
  93.  
  94. //controllo dello status (che deve essere HD_STATUS_INITIALIZED) prima di procedere
  95. if(status != HD_STATUS_INITIALIZED){
  96. #ifdef DEBUG_MODE
  97. printf("WARNING start(): You are not in the right status.\n");
  98. #endif
  99. return 0;
  100. }
  101.  
  102. /*ci connettiamo al server con la funzione hd_connessione_asincrona_header per ricevere
  103. info sul file e controllare che effettivamente esista, il ciclo serve per seguire le
  104. redirezioni (302 found) fino a quando non si trova il vero indirizzo*/
  105. while(status == HD_STATUS_FILE_REDIRECTED || status == HD_STATUS_INITIALIZED){
  106.  
  107. hd_connessione_header(this);
  108.  
  109. //controlliamo i possibili errori
  110. if(status == HD_STATUS_PROTOCOL_NOT_HTTP11){
  111. #ifdef DEBUG_MODE
  112. printf("ERROR start(): HD_STATUS_PROTOCOL_NOT_HTTP11\n");
  113. #endif
  114. return 0;
  115. }
  116. if(status == HD_STATUS_FILE_NOT_FOUND){
  117. #ifdef DEBUG_MODE
  118. printf("start(): HTTP PROTOCOL 404: HD_STATUS_FILE_NOT_FOUND\n");
  119. #endif
  120. return 0;
  121. }
  122. if(status == HD_STATUS_HTTP_CODE_NOT_RECOGNIZED){
  123. #ifdef DEBUG_MODE
  124. printf("ERROR start(): HD_STATUS_HTTP_CODE_NOT_RECOGNIZED, forse non supportato\n");
  125. #endif
  126. return 0;
  127. }
  128.  
  129. }
  130.  
  131. /*se il server ci ha comuncato la grandezza del file da scaricare allora controlliamo
  132. se il server accetta il range, se lo accetta procediamo al multidownload e possibilità
  133. di pausa, se non lo accetta allora dobbiamo fare un download normale*/
  134. if(is_size_comunicated){
  135. #ifdef DEBUG_MODE
  136. printf("start(): File size: %d bytes\n",file_size);
  137. #endif
  138.  
  139. /*il server non ci ha comunicato di accettare i range, ma non tutte le speranze sono perdute
  140. perche il server non è obbligato a comunicarci la disponibilità del servizio: possiamo
  141. inviare al server una richiesta con range per vedere se il servizio effettivamente esiste*/
  142. if(!is_range_accepted){
  143.  
  144. //inviamo una richiesta con range sperando di rivere un 206 PARTIAL CONTENT
  145. hd_connessione_header_partial_content(this);
  146.  
  147. }
  148.  
  149. /*se il server accetta il range-bytes allora possiamo spezzare il download in piu segmenti*/
  150. if(is_range_accepted){ //range accettato
  151. #ifdef DEBUG_MODE
  152. printf("start(): Accept-Ranges: bytes\n");
  153. #endif
  154.  
  155. //prepariamo matrice dati per il multidownload
  156. multidownload_points.create_with_value(multidownload+1, 3, 0);
  157. for(x=0; x<multidownload; x++){
  158. multidownload_points[x][0] = (file_size/multidownload)*x; //impostiamo punto di partenza segmento
  159. multidownload_points[x][1] = multidownload_points[x][0]; //impostiamo punto attuale del segmento
  160. }
  161. multidownload_points[multidownload][0] = file_size;
  162.  
  163. #ifdef DEBUG_MODE
  164. printf("start(): multidownload possibile, segmenti %d\n", multidownload);
  165. #endif
  166.  
  167. if(multidownload == 0)
  168. //se è preteso, avviamo un download normale, senza multidownload ne pausa
  169. CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) hd_connessione_download_vanilla, this, 0, &thread_id);
  170. else
  171. //avviamo in modo asincrono la funzione che si occuperà di avviare il multidownload
  172. CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) hd_multidownload_luncher, this, 0, &thread_id);
  173.  
  174. }
  175. else{ //range non accettato
  176.  
  177. //senza range, avviamo un download normale, senza multidownload ne pausa
  178. CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) hd_connessione_download_vanilla, this, 0, &thread_id);
  179.  
  180. }
  181. }
  182. else{ //file size non comunicato
  183. #ifdef DEBUG_MODE
  184. printf("start(): File size not comunicated :(\n",file_size);
  185. #endif
  186.  
  187. //senza grandezza file, avviamo un download normale, senza multidownload ne pausa
  188. CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) hd_connessione_download_vanilla, this, 0, &thread_id);
  189.  
  190. }
  191.  
  192. return 1;
  193. }
  194.  
  195. int http_download::stop(){
  196. long x,y;
  197.  
  198. if(status == HD_STATUS_DOWNLOADING){
  199. status = HD_STATUS_STOPPED;
  200.  
  201. while(!vanilla_ready_to_stop)
  202. Sleep(10);
  203. vanilla_ready_to_stop = 0;
  204.  
  205. //qui devo cancellare il file dove sono stati scaricati i dati
  206.  
  207. status = HD_STATUS_UNINITIALIZED;
  208.  
  209. return 1;
  210. }
  211. else if(status == HD_STATUS_MULTIDOWNLOADING || status == HD_STATUS_PAUSED
  212. || status == HD_STATUS_SAVED){
  213. status = HD_STATUS_STOPPED;
  214.  
  215. //controlliamo ed eventualmente aspettiamo che i download parziali siano tutti terminati
  216. while(1){
  217. y=0;
  218. for(x=0;x<multidownload;x++)
  219. if(multidownload_points[x][2] == 0)
  220. y++;
  221. if(y==multidownload)
  222. break;
  223. Sleep(10);
  224. }
  225.  
  226. //aspettiamo che luncher abbia ricevuto il segnale
  227. while(1){
  228. if(luncher_ready_to_stop == 1)
  229. break;
  230. Sleep(10);
  231. } luncher_ready_to_stop = 0;
  232.  
  233. //togliamo le cose che vanno tolte e resettiamo alcune variabili
  234. multidownload_points.~matrice();
  235. file_size = 0;
  236. is_range_accepted = 0;
  237. is_size_comunicated = 0;
  238.  
  239. luncher_ready_to_pause = 0;
  240. luncher_ready_to_stop = 0;
  241. vanilla_ready_to_stop = 0;
  242.  
  243. /*qui si dovranno cancellare i file temporanei, ma se si è in stato
  244. HD_STATUS_SAVED vanno lasciati ;)*/
  245.  
  246. status = HD_STATUS_INITIALIZED;
  247.  
  248. return 1;
  249. }
  250. else{
  251. #ifdef DEBUG_MODE
  252. printf("WARNING stop(): non si puo usare stop() in questa situazione.\n",file_size);
  253. #endif
  254. return 0;
  255. }
  256. }
  257.  
  258. int http_download::pause(){
  259.  
  260. if(status != HD_STATUS_MULTIDOWNLOADING){
  261. #ifdef DEBUG_MODE
  262. printf("WARNING pause(): puo essere usata solo in stato HD_STATUS_MULTIDOWNLOADING\n",file_size);
  263. #endif
  264. return 0;
  265. }
  266.  
  267. status = HD_STATUS_PAUSED;
  268.  
  269. /*ora attendiamo che la funzione asincrona incaricata della gestione del multidownload, che è
  270. hd_multidownload_luncher(), rilevi la chiusura dei download parziali e si metta a sua volta in pausa.
  271. questo meccanismo serve per non terminare il metodo pause() prima che la pausa non sia avvenuto
  272. a tutti gli effetti. In questo senso la funzione pause() è "bloccante"
  273. di modificare la variabile luncher_ready_to_pause se ne occupa solamente hd_multidownload_luncher()*/
  274. while(!luncher_ready_to_pause)
  275. Sleep(50);
  276.  
  277. #ifdef DEBUG_MODE
  278. printf("pause(): pausa bloccante avvenuta con successo.\n");
  279. #endif
  280.  
  281. return 1;
  282. }
  283.  
  284. int http_download::resume(){
  285.  
  286. if(status != HD_STATUS_PAUSED){
  287. #ifdef DEBUG_MODE
  288. printf("WARNING resume(): puo essere usata solo in stato HD_STATUS_PAUSED\n",file_size);
  289. #endif
  290. return 0;
  291. }
  292.  
  293. /*di riavviare tutto si occuperà hd_multidownload_luncher()*/
  294. status = HD_STATUS_RESUME;
  295.  
  296. return 1;
  297. }
  298.  
  299. int http_download::save(){
  300. long x,y;
  301.  
  302. char *_file_matrice;
  303. char *_main_content;
  304. FILE *main;
  305.  
  306. /*la funzione save() è possibile solo nello stato HD_STATUS_PAUSED*/
  307. if(status != HD_STATUS_PAUSED){
  308. #ifdef DEBUG_MODE
  309. printf("WARNING save(): puo essere usata solo in stato HD_STATUS_PAUSED\n",file_size);
  310. #endif
  311. return 0;
  312. }
  313. //controlliamo ed eventualmente aspettiamo che i download parziali siano tutti terminati
  314. while(1){
  315. y=0;
  316. for(x=0;x<multidownload;x++)
  317. if(multidownload_points[x][2] == 0)
  318. y++;
  319. if(y==multidownload)
  320. break;
  321. Sleep(10);
  322. }
  323.  
  324. //salviamo la matrice multidownload_points
  325. _file_matrice = new char[10000];
  326. sprintf(_file_matrice,"%s.points",file);
  327. multidownload_points.save_in_file(_file_matrice);
  328.  
  329. //salviamo i dati principali
  330. _main_content = new char[100000];
  331.  
  332. main = fopen(file, "wb");
  333.  
  334. //scriviamo magic number
  335. fwrite("HD_FILE\0", 1, 8, main);
  336. //scriviamo url
  337. fwrite(url, 1, strlen(url)+1, main);
  338. //scriviamo porta
  339. itoa(porta, _file_matrice, 10); //utilizziamo _file_matrice come buffer visto che non ci serve piu ;)
  340. fwrite(_file_matrice, 1, strlen(_file_matrice)+1, main);
  341.  
  342. fclose(main);
  343.  
  344. delete [] _file_matrice;
  345. delete [] _main_content;
  346.  
  347. status = HD_STATUS_SAVED;
  348.  
  349. //alla fine del salvataggio stoppiamo il download
  350. stop();
  351.  
  352. return 1;
  353. }
  354.  
  355. int http_download::load(char *_load_file){
  356. long x,y;
  357.  
  358. char *_load_file_matrice;
  359. char *_url;
  360. char *_porta;
  361.  
  362. FILE *load_file_stream;
  363. char *buffer;
  364. long lbuffer;
  365.  
  366. if(status != HD_STATUS_UNINITIALIZED){
  367. #ifdef DEBUG_MODE
  368. printf("WARNING load(): puo essere usata solo in stato HD_STATUS_UNINITIALIZED\n");
  369. #endif
  370. return 0;
  371. }
  372.  
  373. if(hd_is_file(_load_file) == 0){ //controllo esistenza file
  374. #ifdef DEBUG_MODE
  375. printf("ERROR load(): file non esite :(\n");
  376. #endif
  377. return 0;
  378. }
  379.  
  380. _load_file_matrice = new char[10000];
  381. sprintf(_load_file_matrice,"%s.points",_load_file);
  382.  
  383. if(hd_is_file(_load_file_matrice) == 0){ //controllo esistenza file matrice
  384. #ifdef DEBUG_MODE
  385. printf("ERROR load(): file matrice non esite :(\n");
  386. #endif
  387. delete [] _load_file_matrice;
  388. return 0;
  389. }
  390.  
  391. load_file_stream = fopen(_load_file, "rb");
  392. fseek(load_file_stream, 0, SEEK_END);
  393. lbuffer = ftell(load_file_stream);
  394. rewind(load_file_stream);
  395. buffer = new char[lbuffer];
  396. fread(buffer, 1, lbuffer, load_file_stream);
  397. fclose(load_file_stream);
  398.  
  399. if(strncmp(buffer, "HD_FILE", 7) != 0){ //controllo il magic number
  400. #ifdef DEBUG_MODE
  401. printf("ERROR load(): magic number non corrisponde, non posso aprirlo :(\n");
  402. #endif
  403. delete [] _load_file_matrice;
  404. delete [] buffer;
  405. return 0;
  406. }
  407.  
  408. y=0;
  409. for(x=0;x<lbuffer;x++){
  410. if(buffer[x] == '\0')
  411. y++;
  412. if(y==2)
  413. break;
  414. }
  415. y=x;
  416.  
  417. _url = &buffer[8];
  418. _porta = &buffer[x+1];
  419.  
  420. //carico multidownload_points
  421. multidownload_points.load_from_file(_load_file_matrice);
  422. //carico multidownload
  423. multidownload = multidownload_points.rows()-1;
  424. //carico file
  425. sprintf(file,"%s",_load_file);
  426. //carico url
  427. strncpy(url, _url, strlen(_url)+1);
  428. //carico host
  429. for(x=7; x<(int)strlen(_url) ;x++)
  430. if(_url[x] == '/'){
  431. break;
  432. }
  433. strncpy(host, &_url[7], x-7);
  434. host[x-7] = '\0';
  435. //carico host_url
  436. strncpy(host_url, &url[x], strlen(_url)-x+1);
  437. host_url[strlen(_url)-x+1] = '\0';
  438. //carico porta
  439. porta = atoi(_porta);
  440. //download buffer size
  441. buffer_size = HD_DOWNLOAD_BUFFER_DEFAULT_SIZE;
  442. //aggiornamento status
  443. status = HD_STATUS_INITIALIZED;
  444.  
  445. delete [] buffer;
  446. delete [] _load_file_matrice;
  447.  
  448. return 1;
  449. }
  450.  
  451. int http_download::backup(char *_save_file){
  452.  
  453. //long x;
  454. //partial_download_data *_dati_multidownload;
  455.  
  456. ////creiamo la struttura partial_download_data
  457. //_dati_multidownload = new partial_download_data[multidownload];
  458.  
  459. //for(x=0;x<multidownload;x++){ //carichiamo i dati che ci servono nella struttura
  460. // _dati_multidownload[x].id_segmento = x;
  461. // _dati_multidownload[x].file_parziale = new char[strlen(file)+5];
  462. // sprintf(_dati_multidownload[x].file_parziale,"%s.%03d",file,x);
  463. //}
  464.  
  465. return 1;
  466. }
  467.  
  468. int http_download::get_status(){
  469. return status;
  470. }
  471.  
  472. int http_download::print(){
  473.  
  474. if(status == HD_STATUS_UNINITIALIZED){
  475. #ifdef DEBUG_MODE
  476. printf("WARNING print(): non puoi eseguire a HD_STATUS_UNINITIALIZED.\n");
  477. #endif
  478. return 0;
  479. }
  480.  
  481. printf("file: %s\n", file);
  482. printf("url: %s\n", url);
  483. printf("host: %s\n", host);
  484. printf("host_url: %s\n", host_url);
  485. printf("porta: %d\n", porta);
  486. printf("download: %d\n", multidownload);
  487. multidownload_points.print();
  488.  
  489. return 1;
  490. }
  491.  
  492. int hd_connessione_download_vanilla(http_download *download){
  493.  
  494. long x=0;
  495.  
  496. struct sockaddr_in indirizzo;
  497. struct hostent *ip;
  498. WORD socket_version;
  499. WSADATA socket_data;
  500. SOCKET sock;
  501. int sock_err;
  502.  
  503. char *richiesta_http;
  504. char *risposta_http;
  505. char header_buffer;
  506.  
  507. FILE *file_stream;
  508. long downloaded_bytes, written_bytes, total_written_bytes=0, total_downloaded_bytes=0;
  509. char *download_buffer;
  510. long _buffer_size = download->buffer_size;
  511.  
  512. //verifichiamo che l'oggetto download sia pronto
  513. if(download->status != HD_STATUS_FILE_OK){
  514. #ifdef DEBUG_MODE
  515. printf("WARNING hd_connessione_download_vanilla(): not the right status.\n");
  516. #endif
  517. return 0;
  518. }
  519.  
  520. //avviamo socket
  521. socket_version = MAKEWORD(2, 2);
  522. WSAStartup(socket_version, &socket_data); //attiva la lib winsock 2.2
  523.  
  524. //dati per la connessione
  525. ip = gethostbyname(download->host);
  526. indirizzo.sin_family = AF_INET; //tipo di indirizzo
  527. indirizzo.sin_port = htons(download->porta); //porta in cui è in ascolto server HTTP
  528. memcpy(&indirizzo.sin_addr, ip->h_addr, ip->h_length); //copia l'indirizzo nella struttura indirizzo
  529.  
  530. //richiesta HTTP
  531. richiesta_http = new char[10000];
  532. sprintf(richiesta_http,"GET %s HTTP/1.1\n"\
  533. "host: %s\n"\
  534. "Keep-Alive: 300\n"\
  535. "Connection: keep-alive\n"\
  536. "\n\0"\
  537. , download->host_url, download->host);
  538.  
  539. #ifdef DEBUG_MODE
  540. printf("%s\n",richiesta_http);
  541. #endif
  542.  
  543. //ci connettiamo
  544. sock = socket(AF_INET, SOCK_STREAM, 0);
  545. sock_err = connect(sock, (struct sockaddr *)&indirizzo, sizeof(indirizzo));
  546. if(!sock || sock_err != 0){
  547. #ifdef DEBUG_MODE
  548. printf("ERROR hd_connessione_download_vanilla(): socket: %d connect: %d\n", sock, sock_err);
  549. #endif
  550. return 0;
  551. }
  552.  
  553. //mandiamo richiesta HTTP
  554. send(sock, richiesta_http, strlen(richiesta_http)+1, 0);
  555.  
  556. //riceviamo risposta: header HTTP
  557. risposta_http = new char[10000];
  558. while(
  559. recv(sock, &header_buffer, 1, 0) != 0
  560. ){
  561. risposta_http[x] = header_buffer;
  562. x++;
  563.  
  564. if(risposta_http[x-1] == '\x0a' && risposta_http[x-3] == '\x0a')//controllo per vedere se l'header è finito
  565. break;
  566. }
  567. risposta_http[x] = '\0';
  568.  
  569. #ifdef DEBUG_MODE
  570. printf("%s\n",risposta_http);
  571. #endif
  572.  
  573. //controlliamo header HTTP ricevuto in risposta
  574. if( strncmp("HTTP/1.1", risposta_http, 8) != 0 ){ //controlliamo che il protocollo sia HTTP/1.1
  575. download->status = HD_STATUS_PROTOCOL_NOT_HTTP11;
  576.  
  577. delete [] richiesta_http;
  578. delete [] risposta_http;
  579.  
  580. shutdown(sock, 2);
  581. closesocket(sock);
  582. WSACleanup();
  583.  
  584. return 0;
  585. }
  586.  
  587. if( strncmp("200", &risposta_http[9], 3) == 0 ){ //verifichiamo se tutto ok e iniziamo a scaricare
  588.  
  589. download->status = HD_STATUS_DOWNLOADING;
  590.  
  591. download_buffer = new char[_buffer_size]; //alloco la memoria per il buffer
  592. file_stream = fopen(download->file, "wb"); //apro il file in cui salvare i dati
  593.  
  594. //riceviamo risposta: file
  595. while (1){ //prendiamo il file un po alla volta
  596. downloaded_bytes = recv(sock, download_buffer, _buffer_size, 0);
  597.  
  598. if(!(downloaded_bytes > 0))
  599. break;
  600.  
  601. written_bytes = fwrite(download_buffer, 1, downloaded_bytes, file_stream); //scrivo i dati
  602. total_written_bytes += written_bytes;
  603. total_downloaded_bytes += downloaded_bytes;
  604.  
  605. #ifdef DEBUG_MODE
  606. printf("d:%d w:%d\n",total_downloaded_bytes,total_written_bytes);
  607. #endif
  608.  
  609. if(download->status == HD_STATUS_STOPPED){ //controlliamo di non aver ricevuto l'ordine di fermarci
  610. download->vanilla_ready_to_stop = 1;
  611. break;
  612. }
  613. }
  614.  
  615. fclose(file_stream); //chiudiamo file
  616. delete [] download_buffer; //disallochiamo buffer
  617.  
  618. }
  619. else{
  620. download->status = HD_STATUS_HTTP_CODE_NOT_RECOGNIZED;
  621.  
  622. delete [] richiesta_http;
  623. delete [] risposta_http;
  624.  
  625. shutdown(sock, 2);
  626. closesocket(sock);
  627. WSACleanup();
  628.  
  629. return 0;
  630. }
  631.  
  632. delete [] richiesta_http;
  633. delete [] risposta_http;
  634.  
  635. shutdown(sock, 2);
  636. closesocket(sock);
  637. WSACleanup();
  638.  
  639. /*questo controllo serve per fare in modo di non segnare come HD_STATUS_DOWNLOAD_COMPLETED
  640. un oggetto che invece è stato stoppato ed è in status HD_STATUS_STOPPED*/
  641. if(download->status == HD_STATUS_DOWNLOADING)
  642. download->status = HD_STATUS_DOWNLOAD_COMPLETED;
  643.  
  644. return 1;
  645. }
  646.  
  647. int hd_connessione_header_partial_content(http_download *download){
  648. long x=0;
  649.  
  650. struct sockaddr_in indirizzo;
  651. struct hostent *ip;
  652. WORD socket_version;
  653. WSADATA socket_data;
  654. SOCKET sock;
  655. int sock_err;
  656.  
  657. char *richiesta_http;
  658. char *risposta_http;
  659. char header_buffer;
  660.  
  661. //verifichiamo che la richiesta partial content sia inviata con status HD_STATUS_FILE_OK
  662. if(download->status != HD_STATUS_FILE_OK){
  663. #ifdef DEBUG_MODE
  664. printf("WARNING hd_connessione_header_partial_content(): not the right status.\n");
  665. #endif
  666. return 0;
  667. }
  668.  
  669. //avviamo socket
  670. socket_version = MAKEWORD(2, 2);
  671. WSAStartup(socket_version, &socket_data); //attiva la lib winsock 2.2
  672.  
  673. //dati per la connessione
  674. ip = gethostbyname(download->host);
  675. indirizzo.sin_family = AF_INET; //tipo di indirizzo
  676. indirizzo.sin_port = htons(download->porta); //porta in cui è in ascolto server HTTP
  677. memcpy(&indirizzo.sin_addr, ip->h_addr, ip->h_length); //copia l'indirizzo nella struttura indirizzo
  678.  
  679. //richiesta HTTP partial download
  680. richiesta_http = new char[10000];
  681. sprintf(richiesta_http,"GET %s HTTP/1.1\n"\
  682. "host: %s\n"\
  683. "Keep-Alive: 300\n"\
  684. "Connection: keep-alive\n"\
  685. "Range: bytes=1-\n"\
  686. "\n\0"\
  687. , download->host_url, download->host);
  688.  
  689. #ifdef DEBUG_MODE
  690. printf("%s\n",richiesta_http);
  691. #endif
  692.  
  693. //ci connettiamo
  694. sock = socket(AF_INET, SOCK_STREAM, 0);
  695. sock_err = connect(sock, (struct sockaddr *)&indirizzo, sizeof(indirizzo));
  696. if(!sock || sock_err != 0){
  697. #ifdef DEBUG_MODE
  698. printf("ERROR hd_connessione_header_partial_content(): socket: %d connect: %d\n", sock, sock_err);
  699. #endif
  700. return 0;
  701. }
  702.  
  703. //mandiamo richiesta HTTP
  704. send(sock, richiesta_http, strlen(richiesta_http)+1, 0);
  705.  
  706. //riceviamo risposta: header HTTP
  707. risposta_http = new char[10000];
  708. while(
  709. recv(sock, &header_buffer, 1, 0) != 0
  710. ){
  711. risposta_http[x] = header_buffer;
  712. x++;
  713.  
  714. if(risposta_http[x-1] == '\x0a' && risposta_http[x-3] == '\x0a')//controllo per vedere se l'header è finito
  715. break;
  716. }
  717. risposta_http[x] = '\0';
  718.  
  719. #ifdef DEBUG_MODE
  720. printf("%s\n",risposta_http);
  721. #endif
  722.  
  723. shutdown(sock, 2);
  724. closesocket(sock);
  725. WSACleanup();
  726.  
  727. //controlliamo header HTTP ricevuto in risposta
  728. if( strncmp("HTTP/1.1", risposta_http, 8) != 0 ){ //controlliamo che il protocollo sia HTTP/1.1
  729. download->status = HD_STATUS_PROTOCOL_NOT_HTTP11;
  730.  
  731. delete [] richiesta_http;
  732. delete [] risposta_http;
  733. return 0;
  734. }
  735.  
  736. if( strncmp("206", &risposta_http[9], 3) == 0 ){ //verifichiamo se il download parziale è stato accettato
  737. download->is_range_accepted = 1;
  738. return 1;
  739. }
  740.  
  741. return 1;
  742. }
  743.  
  744. int hd_connessione_header(http_download *download){
  745.  
  746. long x=0,y;
  747.  
  748. struct sockaddr_in indirizzo;
  749. struct hostent *ip;
  750. WORD socket_version;
  751. WSADATA socket_data;
  752. SOCKET sock;
  753. int sock_err;
  754.  
  755. char *richiesta_http;
  756. char *risposta_http;
  757. char header_buffer;
  758.  
  759. //verifichiamo che l'oggetto download sia pronto
  760. if(download->status != HD_STATUS_INITIALIZED
  761. && download->status != HD_STATUS_FILE_REDIRECTED){
  762. #ifdef DEBUG_MODE
  763. printf("WARNING hd_connessione_header(): not the right status.\n");
  764. #endif
  765. return 0;
  766. }
  767.  
  768. //avviamo socket
  769. socket_version = MAKEWORD(2, 2);
  770. WSAStartup(socket_version, &socket_data); //attiva la lib winsock 2.2
  771.  
  772. //dati per la connessione
  773. ip = gethostbyname(download->host);
  774. indirizzo.sin_family = AF_INET; //tipo di indirizzo
  775. indirizzo.sin_port = htons(download->porta); //porta in cui è in ascolto server HTTP
  776. memcpy(&indirizzo.sin_addr, ip->h_addr, ip->h_length); //copia l'indirizzo nella struttura indirizzo
  777.  
  778. //richiesta HTTP
  779. richiesta_http = new char[10000];
  780. sprintf(richiesta_http,"GET %s HTTP/1.1\n"\
  781. "host: %s\n"\
  782. "Keep-Alive: 300\n"\
  783. "Connection: keep-alive\n"\
  784. "\n\0"\
  785. , download->host_url, download->host);
  786.  
  787. #ifdef DEBUG_MODE
  788. printf("%s\n",richiesta_http);
  789. #endif
  790.  
  791. //ci connettiamo
  792. sock = socket(AF_INET, SOCK_STREAM, 0);
  793. sock_err = connect(sock, (struct sockaddr *)&indirizzo, sizeof(indirizzo));
  794. if(!sock || sock_err != 0){
  795. #ifdef DEBUG_MODE
  796. printf("ERROR hd_connessione_header(): socket: %d connect: %d\n", sock, sock_err);
  797. #endif
  798. return 0;
  799. }
  800.  
  801. //mandiamo richiesta HTTP
  802. send(sock, richiesta_http, strlen(richiesta_http)+1, 0);
  803.  
  804. //riceviamo risposta: header HTTP
  805. risposta_http = new char[10000];
  806. while(
  807. recv(sock, &header_buffer, 1, 0) != 0
  808. ){
  809. risposta_http[x] = header_buffer;
  810. x++;
  811.  
  812. if(risposta_http[x-1] == '\x0a' && risposta_http[x-3] == '\x0a')//controllo per vedere se l'header è finito
  813. break;
  814. }
  815. risposta_http[x] = '\0';
  816.  
  817. #ifdef DEBUG_MODE
  818. printf("%s\n",risposta_http);
  819. #endif
  820.  
  821. shutdown(sock, 2);
  822. closesocket(sock);
  823. WSACleanup();
  824.  
  825. //controlliamo header HTTP ricevuto in risposta
  826. if( strncmp("HTTP/1.1", risposta_http, 8) != 0 ){ //controlliamo che il protocollo sia HTTP/1.1
  827. download->status = HD_STATUS_PROTOCOL_NOT_HTTP11;
  828.  
  829. delete [] richiesta_http;
  830. delete [] risposta_http;
  831. return 0;
  832. }
  833.  
  834. if( strncmp("404", &risposta_http[9], 3) == 0 ){ //verifichiamo se si è verificato l'errore 404 not found
  835. download->status = HD_STATUS_FILE_NOT_FOUND;
  836. }
  837. else if( strncmp("302", &risposta_http[9], 3) == 0 ){ //verifichiamo se c'è un redirect con 302 found
  838. download->status = HD_STATUS_FILE_REDIRECTED;
  839.  
  840. //cerchiamo il nuovo indirizzo dentro l'header della risposta
  841. for(x=0; x<(int)strlen(risposta_http) ;x++){ //iniziamo ricerca indirizzo
  842. if(strncmp("\x0aLocation: ", &risposta_http[x], 11)==0){ //se incontriamo la sequenza "\x0aLocation: "
  843. for(y=x+11;;y++){ //leggiamo l'indirizzo
  844. if(risposta_http[y] == '\x0d'){ //fine dell'indirizzo
  845. risposta_http[y] = '\0'; //terminiamo la stringa
  846. break;
  847. }
  848. }
  849. y = x+11; //&risposta_http[y] è diventata la stringa contenente il nuovo indirizzo
  850. break; //abbiamo trovato il nuovo indirizzo, abbandoniamo la ricerca
  851. }
  852. }
  853.  
  854. //modifichiamo l'oggetto in modo da poter scaricare dal nuovo indirizzo
  855. //url
  856. strncpy(download->url, &risposta_http[y], strlen(&risposta_http[y])+1);
  857. //host
  858. for(x=7; x<(int)strlen(&risposta_http[y]) ;x++)
  859. if(risposta_http[y+x] == '/'){
  860. break;
  861. }
  862. strncpy(download->host, &risposta_http[y+7], x-7);
  863. download->host[x-7] = '\0';
  864. //host_url
  865. strncpy(download->host_url, &risposta_http[y+x], strlen(&risposta_http[y])-x+1);
  866. download->host_url[strlen(&risposta_http[y])-x+1] = '\0';
  867.  
  868. }
  869. else if( strncmp("200", &risposta_http[9], 3) == 0 ){ //verifichiamo se siamo pronti al download
  870. download->status = HD_STATUS_FILE_OK;
  871.  
  872. //controlliamo se il server ci ha comunicato la possiblità di usare range bytes
  873. for(x=0; x<(int)strlen(risposta_http) ;x++){ //cerchiamo il messaggio "Accept-Ranges: bytes"
  874. if(strncmp("Accept-Ranges: bytes", &risposta_http[x], strlen("Accept-Ranges: bytes\0"))==0){
  875. download->is_range_accepted = 1;
  876. break;
  877. }
  878. }
  879.  
  880. //controlliamo se il server ci ha detto quanto è grande il file e in tal caso prendiamo il dato
  881. for(x=0; x<(int)strlen(risposta_http) ;x++){ //cerchiamo il messaggio "Content-Lenght: "
  882. if(strncmp("Content-Length: ", &risposta_http[x], strlen("Content-Length: \0"))==0){
  883. download->is_size_comunicated = 1;
  884. for(y=x+strlen("Content-Length: \0");;y++){ //leggiamo il numero
  885. if(risposta_http[y] == '\x0d'){ //fine del numero
  886. risposta_http[y] = '\0'; //terminiamo la stringa
  887. download->file_size = atoi(&risposta_http[x+strlen("Content-Length: \0")]); //preleviamo numero
  888. risposta_http[y] = '\x0d'; //ripristiniamo la stringa
  889. break;
  890. }
  891. }
  892. break;
  893. }
  894. }
  895.  
  896. }
  897. else{ //se riceviamo un codice http che non è previsto dagli if precedenti
  898. download->status = HD_STATUS_HTTP_CODE_NOT_RECOGNIZED;
  899. }
  900.  
  901. delete [] richiesta_http;
  902. delete [] risposta_http;
  903.  
  904. return 1;
  905. }
  906.  
  907. int hd_multidownload_luncher(http_download *download){
  908.  
  909. DWORD thread_id;
  910. long x,stato1,stato2;
  911. partial_download_data *dati_multidownload;
  912.  
  913. dati_multidownload = new partial_download_data[download->multidownload];
  914.  
  915. for(x=0;x<download->multidownload;x++){ //carichiamo i dati che ci servono nella struttura
  916. dati_multidownload[x].id_segmento = x;
  917. dati_multidownload[x].oggetto = (void *) download;
  918. dati_multidownload[x].file_parziale = new char[strlen(download->file)+5];
  919. sprintf(dati_multidownload[x].file_parziale,"%s.%03d",download->file,x);
  920. }
  921.  
  922. for(x=0;x<download->multidownload;x++){ //avviamo i thread asincroni
  923. download->multidownload_points[x][2] = 1;
  924. CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) hd_connessione_multidownload_segmento,
  925. &dati_multidownload[x], 0, &thread_id);
  926. }
  927.  
  928. //segnaliamo che la procedura di multidownload sta iniziando
  929. download->status = HD_STATUS_MULTIDOWNLOADING;
  930.  
  931. while(1){ //ciclo per la gestione dei download parziali
  932. stato1=0;stato2=0;
  933. for(x=0;x<download->multidownload;x++){ //controlliamo i thread uno ad uno
  934.  
  935. //se il thread si è chiuso e lo status lo consente
  936. if(download->multidownload_points[x][2] == 0 && download->status == HD_STATUS_MULTIDOWNLOADING){
  937. download->multidownload_points[x][2] = 1;
  938. CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) hd_connessione_multidownload_segmento,
  939. &dati_multidownload[x], 0, &thread_id); //lo riavviamo
  940. }
  941. else if (download->multidownload_points[x][2] == 2)
  942. stato2++; //contiamo il numero di segmenti terminati
  943. else if (download->multidownload_points[x][2] == 1)
  944. stato1++; //e il numero di segmenti in download
  945.  
  946. }
  947.  
  948. if(stato2 == download->multidownload){ //se tutti i segmenti hanno finito di scaricare
  949. download->status = HD_STATUS_MULTIDOWNLOADING_ASSEMBLING; //segnaliamo che il download è completato
  950. break; //e chiudiamo questo ciclo di controllo
  951. }
  952.  
  953. if(download->status == HD_STATUS_PAUSED){ //controlliamo se siamo in pausa
  954. while(1){
  955. if(download->status == HD_STATUS_RESUME){
  956. download->status = HD_STATUS_MULTIDOWNLOADING;
  957. download->luncher_ready_to_pause = 0;
  958. break;
  959. }
  960.  
  961. //prima di stoppare luncher ci assicuriamo che tutti i parziali si siano fermati
  962. if(download->status == HD_STATUS_STOPPED){
  963. download->luncher_ready_to_pause = 0;
  964. break;
  965. }
  966.  
  967. if(stato1 == 0){ //comunichiamo che la pausa è avvenuta
  968. download->luncher_ready_to_pause = 1;
  969. }
  970.  
  971. stato1=0; //essendo in loop necessitiamo di ciclo alternativo per controllo stato1
  972. for(x=0;x<download->multidownload;x++)
  973. if(download->multidownload_points[x][2] == 1)
  974. stato1++;
  975.  
  976. Sleep(50);
  977. }
  978.  
  979. }
  980.  
  981. if(download->status == HD_STATUS_STOPPED){ //controlliamo se abbiamo ricevuto l'ordine di fermarci
  982. while(1){
  983. //prima di stoppare luncher ci assicuriamo che tutti i parziali si siano fermati
  984. if(download->status == HD_STATUS_STOPPED && stato1 == 0){
  985. download->luncher_ready_to_stop = 1;
  986. break;
  987. }
  988.  
  989. stato1=0; //essendo in loop necessitiamo di ciclo alternativo per controllo stato1
  990. for(x=0;x<download->multidownload;x++)
  991. if(download->multidownload_points[x][2] == 1)
  992. stato1++;
  993.  
  994. Sleep(50);
  995. }
  996. break;
  997. }
  998.  
  999. Sleep(100);
  1000. }
  1001.  
  1002. //se il download è completato assembliamo i file parziali
  1003. if(download->status == HD_STATUS_MULTIDOWNLOADING_ASSEMBLING){
  1004. if(hd_multidownload_files_assembler(download,dati_multidownload) == 1)
  1005. download->status = HD_STATUS_DOWNLOAD_COMPLETED;
  1006. else
  1007. download->status = HD_STATUS_MULTIDOWNLOADING_ASSEMBLING_ERROR;
  1008. }
  1009.  
  1010. delete [] dati_multidownload;
  1011.  
  1012. #ifdef DEBUG_MODE
  1013. printf("hd_multidownload_luncher(): chiusura...\n");
  1014. #endif
  1015.  
  1016. return 1;
  1017. }
  1018.  
  1019. int hd_connessione_multidownload_segmento(partial_download_data *dati){
  1020. long x;
  1021.  
  1022. http_download *download;
  1023. int id = dati->id_segmento; //id del segmento
  1024.  
  1025. download = (http_download *) dati->oggetto; //puntatore all'istanza della nostra classe per il download
  1026. download->multidownload_points[id][2] = 1; //segnaliamo che il processo parziale sta tentando il download
  1027.  
  1028. struct sockaddr_in indirizzo;
  1029. struct hostent *ip;
  1030. WORD socket_version;
  1031. WSADATA socket_data;
  1032. SOCKET sock;
  1033. int sock_err;
  1034.  
  1035. char *richiesta_http;
  1036. char *risposta_http;
  1037. char header_buffer;
  1038.  
  1039. FILE *file_stream;
  1040. long downloaded_bytes, written_bytes, total_downloaded_bytes=0, total_written_bytes=0;
  1041. char *download_buffer;
  1042. long _buffer_size = download->buffer_size;
  1043.  
  1044. //avviamo socket
  1045. socket_version = MAKEWORD(2, 2);
  1046. WSAStartup(socket_version, &socket_data); //attiva la lib winsock 2.2
  1047.  
  1048. //dati per la connessione
  1049. ip = gethostbyname(download->host);
  1050. indirizzo.sin_family = AF_INET; //tipo di indirizzo
  1051. indirizzo.sin_port = htons(download->porta); //porta in cui è in ascolto server HTTP
  1052. memcpy(&indirizzo.sin_addr, ip->h_addr, ip->h_length); //copia l'indirizzo nella struttura indirizzo
  1053.  
  1054. //richiesta HTTP partial download
  1055. //qui impostiamo il punto del file da cui vogliamo i dati e fino a dove li vogliamo
  1056. richiesta_http = new char[10000];
  1057. sprintf(richiesta_http,"GET %s HTTP/1.1\n"\
  1058. "host: %s\n"\
  1059. "Keep-Alive: 300\n"\
  1060. "Connection: keep-alive\n"\
  1061. "Range: bytes=%d-%d\n"\
  1062. "\n\0"\
  1063. , download->host_url, download->host, (long)download->multidownload_points[id][1],
  1064. (long)download->multidownload_points[id+1][0]-1);
  1065.  
  1066. //ci connettiamo
  1067. sock = socket(AF_INET, SOCK_STREAM, 0);
  1068. sock_err = connect(sock, (struct sockaddr *)&indirizzo, sizeof(indirizzo));
  1069. if(!sock || sock_err != 0){
  1070. #ifdef DEBUG_MODE
  1071. printf("ERROR hd_connessione_multidownload_segmento() id %d: socket: %d connect: %d\n", id, sock, sock_err);
  1072. #endif
  1073.  
  1074. download->multidownload_points[id][2] = 0; //segnaliamo che il processo si sta chiudendo
  1075. return 0;
  1076. }
  1077.  
  1078. //mandiamo richiesta HTTP
  1079. send(sock, richiesta_http, strlen(richiesta_http)+1, 0);
  1080.  
  1081. //riceviamo risposta: header HTTP
  1082. risposta_http = new char[10000];
  1083. x=0;
  1084. while(
  1085. recv(sock, &header_buffer, 1, 0) != 0
  1086. ){
  1087. risposta_http[x] = header_buffer;
  1088. x++;
  1089.  
  1090. if(risposta_http[x-1] == '\x0a' && risposta_http[x-3] == '\x0a')//controllo per vedere se l'header è finito
  1091. break;
  1092. }
  1093. risposta_http[x] = '\0';
  1094.  
  1095. #ifdef DEBUG_MODE
  1096. printf("id: %d\n%s\n%s\n",id,richiesta_http,risposta_http);
  1097. #endif
  1098.  
  1099. //verifichiamo se tutto ok e iniziamo a scaricare
  1100. if( strncmp("206", &risposta_http[9], 3) == 0 ){
  1101.  
  1102. download_buffer = new char[_buffer_size]; //alloco la memoria per il buffer
  1103. if(download->multidownload_points[id][1] == download->multidownload_points[id][0])
  1104. file_stream = fopen(dati->file_parziale, "wb"); //apro il file in cui salvare i dati
  1105. else
  1106. file_stream = fopen(dati->file_parziale, "ab"); //apro il file in cui salvare i dati
  1107.  
  1108. //riceviamo risposta: file
  1109. while (1){ //prendiamo il file un po alla volta
  1110. downloaded_bytes = recv(sock, download_buffer, _buffer_size, 0);
  1111.  
  1112. if(downloaded_bytes <= 0)
  1113. break;
  1114.  
  1115. written_bytes = fwrite(download_buffer, 1, downloaded_bytes, file_stream); //scrivo i dati
  1116. total_downloaded_bytes += downloaded_bytes;
  1117. total_written_bytes += written_bytes;
  1118.  
  1119. //aggiorno la situazione nella matrice download_points
  1120. download->multidownload_points[id][1] += downloaded_bytes;
  1121.  
  1122. #ifdef DEBUG_MODE
  1123. printf("hd_connessione_multidownload_segmento() id %d: d:%d p:%d\n",
  1124. id, total_downloaded_bytes, (long)download->multidownload_points[id][1]);
  1125. #endif
  1126.  
  1127.  
  1128.  
  1129. if(download->status == HD_STATUS_STOPPED) //chiudiamo il processo se c'è l'ordine di stop
  1130. break;
  1131.  
  1132. if(download->status == HD_STATUS_PAUSED || download->status == HD_STATUS_SAVED) //chiudiamo il processo se siamo in pausa
  1133. break;
  1134. }
  1135.  
  1136. fclose(file_stream); //chiudiamo file
  1137. delete [] download_buffer; //disallochiamo buffer
  1138.  
  1139. }
  1140. else if( strncmp("503", &risposta_http[9], 3) == 0 ){
  1141.  
  1142. #ifdef DEBUG_MODE
  1143. printf("hd_connessione_multidownload_segmento() id %d: ricevuta risposta 503, aspettiamo 10 secondi\n", id);
  1144. #endif
  1145.  
  1146. Sleep(10000);
  1147.  
  1148. delete [] richiesta_http;
  1149. delete [] risposta_http;
  1150.  
  1151. shutdown(sock, 2);
  1152. closesocket(sock);
  1153. WSACleanup();
  1154.  
  1155. download->multidownload_points[id][2] = 0; //segnaliamo che il processo si sta chiudendo
  1156. return 0;
  1157. }
  1158. else if( strncmp("416", &risposta_http[9], 3) == 0 ){
  1159.  
  1160. #ifdef DEBUG_MODE
  1161. printf("ERROR hd_connessione_multidownload_segmento() id %d: ricevuta risposta 416, assumiamo di aver finito\n", id);
  1162. #endif
  1163.  
  1164. delete [] richiesta_http;
  1165. delete [] risposta_http;
  1166.  
  1167. shutdown(sock, 2);
  1168. closesocket(sock);
  1169. WSACleanup();
  1170.  
  1171. download->multidownload_points[id][2] = 2; //segnaliamo che il processo si sta chiudendo
  1172. return 0;
  1173. }
  1174. else{
  1175.  
  1176. #ifdef DEBUG_MODE
  1177. printf("ERROR hd_connessione_multidownload_segmento() id %d: il serve ci ha negato il download parziale 206 :(\n", id);
  1178. #endif
  1179.  
  1180. delete [] richiesta_http;
  1181. delete [] risposta_http;
  1182.  
  1183. shutdown(sock, 2);
  1184. closesocket(sock);
  1185. WSACleanup();
  1186.  
  1187. download->multidownload_points[id][2] = 0; //segnaliamo che il processo si sta chiudendo
  1188. return 0;
  1189. }
  1190.  
  1191. delete [] richiesta_http;
  1192. delete [] risposta_http;
  1193.  
  1194. shutdown(sock, 2);
  1195. closesocket(sock);
  1196. WSACleanup();
  1197.  
  1198. if(download->multidownload_points[id][1] >= download->multidownload_points[id+1][0]-1){
  1199. download->multidownload_points[id][2] = 2; //segnaliamo che il processo ha scaricato tutto
  1200. }
  1201. else
  1202. download->multidownload_points[id][2] = 0; //segnaliamo che il processo si sta chiudendo
  1203. return 1;
  1204. }
  1205.  
  1206. int hd_multidownload_files_assembler(http_download *download, partial_download_data *dati){
  1207. long x;
  1208.  
  1209. FILE *f_stream;
  1210. FILE *pf_stream;
  1211. char *pf_name;
  1212. char *copy_buffer;
  1213. long bytes_copied, total_bytes_copied=0, ps_size;
  1214.  
  1215. pf_name = new char[10000];
  1216. copy_buffer = new char[download->buffer_size];
  1217.  
  1218. f_stream = fopen(download->file,"wb"); //apriamo file generale
  1219.  
  1220. //apriamo i file parziali uno ad uno e li copiamo nel file generale
  1221. for(x=0; x<download->multidownload ;x++){
  1222. pf_stream = fopen(dati[x].file_parziale, "rb");
  1223. if(pf_stream == NULL)
  1224. return 0;
  1225.  
  1226. ps_size = (long)(download->multidownload_points[x+1][0]-download->multidownload_points[x][0]); //grandezza segmento
  1227.  
  1228. total_bytes_copied=0;
  1229. while(1){
  1230. bytes_copied = fread(copy_buffer,1,download->buffer_size,pf_stream);
  1231. if(bytes_copied<=0)
  1232. break;
  1233.  
  1234. if(total_bytes_copied+bytes_copied > ps_size)
  1235. fwrite(copy_buffer, 1, ps_size-total_bytes_copied, f_stream);
  1236. else
  1237. fwrite(copy_buffer, 1, bytes_copied, f_stream);
  1238.  
  1239. total_bytes_copied += bytes_copied;
  1240. }
  1241.  
  1242. fclose(pf_stream);
  1243. }
  1244.  
  1245. fclose(f_stream);
  1246.  
  1247. delete [] pf_name;
  1248. delete [] copy_buffer;
  1249.  
  1250. return 1;
  1251. }
  1252.  
  1253. int hd_is_file(char *pathname){
  1254. FILE *file;
  1255. file = fopen(pathname, "rb");
  1256. if(file == NULL)
  1257. return 0;
  1258. fclose(file);
  1259. return 1;
  1260. }