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