xref: /aosp_15_r20/external/mtools/unix2dos.c (revision d5c9a868b113e0ec0db2f27bc2ce8a253e77c4b0)
1 /*  Copyright 1996,1997,1999,2001-2003,2008,2009,2021 Alain Knaff.
2  *  This file is part of mtools.
3  *
4  *  Mtools is free software: you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation, either version 3 of the License, or
7  *  (at your option) any later version.
8  *
9  *  Mtools is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "sysincludes.h"
19 #include "msdos.h"
20 #include "mtools.h"
21 #include "codepage.h"
22 
23 #define U2D_BUFSIZE 4096
24 
25 typedef struct Filter_t {
26 	struct Stream_t head;
27 
28 	char buffer[U2D_BUFSIZE];
29 
30 	size_t readBytes; /* how many bytes read into buffer */
31 	size_t bufPos; /* position in buffer */
32 
33 	bool pendingNl;
34 	bool eof;
35 } Filter_t;
36 
37 /* Add CR before NL, and 0x1a at end of file */
read_filter(Stream_t * Stream,char * output,size_t len)38 static ssize_t read_filter(Stream_t *Stream, char *output, size_t len)
39 {
40 	DeclareThis(Filter_t);
41 	size_t i;
42 
43 	if(This->eof)
44 		return 0;
45 
46 	for(i=0; i < len && !This->eof; i++) {
47 		char c;
48 		if(This->pendingNl) {
49 			c='\n';
50 			This->pendingNl=false;
51 		} else {
52 			if(This->bufPos == This->readBytes) {
53 				ssize_t ret = READS(This->head.Next,
54 						    This->buffer,
55 						    U2D_BUFSIZE);
56 				if(ret < 0) {
57 					/* an error */
58 					/* If we already have read some data,
59 					 * first return count of that data
60 					 * before returning error */
61 					if(i == 0)
62 						return -1;
63 					else
64 						break;
65 				}
66 				This->readBytes = (size_t) ret;
67 				This->bufPos = 0;
68 			}
69 
70 			if(This->bufPos == This->readBytes) {
71 				/* Still at end of buffer, must be end
72 				   of file */
73 				c='\032';
74 				This->eof=true;
75 			} else {
76 				c = This->buffer[This->bufPos++];
77 				if(c == '\n') {
78 					This->pendingNl=true;
79 					c = '\r';
80 				}
81 			}
82 		}
83 		output[i]=c;
84 	}
85 
86 	return (ssize_t) i;
87 }
88 
89 static Class_t FilterClass = {
90 	read_filter,
91 	0,
92 	0,
93 	0,
94 	0, /* flush */
95 	0,
96 	0, /* set geometry */
97 	get_data_pass_through,
98 	0,
99 	0, /* get_dosconvert */
100 	0  /* discard */
101 };
102 
open_unix2dos(Stream_t * Next,int convertCharset UNUSEDP)103 Stream_t *open_unix2dos(Stream_t *Next, int convertCharset UNUSEDP)
104 {
105 	Filter_t *This;
106 
107 	This = New(Filter_t);
108 	if (!This)
109 		return NULL;
110 	init_head(&This->head, &FilterClass, Next);
111 
112 	This->readBytes = This->bufPos = 0;
113 	This->pendingNl = false;
114 	This->eof = false;
115 
116 	return &This->head;
117 }
118