Annotation of parser3/src/types/pa_vfile.C, revision 1.82
1.34 paf 1:
1.5 paf 2: /** @file
1.14 paf 3: Parser: @b file parser type.
1.3 paf 4:
1.81 moko 5: Copyright (c) 2001-2023 Art. Lebedev Studio (http://www.artlebedev.com)
6: Authors: Konstantin Morshnev <moko@design.ru>, Alexandr Petrosian <paf@design.ru>
1.30 paf 7: */
1.3 paf 8:
1.37 paf 9: #include "classes.h"
1.78 moko 10: #include "pa_base64.h"
1.1 paf 11: #include "pa_vfile.h"
12: #include "pa_vstring.h"
1.3 paf 13: #include "pa_vint.h"
1.70 moko 14: #include "pa_charsets.h"
1.50 misha 15: #include "pa_request.h"
1.1 paf 16:
1.82 ! moko 17: volatile const char * IDENT_PA_VFILE_C="$Id: pa_vfile.C,v 1.81 2023/09/26 20:49:12 moko Exp $" IDENT_PA_VFILE_H;
1.51 moko 18:
1.37 paf 19: // externs
20:
21: extern Methoded* file_class;
22:
23: // defines for statics
24:
25: #define SIZE_NAME "size"
26: #define TEXT_NAME "text"
27:
1.50 misha 28: #define MODE_VALUE_TEXT "text"
29: #define MODE_VALUE_BINARY "binary"
30:
1.58 moko 31: #define CONTENT_TYPE_TEXT "text/plain"
32: #define CONTENT_TYPE_BINARY "application/octet-stream"
33:
1.37 paf 34: // statics
35:
36: static const String size_name(SIZE_NAME);
37: static const String text_name(TEXT_NAME);
1.50 misha 38:
39: static const String mode_value_text(MODE_VALUE_TEXT);
40: static const String mode_value_binary(MODE_VALUE_BINARY);
1.37 paf 41:
1.58 moko 42: static const String content_type_text(CONTENT_TYPE_TEXT);
43: static const String content_type_binary(CONTENT_TYPE_BINARY);
44:
1.59 moko 45: inline bool content_type_is_default(Value *content_type){
46: if(content_type){
47: const String *ct=content_type->get_string();
48: return ct == &content_type_text || ct == &content_type_binary;
49: }
50: return true;
51: }
52:
1.37 paf 53: // methods
54:
55: VStateless_class *VFile::get_class() { return file_class; }
56:
1.76 moko 57: HashStringValue *VFile::get_hash() { Value *prefetch PA_ATTR_UNUSED =get_element(text_name); return &ffields; }
1.74 moko 58:
59:
1.61 moko 60: void VFile::set_all(bool atainted, bool ais_text_mode, const char* avalue_ptr, size_t avalue_size, const String* afile_name) {
1.8 paf 61: fvalue_ptr=avalue_ptr;
62: fvalue_size=avalue_size;
1.53 misha 63:
1.43 misha 64: ftext_tainted=atainted;
1.60 moko 65: fis_text_content=ais_text_mode;
1.8 paf 66:
1.10 paf 67: ffields.clear();
1.43 misha 68:
1.60 moko 69: set_name(afile_name);
1.73 moko 70: ffields.put(size_name, new VDouble(fvalue_size));
1.58 moko 71: set_mode(ais_text_mode);
1.54 moko 72: }
1.53 misha 73:
1.54 moko 74: void VFile::set(bool atainted, bool ais_text_mode, char* avalue_ptr, size_t avalue_size, const String* afile_name, Value* acontent_type, Request* r) {
75: if(ais_text_mode && avalue_ptr && avalue_size) {
76: fix_line_breaks(avalue_ptr, avalue_size);
77: }
1.61 moko 78: set_all(atainted, ais_text_mode, avalue_ptr, avalue_size, afile_name);
1.60 moko 79: set_content_type(acontent_type, afile_name, r);
1.50 misha 80: }
81:
1.54 moko 82: void VFile::set_binary(bool atainted, const char* avalue_ptr, size_t avalue_size, const String* afile_name, Value* acontent_type, Request* r) {
1.61 moko 83: set_all(atainted, false, avalue_ptr, avalue_size, afile_name);
1.60 moko 84: set_content_type(acontent_type, afile_name, r);
85: }
86:
87: void VFile::set_binary_string(bool atainted, const char* avalue_ptr, size_t avalue_size) {
1.61 moko 88: set_all(atainted, false, avalue_ptr, avalue_size, 0);
1.54 moko 89: }
1.53 misha 90:
1.71 moko 91: void VFile::set(VFile& avfile, bool *ais_text_mode, const String* afile_name, Value* acontent_type, Request* r) {
1.58 moko 92: fvalue_ptr=avfile.fvalue_ptr;
93: fvalue_size=avfile.fvalue_size;
94: ftext_tainted=avfile.ftext_tainted;
1.69 moko 95: fis_text_mode=avfile.fis_text_mode;
1.58 moko 96: fis_text_content=avfile.fis_text_content;
1.53 misha 97:
98: ffields.clear();
1.50 misha 99: for(HashStringValue::Iterator i(avfile.ffields); i; i.next())
1.53 misha 100: if(i.key() != text_name) // do not copy cached .text value
1.58 moko 101: ffields.put(*new String(i.key(), String::L_TAINTED), i.value());
1.54 moko 102:
1.71 moko 103: if(ais_text_mode)
104: set_mode(*ais_text_mode);
1.58 moko 105:
106: if(afile_name)
107: set_name(afile_name);
108:
1.71 moko 109: if(acontent_type || afile_name || ( ais_text_mode && content_type_is_default(ffields.get(content_type_name)) ))
1.58 moko 110: set_content_type(acontent_type, afile_name, r);
1.53 misha 111: }
112:
113: const char* VFile::text_cstr() {
114: const char* p=value_ptr();
1.54 moko 115: if(fis_text_content)
1.53 misha 116: return p;
117:
118: size_t size=fvalue_size;
119:
120: if(const char *premature_zero_pos=(const char *)memchr(p, 0, size))
121: size=premature_zero_pos-p;
122:
1.63 moko 123: char *copy_ptr=size?pa_strdup(p, size):0;
1.54 moko 124: // text mode but binary content
1.53 misha 125: if(fis_text_mode && size)
126: fix_line_breaks(copy_ptr, size);
127: return copy_ptr;
1.50 misha 128: }
129:
1.53 misha 130: void VFile::set_mode(bool ais_text_mode){
131: fis_text_mode=ais_text_mode;
1.56 moko 132: if(fvalue_ptr)
133: ffields.put(mode_name, new VString(ais_text_mode? mode_value_text : mode_value_binary ));
1.50 misha 134: }
135:
136: void VFile::set_name(const String* afile_name){
1.79 moko 137: const char *lfile_name;
1.57 misha 138: if(afile_name && !afile_name->is_empty()) {
1.67 moko 139: if(afile_name->starts_with("http://") || afile_name->starts_with("https://")){
140: size_t query=afile_name->pos('?');
141: if(query!=STRING_NOT_FOUND)
142: afile_name=&afile_name->mid(0,query);
143: }
1.79 moko 144: lfile_name=pa_filename(afile_name->taint_cstr(String::L_FILE_SPEC));
1.66 moko 145: if(!lfile_name[0])
1.79 moko 146: lfile_name=NONAME_DAT;
1.14 paf 147: } else
1.79 moko 148: lfile_name=NONAME_DAT;
1.50 misha 149:
1.53 misha 150: ffields.put(name_name, new VString(*new String(lfile_name, String::L_FILE_SPEC)));
1.50 misha 151: }
1.43 misha 152:
1.50 misha 153: void VFile::set_content_type(Value* acontent_type, const String* afile_name, Request* r){
154: if(!acontent_type && afile_name && r)
155: acontent_type=new VString(r->mime_type_of(afile_name));
1.43 misha 156:
1.58 moko 157: if(!acontent_type)
158: acontent_type=new VString(fis_text_mode ? content_type_text : content_type_binary);
159:
160: ffields.put(content_type_name, acontent_type);
1.43 misha 161: }
162:
1.70 moko 163: Charset* VFile::detect_binary_charset(Charset *charset){
164: if(!charset)
1.68 moko 165: if(Value* content_type=ffields.get(content_type_name))
166: if(const String *ct=content_type->get_string())
1.70 moko 167: charset=detect_charset(ct->cstr());
1.72 moko 168: return pa_charsets.checkBOM((char*&)fvalue_ptr, fvalue_size, charset); // checkBOM can alter ptr, but not the content
1.68 moko 169: }
170:
171: void VFile::transcode(Charset& from_charset, Charset& to_charset){
172: String::C result=Charset::transcode(String::C(fvalue_ptr, fvalue_size), from_charset, to_charset);
173: fvalue_ptr=result.str;
174: fvalue_size=result.length;
175: ffields.put(size_name, new VInt(fvalue_size));
176: }
177:
1.46 misha 178: void VFile::save(Request_charsets& charsets, const String& file_spec, bool is_text, Charset* asked_charset) {
179: if(fvalue_ptr)
180: file_write(charsets, file_spec, fvalue_ptr, fvalue_size, is_text, false/*do_append*/, asked_charset);
181: else
1.58 moko 182: throw Exception(PARSER_RUNTIME, &file_spec, "saving stat-ed file");
1.46 misha 183: }
184:
1.50 misha 185: bool VFile::is_text_mode(const String& mode) {
186: if(mode==mode_value_text)
187: return true;
188: if(mode==mode_value_binary)
189: return false;
1.82 ! moko 190: throw Exception(PARSER_RUNTIME, &mode, "is an invalid mode, must be either '" MODE_VALUE_TEXT "' or '" MODE_VALUE_BINARY "'");
1.50 misha 191: }
1.58 moko 192:
1.68 moko 193: bool VFile::is_valid_mode(const String& mode) {
1.50 misha 194: return (mode==mode_value_text || mode==mode_value_binary);
195: }
196:
1.45 misha 197: Value* VFile::get_element(const String& aname) {
1.43 misha 198: Value* result;
199:
200: // $method
1.45 misha 201: if(result=VStateless_object::get_element(aname))
1.43 misha 202: return result;
203:
204: // $field
205: if(result=ffields.get(aname))
206: return result;
207:
208: // $text - if not cached
1.53 misha 209: if(aname == text_name && fvalue_ptr && fvalue_size) {
1.43 misha 210: // assigned file have ptr and we really have some bytes
1.42 misha 211:
1.53 misha 212: result=new VString(*new String(text_cstr(), ftext_tainted ? String::L_TAINTED : String::L_AS_IS));
1.42 misha 213:
1.53 misha 214: // cache it
1.43 misha 215: ffields.put(text_name, result);
1.35 paf 216:
217: return result;
1.43 misha 218: }
1.35 paf 219:
1.43 misha 220: return 0;
1.3 paf 221: }
1.48 misha 222:
1.52 moko 223: const String* VFile::get_json_string(Json_options& options){
1.49 moko 224: String& result=*new String("{\n", String::L_AS_IS);
225:
226: String * indent=NULL;
227:
1.52 moko 228: if (options.indent){
229: indent = new String(",\n\t", String::L_AS_IS); *indent << options.indent << "\"";
230: result << "\t" << options.indent;
1.49 moko 231: }
232:
233: result << "\"class\":\"file\"";
1.48 misha 234:
235: for(HashStringValue::Iterator i(ffields); i; i.next() ){
236: String::Body key=i.key();
237: if(key != text_name){
1.49 moko 238: indent ? result << *indent : result << ",\n\"";
239: result << String(key, String::L_JSON) << "\":" << *i.value()->get_json_string(options);
1.48 misha 240: }
241: }
242:
243: if(fvalue_ptr){
1.52 moko 244: switch(options.file){
1.48 misha 245: case Json_options::F_BASE64:
246: {
1.49 moko 247: indent ? result << *indent : result << ",\n\"";
248: result << "base64\":\"";
1.48 misha 249: const char* encoded=pa_base64_encode(fvalue_ptr, fvalue_size);
1.55 moko 250: result.append_help_length(encoded, 0, String::L_JSON);
1.49 moko 251: result << "\"";
1.48 misha 252: break;
253: }
254: case Json_options::F_TEXT:
255: {
1.49 moko 256: indent ? result << *indent : result << ",\n\"";
257: result << "text\":\"";
1.55 moko 258: result.append_help_length(text_cstr(), 0, String::L_JSON);
1.49 moko 259: result << "\"";
1.48 misha 260: break;
261: }
1.64 moko 262: case Json_options::F_BODYLESS: break;
1.48 misha 263: }
264: }
265:
1.52 moko 266: result << "\n" << options.indent << "}";
1.49 moko 267: return &result;
1.48 misha 268: }
E-mail: